QA回归测试自动化 qa-regression

这个技能用于自动化QA回归测试,通过Playwright构建可重用的测试技能,覆盖登录流程、仪表板检查、用户创建等常见测试场景,确保测试的一致性和效率。关键词:自动化测试、回归测试、Playwright、QA、测试技能、持续集成、Web测试。

测试 0 次安装 0 次浏览 更新于 3/8/2026

name: qa-regression description: 使用可重用的测试技能自动化QA回归测试。创建登录流程、仪表板检查、用户创建和其他常见测试场景,确保一致运行。 license: MIT

QA回归测试

使用Playwright构建和运行自动化回归测试。每个测试都是可重用的技能,可以组合成完整的测试套件。

设置

npm init -y
npm install playwright @playwright/test
npx playwright install

测试结构

tests/文件夹中创建测试:

tests/
├── auth/
│   ├── login.spec.ts
│   └── logout.spec.ts
├── dashboard/
│   └── load.spec.ts
├── users/
│   ├── create.spec.ts
│   └── delete.spec.ts
└── regression.spec.ts   # 完整套件

常见测试技能

登录测试

// tests/auth/login.spec.ts
import { test, expect } from '@playwright/test';

test.describe('登录流程', () => {
  test('应使用有效凭据登录', async ({ page }) => {
    await page.goto('/login');

    await page.fill('[data-testid="email"]', process.env.TEST_EMAIL!);
    await page.fill('[data-testid="password"]', process.env.TEST_PASSWORD!);
    await page.click('[data-testid="submit"]');

    // 验证重定向到仪表板
    await expect(page).toHaveURL(/dashboard/);
    await expect(page.locator('[data-testid="user-menu"]')).toBeVisible();
  });

  test('应显示无效凭据错误', async ({ page }) => {
    await page.goto('/login');

    await page.fill('[data-testid="email"]', 'wrong@example.com');
    await page.fill('[data-testid="password"]', 'wrongpassword');
    await page.click('[data-testid="submit"]');

    await expect(page.locator('[data-testid="error-message"]')).toBeVisible();
  });
});

仪表板加载测试

// tests/dashboard/load.spec.ts
import { test, expect } from '@playwright/test';
import { login } from '../helpers/auth';

test.describe('仪表板', () => {
  test.beforeEach(async ({ page }) => {
    await login(page);
  });

  test('应在3秒内加载仪表板', async ({ page }) => {
    const start = Date.now();
    await page.goto('/dashboard');
    await page.waitForSelector('[data-testid="dashboard-content"]');
    const loadTime = Date.now() - start;

    expect(loadTime).toBeLessThan(3000);
  });

  test('应显示所有小部件', async ({ page }) => {
    await page.goto('/dashboard');

    await expect(page.locator('[data-testid="stats-widget"]')).toBeVisible();
    await expect(page.locator('[data-testid="chart-widget"]')).toBeVisible();
    await expect(page.locator('[data-testid="activity-widget"]')).toBeVisible();
  });

  test('应在按钮点击时刷新数据', async ({ page }) => {
    await page.goto('/dashboard');

    const initialValue = await page.locator('[data-testid="last-updated"]').textContent();
    await page.click('[data-testid="refresh-button"]');
    await page.waitForTimeout(1000);
    const newValue = await page.locator('[data-testid="last-updated"]').textContent();

    expect(newValue).not.toBe(initialValue);
  });
});

创建用户测试

// tests/users/create.spec.ts
import { test, expect } from '@playwright/test';
import { login } from '../helpers/auth';
import { generateTestUser, deleteTestUser } from '../helpers/users';

