diff --git a/test/js-api/esm-integration/exports.tentative.any.js b/test/js-api/esm-integration/exports.tentative.any.js new file mode 100644 index 000000000..9feaa283a --- /dev/null +++ b/test/js-api/esm-integration/exports.tentative.any.js @@ -0,0 +1,36 @@ +// META: global=window,dedicatedworker,jsshell,shadowrealm + +"use strict"; + +promise_test(async () => { + const mod = await import("./resources/exports.wasm"); + + assert_array_equals(Object.getOwnPropertyNames(mod).sort(), [ + "a\u200Bb\u0300c", + "func", + "glob", + "mem", + "tab", + "value with spaces", + "🎯test-func!", + ]); + assert_true(mod.func instanceof Function); + assert_true(mod.mem instanceof WebAssembly.Memory); + assert_true(mod.tab instanceof WebAssembly.Table); + + assert_false(mod.glob instanceof WebAssembly.Global); + assert_equals(typeof mod.glob, "number"); + + assert_throws_js(TypeError, () => { + mod.func = 2; + }); + + assert_equals(typeof mod["value with spaces"], "number"); + assert_equals(mod["value with spaces"], 123); + + assert_true(mod["🎯test-func!"] instanceof Function); + assert_equals(mod["🎯test-func!"](), 456); + + assert_equals(typeof mod["a\u200Bb\u0300c"], "number"); + assert_equals(mod["a\u200Bb\u0300c"], 789); +}, "Exported names from a WebAssembly module"); diff --git a/test/js-api/esm-integration/global-exports-live-bindings.tentative.any.js b/test/js-api/esm-integration/global-exports-live-bindings.tentative.any.js new file mode 100644 index 000000000..d80c30943 --- /dev/null +++ b/test/js-api/esm-integration/global-exports-live-bindings.tentative.any.js @@ -0,0 +1,46 @@ +// META: global=window,dedicatedworker,jsshell,shadowrealm + +promise_test(async () => { + const wasmExports = await import("./resources/globals.wasm"); + + wasmExports.setLocalMutI32(555); + assert_equals(wasmExports.getLocalMutI32(), 555); + assert_equals(wasmExports.localMutI32, 555); + + wasmExports.setLocalMutI64(444n); + assert_equals(wasmExports.getLocalMutI64(), 444n); + assert_equals(wasmExports.localMutI64, 444n); + + wasmExports.setLocalMutF32(3.33); + assert_equals(Math.round(wasmExports.getLocalMutF32() * 100) / 100, 3.33); + assert_equals(Math.round(wasmExports.localMutF32 * 100) / 100, 3.33); + + wasmExports.setLocalMutF64(2.22); + assert_equals(wasmExports.getLocalMutF64(), 2.22); + assert_equals(wasmExports.localMutF64, 2.22); + + const anotherTestObj = { another: "test object" }; + wasmExports.setLocalMutExternref(anotherTestObj); + assert_equals(wasmExports.getLocalMutExternref(), anotherTestObj); + assert_equals(wasmExports.localMutExternref, anotherTestObj); +}, "Local mutable global exports should be live bindings"); + +promise_test(async () => { + const wasmExports = await import("./resources/globals.wasm"); + + wasmExports.setDepMutI32(3001); + assert_equals(wasmExports.getDepMutI32(), 3001); + assert_equals(wasmExports.depMutI32, 3001); + + wasmExports.setDepMutI64(30000000001n); + assert_equals(wasmExports.getDepMutI64(), 30000000001n); + assert_equals(wasmExports.depMutI64, 30000000001n); + + wasmExports.setDepMutF32(30.01); + assert_equals(Math.round(wasmExports.getDepMutF32() * 100) / 100, 30.01); + assert_equals(Math.round(wasmExports.depMutF32 * 100) / 100, 30.01); + + wasmExports.setDepMutF64(300.0001); + assert_equals(wasmExports.getDepMutF64(), 300.0001); + assert_equals(wasmExports.depMutF64, 300.0001); +}, "Dep module mutable global exports should be live bindings"); diff --git a/test/js-api/esm-integration/global-exports.tentative.any.js b/test/js-api/esm-integration/global-exports.tentative.any.js new file mode 100644 index 000000000..51ebcaf95 --- /dev/null +++ b/test/js-api/esm-integration/global-exports.tentative.any.js @@ -0,0 +1,111 @@ +// META: global=window,dedicatedworker,jsshell,shadowrealm + +promise_test(async () => { + const wasmModule = await import("./resources/globals.wasm"); + + assert_equals(wasmModule.importedI32, 42); + assert_equals(wasmModule.importedI64, 9223372036854775807n); + assert_equals(Math.round(wasmModule.importedF32 * 100000) / 100000, 3.14159); + assert_equals(wasmModule.importedF64, 3.141592653589793); + assert_not_equals(wasmModule.importedExternref, null); + assert_equals(wasmModule.importedNullExternref, null); +}, "WebAssembly module global values should be unwrapped when importing in ESM integration"); + +promise_test(async () => { + const wasmModule = await import("./resources/globals.wasm"); + + assert_equals(wasmModule.importedMutI32, 100); + assert_equals(wasmModule.importedMutI64, 200n); + assert_equals( + Math.round(wasmModule.importedMutF32 * 100000) / 100000, + 2.71828 + ); + assert_equals(wasmModule.importedMutF64, 2.718281828459045); + assert_not_equals(wasmModule.importedMutExternref, null); + assert_equals(wasmModule.importedMutExternref.mutable, "global"); +}, "WebAssembly mutable global values should be unwrapped when importing in ESM integration"); + +promise_test(async () => { + const wasmModule = await import("./resources/globals.wasm"); + + assert_equals(wasmModule["🚀localI32"], 42); + assert_equals(wasmModule.localMutI32, 100); + assert_equals(wasmModule.localI64, 9223372036854775807n); + assert_equals(wasmModule.localMutI64, 200n); + assert_equals(Math.round(wasmModule.localF32 * 100000) / 100000, 3.14159); + assert_equals(Math.round(wasmModule.localMutF32 * 100000) / 100000, 2.71828); + assert_equals(wasmModule.localF64, 2.718281828459045); + assert_equals(wasmModule.localMutF64, 3.141592653589793); +}, "WebAssembly local global values should be unwrapped when exporting in ESM integration"); + +promise_test(async () => { + const wasmModule = await import("./resources/globals.wasm"); + + assert_equals(wasmModule.depI32, 1001); + assert_equals(wasmModule.depMutI32, 2001); + assert_equals(wasmModule.depI64, 10000000001n); + assert_equals(wasmModule.depMutI64, 20000000001n); + assert_equals(Math.round(wasmModule.depF32 * 100) / 100, 10.01); + assert_equals(Math.round(wasmModule.depMutF32 * 100) / 100, 20.01); + assert_equals(wasmModule.depF64, 100.0001); + assert_equals(wasmModule.depMutF64, 200.0001); +}, "WebAssembly module globals from imported WebAssembly modules should be unwrapped"); + +promise_test(async () => { + const wasmModule = await import("./resources/globals.wasm"); + + assert_equals(wasmModule.importedI32, 42); + assert_equals(wasmModule.importedMutI32, 100); + assert_equals(wasmModule.importedI64, 9223372036854775807n); + assert_equals(wasmModule.importedMutI64, 200n); + assert_equals(Math.round(wasmModule.importedF32 * 100000) / 100000, 3.14159); + assert_equals( + Math.round(wasmModule.importedMutF32 * 100000) / 100000, + 2.71828 + ); + assert_equals(wasmModule.importedF64, 3.141592653589793); + assert_equals(wasmModule.importedMutF64, 2.718281828459045); + assert_equals(wasmModule.importedExternref !== null, true); + assert_equals(wasmModule.importedMutExternref !== null, true); + assert_equals(wasmModule.importedNullExternref, null); + + assert_equals(wasmModule["🚀localI32"], 42); + assert_equals(wasmModule.localMutI32, 100); + assert_equals(wasmModule.localI64, 9223372036854775807n); + assert_equals(wasmModule.localMutI64, 200n); + assert_equals(Math.round(wasmModule.localF32 * 100000) / 100000, 3.14159); + assert_equals(Math.round(wasmModule.localMutF32 * 100000) / 100000, 2.71828); + assert_equals(wasmModule.localF64, 2.718281828459045); + assert_equals(wasmModule.localMutF64, 3.141592653589793); + + assert_equals(wasmModule.getImportedMutI32(), 100); + assert_equals(wasmModule.getImportedMutI64(), 200n); + assert_equals( + Math.round(wasmModule.getImportedMutF32() * 100000) / 100000, + 2.71828 + ); + assert_equals(wasmModule.getImportedMutF64(), 2.718281828459045); + assert_equals(wasmModule.getImportedMutExternref() !== null, true); + + assert_equals(wasmModule.getLocalMutI32(), 100); + assert_equals(wasmModule.getLocalMutI64(), 200n); + assert_equals( + Math.round(wasmModule.getLocalMutF32() * 100000) / 100000, + 2.71828 + ); + assert_equals(wasmModule.getLocalMutF64(), 3.141592653589793); + assert_equals(wasmModule.getLocalMutExternref(), null); + + assert_equals(wasmModule.depI32, 1001); + assert_equals(wasmModule.depMutI32, 2001); + assert_equals(wasmModule.getDepMutI32(), 2001); + assert_equals(wasmModule.depI64, 10000000001n); + assert_equals(wasmModule.depMutI64, 20000000001n); + assert_equals(wasmModule.getDepMutI64(), 20000000001n); + assert_equals(Math.round(wasmModule.depF32 * 100) / 100, 10.01); + assert_equals(Math.round(wasmModule.depMutF32 * 100) / 100, 20.01); + assert_equals(Math.round(wasmModule.getDepMutF32() * 100) / 100, 20.01); + assert_equals(wasmModule.depF64, 100.0001); + assert_equals(wasmModule.depMutF64, 200.0001); + assert_equals(wasmModule.getDepMutF64(), 200.0001); +}, "WebAssembly should properly handle all global types"); diff --git a/test/js-api/esm-integration/js-wasm-cycle.tentative.any.js b/test/js-api/esm-integration/js-wasm-cycle.tentative.any.js new file mode 100644 index 000000000..ce71a33a2 --- /dev/null +++ b/test/js-api/esm-integration/js-wasm-cycle.tentative.any.js @@ -0,0 +1,7 @@ +// META: global=window,dedicatedworker,jsshell,shadowrealm + +promise_test(async () => { + const { f } = await import("./resources/js-wasm-cycle.js"); + + assert_equals(f(), 24); +}, "Check bindings in JavaScript and WebAssembly cycle (JS higher)"); diff --git a/test/js-api/esm-integration/mutable-global-sharing.tentative.any.js b/test/js-api/esm-integration/mutable-global-sharing.tentative.any.js new file mode 100644 index 000000000..c636da929 --- /dev/null +++ b/test/js-api/esm-integration/mutable-global-sharing.tentative.any.js @@ -0,0 +1,78 @@ +promise_test(async () => { + const exporterModule = await import("./resources/mutable-global-export.wasm"); + const reexporterModule = await import( + "./resources/mutable-global-reexport.wasm" + ); + + assert_equals(exporterModule.mutableValue, 100); + assert_equals(reexporterModule.reexportedMutableValue, 100); +}, "WebAssembly modules should export shared mutable globals with correct initial values"); + +promise_test(async () => { + const exporterModule = await import("./resources/mutable-global-export.wasm"); + const reexporterModule = await import( + "./resources/mutable-global-reexport.wasm" + ); + + exporterModule.setGlobal(500); + + assert_equals(exporterModule.getGlobal(), 500, "exporter should see 500"); + assert_equals(reexporterModule.getImportedGlobal(), 500); + + reexporterModule.setImportedGlobal(600); + + assert_equals(exporterModule.getGlobal(), 600); + assert_equals(reexporterModule.getImportedGlobal(), 600); + + exporterModule.setGlobal(700); + + assert_equals(exporterModule.getGlobal(), 700); + assert_equals(reexporterModule.getImportedGlobal(), 700); +}, "Wasm-to-Wasm mutable global sharing is live"); + +promise_test(async () => { + const module1 = await import("./resources/mutable-global-export.wasm"); + const module2 = await import("./resources/mutable-global-export.wasm"); + + assert_equals(module1, module2); + + module1.setGlobal(800); + assert_equals(module1.getGlobal(), 800, "module1 should see its own change"); + assert_equals(module2.getGlobal(), 800); +}, "Multiple JavaScript imports return the same WebAssembly module instance"); + +promise_test(async () => { + const exporterModule = await import("./resources/mutable-global-export.wasm"); + const reexporterModule = await import( + "./resources/mutable-global-reexport.wasm" + ); + + assert_equals(exporterModule.getV128Lane(0), 1); + assert_equals(exporterModule.getV128Lane(1), 2); + assert_equals(exporterModule.getV128Lane(2), 3); + assert_equals(exporterModule.getV128Lane(3), 4); + + assert_equals(reexporterModule.getImportedV128Lane(0), 1); + assert_equals(reexporterModule.getImportedV128Lane(1), 2); + assert_equals(reexporterModule.getImportedV128Lane(2), 3); + assert_equals(reexporterModule.getImportedV128Lane(3), 4); +}, "v128 globals should work correctly in WebAssembly-to-WebAssembly imports"); + +promise_test(async () => { + const exporterModule = await import("./resources/mutable-global-export.wasm"); + const reexporterModule = await import( + "./resources/mutable-global-reexport.wasm" + ); + + exporterModule.setV128Global(10, 20, 30, 40); + + assert_equals(exporterModule.getV128Lane(0), 10); + assert_equals(exporterModule.getV128Lane(1), 20); + assert_equals(exporterModule.getV128Lane(2), 30); + assert_equals(exporterModule.getV128Lane(3), 40); + + assert_equals(reexporterModule.getImportedV128Lane(0), 10); + assert_equals(reexporterModule.getImportedV128Lane(1), 20); + assert_equals(reexporterModule.getImportedV128Lane(2), 30); + assert_equals(reexporterModule.getImportedV128Lane(3), 40); +}, "v128 global mutations should work correctly between WebAssembly modules"); diff --git a/test/js-api/esm-integration/namespace-instance.tentative.any.js b/test/js-api/esm-integration/namespace-instance.tentative.any.js new file mode 100644 index 000000000..e5e4e0721 --- /dev/null +++ b/test/js-api/esm-integration/namespace-instance.tentative.any.js @@ -0,0 +1,52 @@ +// META: global=window,dedicatedworker,jsshell,shadowrealm + +promise_test(async () => { + const wasmNamespace = await import("./resources/mutable-global-export.wasm"); + const instance = WebAssembly.namespaceInstance(wasmNamespace); + + assert_true(instance instanceof WebAssembly.Instance); + + wasmNamespace.setGlobal(999); + assert_equals(instance.exports.getGlobal(), 999); + + instance.exports.setGlobal(888); + assert_equals(wasmNamespace.getGlobal(), 888); +}, "WebAssembly.namespaceInstance() should return the underlying instance with shared state"); + +promise_test(async () => { + assert_throws_js(TypeError, () => WebAssembly.namespaceInstance({})); + assert_throws_js(TypeError, () => WebAssembly.namespaceInstance(null)); + assert_throws_js(TypeError, () => WebAssembly.namespaceInstance(undefined)); + assert_throws_js(TypeError, () => WebAssembly.namespaceInstance(42)); + assert_throws_js(TypeError, () => + WebAssembly.namespaceInstance("not a namespace") + ); + assert_throws_js(TypeError, () => WebAssembly.namespaceInstance([])); + assert_throws_js(TypeError, () => + WebAssembly.namespaceInstance(function () {}) + ); + + const jsModule = await import("./resources/globals.js"); + assert_throws_js(TypeError, () => WebAssembly.namespaceInstance(jsModule)); +}, "WebAssembly.namespaceInstance() should throw TypeError for non-WebAssembly namespaces"); + +promise_test(async () => { + const exportsModule = await import("./resources/exports.wasm"); + const globalsModule = await import("./resources/globals.wasm"); + + const exportsInstance = WebAssembly.namespaceInstance(exportsModule); + const globalsInstance = WebAssembly.namespaceInstance(globalsModule); + + assert_not_equals(exportsInstance, globalsInstance); + assert_true(exportsInstance.exports.func instanceof Function); + assert_true(globalsInstance.exports.getLocalMutI32 instanceof Function); + + globalsModule.setLocalMutI32(12345); + assert_equals(globalsInstance.exports.getLocalMutI32(), 12345); + + globalsInstance.exports.setLocalMutI32(54321); + assert_equals(globalsModule.getLocalMutI32(), 54321); + + const exportsInstance2 = WebAssembly.namespaceInstance(exportsModule); + assert_equals(exportsInstance, exportsInstance2); +}, "WebAssembly.namespaceInstance() should work correctly with multiple modules"); diff --git a/test/js-api/esm-integration/reserved-import-names.tentative.any.js b/test/js-api/esm-integration/reserved-import-names.tentative.any.js new file mode 100644 index 000000000..aa17735b0 --- /dev/null +++ b/test/js-api/esm-integration/reserved-import-names.tentative.any.js @@ -0,0 +1,41 @@ +// Test that wasm: and wasm-js: reserved cases should cause WebAssembly.LinkError + +promise_test(async (t) => { + await promise_rejects_js( + t, + WebAssembly.LinkError, + import("./resources/invalid-import-name.wasm") + ); +}, "wasm: reserved import names should cause WebAssembly.LinkError"); + +promise_test(async (t) => { + await promise_rejects_js( + t, + WebAssembly.LinkError, + import("./resources/invalid-import-name-wasm-js.wasm") + ); +}, "wasm-js: reserved import names should cause WebAssembly.LinkError"); + +promise_test(async (t) => { + await promise_rejects_js( + t, + WebAssembly.LinkError, + import("./resources/invalid-export-name.wasm") + ); +}, "wasm: reserved export names should cause WebAssembly.LinkError"); + +promise_test(async (t) => { + await promise_rejects_js( + t, + WebAssembly.LinkError, + import("./resources/invalid-export-name-wasm-js.wasm") + ); +}, "wasm-js: reserved export names should cause WebAssembly.LinkError"); + +promise_test(async (t) => { + await promise_rejects_js( + t, + WebAssembly.LinkError, + import("./resources/invalid-import-module.wasm") + ); +}, "wasm-js: reserved module names should cause WebAssembly.LinkError"); diff --git a/test/js-api/esm-integration/resolve-export.tentative.any.js b/test/js-api/esm-integration/resolve-export.tentative.any.js new file mode 100644 index 000000000..86325d11b --- /dev/null +++ b/test/js-api/esm-integration/resolve-export.tentative.any.js @@ -0,0 +1,9 @@ +// META: global=window,dedicatedworker,jsshell,shadowrealm + +promise_test(async (t) => { + await promise_rejects_js( + t, + SyntaxError, + import("./resources/resolve-export.js") + ); +}, "ResolveExport on invalid re-export from WebAssembly"); diff --git a/test/js-api/esm-integration/resources/dep.wasm b/test/js-api/esm-integration/resources/dep.wasm new file mode 100644 index 000000000..ad9abfaa6 Binary files /dev/null and b/test/js-api/esm-integration/resources/dep.wasm differ diff --git a/test/js-api/esm-integration/resources/exports.wasm b/test/js-api/esm-integration/resources/exports.wasm new file mode 100644 index 000000000..7382eff03 Binary files /dev/null and b/test/js-api/esm-integration/resources/exports.wasm differ diff --git a/test/js-api/esm-integration/resources/globals.js b/test/js-api/esm-integration/resources/globals.js new file mode 100644 index 000000000..fabf23faf --- /dev/null +++ b/test/js-api/esm-integration/resources/globals.js @@ -0,0 +1,29 @@ +const i32_value = 42; +export { i32_value as "🚀i32_value" }; +export const i64_value = 9223372036854775807n; +export const f32_value = 3.14159; +export const f64_value = 3.141592653589793; + +export const i32_mut_value = new WebAssembly.Global( + { value: "i32", mutable: true }, + 100 +); +export const i64_mut_value = new WebAssembly.Global( + { value: "i64", mutable: true }, + 200n +); +export const f32_mut_value = new WebAssembly.Global( + { value: "f32", mutable: true }, + 2.71828 +); +export const f64_mut_value = new WebAssembly.Global( + { value: "f64", mutable: true }, + 2.718281828459045 +); + +export const externref_value = { hello: "world" }; +export const externref_mut_value = new WebAssembly.Global( + { value: "externref", mutable: true }, + { mutable: "global" } +); +export const null_externref_value = null; diff --git a/test/js-api/esm-integration/resources/globals.wasm b/test/js-api/esm-integration/resources/globals.wasm new file mode 100644 index 000000000..c5e6dd9f1 Binary files /dev/null and b/test/js-api/esm-integration/resources/globals.wasm differ diff --git a/test/js-api/esm-integration/resources/invalid-export-name-wasm-js.wasm b/test/js-api/esm-integration/resources/invalid-export-name-wasm-js.wasm new file mode 100644 index 000000000..a6b9a7f7c Binary files /dev/null and b/test/js-api/esm-integration/resources/invalid-export-name-wasm-js.wasm differ diff --git a/test/js-api/esm-integration/resources/invalid-export-name.wasm b/test/js-api/esm-integration/resources/invalid-export-name.wasm new file mode 100644 index 000000000..e66fcebf1 Binary files /dev/null and b/test/js-api/esm-integration/resources/invalid-export-name.wasm differ diff --git a/test/js-api/esm-integration/resources/invalid-import-module.wasm b/test/js-api/esm-integration/resources/invalid-import-module.wasm new file mode 100644 index 000000000..ead151ac0 Binary files /dev/null and b/test/js-api/esm-integration/resources/invalid-import-module.wasm differ diff --git a/test/js-api/esm-integration/resources/invalid-import-name-wasm-js.wasm b/test/js-api/esm-integration/resources/invalid-import-name-wasm-js.wasm new file mode 100644 index 000000000..15131a28a Binary files /dev/null and b/test/js-api/esm-integration/resources/invalid-import-name-wasm-js.wasm differ diff --git a/test/js-api/esm-integration/resources/invalid-import-name.wasm b/test/js-api/esm-integration/resources/invalid-import-name.wasm new file mode 100644 index 000000000..3c6314182 Binary files /dev/null and b/test/js-api/esm-integration/resources/invalid-import-name.wasm differ diff --git a/test/js-api/esm-integration/resources/js-string-builtins.wasm b/test/js-api/esm-integration/resources/js-string-builtins.wasm new file mode 100644 index 000000000..4c4ff4df7 Binary files /dev/null and b/test/js-api/esm-integration/resources/js-string-builtins.wasm differ diff --git a/test/js-api/esm-integration/resources/js-wasm-cycle.js b/test/js-api/esm-integration/resources/js-wasm-cycle.js new file mode 100644 index 000000000..9f14dc04b --- /dev/null +++ b/test/js-api/esm-integration/resources/js-wasm-cycle.js @@ -0,0 +1,17 @@ +function f() { + return 42; +} +export { f }; + +import { mem, tab, glob, func } from "./js-wasm-cycle.wasm"; +assert_false(glob instanceof WebAssembly.Global, "imported global should be unwrapped in ESM integration"); +assert_equals(glob, 1, "unwrapped global should have direct value"); +assert_true(mem instanceof WebAssembly.Memory); +assert_true(tab instanceof WebAssembly.Table); +assert_true(func instanceof Function); + +f = () => { + return 24; +}; + +assert_equals(func(), 42); diff --git a/test/js-api/esm-integration/resources/js-wasm-cycle.wasm b/test/js-api/esm-integration/resources/js-wasm-cycle.wasm new file mode 100644 index 000000000..77a3b86ab Binary files /dev/null and b/test/js-api/esm-integration/resources/js-wasm-cycle.wasm differ diff --git a/test/js-api/esm-integration/resources/log.js b/test/js-api/esm-integration/resources/log.js new file mode 100644 index 000000000..0c4f5ed51 --- /dev/null +++ b/test/js-api/esm-integration/resources/log.js @@ -0,0 +1 @@ +export function logExec() { log.push("executed"); } diff --git a/test/js-api/esm-integration/resources/mutable-global-export.wasm b/test/js-api/esm-integration/resources/mutable-global-export.wasm new file mode 100644 index 000000000..89c478b19 Binary files /dev/null and b/test/js-api/esm-integration/resources/mutable-global-export.wasm differ diff --git a/test/js-api/esm-integration/resources/mutable-global-reexport.wasm b/test/js-api/esm-integration/resources/mutable-global-reexport.wasm new file mode 100644 index 000000000..b06f94a75 Binary files /dev/null and b/test/js-api/esm-integration/resources/mutable-global-reexport.wasm differ diff --git a/test/js-api/esm-integration/resources/resolve-export.js b/test/js-api/esm-integration/resources/resolve-export.js new file mode 100644 index 000000000..81145e037 --- /dev/null +++ b/test/js-api/esm-integration/resources/resolve-export.js @@ -0,0 +1 @@ +export { f } from "./resolve-export.wasm"; diff --git a/test/js-api/esm-integration/resources/resolve-export.wasm b/test/js-api/esm-integration/resources/resolve-export.wasm new file mode 100644 index 000000000..d8fc92d02 Binary files /dev/null and b/test/js-api/esm-integration/resources/resolve-export.wasm differ diff --git a/test/js-api/esm-integration/resources/wasm-export-to-wasm.wasm b/test/js-api/esm-integration/resources/wasm-export-to-wasm.wasm new file mode 100644 index 000000000..0ee948f96 Binary files /dev/null and b/test/js-api/esm-integration/resources/wasm-export-to-wasm.wasm differ diff --git a/test/js-api/esm-integration/resources/wasm-import-from-wasm.wasm b/test/js-api/esm-integration/resources/wasm-import-from-wasm.wasm new file mode 100644 index 000000000..652ff1431 Binary files /dev/null and b/test/js-api/esm-integration/resources/wasm-import-from-wasm.wasm differ diff --git a/test/js-api/esm-integration/source-phase-string-builtins.tentative.any.js b/test/js-api/esm-integration/source-phase-string-builtins.tentative.any.js new file mode 100644 index 000000000..e79b457dd --- /dev/null +++ b/test/js-api/esm-integration/source-phase-string-builtins.tentative.any.js @@ -0,0 +1,39 @@ +// META: global=window,dedicatedworker,jsshell,shadowrealm + +promise_test(async () => { + const wasmModuleSource = await import.source("./resources/js-string-builtins.wasm"); + + assert_true(wasmModuleSource instanceof WebAssembly.Module); + + const instance = new WebAssembly.Instance(wasmModuleSource, {}); + + assert_equals(instance.exports.getLength("hello"), 5); + assert_equals( + instance.exports.concatStrings("hello", " world"), + "hello world" + ); + assert_equals(instance.exports.compareStrings("test", "test"), 1); + assert_equals(instance.exports.compareStrings("test", "different"), 0); + assert_equals(instance.exports.testString("hello"), 1); + assert_equals(instance.exports.testString(42), 0); +}, "String builtins should be supported in source phase imports"); + +promise_test(async () => { + const wasmModuleSource = await import.source("./resources/js-string-builtins.wasm"); + + const exports = WebAssembly.Module.exports(wasmModuleSource); + const exportNames = exports.map((exp) => exp.name); + + assert_true(exportNames.includes("getLength")); + assert_true(exportNames.includes("concatStrings")); + assert_true(exportNames.includes("compareStrings")); + assert_true(exportNames.includes("testString")); +}, "Source phase import should properly expose string builtin exports"); + +promise_test(async () => { + const wasmModuleSource = await import.source("./resources/js-string-builtins.wasm"); + + const imports = WebAssembly.Module.imports(wasmModuleSource); + + assert_equals(imports.length, 0); +}, "Source phase import should handle string builtin import reflection correctly"); diff --git a/test/js-api/esm-integration/source-phase.tentative.any.js b/test/js-api/esm-integration/source-phase.tentative.any.js new file mode 100644 index 000000000..59a712265 --- /dev/null +++ b/test/js-api/esm-integration/source-phase.tentative.any.js @@ -0,0 +1,42 @@ +// META: global=window,dedicatedworker,jsshell,shadowrealm + +promise_test(async () => { + const exportedNamesSource = await import.source("./resources/exports.wasm"); + + assert_true(exportedNamesSource instanceof WebAssembly.Module); + const AbstractModuleSource = Object.getPrototypeOf(WebAssembly.Module); + assert_equals(AbstractModuleSource.name, "AbstractModuleSource"); + assert_true(exportedNamesSource instanceof AbstractModuleSource); + + assert_array_equals( + WebAssembly.Module.exports(exportedNamesSource) + .map(({ name }) => name) + .sort(), + [ + "a\u200Bb\u0300c", + "func", + "glob", + "mem", + "tab", + "value with spaces", + "🎯test-func!", + ] + ); + + const wasmImportFromWasmSource = await import.source( + "./resources/wasm-import-from-wasm.wasm" + ); + + assert_true(wasmImportFromWasmSource instanceof WebAssembly.Module); + + let logged = false; + const instance = await WebAssembly.instantiate(wasmImportFromWasmSource, { + "./wasm-export-to-wasm.wasm": { + log() { + logged = true; + }, + }, + }); + instance.exports.logExec(); + assert_true(logged, "WebAssembly instance should execute imported function"); +}, "Source phase imports"); diff --git a/test/js-api/esm-integration/string-builtins.tentative.any.js b/test/js-api/esm-integration/string-builtins.tentative.any.js new file mode 100644 index 000000000..bac8fd927 --- /dev/null +++ b/test/js-api/esm-integration/string-builtins.tentative.any.js @@ -0,0 +1,12 @@ +// META: global=window,dedicatedworker,jsshell,shadowrealm + +promise_test(async () => { + const wasmModule = await import("./resources/js-string-builtins.wasm"); + + assert_equals(wasmModule.getLength("hello"), 5); + assert_equals(wasmModule.concatStrings("hello", " world"), "hello world"); + assert_equals(wasmModule.compareStrings("test", "test"), 1); + assert_equals(wasmModule.compareStrings("test", "different"), 0); + assert_equals(wasmModule.testString("hello"), 1); + assert_equals(wasmModule.testString(42), 0); +}, "String builtins should be supported in imports in ESM integration"); diff --git a/test/js-api/esm-integration/v128-tdz.tentative.any.js b/test/js-api/esm-integration/v128-tdz.tentative.any.js new file mode 100644 index 000000000..5d11e5901 --- /dev/null +++ b/test/js-api/esm-integration/v128-tdz.tentative.any.js @@ -0,0 +1,11 @@ +// META: global=window,dedicatedworker,jsshell,shadowrealm + +promise_test(async () => { + const exporterModule = await import("./resources/mutable-global-export.wasm"); + const reexporterModule = await import( + "./resources/mutable-global-reexport.wasm" + ); + + assert_throws_js(ReferenceError, () => exporterModule.v128Export); + assert_throws_js(ReferenceError, () => reexporterModule.reexportedV128Export); +}, "v128 global exports should cause TDZ errors"); diff --git a/test/js-api/esm-integration/wasm-import-wasm-export.tentative.any.js b/test/js-api/esm-integration/wasm-import-wasm-export.tentative.any.js new file mode 100644 index 000000000..2c1a1446e --- /dev/null +++ b/test/js-api/esm-integration/wasm-import-wasm-export.tentative.any.js @@ -0,0 +1,14 @@ +// META: global=window,dedicatedworker,jsshell,shadowrealm + +promise_test(async () => { + globalThis.log = []; + + const { logExec } = await import("./resources/wasm-import-from-wasm.wasm"); + logExec(); + + assert_equals(globalThis.log.length, 1, "log should have one entry"); + assert_equals(globalThis.log[0], "executed"); + + // Clean up + delete globalThis.log; +}, "Check import and export between WebAssembly modules");