/playwright-core
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.
$ npx -y skills add hzijad/playwright-agent-skills --skill playwright-core --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/playwright-core
Context preview
The summary Claude sees to decide when to auto-load this skill.
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.
SKILL.md
playwright-core.SKILL.mdname: playwright-core
description: 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.
Playwright Core: Test Architecture and Quality Gates
Overview
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.
When to Use
- Before writing new Playwright E2E tests or component tests.
- When reviewing a PR that adds or modifies test coverage.
- When fixing a "flaky" test that passes locally but fails in CI.
- When refactoring existing Page Object Models (POMs) or test fixtures.
When Not to Use
- When you need authenticated state reuse; use `playwright-auth-state` instead.
- When you need request interception; use `playwright-network-mocking` instead.
- When you are diagnosing a specific failure or flake; use `playwright-debugging` instead.
- When you need CI configuration, fixture scaffolding, or a broader test framework recipe.
The Five-Axis Test Review
Every Playwright test must be evaluated across these five dimensions before execution:
1. Resiliency (Locator Strategy)
Does the test target user intent, or is it coupled to implementation?
- Are we using `getByRole` as the absolute first choice?
- Are we avoiding CSS classes, XPaths, and DOM hierarchy dependencies?
- If the developer changes a `<div>` to a `<span>`, or swaps a CSS framework (e.g., Bootstrap to Tailwind), will the test survive?
2. Determinism (Web-First Assertions)
Are we relying on Playwright's actionability engine, or are we manually guessing execution speed?
- Are there any `page.waitForTimeout()` calls? These are strictly forbidden.
- Are we using auto-retrying assertions like `expect(locator).toBeVisible()`?
- Are we properly awaiting asynchronous UI state changes, such as waiting for a loading spinner to detach, before interacting?
3. Isolation (Clean Slate)
Can this test run in complete isolation, in any order, and in parallel?
- Does the test rely on data created by a previous test?
- Is state setup and teardown handled cleanly in `test.beforeEach` and `test.afterEach`?
- Are we bypassing the UI for data setup, using API calls to focus purely on the target behavior?
4. Readability (DAMP over DRY)
Can another engineer read the test top-to-bottom and understand the business requirement?
- Do the test names describe the behavior and the outcome?
- Is the test DAMP, meaning Descriptive And Meaningful Phrases? Slight repetition in setup is vastly preferred over 10 layers of abstracted, unreadable helper functions.
- Does the test follow the Arrange-Act-Assert (AAA) pattern clearly?
5. Intent (Testing Behavior)
Does the test verify what the user cares about?
- Are we asserting internal component state variables, or the visible DOM?
- Are we checking for accessibility text rather than raw HTML nodes?
---
Structural Remedies
When you identify a structural problem in a test, do not just patch it. Reach for a named restructuring:
- **Replace brittle CSS selectors** with accessible locators (`getByRole`, `getByLabel`).
- **Replace hardcoded sleeps** with `expect().toBeVisible()` or `page.waitForResponse()`.
- **Collapse abstracted helper logic** back into the test block if it hides the core user journey.
- **Extract deeply nested POMs** into flat, feature-specific Page Objects.
- **Split multi-assertion monolith tests** into separate `test()` blocks with a shared `beforeEach`.
---
Strict Locator Hierarchy
You must follow this exact order of preference when querying the DOM. Fall to the next level only if the previous is impossible.
1. `page.getByRole()` - Always the first choice. Tests accessibility and user intent simultaneously. 2. `page.getByLabel()` - The standard for form inputs. 3. `page.getByPlaceholder()` - Acceptable for inputs without labels. 4. `page.getByText()` - For generic non-interactive text elements. 5. `page.getByTestId()` - The fallback. Use only when semantic querying is impossible, such as dynamic SVG charts. 6. CSS/XPath - Forbidden unless explicitly requested for legacy integration.
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.
---
Code Standards & Anti-Patterns
Web-First Assertions
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();Actionability Before Interaction
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();###
Read more
name: playwright-core description: 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.
Playwright Core: Test Architecture and Quality Gates
Overview
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.
When to Use
- Before writing new Playwright E2E tests or component tests.
- When reviewing a PR that adds or modifies test coverage.
- When fixing a "flaky" test that passes locally but fails in CI.
- When refactoring existing Page Object Models (POMs) or test fixtures.
When Not to Use
- When you need authenticated state reuse; use `playwright-auth-state` instead.
- When you need request interception; use `playwright-network-mocking` instead.
- When you are diagnosing a specific failure or flake; use `playwright-debugging` instead.
- When you need CI configuration, fixture scaffolding, or a broader test framework recipe.
The Five-Axis Test Review
Every Playwright test must be evaluated across these five dimensions before execution:
1. Resiliency (Locator Strategy)
Does the test target user intent, or is it coupled to implementation?
- Are we using `getByRole` as the absolute first choice?
- Are we avoiding CSS classes, XPaths, and DOM hierarchy dependencies?
- If the developer changes a `<div>` to a `<span>`, or swaps a CSS framework (e.g., Bootstrap to Tailwind), will the test survive?
2. Determinism (Web-First Assertions)
Are we relying on Playwright's actionability engine, or are we manually guessing execution speed?
- Are there any `page.waitForTimeout()` calls? These are strictly forbidden.
- Are we using auto-retrying assertions like `expect(locator).toBeVisible()`?
- Are we properly awaiting asynchronous UI state changes, such as waiting for a loading spinner to detach, before interacting?
3. Isolation (Clean Slate)
Can this test run in complete isolation, in any order, and in parallel?
- Does the test rely on data created by a previous test?
- Is state setup and teardown handled cleanly in `test.beforeEach` and `test.afterEach`?
- Are we bypassing the UI for data setup, using API calls to focus purely on the target behavior?
4. Readability (DAMP over DRY)
Can another engineer read the test top-to-bottom and understand the business requirement?
- Do the test names describe the behavior and the outcome?
- Is the test DAMP, meaning Descriptive And Meaningful Phrases? Slight repetition in setup is vastly preferred over 10 layers of abstracted, unreadable helper functions.
- Does the test follow the Arrange-Act-Assert (AAA) pattern clearly?
5. Intent (Testing Behavior)
Does the test verify what the user cares about?
- Are we asserting internal component state variables, or the visible DOM?
- Are we checking for accessibility text rather than raw HTML nodes?
---
Structural Remedies
When you identify a structural problem in a test, do not just patch it. Reach for a named restructuring:
- **Replace brittle CSS selectors** with accessible locators (`getByRole`, `getByLabel`).
- **Replace hardcoded sleeps** with `expect().toBeVisible()` or `page.waitForResponse()`.
- **Collapse abstracted helper logic** back into the test block if it hides the core user journey.
- **Extract deeply nested POMs** into flat, feature-specific Page Objects.
- **Split multi-assertion monolith tests** into separate `test()` blocks with a shared `beforeEach`.
---
Strict Locator Hierarchy
You must follow this exact order of preference when querying the DOM. Fall to the next level only if the previous is impossible.
1. `page.getByRole()` - Always the first choice. Tests accessibility and user intent simultaneously. 2. `page.getByLabel()` - The standard for form inputs. 3. `page.getByPlaceholder()` - Acceptable for inputs without labels. 4. `page.getByText()` - For generic non-interactive text elements. 5. `page.getByTestId()` - The fallback. Use only when semantic querying is impossible, such as dynamic SVG charts. 6. CSS/XPath - Forbidden unless explicitly requested for legacy integration.
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.
---
Code Standards & Anti-Patterns
Web-First Assertions
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();Actionability Before Interaction
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();###
Showing the first part of this file.
Playwright test patterns that avoid the mistakes agents make by default. Playwright Agent Skills is a small, opinionated set of reusable prompts for writing and reviewing Playwright tests.
Repo: hzijad/playwright-agent-skills
Other skills on playwright-agent-skills.
- /playwright-auth-state
Playwright workflows for authenticated browser state reuse through storageState and setup projects.
Open skill - /playwright-debugging
Diagnostic Playwright workflows for flaky or failing tests, including trace analysis, UI mode, and state isolation.
Open skill - /playwright-network-mocking
Playwright workflows for deterministic third-party responses using page.route().
Open skill

