← All skills
Tencent SkillHub Β· Developer Tools

E2E Testing Patterns

Build reliable, fast E2E test suites with Playwright and Cypress. Critical user journey coverage, flaky test elimination, CI/CD integration.

skill openclawclawhub Free
0 Downloads
0 Stars
0 Installs
0 Score
High Signal

Build reliable, fast E2E test suites with Playwright and Cypress. Critical user journey coverage, flaky test elimination, CI/CD integration.

⬇ 0 downloads β˜… 0 stars Unverified but indexed

Install for OpenClaw

Quick setup
  1. Download the package from Yavira.
  2. Extract the archive and review SKILL.md first.
  3. Import or place the package into your OpenClaw setup.

Requirements

Target platform
OpenClaw
Install method
Manual import
Extraction
Extract archive
Prerequisites
OpenClaw
Primary doc
SKILL.md

Package facts

Download mode
Yavira redirect
Package format
ZIP package
Source platform
Tencent SkillHub
What's included
README.md, SKILL.md

Validation

  • Use the Yavira download entry.
  • Review SKILL.md after the package is downloaded.
  • Confirm the extracted package contains the expected setup assets.

Install with your agent

Agent handoff

Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.

  1. Download the package from Yavira.
  2. Extract it into a folder your agent can access.
  3. Paste one of the prompts below and point your agent at the extracted folder.
New install

I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete.

Upgrade existing

I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run.

Trust & source

Release facts

Source
Tencent SkillHub
Verification
Indexed source record
Version
1.0.0

Documentation

ClawHub primary doc Primary doc: SKILL.md 23 sections Open source page

E2E Testing Patterns

Test what users do, not how code works. E2E tests prove the system works as a whole β€” they're your confidence to ship.

OpenClaw / Moltbot / Clawbot

npx clawhub@latest install e2e-testing-patterns

WHAT This Skill Does

Provides patterns for building end-to-end test suites that: Catch regressions before users do Run fast enough for CI/CD Remain stable (no flaky failures) Cover critical user journeys without over-testing

WHEN To Use

Implementing E2E test automation for a web application Debugging flaky tests that fail intermittently Setting up CI/CD test pipelines with browser tests Testing critical user workflows (auth, checkout, signup) Choosing what to test with E2E vs unit/integration tests

Test Pyramid β€” Know Your Layer

/\ /E2E\ ← FEW: Critical paths only (this skill) /─────\ /Integr\ ← MORE: Component interactions, API contracts /────────\ /Unit Tests\ ← MANY: Fast, isolated, cover edge cases /────────────\

What E2E Tests Are For

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 compatibilityEdge cases (too slow, use unit tests)Real API integrationInternal implementation detailsAuthentication flowsComponent 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.

Core Principles

PrincipleWhyHowTest behavior, not implementationSurvives refactorsAssert on user-visible outcomes, not DOM structureIndependent testsParallelizable, debuggableEach test creates its own data, cleans up afterDeterministic waitsNo flakinessWait for conditions, not fixed timeoutsStable selectorsSurvives UI changesUse data-testid, roles, labels β€” never CSS classesFast feedbackDevelopers run themMock external services, parallelize, shard

Configuration

// 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"] } }, ], });

Pattern: Page Object Model

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("user@example.com", "password123"); await expect(page).toHaveURL("/dashboard"); await expect(page.getByRole("heading", { name: "Dashboard" })).toBeVisible(); });

Pattern: Fixtures for Test Data

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); // ... });

Pattern: Smart Waiting

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;

Pattern: Network Mocking

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(); });

Custom Commands

// 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("user@example.com", "password"); cy.dataCy("submit-button").click();

Network Intercepts

// Mock API cy.intercept("GET", "/api/users", { statusCode: 200, body: [{ id: 1, name: "John" }], }).as("getUsers"); cy.visit("/users"); cy.wait("@getUsers"); cy.get('[data-testid="user-list"]').children().should("have.length", 1);

Selector Strategy

PrioritySelector TypeExampleWhy1Role + namegetByRole("button", { name: "Submit" })Accessible, user-facing2LabelgetByLabel("Email address")Accessible, semantic3data-testidgetByTestId("checkout-form")Stable, explicit for testing4Text contentgetByText("Welcome back")User-facing❌CSS classes.btn-primaryBreaks on styling changes❌DOM structurediv > form > input:nth-child(2)Breaks on any restructure // ❌ BAD: Brittle selectors cy.get(".btn.btn-primary.submit-button").click(); cy.get("div > form > div:nth-child(2) > input").type("text"); // βœ… GOOD: Stable selectors page.getByRole("button", { name: "Submit" }).click(); page.getByLabel("Email address").fill("user@example.com"); page.getByTestId("email-input").fill("user@example.com");

