* test: run each heavy unit test file in its own process `test:unit` and `test:unit:heavy` ran every file in one `bun test` process. A heavy fixture file alone takes 2-6 GB, and what one file keeps stays alive for the rest of the run. Quick files still share one process; heavy files now run one per process, so the peak is the heaviest single file. Coverage runs keep one process, since coverage is collected per process. stale-overrides parses material3.fig and joins the heavy list, and a guard fails when a quick test reads a large fixture corpus. * test(core): keep one material3 graph alive at a time in stale-overrides The edited-document test held the exported reader graph, the reopened graph, and the parsed node changes at once, and the first test's graph was still alive when the second started. Each step now runs in its own function and returns only what the next check needs, and the file collects garbage between steps and tests. The checks are unchanged; peak memory drops from 5.6 GB to 3.6 GB.
108 lines
3.8 KiB
TypeScript
108 lines
3.8 KiB
TypeScript
import { expect, test } from 'bun:test'
|
|
|
|
import { resolveWorkspaceRoot } from '@open-pencil/package-artifacts-tools'
|
|
|
|
import {
|
|
isHeavyUnitTest,
|
|
LARGE_FIXTURES,
|
|
listHeavyUnitTests,
|
|
listUnitTests,
|
|
pathsForUnitTestGroup,
|
|
unitTestGroupNames
|
|
} from '../src/shards'
|
|
|
|
const REPO_ROOT = await resolveWorkspaceRoot(import.meta.dir)
|
|
|
|
async function discover(pattern: string): Promise<string[]> {
|
|
return Array.fromAsync(new Bun.Glob(pattern).scan({ cwd: REPO_ROOT }))
|
|
}
|
|
|
|
test('every app, engine and package-local test belongs to exactly one shard', async () => {
|
|
const discovered = [
|
|
...(await discover('tests/app/**/*.test.ts')),
|
|
...(await discover('tests/integration/**/*.test.ts')),
|
|
...(await discover('tests/engine/**/*.test.ts')),
|
|
...(await discover('packages/*/tests/**/*.test.ts'))
|
|
].filter((file) => !file.startsWith('packages/harness/'))
|
|
const paths = pathsForUnitTestGroup('all')
|
|
const invalidAssignments = discovered.flatMap((file) => {
|
|
const owners = paths.filter((path) => file.startsWith(`${path}/`))
|
|
return owners.length === 1 ? [] : [{ file, owners }]
|
|
})
|
|
|
|
expect(discovered.length).toBeGreaterThan(0)
|
|
expect(invalidAssignments).toEqual([])
|
|
expect((await listUnitTests('all', { includeHeavy: true })).sort()).toEqual(discovered.sort())
|
|
})
|
|
|
|
test('canonical destinations are registered before they hold files', async () => {
|
|
const paths = pathsForUnitTestGroup('all')
|
|
expect(paths).toContain('tests/app')
|
|
expect(paths).toContain('tests/integration')
|
|
for (const owner of [
|
|
'core',
|
|
'scene-graph',
|
|
'vue',
|
|
'fig',
|
|
'kiwi',
|
|
'dom-css',
|
|
'design-jsx',
|
|
'emit',
|
|
'pen',
|
|
'cli',
|
|
'mcp'
|
|
]) {
|
|
expect(paths).toContain(`packages/${owner}/tests`)
|
|
}
|
|
await expect(listUnitTests('all')).resolves.toBeArray()
|
|
})
|
|
|
|
test('quick and explicit heavy tests partition the full engine suite', async () => {
|
|
const quick = await listUnitTests('all')
|
|
const heavy = await listHeavyUnitTests()
|
|
const all = await listUnitTests('all', { includeHeavy: true })
|
|
|
|
expect(quick.filter((file) => heavy.includes(file))).toEqual([])
|
|
expect([...quick, ...heavy].sort()).toEqual(all)
|
|
})
|
|
|
|
test('unit test groups cover all declared shards', () => {
|
|
expect(unitTestGroupNames()).toContain('all')
|
|
expect(pathsForUnitTestGroup('dom')).toContain('tests/engine/dom-css')
|
|
expect(pathsForUnitTestGroup('fig')).toContain('packages/fig/tests')
|
|
expect(pathsForUnitTestGroup('all')).toContain('tests/engine/io')
|
|
})
|
|
|
|
test('heavy unit test matcher excludes fixture-heavy tests', () => {
|
|
expect(isHeavyUnitTest('tests/engine/io/fig/heavy/fixtures.test.ts')).toBe(true)
|
|
expect(isHeavyUnitTest('packages/core/tests/io/formats/fig/roundtrip/glyph-blob.test.ts')).toBe(
|
|
true
|
|
)
|
|
expect(isHeavyUnitTest('tests/engine/dom-css/runtime.test.ts')).toBe(false)
|
|
})
|
|
|
|
test('quick unit test listing excludes heavy tests', async () => {
|
|
const quickFiles = await listUnitTests('all')
|
|
expect(quickFiles).toContain('tests/engine/dom-css/runtime.test.ts')
|
|
expect(quickFiles).not.toContain('tests/engine/io/fig/heavy/fixtures.test.ts')
|
|
expect(quickFiles).not.toContain('tests/engine/io/fig/roundtrip/glyph-blob.test.ts')
|
|
})
|
|
|
|
test('heavy unit test listing contains only heavy tests', async () => {
|
|
const heavyFiles = await listHeavyUnitTests()
|
|
expect(heavyFiles).toContain('tests/engine/io/fig/heavy/fixtures.test.ts')
|
|
expect(heavyFiles.every(isHeavyUnitTest)).toBe(true)
|
|
})
|
|
|
|
test('every test that reads a large fixture is heavy', async () => {
|
|
const quick = await listUnitTests('all')
|
|
const readers = await Promise.all(
|
|
quick.map(async (file) => {
|
|
const source = await Bun.file(`${REPO_ROOT}/${file}`).text()
|
|
return LARGE_FIXTURES.some((fixture) => source.includes(fixture)) ? [file] : []
|
|
})
|
|
)
|
|
// One of these can take several gigabytes; add it to HEAVY_UNIT_TEST_PATTERNS.
|
|
expect(readers.flat()).toEqual([])
|
|
})
|