From 0279e78bd7774ea8e9a1b47791211a0743f39465 Mon Sep 17 00:00:00 2001 From: "Charles-P. Clermont" Date: Thu, 1 Oct 2026 08:45:27 -0400 Subject: [PATCH] Reuse Vitest workers across test files --- .../prettier-plugin-liquid/vitest.config.mjs | 2 +- .../theme-check-common/src/test/test-setup.ts | 18 ++++++++++++++++-- vitest.config.mjs | 18 +++++++++++++++++- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/packages/prettier-plugin-liquid/vitest.config.mjs b/packages/prettier-plugin-liquid/vitest.config.mjs index 488dbfd86..01e48be95 100644 --- a/packages/prettier-plugin-liquid/vitest.config.mjs +++ b/packages/prettier-plugin-liquid/vitest.config.mjs @@ -7,7 +7,7 @@ export default defineConfig({ exclude: [...configDefaults.exclude], pool: 'forks', maxWorkers: 1, - isolate: true, + isolate: false, globalSetup: ['./src/test/test-setup.js'], }, }); diff --git a/packages/theme-check-common/src/test/test-setup.ts b/packages/theme-check-common/src/test/test-setup.ts index b906fcf4c..e6ff74f97 100644 --- a/packages/theme-check-common/src/test/test-setup.ts +++ b/packages/theme-check-common/src/test/test-setup.ts @@ -20,7 +20,21 @@ chaiAssertions.forEach(({ name, fn }) => { */ expect.extend({ containOffense }); -process.on('unhandledRejection', (reason) => { +/** + * Vitest runs setup files before every test file, and test files can share one + * process. Mark the process so each worker installs the logger only once. + */ +const unhandledRejectionLoggerInstalled = Symbol.for('theme-tools.unhandledRejectionLogger'); +installUnhandledRejectionLogger(); + +function installUnhandledRejectionLogger() { + if (Reflect.get(process, unhandledRejectionLoggerInstalled)) return; + + Reflect.set(process, unhandledRejectionLoggerInstalled, true); + process.on('unhandledRejection', logUnhandledRejection); +} + +function logUnhandledRejection(reason: unknown) { console.error(reason); debugger; -}); +} diff --git a/vitest.config.mjs b/vitest.config.mjs index 96ec59615..c5ab771fe 100644 --- a/vitest.config.mjs +++ b/vitest.config.mjs @@ -6,16 +6,32 @@ const CI = !!process.env.CI; const alwaysExclude = ['**/browser/test/**', '**/test/browser/**']; /** In CI prettier plugin tests are covered by a different run command */ const ciExclude = ['./packages/prettier-plugin-liquid']; +/** + * Test files that need a fresh module graph. Most mock a dependency of a module + * that another test file already loaded. ObjectCompletionProvider depends on a + * module-level memo in TypeSystem. + */ +const isolatedTests = [ + 'packages/release-orchestrator/src/steps/getPackageJsonRecord.spec.ts', + 'packages/theme-check-common/src/checks/asset-size-css/index.spec.ts', + 'packages/theme-check-common/src/checks/asset-size-javascript/index.spec.ts', + 'packages/theme-language-server-common/src/completions/providers/ContentForParameterCompletionProvider.spec.ts', + 'packages/theme-language-server-common/src/completions/providers/ObjectCompletionProvider.spec.ts', +]; export default defineConfig({ test: { exclude: [...configDefaults.exclude, ...alwaysExclude, ...(CI ? ciExclude : [])], pool: 'forks', maxWorkers: 1, - isolate: true, + isolate: false, setupFiles: [ './packages/theme-check-common/src/test/test-setup.ts', './packages/theme-language-server-common/src/test/test-setup.ts', ], + projects: [ + { extends: true, test: { name: 'shared', exclude: isolatedTests } }, + { extends: true, test: { name: 'isolated', include: isolatedTests, isolate: true } }, + ], }, });