Build reliable, fast E2E test suites with Playwright and Cypress. Critical user journey coverage, flaky test elimination, CI/CD integration.
数据来源:ClawHub。 在 ClawSkills 查看
选择你使用的 Agent
方法一:命令行安装(推荐)
推荐(无需提前安装 clawhub)
npx clawhub@latest --dir ~/.claude/skills install e2e-testing-patterns或使用 clawhub CLI(需提前安装)
clawhub --dir ~/.claude/skills install e2e-testing-patterns⚠️ 需要 Node.js 18+,没有 Node?请使用下方方法二直接下载 ZIP。 安装 Node.js →
方法二:手动下载安装(无需 Node)
下载 ZIP,解压后将文件夹放到以下路径,重启 Agent 即可:
安装路径
~/.claude/skills/e2e-testing-patterns/💡解压后将文件夹放到上方路径,重启 Agent 即可生效
--- name: e2e-testing-patterns model: standard category: testing description: Build reliable, fast E2E test suites with Playwright and Cypress. Critical user journey coverage, flaky test elimination, CI/CD integration. version: 1.0 keywords: [e2e, end-to-end, playwright, cypress, browser testing, integration tests, test automation, flaky tests, visual regression] ---
> Test what users do, not how code works. E2E tests prove the system works as a whole — they're your confidence to ship.
npx clawhub@latest install e2e-testing-patterns
---
Provides patterns for building end-to-end test suites that:
---
/\
/E2E\ ← FEW: Critical paths only (this skill)
/─────\
/Integr\ ← MORE: Component interactions, API contracts
/────────\
/Unit Tests\ ← MANY: Fast, isolated, cover edge cases
/────────────\
| E2E Tests ✓ | NOT E2E Tests ✗ | |-------------|-----------------| | Critical user journeys (login → dashboard → action → logout) | Unit-level logic (use unit tests) | | Multi-step flows (checkout, onboarding wizard) | API contracts (use integration tests) | | Cross-browser compatibility | Edge cases (too slow, use unit tests) | | Real API integration | Internal implementation details | | Authentication flows | Component visual states (use Storybook) |
Rule of thumb: If it would devastate your business to break, E2E test it. If it's just inconvenient, test it faster with unit/integration tests.
---
| Principle | Why | How | |-----------|-----|-----| | Test behavior, not implementation | Survives refactors | Assert on user-visible outcomes, not DOM structure | | Independent tests | Parallelizable, debuggable | Each test creates its own data, cleans up after | | Deterministic waits | No flakiness | Wait for conditions, not fixed timeouts | | Stable selectors | Survives UI changes | Use data-testid, roles, labels — never CSS classes | | Fast feedback | Developers run them | Mock external services, parallelize, shard |
---
// playwright.config.ts
import { defineConfig, devices } from "@playwright/test";
export default defineConfig({
testDir: "./e2e",
timeout: 30000,
expect: { timeout: 5000 },
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: [["html"], ["junit", { outputFile: "results.xml" }]],
use: {
baseURL: "http://localhost:3000",
trace: "on-first-retry",
screenshot: "only-on-failure",
video: "retain-on-failure",
},
projects: [
{ name: "chromium", use: { ...devices["Desktop Chrome"] } },
{ name: "firefox", use: { ...devices["Desktop Firefox"] } },
{ name: "webkit", use: { ...devices["Desktop Safari"] } },
{ name: "mobile", use: { ...devices["iPhone 13"] } },
],
});
Encapsulate page logic. Tests read like user stories.
// pages/LoginPage.ts
import { Page, Locator } from "@playwright/test";
export class LoginPage {
readonly page: Page;
readonly emailInput: Locator;
readonly passwordInput: Locator;
readonly loginButton: Locator;
readonly errorMessage: Locator;
constructor(page: Page) {
this.page = page;
this.emailInput = page.getByLabel("Email");
this.passwordInput = page.getByLabel("Password");
this.loginButton = page.getByRole("button", { name: "Login" });
this.errorMessage = page.getByRole("alert");
}
async goto() {
await this.page.goto("/login");
}
async login(email: string, password: string) {
await this.emailInput.fill(email);
await this.passwordInput.fill(password);
await this.loginButton.click();
}
}
// tests/login.spec.ts
import { test, expect } from "@playwright/test";
import { LoginPage } from "../pages/LoginPage";
test("successful login redirects to dashboard", async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.login("[email protected]", "password123");
await expect(page).toHaveURL("/dashboard");
await expect(page.getByRole("heading", { name: "Dashboard" })).toBeVisible();
});
Create and clean up test data automatically.
// fixtures/test-data.ts
import { test as base } from "@playwright/test";
export const test = base.extend<{ testUser: TestUser }>({
testUser: async ({}, use) => {
// Setup: Create user
const user = await createTestUser({
email: `test-${Date.now()}@example.com`,
password: "Test123!@#",
});
await use(user);
// Teardown: Clean up
await deleteTestUser(user.id);
},
});
// Usage — testUser is created before, deleted after
test("user can update profile", async ({ page, testUser }) => {
await page.goto("/login");
await page.getByLabel("Email").fill(testUser.email);
// ...
});
Never use fixed timeouts. Wait for specific conditions.
// ❌ FLAKY: Fixed timeout
await page.waitForTimeout(3000);
// ✅ STABLE: Wait for conditions
await page.waitForLoadState("networkidle");
await page.waitForURL("/dashboard");
// ✅ BEST: Auto-waiting assertions
await expect(page.getByText("Welcome")).toBeVisible();
await expect(page.getByRole("button", { name: "Submit" })).toBeEnabled();
// Wait for API response
const responsePromise = page.waitForResponse(
(r) => r.url().includes("/api/users") && r.status() === 200
);
await page.getByRole("button", { name: "Load" }).click();
await responsePromise;
Isolate tests from real external services.
test("shows error when API fails", async ({ page }) => {
// Mock the API response
await page.route("**/api/users", (route) => {
route.fulfill({
status: 500,
body: JSON.stringify({ error: "Server Error" }),
});
});
await page.goto("/users");
await expect(page.getByText("Failed to load users")).toBeVisible();
});
test("handles slow network gracefully", async ({ page }) => {
await page.route("**/api/data", async (route) => {
await new Promise((r) => setTimeout(r, 3000)); // Simulate delay
await route.continue();
});
await page.goto("/dashboard");
await expect(page.getByText("Loading...")).toBeVisible();
});
---
// cypress/support/commands.ts
declare global {
namespace Cypress {
interface Chainable {
login(email: string, password: string): Chainable<void>;
dataCy(value: string): Chainable<JQuery<HTMLElement>>;
}
}
}
Cypress.Commands.add("login", (email, password) => {
cy.visit("/login");
cy.get('[data-testid="email"]').type(email);
cy.get('[data-testid="password"]').type(password);
cy.get('[data-testid="login-button"]').click();
cy.url().should("include", "/dashboard");
});
Cypress.Commands.add("dataCy", (value) => {
return cy.get(`[data-cy="${value}"]`);
});
// Usage
cy.login("[email protected]", "password");
cy.dataCy("submit-button").click();
// Mock API
cy.intercept("GET", "/api/users", {
statusCode: 200,
body: [{ id: 1, name: "John" }],
}).as("getUsers");
...安装 E2E Testing Patterns 后,可以对 AI 说这些话来触发它
Help me get started with E2E Testing Patterns
Explains what E2E Testing Patterns does, walks through the setup, and runs a quick demo based on your current project
Use E2E Testing Patterns to build reliable, fast E2E test suites with Playwright and Cypress
Invokes E2E Testing Patterns with the right parameters and returns the result directly in the conversation
What can I do with E2E Testing Patterns in my developer & devops workflow?
Lists the top use cases for E2E Testing Patterns, with example commands for each scenario
将技能文件夹放到 ~/.claude/skills/e2e-testing-patterns/ 目录(个人级,所有项目可用),或 .claude/skills/e2e-testing-patterns/(项目级)。重启 AI 客户端后,用 /e2e-testing-patterns 主动调用,或让 AI 根据上下文自动发现并使用。
E2E Testing Patterns 支持 Claude、Cursor、OpenClaw,可与这些 AI 平台无缝集成,扩展其能力。
E2E Testing Patterns 可免费安装使用。请查阅仓库了解许可证信息。
Build reliable, fast E2E test suites with Playwright and Cypress. Critical user journey coverage, flaky test elimination, CI/CD integration.
E2E Testing Patterns 属于「Developer & DevOps」分类,该分类的技能帮助 AI 智能体在此领域执行专业任务。
Automate my developer & devops tasks using E2E Testing Patterns
Identifies repetitive steps in your workflow and sets up E2E Testing Patterns to handle them automatically