Test code quality and conventions
The core principle: test code is production code. We review it just as seriously, because we will maintain it for years too. The only difference is the audience — the test code's "user" is a future teammate.
Naming rules:
- The test name states the behaviour:
test('rejects login with expired password')— nottest('test2') - File names match the feature:
checkout-coupon.spec.ts - POM methods express user intent:
applyCoupon(code)— notclickBtn3() - Locator variables named by the element's role:
submitButton,errorAlert - Boolean helpers phrased as questions:
isCartEmpty()
Structure rules: one test — one behaviour; the AAA split visible via blank lines; no if/for inside a test (conditional logic makes it non-deterministic — use parameterisation); never swallow failures with try/catch.
Automated enforcement beats human enforcement — keep conventions in the linter, not in a document. The TypeScript + ESLint (typed linting) + eslint-plugin-playwright + Prettier set ends team arguments: formatting is checked in CI, style debates leave code review, and review focuses on logic only.
The single most critical rule is no-floating-promises. The Playwright API is fully async; a line with a forgotten await silently doesn't execute and the test stays green — a false positive. This is the most dangerous class of bug in automation, because it produces no signal at all.
| Rule | What it prevents |
|---|---|
| @typescript-eslint/no-floating-promises | A missing await silently skipping the line — a falsely green test |
| playwright/no-wait-for-timeout | Fixed sleeps — slowness and flakiness |
| playwright/no-focused-test | A forgotten test.only — the suite going "green" on 1 test |
| playwright/expect-expect | An assertion-less "test" — a check that can never fail |
| playwright/no-conditional-in-test | Non-deterministic, hard-to-explain tests built on if/else |
A very strong interview answer to "what's the most dangerous test bug?" → a forgotten `await`. The test is green but verifies nothing. Say you close it with the no-floating-promises lint rule — that shows "I solve problems once" thinking, a middle+ signal.
📚 Sources and documentation
- Best practicesofficialplaywright.dev