test(ci): consolidate import resolution behavior proof (#29782)

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
OrcaWin
2026-10-16 11:05:42 -07:00
committed by GitHub
co-authored by OrcaWin
parent f73ab77b46
commit 42dfd813fe
2 changed files with 37 additions and 61 deletions
@@ -1,8 +1,11 @@
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 { collectUnitDependencyGraph } from './ci-unit-dependency-graph.mjs'
import { afterEach, describe, expect, it } from 'vitest'
import {
buildUnitDependencyGraph,
collectUnitDependencyGraph
} from './ci-unit-dependency-graph.mjs'
import { selectUnitFiles } from './ci-unit-selection.mjs'
const temporary = []
@@ -141,3 +144,35 @@ it.each([
})
}
)
describe('unit graph import resolution', () => {
it('keeps first-match precedence across literal paths, extensions and index files', () => {
const sources = new Map([
['src/leaf', ''],
['src/leaf.ts', ''],
['src/leaf.tsx', ''],
['src/component.tsx', ''],
['src/component.js', ''],
['src/folder/index.ts', ''],
['src/folder/index.tsx', ''],
['src/config.json', '{}'],
['src/renderer/src/view.tsx', ''],
['src/use.ts', "import './leaf'; import './component'; import './folder'; import './config'"],
['src/aliases.ts', "import '@renderer/view'; import '@/view'; import 'external-package'"],
['src/missing.ts', "import './missing-file'"],
['src/dynamic.ts', 'import(variablePath)'],
['config/owner.mjs', "import '../src/leaf'"],
['tests/owner.ts', "import '../src/leaf'"]
])
expect(buildUnitDependencyGraph(sources)).toEqual({
reverse: new Map([
['src/leaf', new Set(['src/use.ts', 'config/owner.mjs', 'tests/owner.ts'])],
['src/component.tsx', new Set(['src/use.ts'])],
['src/folder/index.ts', new Set(['src/use.ts'])],
['src/config.json', new Set(['src/use.ts'])],
['src/renderer/src/view.tsx', new Set(['src/aliases.ts'])]
]),
opaque: new Set(['src/missing.ts', 'src/dynamic.ts', 'config/owner.mjs', 'tests/owner.ts'])
})
})
})
@@ -1,59 +0,0 @@
import { describe, expect, it, vi } from 'vitest'
import { buildUnitDependencyGraph } from './ci-unit-dependency-graph.mjs'
describe('unit graph import resolution', () => {
it('avoids allocating an extension-candidate array for every resolved import', () => {
const consumers = Array.from({ length: 1000 }, (_, index) => `src/consumer-${index}.ts`)
const sources = new Map([
['src/leaf', 'export const value = 1'],
...consumers.map((file) => [file, "import './leaf'"])
])
const originalMap = Array.prototype.map
let extensionArrays = 0
const spy = vi.spyOn(Array.prototype, 'map').mockImplementation(function (...args) {
if (this.length === 10 && this[0] === '' && this[1] === '.ts' && this[9] === '/index.js') {
extensionArrays += 1
}
return originalMap.apply(this, args)
})
try {
const graph = buildUnitDependencyGraph(sources)
spy.mockRestore()
expect([...graph.reverse]).toEqual([['src/leaf', new Set(consumers)]])
expect(graph.opaque).toEqual(new Set())
expect(extensionArrays).toBe(0)
} finally {
spy.mockRestore()
}
})
it('keeps first-match precedence across literal paths, extensions and index files', () => {
const sources = new Map([
['src/leaf', ''],
['src/leaf.ts', ''],
['src/leaf.tsx', ''],
['src/component.tsx', ''],
['src/component.js', ''],
['src/folder/index.ts', ''],
['src/folder/index.tsx', ''],
['src/config.json', '{}'],
['src/renderer/src/view.tsx', ''],
['src/use.ts', "import './leaf'; import './component'; import './folder'; import './config'"],
['src/aliases.ts', "import '@renderer/view'; import '@/view'; import 'external-package'"],
['src/missing.ts', "import './missing-file'"],
['src/dynamic.ts', 'import(variablePath)'],
['config/owner.mjs', "import '../src/leaf'"],
['tests/owner.ts', "import '../src/leaf'"]
])
expect(buildUnitDependencyGraph(sources)).toEqual({
reverse: new Map([
['src/leaf', new Set(['src/use.ts', 'config/owner.mjs', 'tests/owner.ts'])],
['src/component.tsx', new Set(['src/use.ts'])],
['src/folder/index.ts', new Set(['src/use.ts'])],
['src/config.json', new Set(['src/use.ts'])],
['src/renderer/src/view.tsx', new Set(['src/aliases.ts'])]
]),
opaque: new Set(['src/missing.ts', 'src/dynamic.ts', 'config/owner.mjs', 'tests/owner.ts'])
})
})
})