Pure-reference catalog of test-code conventions: AAA structure (Arrange / Act / Assert), per-test single-responsibility, descriptive naming (`{sut}_{scenario}_{expected}`), assertion specificity, mocking rationale (state vs behavior, fake vs mock), fixture-coupling rules, the magic-number / hard-coded-string anti-patterns, and step design (§11: FIRST principles, step granularity, the mechanical → page → business abstraction layers, the rule-of-three extraction heuristic, declarative phrasing); the E2E selector-priority, web-first-assertion, and step-grouping conventions live in references/. Use as the shared rule book a test-code review cites back to, or as onboarding for what makes a test code-reviewable; to score a test's quality on weighted axes use test-design-scorecard, and for setup/teardown isolation specifically use test-isolation-patterns.
88
88%
Does it follow best practices?
Impact
—
Average score across 10 eval scenarios
Passed
No findings from the security scan
Deep reference for the test-code-conventions SKILL.md (§8 and §9). Consult when reviewing end-to-end tests (Playwright / Cypress / Selenium / WebdriverIO) where locator fragility or synchronous assertions are the concern. The universal conventions (§1-§7, §10) stay in the SKILL; these two are E2E-specific.
Per Playwright best practices: "Your DOM can easily change so having your tests depend on your DOM structure can lead to failing tests."
Per Testing Library query priority (highest to lowest):
| Priority | Query | When to use |
|---|---|---|
| 1 | getByRole('button', { name: 'Submit' }) | Default. Tests via the accessibility tree - the same path users take. |
| 2 | getByLabelText('Email') | Form fields with an associated <label>. |
| 3 | getByPlaceholderText, getByText, getByDisplayValue | When labels aren't available. |
| 4 | getByAltText, getByTitle | Images, tooltips. |
| 5 | getByTestId('submit-button') | Last resort. Per Testing Library: "The user cannot see (or hear) these." |
CSS class selectors (.button-primary) and XPath (//div[@class='cart']//button[1]) are not on the priority list - per Playwright best practices they are explicitly identified as brittle.
The same convention holds across runners: Playwright (page.getByRole(...)), Cypress (cy.findByRole(...) via cypress-testing-library), and Selenium (when the test framework supports role-based queries via extensions).
Per Playwright best practices: avoid "manual assertions without waiting. Using isVisible() checks immediately without awaiting, rather than web-first assertions like toBeVisible() that wait for conditions to be met."
// Bad - race condition
expect(page.locator('.toast').isVisible()).toBe(true);
// Good - auto-waits
await expect(page.locator('.toast')).toBeVisible();The web-first form auto-waits for the assertion to become true within the test's timeout, eliminating the wait-N-seconds-and-hope pattern. A synchronous .isVisible() snapshot races the render and flakes on any latency the test author did not anticipate.
// Before - brittle selector, synchronous assertion
await page.locator('.cart-panel .btn-primary').click();
expect(page.locator('.toast-success').isVisible()).toBe(true);
// After - accessibility-first selector, web-first assertion
await page.getByRole('button', { name: 'Checkout' }).click();
await expect(page.getByRole('status')).toHaveText('Order confirmed');The rewrite resolves the button through the accessibility tree (survives DOM refactors) and awaits the outcome (no render race).