|
| 1 | +--- |
| 2 | +name: consolidating-test-setup |
| 3 | +description: Consolidates repeated test setup and teardown into the narrowest shared lifecycle owner. Use when test files repeat initialization, cleanup, environment management, fixtures, or equivalent test doubles. |
| 4 | +--- |
| 5 | + |
| 6 | +# Consolidating test setup |
| 7 | + |
| 8 | +Move repeated test plumbing to the narrowest shared owner that can provide it |
| 9 | +reliably. Keep test files focused on behavior. |
| 10 | + |
| 11 | +## Principles |
| 12 | + |
| 13 | +### Prove the code is equivalent |
| 14 | + |
| 15 | +Repetition is evidence, not proof. Similar code may use different defaults, |
| 16 | +ordering, or lifetimes. Group candidates by behavior before treating them as |
| 17 | +duplicates. |
| 18 | + |
| 19 | +### Centralize invariants, not scenarios |
| 20 | + |
| 21 | +Shared setup should establish conditions that hold for every test in its scope. |
| 22 | +State that explains one scenario belongs with that scenario. |
| 23 | + |
| 24 | +### Use the narrowest owner |
| 25 | + |
| 26 | +Prefer the mechanism that already owns the lifecycle. Use runner configuration |
| 27 | +before hooks, scoped fixtures before global setup, and local setup for local |
| 28 | +requirements. Wider reuse is not better reuse. |
| 29 | + |
| 30 | +### Treat setup and teardown as one contract |
| 31 | + |
| 32 | +Define who creates state, how long it lives, and who releases it. Cleanup must |
| 33 | +finish even when a test fails. Tests must not depend on execution order or on |
| 34 | +another test's cleanup. |
| 35 | + |
| 36 | +A shared default should be deterministic and easy to override. Local exceptions |
| 37 | +must not weaken isolation elsewhere. |
| 38 | + |
| 39 | +### Subtract before abstracting |
| 40 | + |
| 41 | +Remove suspected cargo-cult setup and run the affected tests. A targeted pass |
| 42 | +only marks it provisionally unnecessary. Delete it after the complete relevant |
| 43 | +suite and runner-specific lifecycle checks pass. If a test fails, use the |
| 44 | +failure to identify the contract before designing shared setup. |
| 45 | + |
| 46 | +A helper must own a policy or lifecycle, or remove meaningful reader effort. |
| 47 | +Moving the same lines behind a new name is not an improvement. |
| 48 | + |
| 49 | +### Preserve test intent |
| 50 | + |
| 51 | +Do not hide state that matters to the behavior under test. Check history before |
| 52 | +removing synchronization or cleanup because it may guard a past regression. |
| 53 | +Preserve that guarantee even if the implementation changes. |
| 54 | + |
| 55 | +## Runner-specific guidance |
| 56 | + |
| 57 | +Load only the reference for the runner in use: |
| 58 | + |
| 59 | +- [`reference/vitest.md`](reference/vitest.md) for Vitest and similar |
| 60 | + in-process unit-test runners |
| 61 | +- [`reference/playwright.md`](reference/playwright.md) for Playwright and |
| 62 | + similar browser-test runners |
| 63 | + |
| 64 | +These references supplement the repository's testing guide. They do not replace |
| 65 | +it. Load both only when the task spans both runners. |
| 66 | + |
| 67 | +## Workflow |
| 68 | + |
| 69 | +### 1. Discover |
| 70 | + |
| 71 | +Read the runner configuration, setup files, fixtures, helpers, and test guidance. |
| 72 | +Count repeated lifecycle behavior and note the suites that use it. |
| 73 | + |
| 74 | +### 2. Classify |
| 75 | + |
| 76 | +For each candidate, record: |
| 77 | + |
| 78 | +- the state it owns |
| 79 | +- its lifetime and scope |
| 80 | +- whether it is an invariant or scenario detail |
| 81 | +- intentional differences between suites |
| 82 | +- behavior already supplied by the runner |
| 83 | + |
| 84 | +### 3. Challenge |
| 85 | + |
| 86 | +Remove the candidate and run every affected suite. Classify it as unnecessary, |
| 87 | +universal, common with exceptions, or suite-specific. |
| 88 | + |
| 89 | +Subagents may evaluate disjoint groups of suites. Require evidence and exception |
| 90 | +reports from each. Keep the design and integration decision in the parent task. |
| 91 | + |
| 92 | +### 4. Place |
| 93 | + |
| 94 | +Choose the required lifetime and scope first. Then use the simplest owner at |
| 95 | +that exact boundary: |
| 96 | + |
| 97 | +- native runner behavior that supports the required scope |
| 98 | +- existing shared setup, fixture, or hook |
| 99 | +- a focused helper or test double |
| 100 | +- the individual suite |
| 101 | + |
| 102 | +Do not move state to a broader owner because its mechanism appears earlier in |
| 103 | +the list. |
| 104 | + |
| 105 | +### 5. Migrate |
| 106 | + |
| 107 | +Move one responsibility at a time. Add the shared owner, then remove only the |
| 108 | +local code it replaces. Keep intentional exceptions and scenario setup visible. |
| 109 | +Avoid unrelated test rewrites. |
| 110 | + |
| 111 | +### 6. Prove |
| 112 | + |
| 113 | +Run affected tests, tests of the shared lifecycle, repository static checks, and |
| 114 | +the complete relevant suite. Measure before and after when the new behavior runs |
| 115 | +for every test. Use enough comparable samples to separate a real change from |
| 116 | +normal variance. |
| 117 | + |
| 118 | +## Report |
| 119 | + |
| 120 | +State the repeated contract, its new owner, retained exceptions, rejected |
| 121 | +alternatives, duplication removed, and validation results. Include performance |
| 122 | +evidence when shared setup could affect suite runtime. |
| 123 | + |
| 124 | +## Guardrails |
| 125 | + |
| 126 | +- Do not replace native runner behavior with a custom abstraction. |
| 127 | +- Do not widen setup scope without evidence. |
| 128 | +- Do not add a helper merely to move code. |
| 129 | +- Do not hide global mutable state behind helper indirection. |
| 130 | +- Do not trade visible test intent for shorter files. |
| 131 | +- Do not trust targeted tests alone after changing shared lifecycle behavior. |
0 commit comments