From fd98a4185f663bb29a905fd35dcd7683c460b798 Mon Sep 17 00:00:00 2001 From: Victor Adossi Date: Fri, 17 Oct 2025 09:59:15 +0900 Subject: [PATCH] fix(ci): test runs on windows runner This commit fixes an somewhat odd problem with vitest on windows runners in that it cannot process properly `await import(...)` statements. The changes in this commit represent the minimal changes to make the tests run properly instead of hanging, though there are other improvements to CI forthcoming. --- test/bindings.js | 28 +++++++++++++++++++--------- test/builtins.js | 5 ++++- test/util.js | 21 ++++++++++++++++----- 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/test/bindings.js b/test/bindings.js index 4cb2aca5..c1650a2f 100644 --- a/test/bindings.js +++ b/test/bindings.js @@ -22,16 +22,18 @@ suite('Bindings', async () => { 'utf8', ); - const test = await import(`./cases/${name}/test.js`); + // NOTE: import separated from await due to issues on windows (see note in util.js) + const testcasePromise = import(`./cases/${name}/test.js`); + const testcase = await testcasePromise; // Determine the relevant WIT world to use let witWorld, witPath, worldName, isWasiTarget = false; - if (test.worldName) { + if (testcase.worldName) { witPath = fileURLToPath(new URL('./wit', import.meta.url)); - worldName = test.worldName; + worldName = testcase.worldName; isWasiTarget = true; } else { try { @@ -61,12 +63,13 @@ suite('Bindings', async () => { } } - const enableFeatures = test.enableFeatures || ['http']; + const enableFeatures = testcase.enableFeatures || ['http']; const disableFeatures = - test.disableFeatures || + testcase.disableFeatures || (isWasiTarget ? [] : ['random', 'clocks', 'http', 'stdio']); let testArg; + let instance; try { const { component, imports } = await componentize(source, { sourceName: `${name}.js`, @@ -77,6 +80,7 @@ suite('Bindings', async () => { disableFeatures: maybeLogging(disableFeatures), debugBuild: DEBUG_TEST_ENABLED, }); + const map = { 'wasi:cli-base/*': '@bytecodealliance/preview2-shim/cli-base#*', 'wasi:clocks/*': '@bytecodealliance/preview2-shim/clocks#*', @@ -88,6 +92,7 @@ suite('Bindings', async () => { 'wasi:random/*': '@bytecodealliance/preview2-shim/random#*', 'wasi:sockets/*': '@bytecodealliance/preview2-shim/sockets#*', }; + for (let [impt] of imports) { if (impt.startsWith('wasi:')) continue; if (impt.startsWith('[')) impt = impt.slice(impt.indexOf(']') + 1); @@ -130,15 +135,20 @@ suite('Bindings', async () => { const outputPath = fileURLToPath( new URL(`./output/${name}/${name}.js`, import.meta.url), ); - var instance = await import(outputPath); + + // NOTE: import separated from await due to issues on windows (see note in util.js) + const instancePromise = import(outputPath); + instance = await instancePromise; + } catch (e) { - if (test.err) { - test.err(e); + if (testcase.err) { + testcase.err(e); return; } throw e; } - await test.test(instance, testArg); + + await testcase.test(instance, testArg); }); } }); diff --git a/test/builtins.js b/test/builtins.js index 432e14b1..94ea3c38 100644 --- a/test/builtins.js +++ b/test/builtins.js @@ -19,12 +19,15 @@ suite('Builtins', async () => { for (const filename of builtins) { const name = filename.slice(0, -3); test.concurrent(name, async () => { + // NOTE: import separated from await due to issues on windows (see note in util.js) + const builtinModulePromise = import(`./builtins/${name}.js`); + const { source, test: runTest, disableFeatures, enableFeatures, - } = await import(`./builtins/${name}.js`); + } = await builtinModulePromise; const { component } = await componentize( source, diff --git a/test/util.js b/test/util.js index 13ddeac4..6b77fabd 100644 --- a/test/util.js +++ b/test/util.js @@ -56,10 +56,21 @@ export async function setupComponent(opts) { } const componentJsPath = join(wasiDir, 'component.js'); - var instance = await import(componentJsPath); - return { - instance, - outputDir, - }; + // NOTE: On Windows, vitest has stated suddenly hanging when processing code with an + // `await import(...)` in it, when the `...` is a bare identifier. + // + // This can be worked around in many ways: + // - doing a trivial tranformation on the identifier/argument + // - returning a more traditional promise + // - separating await and import() calls + // + // Here we choose to return the promise more traditionally + return import(componentJsPath) + .then(instance => { + return { + instance, + outputDir, + }; + }); }