Files
orca/config/scripts/vitest-module-cache-resolution-key.test.ts
T
8b64ec281a ci: restore main's Vitest transform cache in PR unit shards (#34512)
* ci: restore main's Vitest transform cache in PR unit shards

Main produces per-shard transform caches on a schedule; PR shards restore
the newest one for the same config/lockfile/runtime policy. A Vitest cache
key generator folds each literal specifier's resolution candidates into the
per-module key so newly added files that shadow a resolution invalidate the
importer, and bails on glob-expanded dynamic imports.

* ci: list the resolution key plugin in the node tsconfig project

* ci: accept Vitest's CACHEDIR.TAG when sealing the unit module cache

Vitest 5.0.5 tags its cache root, which made every seal fail with
'invalid cache entry name' so no producer cache was ever saved.

* ci: reseed the unit module cache when any cache-key input lands on main

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-10-27 20:04:56 -07:00

58 lines
2.1 KiB
TypeScript

import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, expect, it } from 'vitest'
import {
createResolutionFingerprint,
hasExpandedImport
} from './vitest-module-cache-resolution-key'
const roots: string[] = []
afterEach(() => {
for (const root of roots.splice(0)) {
rmSync(root, { recursive: true, force: true })
}
})
function fixture(): string {
const root = mkdtempSync(join(tmpdir(), 'orca-resolution-key-'))
roots.push(root)
mkdirSync(join(root, 'src/lib/foo'), { recursive: true })
writeFileSync(join(root, 'src/lib/foo/index.ts'), '')
return root
}
const source = "import a from './lib/foo'\nimport b from '@/lib/foo?raw'"
const aliases = (root: string) => [{ find: '@', replacement: join(root, 'src') }]
it.each([
['a same-stem sibling shadows a directory index', 'src/lib/foo.ts'],
['a higher-precedence extension appears', 'src/lib/foo.mts'],
['another index candidate appears', 'src/lib/foo/index.mts'],
['the directory gains a package.json', 'src/lib/foo/package.json']
])('changes the key when %s', (_, added) => {
const root = fixture()
const before = createResolutionFingerprint(root, aliases(root))(join(root, 'src/a.ts'), source)
writeFileSync(join(root, added), '{}')
const after = createResolutionFingerprint(root, aliases(root))(join(root, 'src/a.ts'), source)
expect(after).not.toBe(before)
})
it('keeps the key when an unrelated sibling appears', () => {
const root = fixture()
const before = createResolutionFingerprint(root, aliases(root))(join(root, 'src/a.ts'), source)
writeFileSync(join(root, 'src/lib/bar.ts'), '')
const after = createResolutionFingerprint(root, aliases(root))(join(root, 'src/a.ts'), source)
expect(after).toBe(before)
})
it.each([
['import(`./locales/${name}.ts`)', true],
["import('./locales/' + name + '.ts')", true],
['import.meta.glob("./*.ts")', true],
["import('./locales/en.ts')", false],
['import(specifier)', false]
])('treats %s as directory-dependent: %s', (code, expected) => {
expect(hasExpandedImport(code)).toBe(expected)
})