跳转至

E2E 命令

此命令调用 e2e-runner 代理,使用 Playwright 创建、维护并运行 E2E 测试。

此命令的作用

  1. 创建测试旅程 - 针对用户流程创建 Playwright 测试
  2. 运行 E2E 测试 - 在多个浏览器中运行测试
  3. 捕获工件 - 失败时捕获截图、视频和追踪
  4. 上传结果 - HTML 报告及 JUnit XML
  5. 识别不稳定测试 - 隔离不稳定测试

使用时机

应在以下情况使用 /e2e: - 核心用户旅程测试(登录、交易、支付) - 验证多步骤流程能否以 E2E 方式正常工作 - UI 交互与导航测试 - 验证前端与后端之间的集成 - 生产部署准备

工作方式

e2e-runner 代理执行的操作:

  1. 分析用户流程并识别测试场景
  2. 使用 Page Object Model 模式创建 Playwright 测试
  3. 在多个浏览器(Chrome、Firefox、Safari)中运行测试
  4. 通过截图、视频和追踪捕获失败
  5. 根据结果和工件生成报告
  6. 识别不稳定测试并给出修复建议

使用示例

User: /e2e 마켓 검색 및 조회 흐름 테스트

Agent (e2e-runner):
# E2E 테스트 생성: 마켓 검색 및 조회 흐름

## 식별된 테스트 시나리오

**사용자 여정:** 마켓 검색 → 결과 확인 → 마켓 클릭 → 상세 정보 확인

**테스트 범위:**
1. 마켓 페이지로 이동
2. 시맨틱 검색 수행
3. 검색 결과 확인
4. 첫 번째 결과 클릭
5. 마켓 상세 페이지 로드 확인
6. 차트 렌더링 확인

## 생성된 테스트 코드

```typescript
// tests/e2e/markets/search-and-view.spec.ts
import { test, expect } from '@playwright/test'
import { MarketsPage } from '../../pages/MarketsPage'
import { MarketDetailsPage } from '../../pages/MarketDetailsPage'

test.describe('Market Search and View Flow', () => {
  test('user can search markets and view details', async ({ page }) => {
    // 1. 마켓 페이지로 이동
    const marketsPage = new MarketsPage(page)
    await marketsPage.goto()

    // 페이지 로드 확인
    await expect(page).toHaveTitle(/Markets/)
    await expect(page.locator('h1')).toContainText('Markets')

    // 2. 시맨틱 검색 수행
    await marketsPage.searchMarkets('election')

    // API 응답 대기
    await page.waitForResponse(resp =>
      resp.url().includes('/api/markets/search') && resp.status() === 200
    )

    // 3. 검색 결과 확인
    const marketCards = marketsPage.marketCards
    await expect(marketCards.first()).toBeVisible()
    const resultCount = await marketCards.count()
    expect(resultCount).toBeGreaterThan(0)

    // 검색 결과 스크린샷 촬영
    await page.screenshot({ path: 'artifacts/search-results.png' })

    // 4. 첫 번째 결과 클릭
    const firstMarketTitle = await marketCards.first().textContent()
    await marketCards.first().click()

    // 5. 마켓 상세 페이지 로드 확인
    await expect(page).toHaveURL(/\/markets\/[a-z0-9-]+/)

    const detailsPage = new MarketDetailsPage(page)
    await expect(detailsPage.marketName).toBeVisible()
    await expect(detailsPage.marketDescription).toBeVisible()

    // 6. 차트 렌더링 확인
    await expect(detailsPage.priceChart).toBeVisible()

    // 마켓 이름 일치 확인
    const detailsTitle = await detailsPage.marketName.textContent()
    expect(detailsTitle?.toLowerCase()).toContain(
      firstMarketTitle?.toLowerCase().substring(0, 20) || ''
    )

    // 마켓 상세 스크린샷 촬영
    await page.screenshot({ path: 'artifacts/market-details.png' })
  })

  test('search with no results shows empty state', async ({ page }) => {
    const marketsPage = new MarketsPage(page)
    await marketsPage.goto()

    // 존재하지 않는 마켓 검색
    await marketsPage.searchMarkets('xyznonexistentmarket123456')

    // 빈 상태 확인
    await expect(page.locator('[data-testid="no-results"]')).toBeVisible()
    await expect(page.locator('[data-testid="no-results"]')).toContainText(
      /no.*results|no.*markets/i
    )

    const marketCount = await marketsPage.marketCards.count()
    expect(marketCount).toBe(0)
  })

  test('can clear search and see all markets again', async ({ page }) => {
    const marketsPage = new MarketsPage(page)
    await marketsPage.goto()

    // 초기 마켓 수
    const initialCount = await marketsPage.marketCards.count()

    // 검색 수행
    await marketsPage.searchMarkets('trump')
    await page.waitForLoadState('networkidle')

    // 필터링된 결과 확인
    const filteredCount = await marketsPage.marketCards.count()
    expect(filteredCount).toBeLessThan(initialCount)

    // 검색 초기화
    await marketsPage.searchInput.clear()
    await page.waitForLoadState('networkidle')

    // 모든 마켓이 다시 표시되는지 확인
    const finalCount = await marketsPage.marketCards.count()
    expect(finalCount).toBe(initialCount)
  })
})
```

