test-in-tests-folder
Flags a unit test in a separate tests directory instead of beside its subject.
Deterministic checkAdvises by default
Why this rule
Test Files
- A unit test sits beside its source file:
src/auth/AuthService.ts→src/auth/AuthService.unit.test.ts. - Scenario suites: when one boundary genuinely needs more than one test
file (a pipeline with distinct monorepo/nested/park scenarios), qualify the
name —
<File>.<scenario>.unit.test.ts, e.g.runImplementPipeline.monorepo.unit.test.ts. The first segment must name a real source file in the folder; the qualifier is camelCase. A test file whose subjects span several source files is a split candidate, not a naming exception — one subject per test file. - A test imports its subject from the subject's own file: a test beside its
source imports the file it tests (
./AuthService), never an index file (./index) — an import through one loads every file it re-exports to reach one name. A test inside a module may import that module's other files too; a test outside it imports only the module's public files, as any other caller would. - Shared test helpers, mocks, and fixtures live outside
src/in the package's test-support directories (tests/helpers/,test/mocks/,test/fixtures/, a__mocks__/folder beside the module it doubles); only test files themselves sit beside their source. Test-support code undersrc/would read as production source — to scanners and humans alike. - First import:
import { expect, describe, test, jest } from '@jest/globals';— but includejestonly when the file actually usesjest.fn/jest.mock/jest.spyOn, and importbeforeEach/afterEach/afterAllonly when genuinely needed (with setup factories and config-level mock cleanup, most files need none). An unused import failsnoUnusedLocals/lint. - The first
describematches the name of the class or function under test. Keepdescribeblocks flat — scenario variants come fromsetup()parameters, not nesteddescribe+beforeEachpyramids. When you do nest, prefix withwhen ...(condition) orfor ...(variant).
Test files live adjacent to the file they test — never in separate __tests__/ directories.
Examples
The check flags the incorrect code and passes the correct code. Each example is a small repo, because this rule looks across files. It opens on the file that matters; the other files are the repo around it.
Incorrect
srcfeaturetests
export const getLabel = ({ name }: { name: string }): string => name.trim();
Correct
srcfeature
export const getLabel = ({ name }: { name: string }): string => name.trim();
Configure
- Block
"blocking"Stops a run when a file the run changed breaks the rule. - AdviseDefault
"advisory"Reports it and hands it to the refactor agent. Never stops a run. - Off
"off"Not checked. Use it when your own linter already enforces the rule.
Add this to your lightsout.config.json, then change the value.
{"standards-checks": {"test-in-tests-folder": "advisory"}}