test.describe('用户创建', () => {
  let testUser: { email: string; name: string };

  test.beforeEach(async ({ page }) => {
    await login(page);
    testUser = generateTestUser();
  });

  test.afterEach(async () => {
    // 清理
    await deleteTestUser(testUser.email);
  });

  test('应成功创建新用户', async ({ page }) => {
    await page.goto('/users/new');

    await page.fill('[data-testid="user-name"]', testUser.name);
    await page.fill('[data-testid="user-email"]', testUser.email);
    await page.selectOption('[data-testid="user-role"]', 'member');
    await page.click('[data-testid="create-user-btn"]');

    // 验证成功
    await expect(page.locator('[data-testid="success-toast"]')).toBeVisible();
    await expect(page).toHaveURL(/users/);

    // 验证用户出现在列表中
    await expect(page.locator(`text=${testUser.email}`)).toBeVisible();
  });

  test('应验证必填字段', async ({ page }) => {
    await page.goto('/users/new');
    await page.click('[data-testid="create-user-btn"]');

    await expect(page.locator('[data-testid="name-error"]')).toBeVisible();
    await expect(page.locator('[data-testid="email-error"]')).toBeVisible();
  });
});

共享助手

// tests/helpers/auth.ts
import { Page } from '@playwright/test';

export async function login(page: Page) {
  await page.goto('/login');
  await page.fill('[data-testid="email"]', process.env.TEST_EMAIL!);
  await page.fill('[data-testid="password"]', process.env.TEST_PASSWORD!);
  await page.click('[data-testid="submit"]');
  await page.waitForURL(/dashboard/);
}

export async function logout(page: Page) {
  await page.click('[data-testid="user-menu"]');
  await page.click('[data-testid="logout"]');
  await page.waitForURL(/login/);
}
// tests/helpers/users.ts
export function generateTestUser() {
  const id = Date.now();
  return {
    name: `测试用户 ${id}`,
    email: `test-${id}@example.com`,
  };
}

export async function deleteTestUser(email: string) {
  // API调用来清理测试用户
  await fetch(`${process.env.API_URL}/admin/users`, {
    method: 'DELETE',
    headers: {
      'Authorization': `Bearer ${process.env.ADMIN_TOKEN}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ email }),
  });
}

完整回归套件

// tests/regression.spec.ts
import { test } from '@playwright/test';

// 导入所有测试套件
import './auth/login.spec';
import './auth/logout.spec';
import './dashboard/load.spec';
import './users/create.spec';
import './users/delete.spec';

test.describe('完整回归套件', () => {
  // 测试按上述顺序运行
});

Playwright配置

// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,
  reporter: [
    ['html'],
    ['json', { outputFile: 'test-results.json' }],
  ],
  use: {
    baseURL: process.env.BASE_URL || 'http://localhost:3000',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
  },
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
    {
      name: 'firefox',
      use: { ...devices['Desktop Firefox'] },
    },
    {
      name: 'webkit',
      use: { ...devices['Desktop Safari'] },
    },
  ],
});

运行测试

# 运行所有测试
npx playwright test

# 运行特定测试文件
npx playwright test tests/auth/login.spec.ts

# 在UI模式下运行测试
npx playwright test --ui

# 在headed模式下运行(显示浏览器)
npx playwright test --headed

# 生成报告
npx playwright show-report

CI集成

# .github/workflows/regression.yml
name: 回归测试

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  schedule:
    - cron: '0 6 * * *'  # 每天上午6点

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: 安装依赖
        run: npm ci

      - name: 安装Playwright
        run: npx playwright install --with-deps

      - name: 运行测试
        run: npx playwright test
        env:
          BASE_URL: ${{ secrets.STAGING_URL }}
          TEST_EMAIL: ${{ secrets.TEST_EMAIL }}
          TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}

      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: playwright-report
          path: playwright-report/

最佳实践

  1. 使用data-testid属性 - 比CSS选择器更稳定
  2. 清理测试数据 - 总是删除创建的内容
  3. 避免硬编码等待 - 使用waitForSelector代替waitForTimeout
  4. 并行运行 - 在CI上更快反馈
  5. 失败时截图 - 更容易调试
  6. 环境变量 - 永不提交凭据

快速命令

任务 命令
运行所有 npx playwright test
运行一个文件 npx playwright test login.spec.ts
调试模式 npx playwright test --debug
UI模式 npx playwright test --ui
更新快照 npx playwright test --update-snapshots