## 테스트 실행

```bash
# 생성된 테스트 실행
npx playwright test tests/e2e/markets/search-and-view.spec.ts

Running 3 tests using 3 workers

  ✓  [chromium] › search-and-view.spec.ts:5:3 › user can search markets and view details (4.2s)
  ✓  [chromium] › search-and-view.spec.ts:52:3 › search with no results shows empty state (1.8s)
  ✓  [chromium] › search-and-view.spec.ts:67:3 › can clear search and see all markets again (2.9s)

  3 passed (9.1s)

생성된 아티팩트:
- artifacts/search-results.png
- artifacts/market-details.png
- playwright-report/index.html
```

## 테스트 보고서

```
╔══════════════════════════════════════════════════════════════╗
║                    E2E 테스트 결과                            ║
╠══════════════════════════════════════════════════════════════╣
║ 상태:       PASS: 모든 테스트 통과                                ║
║ 전체:       3개 테스트                                        ║
║ 통과:       3 (100%)                                         ║
║ 실패:       0                                                ║
║ 불안정:     0                                                ║
║ 소요시간:   9.1s                                             ║
╚══════════════════════════════════════════════════════════════╝

아티팩트:
 스크린샷: 2개 파일
 비디오: 0개 파일 (실패 시에만)
 트레이스: 0개 파일 (실패 시에만)
 HTML 보고서: playwright-report/index.html

보고서 확인: npx playwright show-report
```

PASS: CI/CD 통합 준비가 완료된 E2E 테스트 모음!

测试工件

运行测试时会捕获以下工件:

所有测试: - 包含时间线和结果的 HTML 报告 - 用于 CI 集成的 JUnit XML

仅在失败时: - 失败状态的截图 - 测试的视频录制 - 用于调试的追踪文件(分步骤回放) - 网络日志 - 控制台日志

查看工件

# 브라우저에서 HTML 보고서 확인
npx playwright show-report

# 특정 트레이스 파일 확인
npx playwright show-trace artifacts/trace-abc123.zip

# 스크린샷은 artifacts/ 디렉토리에 저장됨
open artifacts/search-results.png

检测不稳定测试

当测试间歇性失败时:

WARNING:  불안정한 테스트 감지됨: tests/e2e/markets/trade.spec.ts

테스트가 10회 중 7회 통과 (70% 통과율)

일반적인 실패 원인:
"요소 '[data-testid="confirm-btn"]'을 대기하는 중 타임아웃"

권장 수정 사항:
1. 명시적 대기 추가: await page.waitForSelector('[data-testid="confirm-btn"]')
2. 타임아웃 증가: { timeout: 10000 }
3. 컴포넌트의 레이스 컨디션 확인
4. 애니메이션에 의해 요소가 숨겨져 있지 않은지 확인

격리 권장: 수정될 때까지 test.fixme()로 표시

浏览器配置

默认情况下,测试会在多个浏览器中运行: - Chromium(桌面 Chrome) - Firefox(桌面) - WebKit(桌面 Safari) - Mobile Chrome(可选)

您可以在 playwright.config.ts 中调整浏览器。

CI/CD 集成

添加到 CI 管道:

# .github/workflows/e2e.yml
- name: Install Playwright
  run: npx playwright install --with-deps

- name: Run E2E tests
  run: npx playwright test

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

最佳实践

应做事项: - 使用 Page Object Model 提高可维护性 - 使用 data-testid 属性作为选择器 - 等待 API 响应,而不是使用任意超时 - 使用 E2E 测试核心用户旅程 - 在合并到 main 之前运行测试 - 测试失败时检查产物

不应做的事项: - 使用脆弱的选择器(CSS 类可能会更改) - 测试实现细节 - 针对生产环境运行测试 - 忽略不稳定的测试 - 跳过失败时的产物检查 - 使用 E2E 测试所有边缘情况(应使用单元测试)

与其他命令的集成

  • 使用 /plan 识别要测试的核心旅程
  • 使用 /tdd 进行单元测试(更快、更精细)
  • 使用 /e2e 进行集成和用户旅程测试
  • 使用 /code-review 验证测试质量

此命令会调用 e2e-runner 代理: ~/.claude/agents/e2e-runner.md

快速命令

# 모든 E2E 테스트 실행
npx playwright test

# 특정 테스트 파일 실행
npx playwright test tests/e2e/markets/search.spec.ts

# headed 모드로 실행 (브라우저 표시)
npx playwright test --headed

# 테스트 디버그
npx playwright test --debug

# 테스트 코드 생성
npx playwright codegen http://localhost:3000

# 보고서 확인
npx playwright show-report

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 ev/ECC