Running Jest and Vitest in the same repo doubles CI runtime because every pipeline executes both runners to cover both test sets. Coverage reports fragment across two tools and merge incorrectly, snapshot formats differ enough to produce false diffs when someone runs the wrong runner, and global setup files (mocks, polyfills, fetch shims) must be duplicated in two configs. Test authors pick whichever syntax they remember, and the suite's actual coverage is impossible to measure accurately.
Medium because the primary impact is CI time and coverage-report unreliability rather than production correctness.
Pick Vitest for new projects (Jest-compatible API, faster, ESM-native) or stay on Jest if you have heavy jest.mock usage. Migrate config, then convert mocks:
# Replace jest.config.js with vitest.config.ts
# Global sed over test files:
# jest.fn() -> vi.fn()
# jest.mock() -> vi.mock()
npm uninstall jest @types/jest ts-jest babel-jest
Update package.json test scripts and remove Jest-specific setup files from src/__tests__/setup/.
ID: ai-slop-code-drift.tooling-stack-drift.dual-test-framework
Severity: medium
What to look for: Apply the three-condition rule against this exact UNIT test framework allowlist: jest, vitest, mocha, ava, tape, tap, @japa/runner, node:test. Note: E2E test frameworks (@playwright/test, cypress, puppeteer, webdriverio, nightwatch) are NOT counted — they coexist with unit test frameworks by design. Count all REMAINING libraries that meet all three conditions (at least 1 non-escape-hatch importing file). Also check package.json devDependencies for these (test runners are usually devDeps, not runtime deps).
Pass criteria: 0 or 1 unit test frameworks from the allowlist actively used. Report even on pass: "Canonical unit test framework: [name] ([N] test files)."
Fail criteria: 2 or more unit test frameworks from the allowlist meet the criteria — half the tests run in Jest, half in Vitest, neither runs the full suite.
Skip (N/A) when: 0 unit test frameworks from the allowlist appear in dependencies OR devDependencies (project has no unit tests at all).
Cross-reference: For test quality analysis, the Test Reality audit (ai-slop-test-theater) checks whether your tests actually test anything.
Detail on fail: "2 active unit test frameworks: 'jest' (12 test files) AND 'vitest' (8 test files). Migrate to one — running both means CI runs the full suite twice."
Remediation: Two test runners means two configs, two snapshot systems, two assertion styles, two CI commands. Pick one and migrate:
# Convert all jest tests to vitest (or vice versa)
# Vitest is largely Jest-compatible, so the migration is mostly:
# - replace `jest.config.js` with `vitest.config.ts`
# - replace `jest.fn()` with `vi.fn()`
# - replace `jest.mock()` with `vi.mock()`
npm uninstall jest @types/jest ts-jest