Skip to content

Commit 39b2b63

Browse files
test(transpile): add regression test for failing JSPI import trap
Co-authored-by: Yan Chen <yan.chen@fastly.com>
1 parent 51f8ba2 commit 39b2b63

1 file changed

Lines changed: 52 additions & 1 deletion

File tree

‎packages/jco-transpile/test/jspi.ts‎

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { mkdir, rm, symlink } from 'node:fs/promises';
33

44
import { fileURLToPath } from 'node:url';
55

6-
import { suite, test, assert } from 'vitest';
6+
import { suite, test, assert, expect } from 'vitest';
77

88
import { transpile } from '../src/index.js';
99

@@ -251,4 +251,55 @@ suite('Host Import Async (JSPI)', () => {
251251
await rm(outFile);
252252
} catch {}
253253
});
254+
255+
// A failing JSPI-suspended import must trap the guest and reject the
256+
// export, rather than leave the guest suspended forever.
257+
test.concurrent('Transpile async, import rejects (NodeJS, JSPI)', async () => {
258+
if (typeof WebAssembly?.Suspending !== 'function') {
259+
return;
260+
}
261+
const tmpDir = await getTmpDir();
262+
const modulesDir = resolve(tmpDir, 'node_modules', '@bytecodealliance');
263+
await mkdir(modulesDir, { recursive: true });
264+
await symlink(
265+
fileURLToPath(new URL('../packages/preview2-shim', import.meta.url)),
266+
resolve(modulesDir, 'preview2-shim'),
267+
'dir',
268+
);
269+
270+
const inducedError = new Error('induced host rejection');
271+
const { instance, cleanup } = await setupAsyncTest({
272+
asyncMode: 'jspi',
273+
component: {
274+
name: 'async_call',
275+
path: resolve('test/fixtures/components/runtime/async_call.component.wasm'),
276+
imports: {
277+
'something:test/test-interface': {
278+
callAsync: async () => {
279+
throw inducedError;
280+
},
281+
callSync: () => 'called sync',
282+
},
283+
},
284+
},
285+
jco: {
286+
transpile: {
287+
extraArgs: {
288+
asyncImports: ['something:test/test-interface#call-async'],
289+
asyncExports: ['run-async'],
290+
},
291+
},
292+
},
293+
});
294+
295+
try {
296+
const exportCall = instance.runAsync();
297+
const timeout = new Promise((_, reject) =>
298+
setTimeout(() => reject(new Error('export call timed out')), 5_000),
299+
);
300+
await expect(Promise.race([exportCall, timeout])).rejects.toBe(inducedError);
301+
} finally {
302+
await cleanup();
303+
}
304+
});
254305
});

0 commit comments

Comments
 (0)