test-file-split
Skill517 starsChanged 3 days agoMITView on GitHub
Protocol for splitting test files that approach or exceed the FR-006 500-line limit (enforced in CI by scripts/check-test-file-cap.ts as a diff-scoped ratchet). Covers describe-block extraction, shared helper management, pure-function extraction, mock isolation verification, and cascading-split detection. Load when a test file approaches or exceeds 500 lines.
We split this skill into the rules it gives an agent
8 rules. About 0 are common, 2 are distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 12
Read first: .opencode/skills/writing-tests/SKILL.md (or .claude/skills/writing-tests/SKILL.md) for bun:test framework rules, mock isolation …
- Very specific: line 46
Create tests/helpers/<module>-shared.ts with shared fixtures, mock factories, and setup functions.
- Very specific: line 49
If only bun:test imports and 1-2 source imports are shared, duplicate them in both files.
- Very specific: line 53
Before renaming or moving shared code as part of the split, size the blast radius with the repo_map tool: run repo_map with action …
- Distinctive: line 63
Add all necessary imports to the new file.
- Distinctive: line 64
Remove now-unused imports from the original file.
- Very specific: line 87
If the co-run fails but isolated runs pass, check for mock.module() leakage.
- Very specific: line 91
After splitting, evaluate whether internal utility functions in the source module can be exported via _test_exports for zero-mock testing.
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Test File Split Protocol (FR-006)
scripts/check-test-file-cap.ts enforces the 500-line cap per test file (FR-006 / SC-006.1) as a diff-scoped ratchet: new test files over 500 lines and existing over-cap files that grew fail the quality gate and block PR merge. Pre-existing over-cap files not touched by the PR are non-blocking. Escape hatch: TEST_CAP_ENFORCE=0 soft-warns. This skill covers the complete splitting protocol.
Read first: .opencode/skills/writing-tests/SKILL.md (or .claude/skills/writing-tests/SKILL.md) for bun:test framework rules, mock isolation patterns, and file placement conventions.
When to use this skill
- A test file exceeds or approaches 500 lines
- CI fails with an FR-006 file-size violation
- You are adding tests to a file that is already above 400 lines (proactive split)
Step 1 — Measure and identify split boundaries
# Check the file
wc -l tests/unit/scripts/my-module.test.ts
# Find all test files exceeding 400 lines (early warning)
find tests/ -name "*.test.ts" -exec wc -l {} \; | sort -rn | awk '$1 > 400'Identify natural describe() block boundaries. Group blocks by functional area:
- Each
describe()block should belong to exactly one split file - Shared
beforeEach/afterEachhooks determine which blocks must stay together
Step 2 — Choose a suffix for the new file
| Pattern | Example | When to use |
<module>-<area>.test.ts | release-notes-fragments-sha.test.ts | Split by functional area (SHA resolution, validation, merge logic) |
<module>-<area>.adversarial.test.ts | auth-login.adversarial.test.ts | Split adversarial tests into their own file |
Step 3 — Manage shared imports and helpers
Three options, in order of preference:
- Extract to shared utility (preferred for complex shared setup):
Create
tests/helpers/<module>-shared.tswith shared fixtures, mock factories, and setup functions. Import from both split files. - Duplicate simple imports (for small overlap):
If only
bun:testimports and 1-2 source imports are shared, duplicate them in both files. Simpler than a utility module for trivial cases. - Extract pure functions from source (for testability):
If the source module has inline validation logic, extract them as exported pure functions (e.g.,
isValidPrNumber,resolveAllCandidates) so both test files can target them independently. See the PR #1762 example below. The extraction pattern: move the inline predicate or validator into an exported pure function and import it from both test files. Before renaming or moving shared code as part of the split, size the blast radius with the repo_map tool: runrepo_mapwith actionimporterson the target file to find every consumer,repo_map(action:dependencies) to see what the target itself needs, andrepo_mapwith actionblast_radiusto enumerate transitive dependents before you move anything.
Step 4 — Extract and move describe blocks
- Cut the selected
describe()blocks from the original file. - Paste them into the new file.
- Add all necessary imports to the new file.
- Remove now-unused imports from the original file.
Step 5 — Verify both files
Line count check
wc -l tests/unit/scripts/my-module.test.ts tests/unit/scripts/my-module-sha.test.ts
# Both must be under 500 linesIsolated run
bun --smol test tests/unit/scripts/my-module.test.ts --timeout 60000
bun --smol test tests/unit/scripts/my-module-sha.test.ts --timeout 60000Co-run (mock isolation verification)
# Critical: Bun shares a single process across test files.
# mock.module leaks can cause co-run failures even when isolated runs pass.
bun --smol test tests/unit/scripts/my-module*.test.ts --timeout 60000If the co-run fails but isolated runs pass, check for mock.module() leakage. See .opencode/skills/writing-tests/SKILL.md → "Mock Isolation Rules" and the _internals DI seam pattern.
Step 6 — Evaluate _test_exports opportunity
After splitting, evaluate whether internal utility functions in the source module can be exported via _test_exports for zero-mock testing. This is a natural cleanup moment — the split already forces you to review test coverage boundaries.
Cascading split warning
If a previously split file exceeds 500 lines again, the test suite is structurally too large for a single module. Do not split a third time — reorganize the tests by source module boundaries instead. Repeated splitting produces fragmented test suites that are hard to navigate and maintain.
Real-world example (PR #1762)
tests/unit/scripts/release-notes-fragments.test.ts exceeded 500 lines. It was split into:
| File | Lines | Content |
release-notes-fragments.test.ts | 379 | Fragment collection, deduplication, output formatting |
release-notes-fragments-sha.test.ts | 261 | extractCommitShasFromBody, mergeCandidateLists, resolveAllCandidates, isValidPrNumber, stripCustomReleaseNotesBlock |
The split also extracted isValidPrNumber and resolveAllCandidates as pure exported functions from the source module, enabling independent testing.
Other versions1 project uses a version of this.
Word for word · 1
- zaxbysauce/opencode-swarm★ 517100% same
Edited · 0
None found.
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository66 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- ci-fix-monitorSkill
- codebase-review-swarmSkill
- commit-prSkill
- contributingSkill
- engineering-conventionsSkill
- fork-pr-operationsSkill
- guardrail-patternsSkill
- issue-tracerSkill
- mock-to-internals-migrationSkill
- pr-review-fixSkill
- qa-sweepSkill
- research-firstSkill
- running-testsSkill
- subprocess-safetySkill
- swarm-ci-monitorSkill
- swarm-implementSkill
- swarm-pr-feedbackSkill
- swarm-pr-reviewSkill
- swarm-pr-subscribeSkill
- swarmSkill
- tech-debt-ci-reviewSkill
- unswarmSkill
- writing-testsSkill
- brainstormSkill
- clarifySkill
- clarify-specSkill
- codebase-review-swarmSkill
- commit-prSkill
- consultSkill
- councilSkill
- critic-gateSkill
- deep-diveSkill
- deep-researchSkill
- design-docsSkill
- discoverSkill
- durable-session-stateSkill
- editing-skillsSkill
- engineering-conventionsSkill
- executeSkill
- fork-pr-operationsSkill
- graphifySkill
- issue-ingestSkill
- issue-tracerSkill
- orchestrating-subagentsSkill
- phase-wrapSkill
- pre-phase-briefingSkill
- qa-sweepSkill
- research-firstSkill
- rust-crate-ciSkill
- specifySkill
- swarm-ci-monitorSkill
- swarm-implementSkill
- swarm-planSkill
- swarm-pr-feedbackSkill
- swarm-pr-reviewSkill
- swarm-pr-subscribeSkill
- swarm-resumeSkill
- The first 60 shown.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

