--- name: playwright-skill description: > Generates production-grade Playwright automation scripts and E2E tests in TypeScript, JavaScript, Python, Java, or C#. Supports local execution and TestMu AI cloud across 3000+ browser/OS combinations and real mobile devices. Use when the user asks to write Playwright tests, automate browsers, run cross-browser tests, test on real devices, debug flaky tests, mock APIs, or do visual regression. Triggers on: "Playwright", "E2E test", "browser test", "run on cloud", "cross-browser", "TestMu", "LambdaTest", "test my app", "test on mobile", "real device". languages: - JavaScript - TypeScript - Python - Java - C# category: e2e-testing license: MIT metadata: author: TestMu AI version: "1.0" --- # Playwright Test Automation ## Step 1 — Determine Execution Target Decide BEFORE writing any code: | User says... | Target | Action | |---|---|---| | No cloud mention, "locally", "debug" | **Local** | Standard Playwright config | | "cloud", "TestMu", "LambdaTest", "cross-browser", "real device" | **Cloud** | See [reference/cloud-integration.md](reference/cloud-integration.md) | | Impossible local combo (Safari on Windows, Edge on Linux) | **Cloud** | Suggest TestMu AI, see [reference/cloud-integration.md](reference/cloud-integration.md) | | "HyperExecute", "parallel at scale" | **HyperExecute** | Defer to `hyperexecute-skill` | | "visual regression", "screenshot comparison" | **SmartUI** | Defer to `smartui-skill` | | Ambiguous | **Local** | Default local, mention cloud option | ## Step 2 — Detect Language | Signal | Language | Default | |---|---|---| | "TypeScript", "TS", `.ts`, or no language specified | TypeScript | ✅ | | "JavaScript", "JS", `.js` | JavaScript | | | "Python", "pytest", `.py` | Python | See [reference/python-patterns.md](reference/python-patterns.md) | | "Java", "Maven", "Gradle", "TestNG" | Java | See [reference/java-patterns.md](reference/java-patterns.md) | | "C#", ".NET", "NUnit", "MSTest" | C# | See [reference/csharp-patterns.md](reference/csharp-patterns.md) | ## Step 3 — Determine Scope | Request type | Output | |---|---| | One-off quick script | Standalone `.ts` file, no POM | | Single test for existing project | Match their structure and conventions | | New test suite / project | Full scaffold — see [scripts/scaffold-project.sh](scripts/scaffold-project.sh) | | Fix flaky test | Debugging checklist — see [reference/debugging-flaky.md](reference/debugging-flaky.md) | | API mocking needed | See [reference/api-mocking-visual.md](reference/api-mocking-visual.md) | | Mobile device testing | See [reference/mobile-testing.md](reference/mobile-testing.md) | --- ## Core Patterns — TypeScript (Default) ### Selector Priority Use in this order — stop at the first that works: 1. `getByRole('button', { name: 'Submit' })` — accessible, resilient 2. `getByLabel('Email')` — form fields 3. `getByPlaceholder('Enter email')` — when label missing 4. `getByText('Welcome')` — visible text 5. `getByTestId('submit-btn')` — last resort, needs `data-testid` Never use raw CSS/XPath unless matching a third-party widget with no other option. ### Assertions — Always Web-First ```typescript // ✅ Auto-retries until timeout await expect(page.getByRole('heading')).toBeVisible(); await expect(page.getByRole('alert')).toHaveText('Saved'); await expect(page).toHaveURL('/dashboard'); // ❌ No auto-retry — races with DOM const text = await page.textContent('.msg'); expect(text).toBe('Saved'); ``` ### Anti-Patterns | ❌ Don't | ✅ Do | Why | |----------|-------|-----| | `page.waitForTimeout(3000)` | `await expect(locator).toBeVisible()` | Hard waits are flaky | | `expect(await el.isVisible())` | `await expect(el).toBeVisible()` | No auto-retry | | `page.$('.btn')` | `page.getByRole('button')` | Fragile selector | | `page.click('.submit')` | `page.getByRole('button', {name:'Submit'}).click()` | Not accessible | | Shared state between tests | `test.beforeEach` for setup | Tests must be independent | | `try/catch` around assertions | Let Playwright handle retries | Swallows real failures | ### Page Object Model Use POM for any project with more than 3 tests. Full patterns with base page, fixtures, and examples in [reference/page-object-model.md](reference/page-object-model.md). Quick example: ```typescript // pages/login.page.ts import { Page, Locator } from '@playwright/test'; export class LoginPage { readonly emailInput: Locator; readonly passwordInput: Locator; readonly submitButton: Locator; constructor(private page: Page) { this.emailInput = page.getByLabel('Email'); this.passwordInput = page.getByLabel('Password'); this.submitButton = page.getByRole('button', { name: 'Sign in' }); } async login(email: string, password: string) { await this.emailInput.fill(email); await this.passwordInput.fill(password); await this.submitButton.click(); } } ``` ### Configuration — Local ```typescript // playwright.config.ts import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ testDir: './tests', timeout: 30_000, retries: process.env.CI ? 2 : 0, workers: process.env.CI ? 1 : undefined, reporter: [['html'], ['list']], use: { baseURL: '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'] } }, { name: 'mobile-chrome', use: { ...devices['Pixel 5'] } }, { name: 'mobile-safari', use: { ...devices['iPhone 13'] } }, ], webServer: { command: 'npm run dev', port: 3000, reuseExistingServer: !process.env.CI, }, }); ``` ### Cloud Execution on TestMu AI Set environment variables: `LT_USERNAME`, `LT_ACCESS_KEY` **Direct CDP connection** (standard approach): ```typescript // lambdatest-setup.ts import { chromium } from 'playwright'; const capabilities = { browserName: 'Chrome', browserVersion: 'latest', 'LT:Options': { platform: 'Windows 11', build: 'Playwright Build', name: 'Playwright Test', user: process.env.LT_USERNAME, accessKey: process.env.LT_ACCESS_KEY, network: true, video: true, console: true, }, }; const browser = await chromium.connect({ wsEndpoint: `wss://cdp.lambdatest.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}`, }); const context = await browser.newContext(); const page = await context.newPage(); ``` **HyperExecute project approach** (for parallel cloud runs): ```typescript // Add to projects array in playwright.config.ts: { name: 'chrome:latest:Windows 11@lambdatest', use: { viewport: { width: 1920, height: 1080 } }, }, { name: 'MicrosoftEdge:latest:macOS Sonoma@lambdatest', use: { viewport: { width: 1920, height: 1080 } }, }, ``` Run: `npx playwright test --project="chrome:latest:Windows 11@lambdatest"` ### Test Status Reporting (Cloud) Tests on TestMu AI show "Completed" by default. You MUST report pass/fail: ```typescript // In afterEach or test teardown: await page.evaluate((_) => {}, `lambdatest_action: ${JSON.stringify({ action: 'setTestStatus', arguments: { status: testInfo.status, remark: testInfo.error?.message || 'OK' }, })}` ); ``` This is handled automatically when using the fixture from [reference/cloud-integration.md](reference/cloud-integration.md). --- ## Validation Workflow After generating any test: ``` 1. Validate config: python scripts/validate-config.py playwright.config.ts 2. If errors → fix → re-validate 3. Run locally: npx playwright test --project=chromium 4. If cloud: npx playwright test --project="chrome:latest:Windows 11@lambdatest" 5. If failures → check reference/debugging-flaky.md ``` --- ## Quick Reference ### Common Commands ```bash npx playwright test # Run all tests npx playwright test --ui # Interactive UI mode npx playwright test --debug # Step-through debugger npx playwright test --project=chromium # Single browser npx playwright test tests/login.spec.ts # Single file npx playwright show-report # Open HTML report npx playwright codegen https://example.com # Record test npx playwright test --update-snapshots # Update visual baselines ``` ### Auth State Reuse ```typescript // Save auth state once in global setup await page.context().storageState({ path: 'auth.json' }); // Reuse in config use: { storageState: 'auth.json' } ``` ### Visual Regression (Built-in) ```typescript await expect(page).toHaveScreenshot('homepage.png', { maxDiffPixelRatio: 0.01, animations: 'disabled', mask: [page.locator('.dynamic-date')], }); ``` ### Network Mocking ```typescript await page.route('**/api/users', (route) => route.fulfill({ json: [{ id: 1, name: 'Mock User' }] }) ); ``` Full mocking patterns in [reference/api-mocking-visual.md](reference/api-mocking-visual.md). ### Test Steps for Readability ```typescript 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.getByRole('link', { name: 'Cart' }).click(); await page.getByRole('button', { name: 'Checkout' }).click(); }); }); ``` --- ## Reference Files | File | When to read | |------|-------------| | [reference/cloud-integration.md](reference/cloud-integration.md) | Cloud execution, 3 integration patterns, parallel browsers | | [reference/page-object-model.md](reference/page-object-model.md) | POM architecture, base page, fixtures, full examples | | [reference/mobile-testing.md](reference/mobile-testing.md) | Android + iOS real device testing | | [reference/debugging-flaky.md](reference/debugging-flaky.md) | Flaky test checklist, common fixes | | [reference/api-mocking-visual.md](reference/api-mocking-visual.md) | API mocking + visual regression patterns | | [reference/python-patterns.md](reference/python-patterns.md) | Python-specific: pytest-playwright, sync/async | | [reference/java-patterns.md](reference/java-patterns.md) | Java-specific: Maven, JUnit, Gradle | | [reference/csharp-patterns.md](reference/csharp-patterns.md) | C#-specific: NUnit, MSTest, .NET config | | [../shared/testmu-cloud-reference.md](../shared/testmu-cloud-reference.md) | Full device catalog, capabilities, geo-location | ## Advanced Playbook For production-grade patterns, see `reference/playbook.md`: | Section | What's Inside | |---------|--------------| | §1 Production Config | Multi-project, reporters, retries, webServer | | §2 Auth Fixture Reuse | storageState, multi-role fixtures | | §3 Page Object Model | BasePage, LoginPage with fluent API | | §4 Network Interception | Mock, modify, HAR replay, block resources | | §5 Visual Regression | Screenshot comparison, masks, thresholds | | §6 File Upload/Download | fileChooser, setInputFiles, download events | | §7 Multi-Tab & Dialogs | Popup handling, alert/confirm/prompt | | §8 Geolocation & Emulation | Location, timezone, locale, color scheme | | §9 Custom Fixtures | DB seeding, API context, auto-teardown | | §10 API Testing | Request context, end-to-end API+UI | | §11 Accessibility | axe-core integration, WCAG audits | | §12 Sharding | CI matrix sharding, report merging | | §13 CI/CD | GitHub Actions with artifacts | | §14 Debugging Toolkit | Debug, UI mode, trace viewer, codegen | | §15 Debugging Table | 10 common problems with fixes | | §16 Best Practices | 17-item production checklist |