Skip to content

Commit e937891

Browse files
Auto-revert Testclaude
andcommitted
ci(playwright): lint rules for UI-in-setup and unjustified page.reload
Two new om-playwright rules, both wired at error with the existing eslint-suppressions.json ratchet — new violations fail lint, existing ones are grandfathered and can only shrink. no-ui-in-test-setup Bans page.click / fill / press / selectOption / check / uncheck / setInputFiles / hover / dblclick / tap / dragAndDrop / focus / blur inside test.beforeAll / beforeEach / afterAll / afterEach. page.goto is intentionally NOT banned — navigating to the URL under test is legitimate setup; it is the user-input subset that turns setup into a slow UI journey. Push state via apiContext.<Entity>.create() or a REST helper, matching the canonical pattern in this codebase (sampled from ClassificationVersionPage / ServiceEntityVersionPage / MetricVersionPage and every other healthy suite). Motivation: PR #32594 measured 21% of API calls wasted, mostly from UI-driven setup. Every UI click in setup adds ~30 API calls to the SUT; over ~4200 tests this compounds into the timeouts we then call flakiness. Baseline: 15 sites across 10 files (small, easy to work down). no-page-reload-without-justification Bans bare page.reload(). Legit reloads (persistence tests, service- worker upgrades, SSO return flows) pass with a `// TEST_KEEP_RELOAD: <reason>` comment on the line above or on the same line as the call. Receiver is Page-scoped by identifier heuristic (`page`, `p`, any *Page`, `this.page`, `browser.newPage()` result) so domain objects like `store.reload()` don't trigger. Motivation: measured appBootsPerUIScenario is 2.3, convergence target is ≤1. Every reload boots the SPA entry chunk again (index.tsx's recordPlaywrightAppBoot beacon counts it via a favicon fetch). Bare reloads used as "refresh to see the update" are the dominant contributor — a stale UI after mutation is a product bug the test shouldn't work around. Baseline: 217 sites across 90 files. Both rules follow the existing plugin conventions in playwright/eslint-rules/: pure ESM, no external deps, RuleTester tests under tests/, wired into index.mjs, gated at error in eslint.config.mjs. Docs in .claude/rules/frontend-playwright.md list both rules alongside the existing highest-value constraints. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent e09460b commit e937891

8 files changed

Lines changed: 1013 additions & 0 deletions

File tree

.claude/rules/frontend-playwright.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,19 @@ Highest-value constraints, all machine-enforced:
3434
under-reports by design — any call it cannot see inside (a helper, a page object) exempts the
3535
test — so it is a backstop, not a guarantee that every test asserts.
3636
- `test.slow()` only inside the one test that needs it, never at file or describe scope.
37+
- **No UI input actions in setup hooks.** `page.click`, `page.fill`, `page.press`, `page.selectOption`,
38+
etc. inside `test.beforeAll`/`beforeEach`/`afterAll`/`afterEach` fail lint
39+
(`om-playwright/no-ui-in-test-setup`). Push setup state via `apiContext.<Entity>.create()` or a REST
40+
helper — the canonical pattern in this codebase already. `page.goto` in setup is *not* banned; only
41+
the input-action subset is. Rationale: every UI click in setup adds ~30 API calls to the SUT (PR
42+
#32594); the SUT-stress this compounds into is what surfaces as "flakiness".
43+
- **`page.reload()` requires a justification comment.** A bare `await page.reload();` fails lint
44+
(`om-playwright/no-page-reload-without-justification`). If the reload is intentional (persistence
45+
test, service-worker upgrade, SSO return flow), add `// TEST_KEEP_RELOAD: <reason>` on the line
46+
above or on the same line. Rationale: every reload boots the SPA again — measured
47+
`appBootsPerUIScenario` is 2.3, convergence target is ≤1, and unjustified reloads are the dominant
48+
contributor. Prefer trusting the app to refetch on mutation (a stale UI after mutation is a product
49+
bug, not a test workaround).
3750
- No `waitForTimeout`, `networkidle`, `force: true`, `waitForSelector`, or element handles.
3851
- Disabling a rule requires a justification: `-- <why>` appended to the directive. A directive with
3952
**no rule list** is never allowed, justified or not — it silences all 18 rules and CI rejects it.

0 commit comments

Comments
 (0)