帮助开发团队设计与优化 Playwright 端到端测试、配置流水线并降低用例不稳定性。
该技能材料显示其本质上是 Playwright E2E 测试模式文档/提示内容,未声明密钥需求或固定远程端点,且为开源 GitHub 来源并有很高社区采用度,整体风险偏低。需注意其内容涉及测试运行、浏览器访问、本地生成报告与截图等典型测试能力,但这些更符合常规留意项而非高风险红旗。
材料与客观检查项均表明无需密钥或环境变量,未见要求输入 API token、账号凭证或将凭证写入配置的说明,凭证泄露面较小。
虽未声明固定远程端点,但示例测试会通过 Playwright 访问目标应用与其接口,如 baseURL 或 /api/search;这属于 E2E 测试的常规网络访问能力。材料未显示将数据外发到无关第三方服务的具体红旗。
Playwright 测试本身意味着在本机/CI 中运行测试代码并驱动浏览器,这是此类工具的固有能力。当前材料更像模式文档,未见申请超出测试用途的系统权限或可疑执行链。
示例会在本地写入截图、trace、video、HTML/JUnit/JSON 报告等测试产物,可能包含页面内容或失败现场;这是常见测试数据落盘行为。未见声明读取或写入超出项目测试目录范围的敏感系统资源。
来源为 GitHub 开源仓库,且社区采用度很高(约 21 万 star),这些都是明显的降风险因素;当前材料也被标注为 prompt-only。虽许可证未声明、维护状态未知,仍未见闭源外发、失维来源或误导性安装指令等高风险红旗。
复制安装指令,让 AI 自动完成配置 · 推荐新手
请帮我安装 askskill 上的 "e2e-testing" 技能: 1. 下载 https://raw.githubusercontent.com/affaan-m/ECC/main/skills/e2e-testing/SKILL.md 2. 保存为 ~/.claude/skills/e2e-testing/SKILL.md 3. 装好后重载技能,告诉我可以用了
请为一个基于 Playwright 的 Web E2E 测试项目设计目录结构,采用 Page Object Model,包含登录、商品搜索和下单三个核心流程,并给出推荐的配置文件与示例测试代码。
返回清晰的项目结构、页面对象划分、配置建议,以及可直接参考的测试示例代码。
请把 Playwright 端到端测试接入 CI/CD,给我一份适用于 GitHub Actions 的工作流示例,要求包含依赖安装、浏览器缓存、测试执行、失败截图与 trace 文件上传。
输出完整的流水线配置方案,并说明测试产物保存与失败排查方式。
我有一批 Playwright 用例经常偶发失败,请分析常见 flaky test 原因,并提供等待策略、选择器优化、重试机制、测试隔离和调试 trace 的改进方案。
给出系统化的 flaky 测试治理建议,帮助提升测试稳定性与可维护性。
Comprehensive Playwright patterns for building stable, fast, and maintainable E2E test suites.
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
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()
}
}
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')
await expect(page.locator('[data-testid="no-results"]')).toBeVisible()
expect(await itemsPage.getItemCount()).toBe(0)
})
})
import { defineConfig, devices } from '@playwright/test'
export default defineConfig({
testDir: './tests/e2e',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: [
['html', { outputFolder: 'playwright-report' }],
['junit', { outputFile: 'playwright-results.xml' }],
['json', { outputFile: 'playwright-results.json' }]
],
use: {
baseURL: process.env.BASE_URL || 'http://localhost:3000',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
actionTimeout: 10000,
navigationTimeout: 30000,
},
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
{ name: 'webkit', use: { ...devices['Desktop Safari'] } },
{ name: 'mobile-chrome', use: { ...devices['Pixel 5'] } },
],
webServer: {
command: 'npm run dev',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
timeout: 120000,
},
})
test('flaky: complex search', async ({ page }) => {
test.fixme(true, 'Flaky - Issue #123')
// test code...
})
test('conditional skip', async ({ page }) => {
test.skip(process.env.CI, 'Flaky in CI - Issue #123')
// test code...
})
npx playwright test tests/search.spec.ts --repeat-each=10
npx playwright test tests/search.spec.ts --retries=3
Race conditions:
// Bad: assumes element is ready
await page.click('[data-testid="button"]')
// Good: auto-wait locator
…
为 Quarkus 项目执行发布前验证闭环,涵盖构建、测试、扫描与差异审查。
帮助开发者编写并运行基于 Markdown 的 Relay 端到端测试。