Install
$ agentstack add skill-hzijad-playwright-agent-skills-playwright-core ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
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-stateinstead. - When you need request interception; use
playwright-network-mockinginstead. - When you are diagnosing a specific failure or flake; use
playwright-debugginginstead. - 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
getByRoleas the absolute first choice? - Are we avoiding CSS classes, XPaths, and DOM hierarchy dependencies?
- If the developer changes a `
to a`, 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.beforeEachandtest.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()orpage.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 sharedbeforeEach.
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.
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.- 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();
The Anti-Rationalization Table
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. |
Red Flags in Code Review
If you see any of the following in existing code, flag them as Required Changes:
- Use of
.locator('.class-name')instead of semantic queries. - Use of
nth()or index-based selection when a semantic locator can disambiguate the target. - Tests relying on the execution outcome of the test immediately above them.
- Any instance of
waitForTimeout. - Complex if/else logic inside a test file. Tests should be linear paths.
- Unhandled promises, such as missing
awaiton actions or assertions. - Testing external dependencies, for example hitting the real Stripe API instead of mocking it.
Verification & Handoff Checklist
Before concluding your task, output this checklist and verify each point:
- [ ] All locators are user-facing (getByRole, getByLabel, etc.).
- [ ] No hardcoded sleeps or waitForTimeout calls exist.
- [ ] Assertions use
expect().to...for auto-retrying. - [ ] The test is strictly isolated and can run in any order.
- [ ] External dependencies are mocked or intercepted.
- [ ] The test reads like a human user journey, not an implementation walkthrough.
If any box is unchecked, treat the test as incomplete.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: hzijad
- Source: hzijad/playwright-agent-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.