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
Reference detail for test-code-conventions §11 (step design): how test steps are grouped into phases and how they are phrased. The SKILL.md spine summarizes and links here; this file holds the full tables, guidance, and code.
Two equivalent step-grouping vocabularies. Same content, different name conventions.
| AAA (xUnit tradition) | Given-When-Then (BDD tradition) |
|---|---|
| Arrange | Given |
| Act | When |
| Assert | Then |
| (Annotate) | (no equivalent; goes in step comments) |
Both express the same three phases. The team picks one and uses it consistently. Don't mix: if some tests use AAA comments and others use Given-When-Then helpers, the cognitive cost grows.
Whatever vocabulary the team uses, the phases must be visually separable. The pattern from test-code-conventions §1:
test('places an order', async () => {
// Arrange
const customer = await aCustomer().withCartItem('sku-001').build();
// Act
const order = await customer.placesOrder();
// Assert
expect(order.status).toBe('confirmed');
});Or, with blank-line separation (no comments needed):
test('places an order', async () => {
const customer = await aCustomer().withCartItem('sku-001').build();
const order = await customer.placesOrder();
expect(order.status).toBe('confirmed');
});Either works; lacking either fails the §1 AAA review.
Even at the business layer, two phrasings exist:
| Imperative | Declarative |
|---|---|
| "The customer enters the email and password and clicks submit" | "The customer signs in" |
| "The customer adds 5 items to the cart and proceeds to checkout" | "The customer initiates checkout with a 5-item cart" |
| "The customer is created with role=admin and org_id=42" | "An admin customer in org 42" |
The declarative form is preferred per Cucumber's better-Gherkin guidance (which applies broadly, not just to Gherkin): "scenarios should describe the intended behaviour of the system, not the implementation."
The test: would the wording need to change if the implementation changed? If yes, the step is imperative; rewrite declaratively.
| Anti-pattern | Why it fails |
|---|---|
Declarative step that hides a critical mechanic (customer.signsIn() when the test is about SSO redirect) | The test no longer tests what it claims to test |
| Imperative step that re-describes the system internals | Brittle to refactors; the test breaks when the implementation changes for unrelated reasons |
| Mixing imperative and declarative within one test | Reader can't tell what abstraction level they're operating at |