Playwright workflows for authenticated browser state reuse through storageState and setup projects.
日本語の概要は準備中です。原文の説明を表示しています。
Conducts rigorous authoring and review of Playwright E2E tests. Enforces accessibility-first locators, web-first assertions, strict isolation, and DAMP architecture. Use when generating, refactoring, or reviewing any Playwright test code.
インストールする前に、エージェントに与えられる指示の中身を確認できます。
Writing end-to-end tests is easy. Writing end-to-end tests that survive UI refactors and network latency without flaking requires discipline.
Use this skill when you are authoring, reviewing, or refactoring Playwright tests that should behave like a real user journey. It pairs well with playwright-auth-state for logged-in flows, playwright-network-mocking for external API control, and playwright-debugging when a test is already failing.
The approval standard: A test is only valid if it tests the application exactly how a human user interacts with it. We do not test implementation details, we do not rely on fixed sleep timers, and we do not share state between tests. If a test fails, it should indicate a true user-facing bug, not a brittle CSS selector or a race condition.
playwright-auth-state instead.playwright-network-mocking instead.playwright-debugging instead.Every Playwright test must be evaluated across these five dimensions before execution:
Does the test target user intent, or is it coupled to implementation?
getByRole as the absolute first choice?<div> to a <span>, or swaps a CSS framework (e.g., Bootstrap to Tailwind), will the test survive?Are we relying on Playwright's actionability engine, or are we manually guessing execution speed?
page.waitForTimeout() calls? These are strictly forbidden.expect(locator).toBeVisible()?Can this test run in complete isolation, in any order, and in parallel?
test.beforeEach and test.afterEach?Can another engineer read the test top-to-bottom and understand the business requirement?
Does the test verify what the user cares about?
When you identify a structural problem in a test, do not just patch it. Reach for a named restructuring:
getByRole, getByLabel).expect().toBeVisible() or page.waitForResponse().test() blocks with a shared beforeEach.You must follow this exact order of preference when querying the DOM. Fall to the next level only if the previous is impossible.
page.getByRole() - Always the first choice. Tests accessibility and user intent simultaneously.page.getByLabel() - The standard for form inputs.page.getByPlaceholder() - Acceptable for inputs without labels.page.getByText() - For generic non-interactive text elements.page.getByTestId() - The fallback. Use only when semantic querying is impossible, such as dynamic SVG charts.When a locator could match more than one element, refine it with semantic filtering instead of switching to position-based selection. Prefer filter(), and(), or a narrower accessible name over nth() or DOM traversal.
Always use auto-retrying assertions. Never read a value and assert it synchronously.
// Bad: synchronous evaluation. Causes race conditions if the element is still rendering.
const isVisible = await page.getByRole('button').isVisible();
expect(isVisible).toBeTruthy();
// Good: Playwright handles the polling and timeout automatically.
await expect(page.getByRole('button', { name: 'Submit' })).toBeVisible();
Do not force clicks on unready elements. Let Playwright wait for actionability.
// Bad: bypassing actionability checks.
await page.locator('.btn').click({ force: true });
// Good: waiting for the app to be ready.
await page.getByRole('button', { name: 'Submit' }).click();
An assertion that has never been observed to fail provides no evidence. Both LLM- and
human-authored tests drift toward assertions that pass regardless of the underlying
behavior — sophisticated-looking checks that are, in spirit, no different from
expect(true).toBeTruthy().
Before treating a new assertion as finished, prove it can go red:
page.route(), remove a required fixture, or
comment out the relevant application behavior — run the test once, and confirm it
fails for the expected reason.This matters most for negative assertions. expect(locator).not.toBeVisible()
passes just as happily when the locator itself is wrong — a typo'd role or name — as it
does when the element is genuinely absent. A negative assertion is only trustworthy once
you've confirmed, at least once, that the same locator resolves correctly when the
element is present. Otherwise a broken selector and a correct negative assertion are
indistinguishable.
When tempted to take shortcuts to generate code faster, refer to this table:
| Rationalization | The Reality & Required Action |
|---|---|
"I'll use page.waitForTimeout(3000) because the transition animation is slow." | REJECTED. Sleep timers guarantee flaky CI suites. Action: Assert the expected end-state, for example await expect(modal).toBeVisible(). |
"Using .submit-btn-active (CSS) is faster than looking up the ARIA role." | REJECTED. Implementation details change often. Action: Locate by user intent: await page.getByRole('button', { name: 'Submit' }). |
| "I'll combine 5 different user flows into one giant test block so it runs faster." | REJECTED. Tests must be isolated. If it fails on step 4, steps 1-3 provide no value. Action: Break them into separate test() blocks. |
"I'll use page.evaluate() to click the element via JavaScript." | REJECTED. Users cannot fire synthetic JS events; they use a mouse. Action: Ensure the element is not obscured and use a standard .click(). |
| "The test passes locally, so I don't need to check the trace." | REJECTED. Local execution does not mimic CI resource constraints. Action: Verify with tracing or multiple repeats to ensure determinism. |
| "The test passes, so the assertion must be correct." | REJECTED. A pass alone proves nothing. Action: break the condition once during authoring and confirm the test goes red before trusting it. |
| "I'll assert the element is not visible to confirm it was removed." | RISKY. This passes identically whether the element was removed or the locator is simply wrong. Action: confirm the same locator resolves when the element is present, at least once. |
If you see any of the following in existing code, flag them as Required Changes:
.locator('.class-name') instead of semantic queries.nth() or index-based selection when a semantic locator can disambiguate the target.waitForTimeout.await on actions or assertions..not.toBeVisible(), .not.toContainText(), etc.) with no evidence the same locator resolves correctly when the element is present.Before concluding your task, output this checklist and verify each point:
expect().to... for auto-retrying.If any box is unchecked, treat the test as incomplete.
まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Playwright workflows for authenticated browser state reuse through storageState and setup projects.
日本語の概要は準備中です。原文の説明を表示しています。
Diagnostic Playwright workflows for flaky or failing tests, including trace analysis, UI mode, and state isolation.
日本語の概要は準備中です。原文の説明を表示しています。
Playwright workflows for deterministic third-party responses using page.route().
日本語の概要は準備中です。原文の説明を表示しています。