Extraction hazards, ranked
benchchanged from a top-level import (v2-v4) to aTestContextfixture (v5), the single test-declaring callable whose entire declaration shape differs across the majors the extractor will encounter in real repos. Getting this wrong either misses all v5 benchmarks or crashes on v4 ones..sequentialwas removed in v5 (test.sequential,describe.sequential, and thesequentialconfig option are all gone) but is common in v2-v4 corpora, treating it as an unknown/ignored member on a v5-only extractor silently drops a real modifier from older code.globals: trueresolution is per-project, not per-repo,test.projectsentries can setextends: falseand diverge onglobals, so a baretest(...)identifier’s meaning depends on which project’s resolved config governs that file. A single “did this repo set globals” boolean is wrong for any repo using projects/workspace with mixed configs.- Look-alikes share call shape, not identity, Playwright, Jest, Cypress, node:test, and Mocha
all expose a
describe(string, fn)/it(string, fn)shape nearly indistinguishable from Vitest’s by name alone. Only import-specifier resolution (or, for globals, resolved per-project config plus absence of any other test-framework import) is sound; name-based matching produces false positives. .each/.fortitle strings are only reproducible when the table is a literal, a non-literal table argument (test.each(getCases())) means row values, row count, and therefore concrete titles are unknowable statically; the extractor must degrade to “unresolved” rather than guess, and must not silently treat it as zero tests.- Title-rendering itself changed in v5 (
pretty-format, no quote-wrapping of interpolated strings, new truncation option), byte-exact title reproduction is version-dependent, not a single fixed algorithm. - Options-object vs. bare-function 2nd argument is a type disambiguation, not a positional one:
test(name, fn)vstest(name, options, fn)requires checking whether the 2nd arg is aFunctionor anObjectliteral; modifier flags can also arrive via the options object ({ skip: true }) and must be unioned with chain-based flags (test.skip) rather than treated as mutually exclusive sources. - Fixture “reaches the callback” the same way built-in context members do, a destructured
name in a test callback is ambiguous between a Vitest built-in (
expect,task,skip,benchin v5) and a usertest.extendfixture unless cross-referenced against the specifictestbinding’s.extendchain; a naive allowlist/denylist of “known” context names breaks the moment a fixture happens to reuse a common name. - In-source tests bind
test/it/expectoffimport.meta.vitest, not off a'vitest'import specifier and not off ambient globals, a resolver that only checks import specifiers orglobals: truewill miss every in-source test, andincludeSource(default[]) gates which files even get scanned for theimport.meta.vitestguard, independently of the ordinaryincludeglob. - A local variable can be named
test/describe/itwithout being Vitest’s (shadowing an import, or a plain helper function), name matching without binding resolution produces false positives even inside an otherwise-legitimate Vitest file. - The mocking family is modelled only where hoisting makes a file-wide answer sound:
collect_mocked_modulesfolds module-top-levelvi.mock/vi.unmockwith string-literal specifiers into one mock set (last in source order wins per specifier, verified against a real Vitest 5 run, see §12), and taints the whole file for everything else: the non-hoistedvi.doMock/vi.doUnmock, an unreadable specifier or factory, and any of the four called outside module top level. A tainted file’s tests are excluded from comparison entirely, which trades a possible false duplicate for a certain false negative, the same direction throughout. The top-level restriction matters because the scan is a whole-program AST walk, and avi.mockfound inside adescribe, a test body, or anifmust not be recorded as file-wide. Vitest 5 refuses to run such a file at all (vitest:mocks: “defined outside of the module’s top level scope”), so there is no runtime context there to model, including in the conditional case, where the call is hoisted out of the branch. See §12 for the full table andfixtures/edge/vi-unmock-file-wide.test.ts/vi-dounmock-scoped.test.ts, which demonstrate the modelled and tainted shapes respectively, and thefixtures/duplicates/not-duplicates-mock-then-unmock*pair, which asserts the mocked and mocked-then-unmocked contexts are compared and found different rather than excluded.[status: current]as implemented bycollect_mocked_modulesinsrc/frontend/extract.rs.
Back to the Vitest surface index.