-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Expand file tree
/
Copy pathvitest.config.unit.ts
More file actions
93 lines (87 loc) · 3.45 KB
/
Copy pathvitest.config.unit.ts
File metadata and controls
93 lines (87 loc) · 3.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import {basename as pathBasename} from 'node:path';
import {readFileSync, globSync} from 'node:fs';
import {mergeConfig, defineConfig} from 'vitest/config';
import baseConfig, {isCI, chromiumBrowser} from './vitest.config.base';
import type {Reporter} from 'vitest/reporters';
import type {TestProject} from 'vitest/node';
// Long browser-mode runs accumulate detached iframe state in the orchestrator
// renderer, eventually crashing it as a flaky `Browser connection was closed`.
// V8 doesn't run major GC often enough on the orchestrator to release it (low
// heap pressure: ~30 MB live set vs 4 GB limit). Force a major GC every 5s via
// CDP. Upstream root cause is a closure pin in vitest's `IframeOrchestrator`.
type CDP = {send: (m: string, p?: object) => Promise<unknown>};
type Provider = {
pages: Map<string, unknown>;
getCDPSession: (id: string) => Promise<CDP>;
};
function orchestratorGCReporter(): Reporter {
let interval: NodeJS.Timeout | null = null;
return {
onInit(vitest: {projects: TestProject[]}) {
let cdp: CDP | null = null;
const tick = async () => {
if (!cdp) {
const project = vitest.projects.find((p) => (p.browser as unknown as {provider?: Provider})?.provider);
const provider = project && (project.browser as unknown as {provider: Provider}).provider;
const sessionId = provider?.pages.keys().next().value;
if (!provider || !sessionId) return;
cdp = await provider.getCDPSession(sessionId);
}
await cdp.send('HeapProfiler.collectGarbage');
};
interval = setInterval(() => { tick().catch(() => { cdp = null; }); }, 5000);
interval.unref?.();
},
onTestRunEnd() {
if (interval) clearInterval(interval);
interval = null;
},
};
}
function styleSpecFixtures() {
const virtualModuleId = 'virtual:style-spec/fixtures';
const resolvedVirtualModuleId = `\0${virtualModuleId}`;
const fixtureFiles = globSync('./test/unit/style-spec/fixture/*.input.json').reduce((acc, file) => {
acc[pathBasename(file).replace('.input.json', '')] = readFileSync(file).toString();
return acc;
}, {});
return {
name: 'style-spec-fixtures',
resolveId(id) {
if (id === virtualModuleId) {
return resolvedVirtualModuleId;
}
},
load(id) {
if (id === resolvedVirtualModuleId) {
return `export const fixtures = ${JSON.stringify(fixtureFiles)}`;
}
}
};
}
export default mergeConfig(baseConfig, defineConfig({
// Forbid Vite's on-demand dep discovery so it can't reload the page mid-run.
// Only CJS deps (those needing ESM interop) must be listed; pure-ESM deps
// work without it.
optimizeDeps: {
noDiscovery: true,
include: [
'@mapbox/mapbox-gl-supported',
'csscolorparser',
'vitest > expect-type',
],
},
test: {
browser: chromiumBrowser(),
include: ['test/unit/**/*.test.ts'],
setupFiles: ['test/unit/setup.ts'],
reporters: isCI ? [
['html', {outputFile: './test/unit/vitest/index.html'}],
['github-actions'],
orchestratorGCReporter(),
] : [orchestratorGCReporter()],
},
plugins: [
styleSpecFixtures()
]
}));