Back to skills
SKILL.md
Swe Developing E2e Test With Playwright
ASecurityPlaywright E2E testing standards from authoritative docs/explanation/software-engineering/automation-testing/tools/playwright/ documentation
- 4 stars
- 0 votes
- 0 copies
- 4 views
- Added September 12, 2026
Works with
Security analysis
100/100Pro scans all 2 files and shows the line behind each finding
npx -y skills add aibot88/sec_skill_store --skill swe-developing-e2e-test-with-playwright --agent claude-codeAre you the author of Swe Developing E2e Test With Playwright?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/aibot88-swe-developing-e2e-test-with-playwright)---
name: swe-developing-e2e-test-with-playwright
description: Playwright E2E testing standards from authoritative docs/explanation/software-engineering/automation-testing/tools/playwright/ documentation
---
# Playwright E2E Testing Standards
## Purpose
Progressive disclosure of Playwright end-to-end testing standards for agents writing E2E tests.
**Authoritative Source**: [docs/explanation/software-engineering/automation-testing/tools/playwright/README.md](../../../docs/explanation/software-engineering/automation-testing/tools/playwright/README.md)
**Usage**: Auto-loaded for agents when writing Playwright E2E tests. Provides quick reference to test organization, selectors, assertions, page objects, and debugging patterns.
## Quick Standards Reference
### Test Organization
**File Structure**: Group tests by feature or page
```
tests/
├── e2e/
│ ├── auth/
│ │ ├── login.spec.ts
│ │ └── register.spec.ts
│ ├── payments/
│ │ ├── murabaha.spec.ts
│ │ └── zakat.spec.ts
│ └── navigation.spec.ts
├── page-objects/
│ ├── pages/
│ │ ├── LoginPage.ts
│ │ └── DashboardPage.ts
│ └── components/
│ ├── Header.ts
│ └── Sidebar.ts
└── fixtures/
└── test-data.ts
```
**Naming Conventions**:
- Test files: `*.spec.ts` (e.g., `login.spec.ts`)
- Page objects: `PascalCase` (e.g., `LoginPage.ts`)
- Test descriptions: Behavior-focused (e.g., "successful login redirects to dashboard")
### Selectors (Accessibility-First)
**Priority Order**: Role → Label → Text → TestID → CSS
```typescript
// ✅ PASS: Accessibility-first selectors
page.getByRole("button", { name: "Submit" }); // Priority 1: Role
page.getByLabel("Email"); // Priority 2: Label
page.getByText("Welcome"); // Priority 3: Text
page.getByTestId("submit-button"); // Priority 4: TestID
page.locator("css=.button"); // Priority 5: CSS (last resort)
```
**Avoid**:
- Overly specific CSS selectors
- XPath unless necessary
- Element IDs that change frequently
- Position-based selectors
### Assertions (Web-First)
**Auto-Waiting Assertions**: Use web-first assertions with automatic retries
```typescript
// ✅ PASS: Web-first assertions (auto-wait)
await expect(page).toHaveTitle("Dashboard");
await expect(page.getByRole("heading")).toContainText("Welcome");
await expect(page.getByLabel("Email")).toBeVisible();
await expect(page.getByTestId("status")).toHaveText("Success");
// ❌ FAIL: Generic assertions (no auto-wait)
const text = await page.getByRole("heading").textContent();
expect(text).toBe("Welcome"); // No retry, flaky
```
**Assertion Types**:
- Visibility: `toBeVisible()`, `toBeHidden()`
- Text: `toHaveText()`, `toContainText()`
- Values: `toHaveValue()`, `toHaveAttribute()`
- States: `toBeEnabled()`, `toBeDisabled()`, `toBeChecked()`
- URL: `toHaveURL()`, URL patterns with regex
### Page Object Model
**Class-Based Pattern**: Encapsulate page locators and actions
```typescript
// ✅ PASS: Page Object Model
import { Page, Locator } from "@playwright/test";
export class LoginPage {
readonly page: Page;
readonly emailInput: Locator;
readonly passwordInput: Locator;
readonly submitButton: Locator;
constructor(page: Page) {
this.page = page;
this.emailInput = page.getByRole("textbox", { name: "Email" });
this.passwordInput = page.getByRole("textbox", { name: "Password" });
this.submitButton = page.getByRole("button", { name: "Sign in" });
}
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.submitButton.click();
}
}
```
**Usage in Tests**:
```typescript
test("successful login", async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.login("user@example.com", "password123");
await expect(page).toHaveURL("/dashboard");
});
```
### Configuration Standards
**playwright.config.ts**: Environment-specific settings
```typescript
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: process.env.CI ? [["html"], ["junit"]] : "html",
use: {
baseURL: process.env.BASE_URL || "http://localhost:3000",
trace: "on-first-retry",
screenshot: "only-on-failure",
},
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
{
name: "firefox",
use: { ...devices["Desktop Firefox"] },
},
{
name: "webkit",
use: { ...devices["Desktop Safari"] },
},
],
});
```
### Best Practices
**Test Isolation**: Each test independent
```typescript
// ✅ PASS: Test isolation with beforeEach
test.describe("User Management", () => {
test.beforeEach(async ({ page }) => {
await page.goto("/users");
await page.getByRole("button", { name: "Add User" }).click();
});
test("creates new user", async ({ page }) => {
// Fresh state from beforeEach
await page.getByLabel("Name").fill("John Doe");
await page.getByRole("button", { name: "Save" }).click();
await expect(page.getByText("User created")).toBeVisible();
});
});
```
**API Testing Integration**: Combine UI and API
```typescript
test("user sees their data after login", async ({ page, request }) => {
// API setup
const response = await request.post("/api/users", {
data: { name: "Test User", email: "test@example.com" },
});
const userId = (await response.json()).id;
// UI verification
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.login("test@example.com", "password");
await expect(page.getByText("Test User")).toBeVisible();
// API cleanup
await request.delete(`/api/users/${userId}`);
});
```
### Anti-Patterns to Avoid
**❌ Manual Waits**:
```typescript
// ❌ FAIL: Manual waits
await page.click("button");
await page.waitForTimeout(2000); // Arbitrary wait, flaky
// ✅ PASS: Auto-waiting
await page.click("button");
await expect(page.getByText("Success")).toBeVisible(); // Auto-retries
```
**❌ Overly Specific Selectors**:
```typescript
// ❌ FAIL: Fragile CSS selector
await page.locator("div.container > div:nth-child(2) > button.primary").click();
// ✅ PASS: Semantic selector
await page.getByRole("button", { name: "Submit" }).click();
```
**❌ Test Interdependence**:
```typescript
// ❌ FAIL: Tests depend on execution order
test("1. create user", async ({ page }) => {
// Creates user, stores in global state
});
test("2. edit user", async ({ page }) => {
// Depends on user from test 1
});
// ✅ PASS: Independent tests
test.describe("User Management", () => {
test.beforeEach(async ({ request }) => {
// Each test creates its own user
await request.post("/api/users", { data: testUser });
});
test("creates user", async ({ page }) => {
// Independent
});
test("edits user", async ({ page }) => {
// Independent
});
});
```
### Debugging Tools
**Trace Viewer**: Post-failure debugging
```bash
# Show trace for failed tests
npx playwright show-trace trace.zip
```
**Inspector**: Step-through debugging
```bash
# Debug specific test
npx playwright test login.spec.ts --debug
```
**Headed Mode**: Visual debugging
```typescript
// playwright.config.ts
use: {
headless: false, // Show browser
slowMo: 500, // Slow down actions
},
```
## demo Context
### Islamic Finance Testing
**Zakat Calculator Tests**:
```typescript
test("calculates zakat correctly", async ({ page }) => {
await page.goto("/zakat-calculator");
await page.getByLabel("Wealth Amount").fill("100000");
await page.getByRole("button", { name: "Calculate" }).click();
// Verify 2.5% calculation
await expect(page.getByTestId("zakat-amount")).toHaveText("RM 2,500.00");
});
```
**Murabaha Contract Tests**:
```typescript
test("murabaha contract workflow", async ({ page }) => {
const murabaha = new MurabahaPage(page);
await murabaha.goto();
await murabaha.createContract({
asset: "Vehicle",
cost: 50000,
profitRate: 5,
});
await expect(page.getByText("Contract Created")).toBeVisible();
await expect(page.getByTestId("total-payment")).toContainText("52,500");
});
```
## Related Standards
**See Authoritative Documentation**:
- [Test Organization](../../../docs/explanation/software-engineering/automation-testing/tools/playwright/test-organization.md) - Test structure, fixtures, grouping
- [Selectors](../../../docs/explanation/software-engineering/automation-testing/tools/playwright/selectors.md) - Accessibility-first selector strategies
- [Assertions](../../../docs/explanation/software-engineering/automation-testing/tools/playwright/assertions.md) - Web-first assertions
- [Page Objects](../../../docs/explanation/software-engineering/automation-testing/tools/playwright/page-objects.md) - Page Object Model patterns
- [Configuration](../../../docs/explanation/software-engineering/automation-testing/tools/playwright/configuration.md) - playwright.config.ts setup
- [Best Practices](../../../docs/explanation/software-engineering/automation-testing/tools/playwright/best-practices.md) - Production testing standards
- [Anti-Patterns](../../../docs/explanation/software-engineering/automation-testing/tools/playwright/anti-patterns.md) - Common mistakes
- [Idioms](../../../docs/explanation/software-engineering/automation-testing/tools/playwright/idioms.md) - Playwright-specific patterns
- [Debugging](../../../docs/explanation/software-engineering/automation-testing/tools/playwright/debugging.md) - Trace viewer, inspector
Files in this skill
- SKILL.md
- source.json
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.