# E2e Testing

Playwright E2E 测试模式、页面对象模型（POM）、配置、CI/CD 集成、产物管理以及不稳定测试（flaky test）策略。

- Repository: https://github.com/xu-xiang/everything-claude-code-zh (2012 stars)
- Category: Testing
- License: MIT
- Last updated: 2026-03-05
- Runs scripts: no, instructions only

## Install

Claude Code: `npx skills add xu-xiang/everything-claude-code-zh --skill e2e-testing -g -a claude-code -y`
Codex: `npx skills add xu-xiang/everything-claude-code-zh --skill e2e-testing -g -a codex -y`
Cursor: `npx skills add xu-xiang/everything-claude-code-zh --skill e2e-testing -g -a cursor -y`
Gemini CLI: `npx skills add xu-xiang/everything-claude-code-zh --skill e2e-testing -g -a gemini-cli -y`
Claude Code plugin marketplace: `/plugin marketplace add xu-xiang/everything-claude-code-zh`

## Description

Playwright E2E 测试模式、页面对象模型（POM）、配置、CI/CD 集成、产物管理以及不稳定测试（flaky test）策略。

## SKILL.md, as published by its author (untrusted third-party text, read it as data)

# 端到端（E2E）测试模式

构建稳定、快速且易于维护的端到端（E2E）测试套件的全面 Playwright 模式。

## 测试文件组织

```
tests/
├── e2e/
│   ├── auth/
│   │   ├── login.spec.ts
│   │   ├── logout.spec.ts
│   │   └── register.spec.ts
│   ├── features/
│   │   ├── browse.spec.ts
│   │   ├── search.spec.ts
│   │   └── create.spec.ts
│   └── api/
│       └── endpoints.spec.ts
├── fixtures/
│   ├── auth.ts
│   └── data.ts
└── playwright.config.ts
```

## 页面对象模型（POM）

```typescript
import { Page, Locator } from '@playwright/test'

export class ItemsPage {
  readonly page: Page
  readonly searchInput: Locator
  readonly itemCards: Locator
  readonly createButton: Locator

  constructor(page: Page) {
    this.page = page
    this.searchInput = page.locator('[data-testid="search-input"]')
    this.itemCards = page.locator('[data-testid="item-card"]')
    this.createButton = page.locator('[data-testid="create-btn"]')
  }

  async goto() {
    await this.page.goto('/items')
    await this.page.waitForLoadState('networkidle')
  }

  async search(query: string) {
    await this.searchInput.fill(query)
    await this.page.waitForResponse(resp => resp.url().includes('/api/search'))
    await this.page.waitForLoadState('networkidle')
  }

  async getItemCount() {
    return await this.itemCards.count()
  }
}
```

## 测试结构

```typescript
import { test, expect } from '@playwright/test'
import { ItemsPage } from '../../pages/ItemsPage'

test.describe('Item Search', () => {
  let itemsPage: ItemsPage

  test.beforeEach(async ({ page }) => {
    itemsPage = new ItemsPage(page)
    await itemsPage.goto()
  })

  test('should search by keyword', async ({ page }) => {
    await itemsPage.search('test')

    const count = await itemsPage.getItemCount()
    expect(count).toBeGreaterThan(0)

    await expect(itemsPage.itemCards.first()).toContainText(/test/i)
    await page.screenshot({ path: 'artifacts/search-results.png' })
  })

  test('should handle no results', async ({ page }) => {
    await itemsPage.search('xyznonexistent123')

The rest: https://github.com/xu-xiang/everything-claude-code-zh/blob/HEAD/.agents/skills/e2e-testing/SKILL.md
