CtrlK
BlogDocsLog inGet started
Tessl Logo

testland/test-code-conventions

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

Quality

88%

Does it follow best practices?

Impact

Average score across 10 eval scenarios

SecuritybySnyk

Passed

No findings from the security scan

Overview
Quality
Evals
Security
Files

e2e-selector-and-assertion-conventions.mdreferences/

E2E selectors and web-first assertions

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.

§8 - E2E selectors

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):

PriorityQueryWhen to use
1getByRole('button', { name: 'Submit' })Default. Tests via the accessibility tree - the same path users take.
2getByLabelText('Email')Form fields with an associated <label>.
3getByPlaceholderText, getByText, getByDisplayValueWhen labels aren't available.
4getByAltText, getByTitleImages, tooltips.
5getByTestId('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).

§9 - Web-first assertions (E2E)

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.

Worked example - reviewing one E2E test file

// 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).

References

SKILL.md

tile.json