diff --git a/test/es-module/test-esm-wasm-escape-import-names.mjs b/test/es-module/test-esm-wasm-escape-import-names.mjs new file mode 100644 index 00000000000000..fa84587f6efc49 --- /dev/null +++ b/test/es-module/test-esm-wasm-escape-import-names.mjs @@ -0,0 +1,10 @@ +// Test that import names are properly escaped +import '../common/index.mjs'; +import { spawnSyncAndAssert } from '../common/child_process.js'; +import * as fixtures from '../common/fixtures.js'; + +spawnSyncAndAssert( + process.execPath, + ['--no-warnings', fixtures.path('es-modules/test-wasm-escape-import-names.mjs')], + { stdout: '', stderr: '', trim: true } +); diff --git a/test/es-module/test-esm-wasm-globals-all-types.mjs b/test/es-module/test-esm-wasm-globals-all-types.mjs new file mode 100644 index 00000000000000..aa9fff3bf07d77 --- /dev/null +++ b/test/es-module/test-esm-wasm-globals-all-types.mjs @@ -0,0 +1,10 @@ +// Test that all WebAssembly global types are properly handled +import '../common/index.mjs'; +import { spawnSyncAndAssert } from '../common/child_process.js'; +import * as fixtures from '../common/fixtures.js'; + +spawnSyncAndAssert( + process.execPath, + ['--no-warnings', fixtures.path('es-modules/test-wasm-globals-all-types.mjs')], + { stdout: '', stderr: '', trim: true } +); diff --git a/test/es-module/test-esm-wasm-js-string-builtins.mjs b/test/es-module/test-esm-wasm-js-string-builtins.mjs new file mode 100644 index 00000000000000..4d5417f7f82baa --- /dev/null +++ b/test/es-module/test-esm-wasm-js-string-builtins.mjs @@ -0,0 +1,10 @@ +// Test that js-string builtins are supported +import '../common/index.mjs'; +import { spawnSyncAndAssert } from '../common/child_process.js'; +import * as fixtures from '../common/fixtures.js'; + +spawnSyncAndAssert( + process.execPath, + ['--no-warnings', fixtures.path('es-modules/test-wasm-js-string-builtins.mjs')], + { stdout: '', stderr: '', trim: true } +); diff --git a/test/es-module/test-esm-wasm-load-exports.mjs b/test/es-module/test-esm-wasm-load-exports.mjs new file mode 100644 index 00000000000000..c0d96f826650b3 --- /dev/null +++ b/test/es-module/test-esm-wasm-load-exports.mjs @@ -0,0 +1,10 @@ +// Test that WASM modules can load and export functions correctly +import '../common/index.mjs'; +import { spawnSyncAndAssert } from '../common/child_process.js'; +import * as fixtures from '../common/fixtures.js'; + +spawnSyncAndAssert( + process.execPath, + ['--no-warnings', fixtures.path('es-modules/test-wasm-load-exports.mjs')], + { stdout: '', stderr: '', trim: true } +); diff --git a/test/es-module/test-esm-wasm-module-instances-warning.mjs b/test/es-module/test-esm-wasm-module-instances-warning.mjs new file mode 100644 index 00000000000000..e8ca55258131d6 --- /dev/null +++ b/test/es-module/test-esm-wasm-module-instances-warning.mjs @@ -0,0 +1,17 @@ +// Test that experimental warning is emitted for WASM module instances +import '../common/index.mjs'; +import assert from 'node:assert'; + +import { spawnSyncAndAssert } from '../common/child_process.js'; +import * as fixtures from '../common/fixtures.js'; + +spawnSyncAndAssert( + process.execPath, + [fixtures.path('es-modules/wasm-modules.mjs')], + { + stderr(output) { + assert.match(output, /ExperimentalWarning/); + assert.match(output, /Importing WebAssembly module instances/); + } + } +); diff --git a/test/es-module/test-esm-wasm-no-code-injection.mjs b/test/es-module/test-esm-wasm-no-code-injection.mjs new file mode 100644 index 00000000000000..af5cbc93276cf1 --- /dev/null +++ b/test/es-module/test-esm-wasm-no-code-injection.mjs @@ -0,0 +1,10 @@ +// Test that code injection through export names is not allowed +import '../common/index.mjs'; +import { spawnSyncAndAssert } from '../common/child_process.js'; +import * as fixtures from '../common/fixtures.js'; + +spawnSyncAndAssert( + process.execPath, + ['--no-warnings', fixtures.path('es-modules/export-name-code-injection.wasm')], + { stdout: '', stderr: '', trim: true } +); diff --git a/test/es-module/test-esm-wasm-non-identifier-exports.mjs b/test/es-module/test-esm-wasm-non-identifier-exports.mjs new file mode 100644 index 00000000000000..87dc1670b14d9a --- /dev/null +++ b/test/es-module/test-esm-wasm-non-identifier-exports.mjs @@ -0,0 +1,10 @@ +// Test that WASM modules can have non-identifier export names +import '../common/index.mjs'; +import { spawnSyncAndAssert } from '../common/child_process.js'; +import * as fixtures from '../common/fixtures.js'; + +spawnSyncAndAssert( + process.execPath, + ['--no-warnings', fixtures.path('es-modules/test-wasm-non-identifier-exports.mjs')], + { stdout: '', stderr: '', trim: true } +); diff --git a/test/es-module/test-esm-wasm-reject-wasm-export-names.mjs b/test/es-module/test-esm-wasm-reject-wasm-export-names.mjs new file mode 100644 index 00000000000000..710933922777bd --- /dev/null +++ b/test/es-module/test-esm-wasm-reject-wasm-export-names.mjs @@ -0,0 +1,10 @@ +// Test WASM module with invalid export name starting with 'wasm:' +import '../common/index.mjs'; +import { spawnSyncAndAssert } from '../common/child_process.js'; +import * as fixtures from '../common/fixtures.js'; + +spawnSyncAndAssert( + process.execPath, + ['--no-warnings', fixtures.path('es-modules/test-wasm-reject-wasm-export-names.mjs')], + { status: 1, stderr: /Invalid Wasm export/ } +); diff --git a/test/es-module/test-esm-wasm-reject-wasm-import-names.mjs b/test/es-module/test-esm-wasm-reject-wasm-import-names.mjs new file mode 100644 index 00000000000000..0c977db2233e02 --- /dev/null +++ b/test/es-module/test-esm-wasm-reject-wasm-import-names.mjs @@ -0,0 +1,10 @@ +// Test WASM module with invalid import name starting with 'wasm:' +import '../common/index.mjs'; +import { spawnSyncAndAssert } from '../common/child_process.js'; +import * as fixtures from '../common/fixtures.js'; + +spawnSyncAndAssert( + process.execPath, + ['--no-warnings', fixtures.path('es-modules/test-wasm-reject-wasm-import-names.mjs')], + { status: 1, stderr: /Invalid Wasm import name/ } +); diff --git a/test/es-module/test-esm-wasm-reject-wasm-js-export-names.mjs b/test/es-module/test-esm-wasm-reject-wasm-js-export-names.mjs new file mode 100644 index 00000000000000..40af037ab67881 --- /dev/null +++ b/test/es-module/test-esm-wasm-reject-wasm-js-export-names.mjs @@ -0,0 +1,10 @@ +// Test WASM module with invalid export name starting with 'wasm-js:' +import '../common/index.mjs'; +import { spawnSyncAndAssert } from '../common/child_process.js'; +import * as fixtures from '../common/fixtures.js'; + +spawnSyncAndAssert( + process.execPath, + ['--no-warnings', fixtures.path('es-modules/test-wasm-reject-wasm-js-export-names.mjs')], + { status: 1, stderr: /Invalid Wasm export/ } +); diff --git a/test/es-module/test-esm-wasm-reject-wasm-js-import-module.mjs b/test/es-module/test-esm-wasm-reject-wasm-js-import-module.mjs new file mode 100644 index 00000000000000..e85d86c6654261 --- /dev/null +++ b/test/es-module/test-esm-wasm-reject-wasm-js-import-module.mjs @@ -0,0 +1,10 @@ +// Test WASM module with invalid import module name starting with 'wasm-js:' +import '../common/index.mjs'; +import { spawnSyncAndAssert } from '../common/child_process.js'; +import * as fixtures from '../common/fixtures.js'; + +spawnSyncAndAssert( + process.execPath, + ['--no-warnings', fixtures.path('es-modules/test-wasm-reject-wasm-js-import-module.mjs')], + { status: 1, stderr: /Invalid Wasm import/ } +); diff --git a/test/es-module/test-esm-wasm-reject-wasm-js-import-names.mjs b/test/es-module/test-esm-wasm-reject-wasm-js-import-names.mjs new file mode 100644 index 00000000000000..14151c349a1b0b --- /dev/null +++ b/test/es-module/test-esm-wasm-reject-wasm-js-import-names.mjs @@ -0,0 +1,10 @@ +// Test WASM module with invalid import name starting with 'wasm-js:' +import '../common/index.mjs'; +import { spawnSyncAndAssert } from '../common/child_process.js'; +import * as fixtures from '../common/fixtures.js'; + +spawnSyncAndAssert( + process.execPath, + ['--no-warnings', fixtures.path('es-modules/test-wasm-reject-wasm-js-import-names.mjs')], + { status: 1, stderr: /Invalid Wasm import name/ } +); diff --git a/test/es-module/test-esm-wasm-source-phase-dynamic.mjs b/test/es-module/test-esm-wasm-source-phase-dynamic.mjs new file mode 100644 index 00000000000000..eb223d8e96e643 --- /dev/null +++ b/test/es-module/test-esm-wasm-source-phase-dynamic.mjs @@ -0,0 +1,10 @@ +// Test that dynamic source phase imports are supported +import '../common/index.mjs'; +import { spawnSyncAndAssert } from '../common/child_process.js'; +import * as fixtures from '../common/fixtures.js'; + +spawnSyncAndAssert( + process.execPath, + ['--no-warnings', fixtures.path('es-modules/test-wasm-source-phase-dynamic.mjs')], + { stdout: '', stderr: '', trim: true } +); diff --git a/test/es-module/test-esm-wasm-source-phase-no-execute-dynamic.mjs b/test/es-module/test-esm-wasm-source-phase-no-execute-dynamic.mjs new file mode 100644 index 00000000000000..77a0eb914bebfe --- /dev/null +++ b/test/es-module/test-esm-wasm-source-phase-no-execute-dynamic.mjs @@ -0,0 +1,10 @@ +// Test that dynamic source phase imports don't execute +import '../common/index.mjs'; +import { spawnSyncAndAssert } from '../common/child_process.js'; +import * as fixtures from '../common/fixtures.js'; + +spawnSyncAndAssert( + process.execPath, + ['--no-warnings', fixtures.path('es-modules/test-wasm-source-phase-no-execute-dynamic.mjs')], + { stdout: '', stderr: '', trim: true } +); diff --git a/test/es-module/test-esm-wasm-source-phase-no-execute.mjs b/test/es-module/test-esm-wasm-source-phase-no-execute.mjs new file mode 100644 index 00000000000000..26bcefccbacb49 --- /dev/null +++ b/test/es-module/test-esm-wasm-source-phase-no-execute.mjs @@ -0,0 +1,10 @@ +// Test that source phase imports don't execute +import '../common/index.mjs'; +import { spawnSyncAndAssert } from '../common/child_process.js'; +import * as fixtures from '../common/fixtures.js'; + +spawnSyncAndAssert( + process.execPath, + ['--no-warnings', fixtures.path('es-modules/test-wasm-source-phase-no-execute.mjs')], + { stdout: '', stderr: '', trim: true } +); diff --git a/test/es-module/test-esm-wasm-source-phase-not-defined-dynamic.mjs b/test/es-module/test-esm-wasm-source-phase-not-defined-dynamic.mjs new file mode 100644 index 00000000000000..8e78a6f4837363 --- /dev/null +++ b/test/es-module/test-esm-wasm-source-phase-not-defined-dynamic.mjs @@ -0,0 +1,10 @@ +// Test that error is thrown for dynamic source phase imports not defined +import '../common/index.mjs'; +import { spawnSyncAndAssert } from '../common/child_process.js'; +import * as fixtures from '../common/fixtures.js'; + +spawnSyncAndAssert( + process.execPath, + ['--no-warnings', fixtures.path('es-modules/test-wasm-source-phase-not-defined-dynamic.mjs')], + { stdout: '', stderr: '', trim: true } +); diff --git a/test/es-module/test-esm-wasm-source-phase-not-defined-static.mjs b/test/es-module/test-esm-wasm-source-phase-not-defined-static.mjs new file mode 100644 index 00000000000000..a53ea04194f149 --- /dev/null +++ b/test/es-module/test-esm-wasm-source-phase-not-defined-static.mjs @@ -0,0 +1,19 @@ +// Test that error is thrown for static source phase imports not defined +import '../common/index.mjs'; +import assert from 'node:assert'; + +import { spawnSyncAndAssert } from '../common/child_process.js'; +import * as fixtures from '../common/fixtures.js'; + +const fileUrl = fixtures.fileURL('es-modules/wasm-source-phase.js').href; +spawnSyncAndAssert( + process.execPath, + ['--no-warnings', fixtures.path('es-modules/test-wasm-source-phase-not-defined-static.mjs')], + { + status: 1, + stderr(output) { + assert.match(output, /Source phase import object is not defined for module/); + assert(output.includes(fileUrl)); + } + } +); diff --git a/test/es-module/test-esm-wasm-source-phase-static.mjs b/test/es-module/test-esm-wasm-source-phase-static.mjs new file mode 100644 index 00000000000000..c0cc1eeb698df3 --- /dev/null +++ b/test/es-module/test-esm-wasm-source-phase-static.mjs @@ -0,0 +1,10 @@ +// Test that static source phase imports are supported +import '../common/index.mjs'; +import { spawnSyncAndAssert } from '../common/child_process.js'; +import * as fixtures from '../common/fixtures.js'; + +spawnSyncAndAssert( + process.execPath, + ['--no-warnings', fixtures.path('es-modules/test-wasm-source-phase-static.mjs')], + { stdout: '', stderr: '', trim: true } +); diff --git a/test/es-module/test-esm-wasm-top-level-execution.mjs b/test/es-module/test-esm-wasm-top-level-execution.mjs new file mode 100644 index 00000000000000..99ce94e00c5350 --- /dev/null +++ b/test/es-module/test-esm-wasm-top-level-execution.mjs @@ -0,0 +1,14 @@ +// Test that WASM modules support top-level execution +import '../common/index.mjs'; +import { spawnSyncAndAssert } from '../common/child_process.js'; +import * as fixtures from '../common/fixtures.js'; + +spawnSyncAndAssert( + process.execPath, + ['--no-warnings', fixtures.path('es-modules/top-level-wasm.wasm')], + { + stdout: '[Object: null prototype] { prop: \'hello world\' }', + stderr: '', + trim: true + } +); diff --git a/test/es-module/test-esm-wasm-vm-source-phase-dynamic.mjs b/test/es-module/test-esm-wasm-vm-source-phase-dynamic.mjs new file mode 100644 index 00000000000000..fd43d9638abcca --- /dev/null +++ b/test/es-module/test-esm-wasm-vm-source-phase-dynamic.mjs @@ -0,0 +1,10 @@ +// Test that error is thrown for vm source phase dynamic import +import '../common/index.mjs'; +import { spawnSyncAndAssert } from '../common/child_process.js'; +import * as fixtures from '../common/fixtures.js'; + +spawnSyncAndAssert( + process.execPath, + ['--no-warnings', '--experimental-vm-modules', fixtures.path('es-modules/test-wasm-vm-source-phase-dynamic.mjs')], + { status: 1, stderr: /Source phase import object is not defined for module/ } +); diff --git a/test/es-module/test-esm-wasm-vm-source-phase-static.mjs b/test/es-module/test-esm-wasm-vm-source-phase-static.mjs new file mode 100644 index 00000000000000..648ad15bd446d3 --- /dev/null +++ b/test/es-module/test-esm-wasm-vm-source-phase-static.mjs @@ -0,0 +1,10 @@ +// Test that error is thrown for vm source phase static import +import '../common/index.mjs'; +import { spawnSyncAndAssert } from '../common/child_process.js'; +import * as fixtures from '../common/fixtures.js'; + +spawnSyncAndAssert( + process.execPath, + ['--no-warnings', '--experimental-vm-modules', fixtures.path('es-modules/test-wasm-vm-source-phase-static.mjs')], + { status: 1, stderr: /Source phase import object is not defined for module/ } +); diff --git a/test/es-module/test-esm-wasm.mjs b/test/es-module/test-esm-wasm.mjs deleted file mode 100644 index 5f3632c8390d22..00000000000000 --- a/test/es-module/test-esm-wasm.mjs +++ /dev/null @@ -1,476 +0,0 @@ -import { spawnPromisified } from '../common/index.mjs'; -import * as fixtures from '../common/fixtures.mjs'; -import { ok, strictEqual, notStrictEqual, match } from 'node:assert'; -import { execPath } from 'node:process'; -import { describe, it } from 'node:test'; - - -describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () => { - it('should load exports', async () => { - const { code, stderr, stdout } = await spawnPromisified(execPath, [ - '--no-warnings', - '--input-type=module', - '--eval', - [ - 'import { strictEqual, match } from "node:assert";', - `import { add, addImported } from ${JSON.stringify(fixtures.fileURL('es-modules/simple.wasm'))};`, - `import { state } from ${JSON.stringify(fixtures.fileURL('es-modules/wasm-dep.mjs'))};`, - 'strictEqual(state, "WASM Start Executed");', - 'strictEqual(add(10, 20), 30);', - 'strictEqual(addImported(0), 42);', - 'strictEqual(state, "WASM JS Function Executed");', - 'strictEqual(addImported(1), 43);', - ].join('\n'), - ]); - - strictEqual(stderr, ''); - strictEqual(stdout, ''); - strictEqual(code, 0); - }); - - it('should not allow code injection through export names', async () => { - const { code, stderr, stdout } = await spawnPromisified(execPath, [ - '--no-warnings', - '--input-type=module', - '--eval', - `import * as wasmExports from ${JSON.stringify(fixtures.fileURL('es-modules/export-name-code-injection.wasm'))};`, - ]); - - strictEqual(stderr, ''); - strictEqual(stdout, ''); - strictEqual(code, 0); - }); - - it('should allow non-identifier export names', async () => { - const { code, stderr, stdout } = await spawnPromisified(execPath, [ - '--no-warnings', - '--input-type=module', - '--eval', - [ - 'import { strictEqual } from "node:assert";', - `import * as wasmExports from ${JSON.stringify(fixtures.fileURL('es-modules/export-name-syntax-error.wasm'))};`, - 'assert.strictEqual(wasmExports["?f!o:oa[r]"], 12682);', - ].join('\n'), - ]); - - strictEqual(stderr, ''); - strictEqual(stdout, ''); - strictEqual(code, 0); - }); - - it('should properly handle all WebAssembly global types', async () => { - const { code, stderr, stdout } = await spawnPromisified(execPath, [ - '--no-warnings', - '--input-type=module', - '--eval', - [ - 'import { strictEqual, deepStrictEqual, ok } from "node:assert";', - - // WASM SIMD is not supported on older architectures such as IBM Power8 - 'let wasmExports;', - 'try {', - ` wasmExports = await import(${JSON.stringify(fixtures.fileURL('es-modules/globals.wasm'))});`, - '} catch (e) {', - ' ok(e instanceof WebAssembly.CompileError);', - ' ok(e.message.includes("SIMD unsupported"));', - '}', - - 'if (wasmExports) {', - - // Test imported globals using direct access - ' strictEqual(wasmExports.importedI32, 42);', - ' strictEqual(wasmExports.importedMutI32, 100);', - ' strictEqual(wasmExports.importedI64, 9223372036854775807n);', - ' strictEqual(wasmExports.importedMutI64, 200n);', - ' strictEqual(Math.round(wasmExports.importedF32 * 100000) / 100000, 3.14159);', - ' strictEqual(Math.round(wasmExports.importedMutF32 * 100000) / 100000, 2.71828);', - ' strictEqual(wasmExports.importedF64, 3.141592653589793);', - ' strictEqual(wasmExports.importedMutF64, 2.718281828459045);', - ' strictEqual(wasmExports.importedExternref !== null, true);', - ' strictEqual(wasmExports.importedMutExternref !== null, true);', - ' strictEqual(wasmExports.importedNullExternref, null);', - - // Test local globals exported directly - ' strictEqual(wasmExports[\'🚀localI32\'], 42);', - ' strictEqual(wasmExports.localMutI32, 100);', - ' strictEqual(wasmExports.localI64, 9223372036854775807n);', - ' strictEqual(wasmExports.localMutI64, 200n);', - ' strictEqual(Math.round(wasmExports.localF32 * 100000) / 100000, 3.14159);', - ' strictEqual(Math.round(wasmExports.localMutF32 * 100000) / 100000, 2.71828);', - ' strictEqual(wasmExports.localF64, 2.718281828459045);', - ' strictEqual(wasmExports.localMutF64, 3.141592653589793);', - - // Test imported globals using getter functions - ' strictEqual(wasmExports.getImportedMutI32(), 100);', - ' strictEqual(wasmExports.getImportedMutI64(), 200n);', - ' strictEqual(Math.round(wasmExports.getImportedMutF32() * 100000) / 100000, 2.71828);', - ' strictEqual(wasmExports.getImportedMutF64(), 2.718281828459045);', - ' strictEqual(wasmExports.getImportedMutExternref() !== null, true);', - - // Test local globals using getter functions - ' strictEqual(wasmExports.getLocalMutI32(), 100);', - ' strictEqual(wasmExports.getLocalMutI64(), 200n);', - ' strictEqual(Math.round(wasmExports.getLocalMutF32() * 100000) / 100000, 2.71828);', - ' strictEqual(wasmExports.getLocalMutF64(), 3.141592653589793);', - ' strictEqual(wasmExports.getLocalMutExternref(), null);', - - ' assert.throws(wasmExports.getLocalMutV128);', - - // Pending TDZ support - ' strictEqual(wasmExports.depV128, undefined);', - - // Test modifying mutable globals and reading the new values - ' wasmExports.setImportedMutI32(999);', - ' strictEqual(wasmExports.getImportedMutI32(), 999);', - - ' wasmExports.setImportedMutI64(888n);', - ' strictEqual(wasmExports.getImportedMutI64(), 888n);', - - ' wasmExports.setImportedMutF32(7.77);', - ' strictEqual(Math.round(wasmExports.getImportedMutF32() * 100) / 100, 7.77);', - - ' wasmExports.setImportedMutF64(6.66);', - ' strictEqual(wasmExports.getImportedMutF64(), 6.66);', - - // Test modifying mutable externref - ' const testObj = { test: "object" };', - ' wasmExports.setImportedMutExternref(testObj);', - ' strictEqual(wasmExports.getImportedMutExternref(), testObj);', - - // Test modifying local mutable globals - ' wasmExports.setLocalMutI32(555);', - ' strictEqual(wasmExports.getLocalMutI32(), 555);', - - ' wasmExports.setLocalMutI64(444n);', - ' strictEqual(wasmExports.getLocalMutI64(), 444n);', - - ' wasmExports.setLocalMutF32(3.33);', - ' strictEqual(Math.round(wasmExports.getLocalMutF32() * 100) / 100, 3.33);', - - ' wasmExports.setLocalMutF64(2.22);', - ' strictEqual(wasmExports.getLocalMutF64(), 2.22);', - - // These mutating pending live bindings support - ' strictEqual(wasmExports.localMutI32, 100);', - ' strictEqual(wasmExports.localMutI64, 200n);', - ' strictEqual(Math.round(wasmExports.localMutF32 * 100) / 100, 2.72);', - ' strictEqual(wasmExports.localMutF64, 3.141592653589793);', - - // Test modifying local mutable externref - ' const anotherTestObj = { another: "test object" };', - ' wasmExports.setLocalMutExternref(anotherTestObj);', - ' strictEqual(wasmExports.getLocalMutExternref(), anotherTestObj);', - ' strictEqual(wasmExports.localMutExternref, null);', - - // Test dep.wasm imports - ' strictEqual(wasmExports.depI32, 1001);', - ' strictEqual(wasmExports.depMutI32, 2001);', - ' strictEqual(wasmExports.getDepMutI32(), 2001);', - ' strictEqual(wasmExports.depI64, 10000000001n);', - ' strictEqual(wasmExports.depMutI64, 20000000001n);', - ' strictEqual(wasmExports.getDepMutI64(), 20000000001n);', - ' strictEqual(Math.round(wasmExports.depF32 * 100) / 100, 10.01);', - ' strictEqual(Math.round(wasmExports.depMutF32 * 100) / 100, 20.01);', - ' strictEqual(Math.round(wasmExports.getDepMutF32() * 100) / 100, 20.01);', - ' strictEqual(wasmExports.depF64, 100.0001);', - ' strictEqual(wasmExports.depMutF64, 200.0001);', - ' strictEqual(wasmExports.getDepMutF64(), 200.0001);', - - // Test modifying dep.wasm mutable globals - ' wasmExports.setDepMutI32(3001);', - ' strictEqual(wasmExports.getDepMutI32(), 3001);', - - ' wasmExports.setDepMutI64(30000000001n);', - ' strictEqual(wasmExports.getDepMutI64(), 30000000001n);', - - ' wasmExports.setDepMutF32(30.01);', - ' strictEqual(Math.round(wasmExports.getDepMutF32() * 100) / 100, 30.01);', - - ' wasmExports.setDepMutF64(300.0001);', - ' strictEqual(wasmExports.getDepMutF64(), 300.0001);', - - // These pending live bindings support - ' strictEqual(wasmExports.depMutI32, 2001);', - ' strictEqual(wasmExports.depMutI64, 20000000001n);', - ' strictEqual(Math.round(wasmExports.depMutF32 * 100) / 100, 20.01);', - ' strictEqual(wasmExports.depMutF64, 200.0001);', - - '}', - ].join('\n'), - ]); - - strictEqual(stderr, ''); - strictEqual(stdout, ''); - strictEqual(code, 0); - }); - - it('should properly escape import names as well', async () => { - const { code, stderr, stdout } = await spawnPromisified(execPath, [ - '--no-warnings', - '--input-type=module', - '--eval', - [ - 'import { strictEqual } from "node:assert";', - `import * as wasmExports from ${JSON.stringify(fixtures.fileURL('es-modules/import-name.wasm'))};`, - 'assert.strictEqual(wasmExports.xor(), 12345);', - ].join('\n'), - ]); - - strictEqual(stderr, ''); - strictEqual(stdout, ''); - strictEqual(code, 0); - }); - - it('should emit experimental warning for module instances', async () => { - const { code, signal, stderr } = await spawnPromisified(execPath, [ - fixtures.path('es-modules/wasm-modules.mjs'), - ]); - - strictEqual(code, 0); - strictEqual(signal, null); - match(stderr, /ExperimentalWarning/); - match(stderr, /Importing WebAssembly module instances/); - }); - - it('should support top-level execution', async () => { - const { code, stderr, stdout } = await spawnPromisified(execPath, [ - '--no-warnings', - fixtures.path('es-modules/top-level-wasm.wasm'), - ]); - - strictEqual(stderr, ''); - strictEqual(stdout, '[Object: null prototype] { prop: \'hello world\' }\n'); - strictEqual(code, 0); - }); - - it('should support static source phase imports', async () => { - const { code, stderr, stdout } = await spawnPromisified(execPath, [ - '--no-warnings', - '--input-type=module', - '--eval', - [ - 'import { strictEqual } from "node:assert";', - `import * as wasmExports from ${JSON.stringify(fixtures.fileURL('es-modules/wasm-source-phase.js'))};`, - 'strictEqual(wasmExports.mod instanceof WebAssembly.Module, true);', - 'const AbstractModuleSourceProto = Object.getPrototypeOf(Object.getPrototypeOf(wasmExports.mod));', - 'const toStringTag = Object.getOwnPropertyDescriptor(AbstractModuleSourceProto, Symbol.toStringTag).get;', - 'strictEqual(toStringTag.call(wasmExports.mod), "WebAssembly.Module");', - ].join('\n'), - ]); - - strictEqual(stderr, ''); - strictEqual(stdout, ''); - strictEqual(code, 0); - }); - - it('should support dynamic source phase imports', async () => { - const { code, stderr, stdout } = await spawnPromisified(execPath, [ - '--no-warnings', - '--input-type=module', - '--eval', - [ - 'import { strictEqual } from "node:assert";', - `import * as wasmExports from ${JSON.stringify(fixtures.fileURL('es-modules/wasm-source-phase.js'))};`, - 'strictEqual(wasmExports.mod instanceof WebAssembly.Module, true);', - 'strictEqual(await wasmExports.dyn("./simple.wasm") instanceof WebAssembly.Module, true);', - 'const AbstractModuleSourceProto = Object.getPrototypeOf(Object.getPrototypeOf(wasmExports.mod));', - 'const toStringTag = Object.getOwnPropertyDescriptor(AbstractModuleSourceProto, Symbol.toStringTag).get;', - 'strictEqual(toStringTag.call(wasmExports.mod), "WebAssembly.Module");', - ].join('\n'), - ]); - - strictEqual(stderr, ''); - strictEqual(stdout, ''); - strictEqual(code, 0); - }); - - it('should not execute source phase imports', async () => { - const { code, stderr, stdout } = await spawnPromisified(execPath, [ - '--no-warnings', - '--input-type=module', - '--eval', - [ - 'import { strictEqual } from "node:assert";', - `import source mod from ${JSON.stringify(fixtures.fileURL('es-modules/unimportable.wasm'))};`, - 'assert.strictEqual(mod instanceof WebAssembly.Module, true);', - `await assert.rejects(import(${JSON.stringify(fixtures.fileURL('es-modules/unimportable.wasm'))}));`, - ].join('\n'), - ]); - - strictEqual(stderr, ''); - strictEqual(stdout, ''); - strictEqual(code, 0); - }); - - it('should not execute dynamic source phase imports', async () => { - const { code, stderr, stdout } = await spawnPromisified(execPath, [ - '--no-warnings', - '--input-type=module', - '--eval', - `await import.source(${JSON.stringify(fixtures.fileURL('es-modules/unimportable.wasm'))})`, - ]); - - strictEqual(stderr, ''); - strictEqual(stdout, ''); - strictEqual(code, 0); - }); - - it('should throw for dynamic source phase imports not defined', async () => { - const fileUrl = fixtures.fileURL('es-modules/wasm-source-phase.js'); - const { code, stderr, stdout } = await spawnPromisified(execPath, [ - '--no-warnings', - '--input-type=module', - '--eval', - [ - 'import { ok, strictEqual } from "node:assert";', - `await assert.rejects(import.source(${JSON.stringify(fileUrl)}), (e) => {`, - ' strictEqual(e instanceof SyntaxError, true);', - ' strictEqual(e.message.includes("Source phase import object is not defined for module"), true);', - ` strictEqual(e.message.includes(${JSON.stringify(fileUrl)}), true);`, - ` return true`, - '});', - ].join('\n'), - ]); - - strictEqual(stderr, ''); - strictEqual(stdout, ''); - strictEqual(code, 0); - }); - - it('should throw for static source phase imports not defined', async () => { - const fileUrl = fixtures.fileURL('es-modules/wasm-source-phase.js'); - const { code, stderr, stdout } = await spawnPromisified(execPath, [ - '--no-warnings', - '--input-type=module', - '--eval', - `import source nosource from ${JSON.stringify(fileUrl)};`, - ]); - match(stderr, /Source phase import object is not defined for module/); - ok(stderr.includes(fileUrl)); - strictEqual(stdout, ''); - notStrictEqual(code, 0); - }); - - it('should throw for vm source phase static import', async () => { - const { code, stderr, stdout } = await spawnPromisified(execPath, [ - '--no-warnings', - '--experimental-vm-modules', - '--input-type=module', - '--eval', - [ - 'const m1 = new vm.SourceTextModule("import source x from \\"y\\";");', - 'const m2 = new vm.SourceTextModule("export var p = 5;");', - 'await m1.link(() => m2);', - 'await m1.evaluate();', - ].join('\n'), - ]); - match(stderr, /Source phase import object is not defined for module/); - strictEqual(stdout, ''); - notStrictEqual(code, 0); - }); - - it('should throw for vm source phase dynamic import', async () => { - const { code, stderr, stdout } = await spawnPromisified(execPath, [ - '--no-warnings', - '--experimental-vm-modules', - '--input-type=module', - '--eval', - [ - 'import { constants } from "node:vm";', - 'const opts = { importModuleDynamically: () => m2 };', - 'const m1 = new vm.SourceTextModule("await import.source(\\"y\\");", opts);', - 'const m2 = new vm.SourceTextModule("export var p = 5;");', - 'await m1.link(() => m2);', - 'await m1.evaluate();', - ].join('\n'), - ]); - match(stderr, /Source phase import object is not defined for module/); - strictEqual(stdout, ''); - notStrictEqual(code, 0); - }); - - it('should reject wasm: import names', async () => { - const { code, stderr, stdout } = await spawnPromisified(execPath, [ - '--no-warnings', - '--input-type=module', - '--eval', - `import(${JSON.stringify(fixtures.fileURL('es-modules/invalid-import-name.wasm'))})`, - ]); - - match(stderr, /Invalid Wasm import name/); - strictEqual(stdout, ''); - notStrictEqual(code, 0); - }); - - it('should reject wasm-js: import names', async () => { - const { code, stderr, stdout } = await spawnPromisified(execPath, [ - '--no-warnings', - '--input-type=module', - '--eval', - `import(${JSON.stringify(fixtures.fileURL('es-modules/invalid-import-name-wasm-js.wasm'))})`, - ]); - - match(stderr, /Invalid Wasm import name/); - strictEqual(stdout, ''); - notStrictEqual(code, 0); - }); - - it('should reject wasm-js: import module names', async () => { - const { code, stderr, stdout } = await spawnPromisified(execPath, [ - '--no-warnings', - '--input-type=module', - '--eval', - `import(${JSON.stringify(fixtures.fileURL('es-modules/invalid-import-module.wasm'))})`, - ]); - - match(stderr, /Invalid Wasm import/); - strictEqual(stdout, ''); - notStrictEqual(code, 0); - }); - - it('should reject wasm: export names', async () => { - const { code, stderr, stdout } = await spawnPromisified(execPath, [ - '--no-warnings', - '--input-type=module', - '--eval', - `import(${JSON.stringify(fixtures.fileURL('es-modules/invalid-export-name.wasm'))})`, - ]); - - match(stderr, /Invalid Wasm export/); - strictEqual(stdout, ''); - notStrictEqual(code, 0); - }); - - it('should reject wasm-js: export names', async () => { - const { code, stderr, stdout } = await spawnPromisified(execPath, [ - '--no-warnings', - '--input-type=module', - '--eval', - `import(${JSON.stringify(fixtures.fileURL('es-modules/invalid-export-name-wasm-js.wasm'))})`, - ]); - - match(stderr, /Invalid Wasm export/); - strictEqual(stdout, ''); - notStrictEqual(code, 0); - }); - - it('should support js-string builtins', async () => { - const { code, stderr, stdout } = await spawnPromisified(execPath, [ - '--no-warnings', - '--input-type=module', - '--eval', - [ - 'import { strictEqual } from "node:assert";', - `import * as wasmExports from ${JSON.stringify(fixtures.fileURL('es-modules/js-string-builtins.wasm'))};`, - 'strictEqual(wasmExports.getLength("hello"), 5);', - 'strictEqual(wasmExports.concatStrings("hello", " world"), "hello world");', - 'strictEqual(wasmExports.compareStrings("test", "test"), 1);', - 'strictEqual(wasmExports.compareStrings("test", "different"), 0);', - ].join('\n'), - ]); - - strictEqual(stderr, ''); - strictEqual(stdout, ''); - strictEqual(code, 0); - }); -}); diff --git a/test/fixtures/es-modules/test-wasm-escape-import-names.mjs b/test/fixtures/es-modules/test-wasm-escape-import-names.mjs new file mode 100644 index 00000000000000..ee39fddd9e09f3 --- /dev/null +++ b/test/fixtures/es-modules/test-wasm-escape-import-names.mjs @@ -0,0 +1,5 @@ +// Test fixture for properly escaping import names +import { strictEqual } from 'node:assert'; +import * as wasmExports from './import-name.wasm'; + +strictEqual(wasmExports.xor(), 12345); diff --git a/test/fixtures/es-modules/test-wasm-globals-all-types.mjs b/test/fixtures/es-modules/test-wasm-globals-all-types.mjs new file mode 100644 index 00000000000000..c48ad4d7190ec2 --- /dev/null +++ b/test/fixtures/es-modules/test-wasm-globals-all-types.mjs @@ -0,0 +1,131 @@ +// Test fixture for all WebAssembly global types +import { strictEqual, ok, throws } from 'node:assert'; + +// WASM SIMD is not supported on older architectures such as IBM Power8 +let wasmExports; +try { + wasmExports = await import('./globals.wasm'); +} catch (e) { + ok(e instanceof WebAssembly.CompileError); + ok(e.message.includes('SIMD unsupported')); +} + +if (wasmExports) { + // Test imported globals using direct access + strictEqual(wasmExports.importedI32, 42); + strictEqual(wasmExports.importedMutI32, 100); + strictEqual(wasmExports.importedI64, 9223372036854775807n); + strictEqual(wasmExports.importedMutI64, 200n); + strictEqual(Math.round(wasmExports.importedF32 * 100000) / 100000, 3.14159); + strictEqual(Math.round(wasmExports.importedMutF32 * 100000) / 100000, 2.71828); + strictEqual(wasmExports.importedF64, 3.141592653589793); + strictEqual(wasmExports.importedMutF64, 2.718281828459045); + strictEqual(wasmExports.importedExternref !== null, true); + strictEqual(wasmExports.importedMutExternref !== null, true); + strictEqual(wasmExports.importedNullExternref, null); + + // Test local globals exported directly + strictEqual(wasmExports['🚀localI32'], 42); + strictEqual(wasmExports.localMutI32, 100); + strictEqual(wasmExports.localI64, 9223372036854775807n); + strictEqual(wasmExports.localMutI64, 200n); + strictEqual(Math.round(wasmExports.localF32 * 100000) / 100000, 3.14159); + strictEqual(Math.round(wasmExports.localMutF32 * 100000) / 100000, 2.71828); + strictEqual(wasmExports.localF64, 2.718281828459045); + strictEqual(wasmExports.localMutF64, 3.141592653589793); + + // Test imported globals using getter functions + strictEqual(wasmExports.getImportedMutI32(), 100); + strictEqual(wasmExports.getImportedMutI64(), 200n); + strictEqual(Math.round(wasmExports.getImportedMutF32() * 100000) / 100000, 2.71828); + strictEqual(wasmExports.getImportedMutF64(), 2.718281828459045); + strictEqual(wasmExports.getImportedMutExternref() !== null, true); + + // Test local globals using getter functions + strictEqual(wasmExports.getLocalMutI32(), 100); + strictEqual(wasmExports.getLocalMutI64(), 200n); + strictEqual(Math.round(wasmExports.getLocalMutF32() * 100000) / 100000, 2.71828); + strictEqual(wasmExports.getLocalMutF64(), 3.141592653589793); + strictEqual(wasmExports.getLocalMutExternref(), null); + + throws(wasmExports.getLocalMutV128); + + // Pending TDZ support + strictEqual(wasmExports.depV128, undefined); + + // Test modifying mutable globals and reading the new values + wasmExports.setImportedMutI32(999); + strictEqual(wasmExports.getImportedMutI32(), 999); + + wasmExports.setImportedMutI64(888n); + strictEqual(wasmExports.getImportedMutI64(), 888n); + + wasmExports.setImportedMutF32(7.77); + strictEqual(Math.round(wasmExports.getImportedMutF32() * 100) / 100, 7.77); + + wasmExports.setImportedMutF64(6.66); + strictEqual(wasmExports.getImportedMutF64(), 6.66); + + // Test modifying mutable externref + const testObj = { test: 'object' }; + wasmExports.setImportedMutExternref(testObj); + strictEqual(wasmExports.getImportedMutExternref(), testObj); + + // Test modifying local mutable globals + wasmExports.setLocalMutI32(555); + strictEqual(wasmExports.getLocalMutI32(), 555); + + wasmExports.setLocalMutI64(444n); + strictEqual(wasmExports.getLocalMutI64(), 444n); + + wasmExports.setLocalMutF32(3.33); + strictEqual(Math.round(wasmExports.getLocalMutF32() * 100) / 100, 3.33); + + wasmExports.setLocalMutF64(2.22); + strictEqual(wasmExports.getLocalMutF64(), 2.22); + + // These mutating pending live bindings support + strictEqual(wasmExports.localMutI32, 100); + strictEqual(wasmExports.localMutI64, 200n); + strictEqual(Math.round(wasmExports.localMutF32 * 100) / 100, 2.72); + strictEqual(wasmExports.localMutF64, 3.141592653589793); + + // Test modifying local mutable externref + const anotherTestObj = { another: 'test object' }; + wasmExports.setLocalMutExternref(anotherTestObj); + strictEqual(wasmExports.getLocalMutExternref(), anotherTestObj); + strictEqual(wasmExports.localMutExternref, null); + + // Test dep.wasm imports + strictEqual(wasmExports.depI32, 1001); + strictEqual(wasmExports.depMutI32, 2001); + strictEqual(wasmExports.getDepMutI32(), 2001); + strictEqual(wasmExports.depI64, 10000000001n); + strictEqual(wasmExports.depMutI64, 20000000001n); + strictEqual(wasmExports.getDepMutI64(), 20000000001n); + strictEqual(Math.round(wasmExports.depF32 * 100) / 100, 10.01); + strictEqual(Math.round(wasmExports.depMutF32 * 100) / 100, 20.01); + strictEqual(Math.round(wasmExports.getDepMutF32() * 100) / 100, 20.01); + strictEqual(wasmExports.depF64, 100.0001); + strictEqual(wasmExports.depMutF64, 200.0001); + strictEqual(wasmExports.getDepMutF64(), 200.0001); + + // Test modifying dep.wasm mutable globals + wasmExports.setDepMutI32(3001); + strictEqual(wasmExports.getDepMutI32(), 3001); + + wasmExports.setDepMutI64(30000000001n); + strictEqual(wasmExports.getDepMutI64(), 30000000001n); + + wasmExports.setDepMutF32(30.01); + strictEqual(Math.round(wasmExports.getDepMutF32() * 100) / 100, 30.01); + + wasmExports.setDepMutF64(300.0001); + strictEqual(wasmExports.getDepMutF64(), 300.0001); + + // These pending live bindings support + strictEqual(wasmExports.depMutI32, 2001); + strictEqual(wasmExports.depMutI64, 20000000001n); + strictEqual(Math.round(wasmExports.depMutF32 * 100) / 100, 20.01); + strictEqual(wasmExports.depMutF64, 200.0001); +} diff --git a/test/fixtures/es-modules/test-wasm-js-string-builtins.mjs b/test/fixtures/es-modules/test-wasm-js-string-builtins.mjs new file mode 100644 index 00000000000000..2364f246b2558d --- /dev/null +++ b/test/fixtures/es-modules/test-wasm-js-string-builtins.mjs @@ -0,0 +1,8 @@ +// Test fixture for js-string builtins support +import { strictEqual } from 'node:assert'; +import * as wasmExports from './js-string-builtins.wasm'; + +strictEqual(wasmExports.getLength('hello'), 5); +strictEqual(wasmExports.concatStrings('hello', ' world'), 'hello world'); +strictEqual(wasmExports.compareStrings('test', 'test'), 1); +strictEqual(wasmExports.compareStrings('test', 'different'), 0); diff --git a/test/fixtures/es-modules/test-wasm-load-exports.mjs b/test/fixtures/es-modules/test-wasm-load-exports.mjs new file mode 100644 index 00000000000000..cdb1caa3c90457 --- /dev/null +++ b/test/fixtures/es-modules/test-wasm-load-exports.mjs @@ -0,0 +1,11 @@ +// Test fixture for loading WASM exports +import { strictEqual, match } from 'node:assert'; +import { fileURLToPath } from 'node:url'; +import { add, addImported } from './simple.wasm'; +import { state } from './wasm-dep.mjs'; + +strictEqual(state, 'WASM Start Executed'); +strictEqual(add(10, 20), 30); +strictEqual(addImported(0), 42); +strictEqual(state, 'WASM JS Function Executed'); +strictEqual(addImported(1), 43); diff --git a/test/fixtures/es-modules/test-wasm-non-identifier-exports.mjs b/test/fixtures/es-modules/test-wasm-non-identifier-exports.mjs new file mode 100644 index 00000000000000..14e43adf20201a --- /dev/null +++ b/test/fixtures/es-modules/test-wasm-non-identifier-exports.mjs @@ -0,0 +1,5 @@ +// Test fixture for non-identifier export names +import { strictEqual } from 'node:assert'; +import * as wasmExports from './export-name-syntax-error.wasm'; + +strictEqual(wasmExports['?f!o:oa[r]'], 12682); diff --git a/test/fixtures/es-modules/test-wasm-reject-wasm-export-names.mjs b/test/fixtures/es-modules/test-wasm-reject-wasm-export-names.mjs new file mode 100644 index 00000000000000..684132910fc2d4 --- /dev/null +++ b/test/fixtures/es-modules/test-wasm-reject-wasm-export-names.mjs @@ -0,0 +1,6 @@ +// Test WASM module with invalid export name starting with 'wasm:' +import { fileURLToPath } from 'node:url'; +import { pathToFileURL } from 'node:url'; + +const url = pathToFileURL(fileURLToPath(new URL('./invalid-export-name.wasm', import.meta.url))).href; +await import(url); diff --git a/test/fixtures/es-modules/test-wasm-reject-wasm-import-names.mjs b/test/fixtures/es-modules/test-wasm-reject-wasm-import-names.mjs new file mode 100644 index 00000000000000..aa4aa59238b018 --- /dev/null +++ b/test/fixtures/es-modules/test-wasm-reject-wasm-import-names.mjs @@ -0,0 +1,6 @@ +// Test WASM module with invalid import name starting with 'wasm:' +import { fileURLToPath } from 'node:url'; +import { pathToFileURL } from 'node:url'; + +const url = pathToFileURL(fileURLToPath(new URL('./invalid-import-name.wasm', import.meta.url))).href; +await import(url); diff --git a/test/fixtures/es-modules/test-wasm-reject-wasm-js-export-names.mjs b/test/fixtures/es-modules/test-wasm-reject-wasm-js-export-names.mjs new file mode 100644 index 00000000000000..a96871d827c22a --- /dev/null +++ b/test/fixtures/es-modules/test-wasm-reject-wasm-js-export-names.mjs @@ -0,0 +1,6 @@ +// Test WASM module with invalid export name starting with 'wasm-js:' +import { fileURLToPath } from 'node:url'; +import { pathToFileURL } from 'node:url'; + +const url = pathToFileURL(fileURLToPath(new URL('./invalid-export-name-wasm-js.wasm', import.meta.url))).href; +await import(url); diff --git a/test/fixtures/es-modules/test-wasm-reject-wasm-js-import-module.mjs b/test/fixtures/es-modules/test-wasm-reject-wasm-js-import-module.mjs new file mode 100644 index 00000000000000..d23dfea8a78d12 --- /dev/null +++ b/test/fixtures/es-modules/test-wasm-reject-wasm-js-import-module.mjs @@ -0,0 +1,6 @@ +// Test WASM module with invalid import module name starting with 'wasm-js:' +import { fileURLToPath } from 'node:url'; +import { pathToFileURL } from 'node:url'; + +const url = pathToFileURL(fileURLToPath(new URL('./invalid-import-module.wasm', import.meta.url))).href; +await import(url); diff --git a/test/fixtures/es-modules/test-wasm-reject-wasm-js-import-names.mjs b/test/fixtures/es-modules/test-wasm-reject-wasm-js-import-names.mjs new file mode 100644 index 00000000000000..817b1437d9523d --- /dev/null +++ b/test/fixtures/es-modules/test-wasm-reject-wasm-js-import-names.mjs @@ -0,0 +1,6 @@ +// Test WASM module with invalid import name starting with 'wasm-js:' +import { fileURLToPath } from 'node:url'; +import { pathToFileURL } from 'node:url'; + +const url = pathToFileURL(fileURLToPath(new URL('./invalid-import-name-wasm-js.wasm', import.meta.url))).href; +await import(url); diff --git a/test/fixtures/es-modules/test-wasm-source-phase-dynamic.mjs b/test/fixtures/es-modules/test-wasm-source-phase-dynamic.mjs new file mode 100644 index 00000000000000..a544fbbec5ace2 --- /dev/null +++ b/test/fixtures/es-modules/test-wasm-source-phase-dynamic.mjs @@ -0,0 +1,9 @@ +// Test fixture for dynamic source phase imports +import { strictEqual } from 'node:assert'; +import * as wasmExports from './wasm-source-phase.js'; + +strictEqual(wasmExports.mod instanceof WebAssembly.Module, true); +strictEqual(await wasmExports.dyn('./simple.wasm') instanceof WebAssembly.Module, true); +const AbstractModuleSourceProto = Object.getPrototypeOf(Object.getPrototypeOf(wasmExports.mod)); +const toStringTag = Object.getOwnPropertyDescriptor(AbstractModuleSourceProto, Symbol.toStringTag).get; +strictEqual(toStringTag.call(wasmExports.mod), 'WebAssembly.Module'); diff --git a/test/fixtures/es-modules/test-wasm-source-phase-no-execute-dynamic.mjs b/test/fixtures/es-modules/test-wasm-source-phase-no-execute-dynamic.mjs new file mode 100644 index 00000000000000..5979ad29184bde --- /dev/null +++ b/test/fixtures/es-modules/test-wasm-source-phase-no-execute-dynamic.mjs @@ -0,0 +1,6 @@ +// Test fixture that dynamic source phase imports don't execute +import { fileURLToPath } from 'node:url'; +import { pathToFileURL } from 'node:url'; + +const unimportableUrl = pathToFileURL(fileURLToPath(new URL('./unimportable.wasm', import.meta.url))).href; +await import.source(unimportableUrl); diff --git a/test/fixtures/es-modules/test-wasm-source-phase-no-execute.mjs b/test/fixtures/es-modules/test-wasm-source-phase-no-execute.mjs new file mode 100644 index 00000000000000..e1a2a486364cef --- /dev/null +++ b/test/fixtures/es-modules/test-wasm-source-phase-no-execute.mjs @@ -0,0 +1,9 @@ +// Test fixture that source phase imports don't execute +import { strictEqual, rejects } from 'node:assert'; +import { fileURLToPath } from 'node:url'; +import { pathToFileURL } from 'node:url'; +import source mod from './unimportable.wasm'; + +strictEqual(mod instanceof WebAssembly.Module, true); +const unimportableUrl = pathToFileURL(fileURLToPath(new URL('./unimportable.wasm', import.meta.url))).href; +await rejects(import(unimportableUrl)); diff --git a/test/fixtures/es-modules/test-wasm-source-phase-not-defined-dynamic.mjs b/test/fixtures/es-modules/test-wasm-source-phase-not-defined-dynamic.mjs new file mode 100644 index 00000000000000..9ce07461492668 --- /dev/null +++ b/test/fixtures/es-modules/test-wasm-source-phase-not-defined-dynamic.mjs @@ -0,0 +1,12 @@ +// Test fixture that throws when source phase not defined for dynamic import +import { ok, strictEqual, rejects } from 'node:assert'; +import { fileURLToPath } from 'node:url'; +import { pathToFileURL } from 'node:url'; + +const fileUrl = pathToFileURL(fileURLToPath(new URL('./wasm-source-phase.js', import.meta.url))).href; +await rejects(import.source(fileUrl), (e) => { + strictEqual(e instanceof SyntaxError, true); + strictEqual(e.message.includes('Source phase import object is not defined for module'), true); + strictEqual(e.message.includes(fileUrl), true); + return true; +}); diff --git a/test/fixtures/es-modules/test-wasm-source-phase-not-defined-static.mjs b/test/fixtures/es-modules/test-wasm-source-phase-not-defined-static.mjs new file mode 100644 index 00000000000000..5b308f366f599c --- /dev/null +++ b/test/fixtures/es-modules/test-wasm-source-phase-not-defined-static.mjs @@ -0,0 +1,2 @@ +// Test fixture that throws when source phase not defined for static import +import source nosource from './wasm-source-phase.js'; diff --git a/test/fixtures/es-modules/test-wasm-source-phase-static.mjs b/test/fixtures/es-modules/test-wasm-source-phase-static.mjs new file mode 100644 index 00000000000000..1cdbe06d11436f --- /dev/null +++ b/test/fixtures/es-modules/test-wasm-source-phase-static.mjs @@ -0,0 +1,8 @@ +// Test fixture for static source phase imports +import { strictEqual } from 'node:assert'; +import * as wasmExports from './wasm-source-phase.js'; + +strictEqual(wasmExports.mod instanceof WebAssembly.Module, true); +const AbstractModuleSourceProto = Object.getPrototypeOf(Object.getPrototypeOf(wasmExports.mod)); +const toStringTag = Object.getOwnPropertyDescriptor(AbstractModuleSourceProto, Symbol.toStringTag).get; +strictEqual(toStringTag.call(wasmExports.mod), 'WebAssembly.Module'); diff --git a/test/fixtures/es-modules/test-wasm-vm-source-phase-dynamic.mjs b/test/fixtures/es-modules/test-wasm-vm-source-phase-dynamic.mjs new file mode 100644 index 00000000000000..2da4cfa06764da --- /dev/null +++ b/test/fixtures/es-modules/test-wasm-vm-source-phase-dynamic.mjs @@ -0,0 +1,8 @@ +// Test fixture that throws for vm source phase dynamic import +import vm from 'node:vm'; + +const opts = { importModuleDynamically: () => m2 }; +const m1 = new vm.SourceTextModule('await import.source("y");', opts); +const m2 = new vm.SourceTextModule('export var p = 5;'); +await m1.link(() => m2); +await m1.evaluate(); diff --git a/test/fixtures/es-modules/test-wasm-vm-source-phase-static.mjs b/test/fixtures/es-modules/test-wasm-vm-source-phase-static.mjs new file mode 100644 index 00000000000000..dee9a84ab1b721 --- /dev/null +++ b/test/fixtures/es-modules/test-wasm-vm-source-phase-static.mjs @@ -0,0 +1,7 @@ +// Test fixture that throws for vm source phase static import +import vm from 'node:vm'; + +const m1 = new vm.SourceTextModule('import source x from "y";'); +const m2 = new vm.SourceTextModule('export var p = 5;'); +await m1.link(() => m2); +await m1.evaluate();