Visual Regression Testing

// Playwright visual comparisons test("homepage looks correct", async ({ page }) => { await page.goto("/"); await expect(page).toHaveScreenshot("homepage.png", { fullPage: true, maxDiffPixels: 100, }); }); test("button states", async ({ page }) => { const button = page.getByRole("button", { name: "Submit" }); await expect(button).toHaveScreenshot("button-default.png"); await button.hover(); await expect(button).toHaveScreenshot("button-hover.png"); });

Accessibility Testing

// npm install @axe-core/playwright import AxeBuilder from "@axe-core/playwright"; test("page has no accessibility violations", async ({ page }) => { await page.goto("/"); const results = await new AxeBuilder({ page }) .exclude("#third-party-widget") // Exclude things you can't control .analyze(); expect(results.violations).toEqual([]); });

Debugging Failed Tests

# Run in headed mode (see the browser) npx playwright test --headed # Debug mode (step through) npx playwright test --debug # Show trace viewer for failed tests npx playwright show-report // Add test steps for better failure reports test("checkout flow", async ({ page }) => { await test.step("Add item to cart", async () => { await page.goto("/products"); await page.getByRole("button", { name: "Add to Cart" }).click(); }); await test.step("Complete checkout", async () => { await page.goto("/checkout"); // ... if this fails, you know which step }); }); // Pause for manual inspection await page.pause();

Flaky Test Checklist

When a test fails intermittently, check: IssueFixFixed waitForTimeout() callsReplace with waitForSelector() or expect assertionsRace conditions on page loadWait for networkidle or specific elementsTest data pollutionEnsure tests create/clean their own dataAnimation timingWait for animations to complete or disable themViewport inconsistencySet explicit viewport in configRandom test order issuesTests must be independentThird-party service flakinessMock external APIs

CI/CD Integration

# GitHub Actions example name: E2E Tests on: [push, pull_request] jobs: e2e: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 - run: npm ci - run: npx playwright install --with-deps - run: npm run build - run: npm run start & npx wait-on http://localhost:3000 - run: npx playwright test - uses: actions/upload-artifact@v4 if: failure() with: name: playwright-report path: playwright-report/

NEVER Do

NEVER use fixed waitForTimeout() or cy.wait(ms) β€” they cause flaky tests and slow down suites NEVER rely on CSS classes or DOM structure for selectors β€” use roles, labels, or data-testid NEVER share state between tests β€” each test must be completely independent NEVER test implementation details β€” test what users see and do, not internal structure NEVER skip cleanup β€” always delete test data you created, even on failure NEVER test everything with E2E β€” reserve for critical paths; use faster tests for edge cases NEVER ignore flaky tests β€” fix them immediately or delete them; a flaky test is worse than no test NEVER hardcode test data in selectors β€” use dynamic waits for content that varies

Playwright Commands

// Navigation await page.goto("/path"); await page.goBack(); await page.reload(); // Interactions await page.click("selector"); await page.fill("selector", "text"); await page.type("selector", "text"); // Types character by character await page.selectOption("select", "value"); await page.check("checkbox"); // Assertions await expect(page).toHaveURL("/expected"); await expect(locator).toBeVisible(); await expect(locator).toHaveText("expected"); await expect(locator).toBeEnabled(); await expect(locator).toHaveCount(3);

Cypress Commands

// Navigation cy.visit("/path"); cy.go("back"); cy.reload(); // Interactions cy.get("selector").click(); cy.get("selector").type("text"); cy.get("selector").clear().type("text"); cy.get("select").select("value"); cy.get("checkbox").check(); // Assertions cy.url().should("include", "/expected"); cy.get("selector").should("be.visible"); cy.get("selector").should("have.text", "expected"); cy.get("selector").should("have.length", 3);

Category context

Code helpers, APIs, CLIs, browser automation, testing, and developer operations.

Source: Tencent SkillHub

Largest current source with strong distribution and engagement signals.

Package contents

Included in package
2 Docs
  • SKILL.md Primary doc
  • README.md Docs