
Playwright Pro
Write reliable Playwright tests using web-first, auto-retrying assertions instead of flaky manual waits.
Overview
Playwright-pro is an agent skill for the Ship phase that documents web-first Playwright assertions and page checks for stable end-to-end tests.
Install
npx skills add https://github.com/alirezarezvani/claude-skills --skill playwright-proWhat is this skill?
- Web-first expect() assertions that auto-retry until timeout for dynamic UI
- Locator coverage: visibility, text, value, attributes, enabled/checked/focused state, count, CSS, screenshots
- Page-level URL and title assertions with string or regex matchers
- Explicit anti-patterns section—avoid non-retrying checks that flake in CI
- TypeScript-first examples ready to paste into Playwright test files
Adoption & trust: 537 installs on skills.sh; 17.5k GitHub stars; 2/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your Playwright tests flake because the agent uses one-off waits or non-retrying checks instead of expect() assertions built for dynamic pages.
Who is it for?
Solo builders adding or fixing Playwright e2e coverage on a React/Vue/SSR app before shipping to production.
Skip if: Projects with no browser tests planned, or teams that need API-only contract testing without a Playwright runner installed.
When should I use this skill?
You are writing or reviewing Playwright tests and need correct expect() patterns for locators and pages.
What do I get? / Deliverables
You get copy-paste TypeScript assertion patterns aligned with Playwright best practices so CI e2e runs retry safely on real browser timing.
- Assertion snippets integrated into .spec.ts files
- Reduced flaky patterns per anti-pattern guidance
Recommended Skills
Journey fit
End-to-end assertion patterns belong on the Ship shelf because they stabilize release confidence right before and after deploy. Testing subphase is the right home for assertion catalogs and anti-patterns that define how UI specs should behave under load and dynamic DOM updates.
How it compares
Assertion and locator cookbook for Playwright—not a full Page Object Model generator or visual regression platform.
Common Questions / FAQ
Who is playwright-pro for?
Developers and agent-assisted workflows writing Playwright end-to-end tests who want authoritative assertion snippets without digging through docs each time.
When should I use playwright-pro?
In Ship while authoring tests, debugging CI flakes, or reviewing agent-generated specs before a release candidate merge.
Is playwright-pro safe to install?
It is documentation-style guidance with no mandatory network calls; still review the Security Audits panel on this Prism page before trusting any third-party skill package in your CI secrets context.
SKILL.md
READMESKILL.md - Playwright Pro
# Assertions Reference ## Web-First Assertions (Always Use These) Auto-retry until timeout. Safe for dynamic content. ```typescript // Visibility await expect(locator).toBeVisible(); await expect(locator).not.toBeVisible(); await expect(locator).toBeHidden(); // Text await expect(locator).toHaveText('exact text'); await expect(locator).toHaveText(/partial/i); await expect(locator).toContainText('partial'); // Value (inputs) await expect(locator).toHaveValue('entered text'); await expect(locator).toHaveValues(['option1', 'option2']); // Attributes await expect(locator).toHaveAttribute('href', '/dashboard'); await expect(locator).toHaveClass(/active/); await expect(locator).toHaveId('main-nav'); // State await expect(locator).toBeEnabled(); await expect(locator).toBeDisabled(); await expect(locator).toBeChecked(); await expect(locator).toBeEditable(); await expect(locator).toBeFocused(); await expect(locator).toBeAttached(); // Count await expect(locator).toHaveCount(5); await expect(locator).toHaveCount(0); // element doesn't exist // CSS await expect(locator).toHaveCSS('color', 'rgb(255, 0, 0)'); // Screenshots await expect(locator).toHaveScreenshot('button.png'); await expect(page).toHaveScreenshot('full-page.png'); ``` ## Page Assertions ```typescript await expect(page).toHaveURL('/dashboard'); await expect(page).toHaveURL(/\/dashboard/); await expect(page).toHaveTitle('Dashboard - App'); await expect(page).toHaveTitle(/Dashboard/); ``` ## Anti-Patterns (Never Do This) ```typescript // BAD — no auto-retry const text = await locator.textContent(); expect(text).toBe('Hello'); // BAD — snapshot in time, not reactive const isVisible = await locator.isVisible(); expect(isVisible).toBe(true); // BAD — evaluating in page context const value = await page.evaluate(() => document.querySelector('input')?.value ); expect(value).toBe('test'); ``` ## Custom Timeout ```typescript // Override timeout for slow operations await expect(locator).toBeVisible({ timeout: 30_000 }); ``` ## Soft Assertions Continue test even if assertion fails (report all failures at end): ```typescript await expect.soft(locator).toHaveText('Expected'); await expect.soft(page).toHaveURL('/next'); // Test continues even if above fail ``` # Common Pitfalls (Top 10) ## 1. waitForTimeout **Symptom:** Slow, flaky tests. ```typescript // BAD await page.waitForTimeout(3000); // GOOD await expect(page.getByTestId('result')).toBeVisible(); ``` ## 2. Non-Web-First Assertions **Symptom:** Assertions fail on dynamic content. ```typescript // BAD — checks once, no retry const text = await page.textContent('.msg'); expect(text).toBe('Done'); // GOOD — retries until timeout await expect(page.getByText('Done')).toBeVisible(); ``` ## 3. Missing await **Symptom:** Random passes/failures, tests seem to skip steps. ```typescript // BAD page.goto('/dashboard'); expect(page.getByText('Welcome')).toBeVisible(); // GOOD await page.goto('/dashboard'); await expect(page.getByText('Welcome')).toBeVisible(); ``` ## 4. Hardcoded URLs **Symptom:** Tests break in different environments. ```typescript // BAD await page.goto('http://localhost:3000/login'); // GOOD — uses baseURL from config await page.goto('/login'); ``` ## 5. CSS Selectors Instead of Roles **Symptom:** Tests break after CSS refactors. ```typescript // BAD await page.click('#submit-btn'); // GOOD await page.getByRole('button', { name: 'Submit' }).click(); ``` ## 6. Shared State Between Tests **Symptom:** Tests pass alone, fail in suite. ```typescript // BAD — test B depends on test A let userId: string; test('create user', async () => { userId = '123'; }); test('edit user', async () => { /* uses userId */ }); // GOOD — each test is independent test('edit user', async ({ request }) => { const res = await request.post('/api/users', { data: { name: 'Test' } }); const { id } = await res.json(); // ... }); ``` ## 7. Using networkidle **Symptom:** Tests hang or timeout unpredictabl