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, and the magic-number / hard-coded-string anti-patterns; the E2E selector-priority and web-first-assertion 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.

75

Quality

94%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

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