diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /dom/worklet/tests | |
parent | Initial commit. (diff) | |
download | thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
29 files changed, 1343 insertions, 0 deletions
diff --git a/dom/worklet/tests/common.js b/dom/worklet/tests/common.js new file mode 100644 index 0000000000..df6005cfe4 --- /dev/null +++ b/dom/worklet/tests/common.js @@ -0,0 +1,23 @@ +window.onload = function () { + // We are the parent. Let's load the test. + if (parent == this || !location.search.includes("worklet_iframe")) { + SimpleTest.waitForExplicitFinish(); + + configureTest().then(() => { + var iframe = document.createElement("iframe"); + iframe.src = location.href + "?worklet_iframe"; + document.body.appendChild(iframe); + }); + + return; + } + + // Here we are in the iframe. + window.SimpleTest = parent.SimpleTest; + window.is = parent.is; + window.isnot = parent.isnot; + window.ok = parent.ok; + window.info = parent.info; + + runTestInIframe(); +}; diff --git a/dom/worklet/tests/dynamic_import.js b/dom/worklet/tests/dynamic_import.js new file mode 100644 index 0000000000..a5196d212f --- /dev/null +++ b/dom/worklet/tests/dynamic_import.js @@ -0,0 +1,7 @@ +import("./empty-worklet-script.js") + .then(() => { + console.log("Fail"); + }) + .catch(e => { + console.log(e.name + ": Success"); + }); diff --git a/dom/worklet/tests/invalid_specifier.mjs b/dom/worklet/tests/invalid_specifier.mjs new file mode 100644 index 0000000000..128b60ffa6 --- /dev/null +++ b/dom/worklet/tests/invalid_specifier.mjs @@ -0,0 +1,3 @@ +/* eslint-disable import/no-unassigned-import */ +/* eslint-disable import/no-unresolved */ +import "foo"; diff --git a/dom/worklet/tests/mochitest.ini b/dom/worklet/tests/mochitest.ini new file mode 100644 index 0000000000..ebc85359cb --- /dev/null +++ b/dom/worklet/tests/mochitest.ini @@ -0,0 +1,40 @@ +[DEFAULT] +scheme = https +support-files = + common.js + +[test_audioWorklet.html] +support-files=worklet_audioWorklet.js +[test_audioWorkletGlobalScopeRegisterProcessor.html] +support-files=worklet_test_audioWorkletGlobalScopeRegisterProcessor.js +[test_audioWorklet_WASM.html] +skip-if = release_or_beta # requires dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled +support-files=worklet_audioWorklet_WASM.js +[test_audioWorklet_insecureContext.html] +scheme = http +skip-if = + http3 +[test_audioWorklet_options.html] +skip-if = release_or_beta # requires dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled +support-files=worklet_audioWorklet_options.js +[test_basic.html] +[test_console.html] +support-files=worklet_console.js +[test_dump.html] +support-files=worklet_dump.js +[test_dynamic_import.html] +support-files=dynamic_import.js +[test_exception.html] +support-files = + worklet_exception.js + invalid_specifier.mjs +[test_fetch_failed.html] +support-files=specifier_with_user.mjs +[test_import_with_cache.html] +skip-if = verify +support-files=server_import_with_cache.sjs +[test_paintWorklet.html] +skip-if = release_or_beta +support-files=worklet_paintWorklet.js +[test_promise.html] +support-files=worklet_promise.js diff --git a/dom/worklet/tests/server_import_with_cache.sjs b/dom/worklet/tests/server_import_with_cache.sjs new file mode 100644 index 0000000000..ed34a7a72f --- /dev/null +++ b/dom/worklet/tests/server_import_with_cache.sjs @@ -0,0 +1,12 @@ +function handleRequest(request, response) { + response.setHeader("Content-Type", "text/javascript", false); + + var state = getState("alreadySent"); + if (!state) { + setState("alreadySent", "1"); + } else { + response.setStatusLine("1.1", 404, "Not Found"); + } + + response.write("42"); +} diff --git a/dom/worklet/tests/specifier_with_user.mjs b/dom/worklet/tests/specifier_with_user.mjs new file mode 100644 index 0000000000..3d9bdb45cf --- /dev/null +++ b/dom/worklet/tests/specifier_with_user.mjs @@ -0,0 +1,3 @@ +/* eslint-disable import/no-unassigned-import */ +/* eslint-disable import/no-unresolved */ +import "http://user@example1.com/a.js"; diff --git a/dom/worklet/tests/test_audioWorklet.html b/dom/worklet/tests/test_audioWorklet.html new file mode 100644 index 0000000000..f7f3665e2f --- /dev/null +++ b/dom/worklet/tests/test_audioWorklet.html @@ -0,0 +1,53 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for AudioWorklet</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript" src="common.js"></script> +</head> +<body> + +<script type="application/javascript"> + +function configureTest() { + const ConsoleAPIStorage = SpecialPowers.Cc[ + "@mozilla.org/consoleAPI-storage;1" + ].getService(SpecialPowers.Ci.nsIConsoleAPIStorage); + + function consoleListener() { + this.observe = this.observe.bind(this); + ConsoleAPIStorage.addLogEventListener(this.observe, SpecialPowers.wrap(document).nodePrincipal); + } + + consoleListener.prototype = { + observe(aSubject) { + var obj = aSubject.wrappedJSObject; + if (obj.arguments[0] == "So far so good") { + ok(true, "Message received \\o/"); + + ConsoleAPIStorage.removeLogEventListener(this.observe); + SimpleTest.finish(); + return; + } + } + } + + var cl = new consoleListener(); + + return SpecialPowers.pushPrefEnv( + {"set": [["dom.audioworklet.enabled", true], + ["dom.worklet.enabled", true]]}); +} + +// This function is called into an iframe. +function runTestInIframe() { + ok(window.isSecureContext, "Test should run in secure context"); + var audioContext = new AudioContext(); + ok(audioContext.audioWorklet instanceof AudioWorklet, + "AudioContext.audioWorklet should be an instance of AudioWorklet"); + audioContext.audioWorklet.addModule("worklet_audioWorklet.js") +} +</script> +</body> +</html> diff --git a/dom/worklet/tests/test_audioWorkletGlobalScopeRegisterProcessor.html b/dom/worklet/tests/test_audioWorkletGlobalScopeRegisterProcessor.html new file mode 100644 index 0000000000..c26df05ad0 --- /dev/null +++ b/dom/worklet/tests/test_audioWorkletGlobalScopeRegisterProcessor.html @@ -0,0 +1,78 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for AudioWorklet</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript" src="common.js"></script> +</head> +<body> + +<script type="application/javascript"> + +function configureTest() { + + var expected_errors = [ + "TypeError: AudioWorkletGlobalScope.registerProcessor: Argument 2 is not a constructor.", + "NotSupportedError: AudioWorkletGlobalScope.registerProcessor: Argument 1 should not be an empty string.", + "TypeError: AudioWorkletGlobalScope.registerProcessor: Argument 2 is not an object.", + "TypeError: AudioWorkletGlobalScope.registerProcessor: Element 0 in parameterDescriptors can't be converted to a dictionary.", + "NotSupportedError: AudioWorkletGlobalScope.registerProcessor: Argument 1 is invalid: a class with the same name is already registered.", + "TypeError: AudioWorkletGlobalScope.registerProcessor: Missing required 'name' member of AudioParamDescriptor.", + "TypeError: AudioWorkletGlobalScope.registerProcessor: 'defaultValue' member of AudioParamDescriptor is not a finite floating-point value.", + "TypeError: AudioWorkletGlobalScope.registerProcessor: 'minValue' member of AudioParamDescriptor is not a finite floating-point value.", + "TypeError: AudioWorkletGlobalScope.registerProcessor: 'maxValue' member of AudioParamDescriptor is not a finite floating-point value.", + "NotSupportedError: AudioWorkletGlobalScope.registerProcessor: Duplicated name \"test\" in parameterDescriptors.", + "TypeError: AudioWorkletGlobalScope.registerProcessor: Element 0 in parameterDescriptors can't be converted to a dictionary.", + "InvalidStateError: AudioWorkletGlobalScope.registerProcessor: In parameterDescriptors, test defaultValue is out of the range defined by minValue and maxValue.", + "InvalidStateError: AudioWorkletGlobalScope.registerProcessor: In parameterDescriptors, test defaultValue is out of the range defined by minValue and maxValue.", + "InvalidStateError: AudioWorkletGlobalScope.registerProcessor: In parameterDescriptors, test minValue should be smaller than maxValue.", + ]; + + var expected_errors_i = 0; + + const ConsoleAPIStorage = SpecialPowers.Cc[ + "@mozilla.org/consoleAPI-storage;1" + ].getService(SpecialPowers.Ci.nsIConsoleAPIStorage); + + function consoleListener() { + this.observe = this.observe.bind(this); + ConsoleAPIStorage.addLogEventListener(this.observe, SpecialPowers.wrap(document).nodePrincipal); + } + + consoleListener.prototype = { + observe(aSubject) { + var obj = aSubject.wrappedJSObject; + if (obj.arguments[0] == expected_errors[expected_errors_i]) { + ok(true, "Expected error received: " + obj.arguments[0]); + expected_errors_i++; + } + + if (expected_errors_i == expected_errors.length) { + // All errors have been received, this test has been completed + // succesfully! + ConsoleAPIStorage.removeLogEventListener(this.observe); + SimpleTest.finish(); + return; + } + } + } + + var cl = new consoleListener(); + + return SpecialPowers.pushPrefEnv( + {"set": [["dom.audioworklet.enabled", true], + ["dom.worklet.enabled", true]]}); +} + +// This function is called into an iframe. +function runTestInIframe() { + ok(window.isSecureContext, "Test should run in secure context"); + var audioContext = new AudioContext(); + ok(audioContext.audioWorklet instanceof AudioWorklet, + "AudioContext.audioWorklet should be an instance of AudioWorklet"); + audioContext.audioWorklet.addModule("worklet_test_audioWorkletGlobalScopeRegisterProcessor.js") +} +</script> +</body> +</html> diff --git a/dom/worklet/tests/test_audioWorklet_WASM.html b/dom/worklet/tests/test_audioWorklet_WASM.html new file mode 100644 index 0000000000..127cc8b924 --- /dev/null +++ b/dom/worklet/tests/test_audioWorklet_WASM.html @@ -0,0 +1,85 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for AudioWorklet + WASM</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript" src="common.js"></script> +</head> +<body> + +<script type="application/javascript"> + +function configureTest() { + return SpecialPowers.pushPrefEnv( + {"set": [["dom.audioworklet.enabled", true], + ["dom.worklet.enabled", true], + ["dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", true], + ["browser.tabs.remote.useCrossOriginOpenerPolicy", true], + ["browser.tabs.remote.useCrossOriginEmbedderPolicy", true], + ["javascript.options.shared_memory", true], + ]}); +} + +function create_wasmModule() { + return new Promise(resolve => { + info("Checking if we can play with WebAssembly..."); + + if (!SpecialPowers.Cu.getJSTestingFunctions().wasmIsSupported()) { + resolve(null); + return; + } + + ok(WebAssembly, "WebAssembly object should exist"); + ok(WebAssembly.compile, "WebAssembly.compile function should exist"); + + const wasmTextToBinary = SpecialPowers.unwrap(SpecialPowers.Cu.getJSTestingFunctions().wasmTextToBinary); + /* + js -e ' + t = wasmTextToBinary(` + (module + (func $foo (result i32) (i32.const 42)) + (export "foo" (func $foo)) + ) + `); + print(t) + ' + */ + // eslint-disable-next-line + const fooModuleCode = new Uint8Array([0,97,115,109,1,0,0,0,1,5,1,96,0,1,127,3,2,1,0,7,7,1,3,102,111,111,0,0,10,6,1,4,0,65,42,11,0,13,4,110,97,109,101,1,6,1,0,3,102,111,111]); + + WebAssembly.compile(fooModuleCode).then(m => { + ok(m instanceof WebAssembly.Module, "The WasmModule has been compiled."); + resolve(m); + }, () => { + ok(false, "The compilation of the wasmModule failed."); + resolve(null); + }); + }); +} + +function runTestInIframe() { + let audioContext = new AudioContext(); + audioContext.audioWorklet.addModule("worklet_audioWorklet_WASM.js") + .then(() => create_wasmModule()) + .then(wasmModule => { + const node = new AudioWorkletNode(audioContext, 'wasm'); + let msgId = 0; + node.port.onmessage = e => { + if (msgId++ == 0) { + ok(e.data.wasmModule instanceof WebAssembly.Module, "WasmModule received"); + } else { + ok(e.data.sab instanceof SharedArrayBuffer, "SAB received"); + SimpleTest.finish(); + } + } + + node.port.postMessage({wasmModule}); + node.port.postMessage({sab: new SharedArrayBuffer(1024)}); + node.connect(audioContext.destination); + }); +} +</script> + +</body> +</html> diff --git a/dom/worklet/tests/test_audioWorklet_insecureContext.html b/dom/worklet/tests/test_audioWorklet_insecureContext.html new file mode 100644 index 0000000000..3cbb419ac3 --- /dev/null +++ b/dom/worklet/tests/test_audioWorklet_insecureContext.html @@ -0,0 +1,29 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for No AudioWorklet in insecure context</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript" src="common.js"></script> +</head> +<body> + +<script type="application/javascript"> + +function configureTest() { + return SpecialPowers.pushPrefEnv( + {"set": [["dom.audioworklet.enabled", true], + ["dom.worklet.enabled", true]]}); +} + +// This function is called into an iframe. +function runTestInIframe() { + ok(!window.isSecureContext, "Test should run in an insecure context"); + var audioContext = new AudioContext(); + ok(!("audioWorklet" in audioContext), + "AudioWorklet shouldn't be defined in AudioContext in a insecure context"); + SimpleTest.finish(); +} +</script> +</body> +</html> diff --git a/dom/worklet/tests/test_audioWorklet_options.html b/dom/worklet/tests/test_audioWorklet_options.html new file mode 100644 index 0000000000..df7a8b5649 --- /dev/null +++ b/dom/worklet/tests/test_audioWorklet_options.html @@ -0,0 +1,81 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for AudioWorklet + Options + WASM</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript" src="common.js"></script> +</head> +<body> +<script type="application/javascript"> + +function configureTest() { + return SpecialPowers.pushPrefEnv( + {"set": [["dom.audioworklet.enabled", true], + ["dom.worklet.enabled", true], + ["dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", true], + ["browser.tabs.remote.useCrossOriginOpenerPolicy", true], + ["browser.tabs.remote.useCrossOriginEmbedderPolicy", true], + ["javascript.options.shared_memory", true], + ]}); +} + +function create_wasmModule() { + return new Promise(resolve => { + info("Checking if we can play with WebAssembly..."); + + if (!SpecialPowers.Cu.getJSTestingFunctions().wasmIsSupported()) { + resolve(null); + return; + } + + ok(WebAssembly, "WebAssembly object should exist"); + ok(WebAssembly.compile, "WebAssembly.compile function should exist"); + + const wasmTextToBinary = SpecialPowers.unwrap(SpecialPowers.Cu.getJSTestingFunctions().wasmTextToBinary); + + /* + js -e ' + t = wasmTextToBinary(` + (module + (func $foo (result i32) (i32.const 42)) + (export "foo" (func $foo)) + ) + `); + print(t) + ' + */ + // eslint-disable-next-line + const fooModuleCode = new Uint8Array([0,97,115,109,1,0,0,0,1,5,1,96,0,1,127,3,2,1,0,7,7,1,3,102,111,111,0,0,10,6,1,4,0,65,42,11,0,13,4,110,97,109,101,1,6,1,0,3,102,111,111]); + + WebAssembly.compile(fooModuleCode).then(m => { + ok(m instanceof WebAssembly.Module, "The WasmModule has been compiled."); + resolve(m); + }, () => { + ok(false, "The compilation of the wasmModule failed."); + resolve(null); + }); + }); +} + +function runTestInIframe() { + let audioContext = new AudioContext(); + audioContext.audioWorklet.addModule("worklet_audioWorklet_options.js") + .then(() => create_wasmModule()) + .then(wasmModule => { + const node = new AudioWorkletNode(audioContext, 'options', { processorOptions: { + wasmModule, sab: new SharedArrayBuffer(1024), + }}); + node.port.onmessage = e => { + ok(e.data.wasmModule instanceof WebAssembly.Module, "WasmModule received"); + ok(e.data.sab instanceof SharedArrayBuffer, "SAB received"); + SimpleTest.finish(); + } + + node.connect(audioContext.destination); + }); +} + +</script> +</body> +</html> diff --git a/dom/worklet/tests/test_basic.html b/dom/worklet/tests/test_basic.html new file mode 100644 index 0000000000..b13cadd6d1 --- /dev/null +++ b/dom/worklet/tests/test_basic.html @@ -0,0 +1,66 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for Worklet</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript" src="common.js"></script> +</head> +<body> + +<script type="application/javascript"> + +function configureTest() { + return SpecialPowers.pushPrefEnv( + {"set": [["dom.audioworklet.enabled", true], + ["dom.worklet.enabled", true]]}); +} + +// This function is called into an iframe. +function runTestInIframe() { + var audioContext = new AudioContext(); + ok(!!audioContext.audioWorklet, "audioContext.audioWorklet exists"); + + // First loading + audioContext.audioWorklet.addModule("common.js") + .then(() => { + ok(true, "Import should load a resource."); + }) + + // Second loading - same file + .then(() => { + return audioContext.audioWorklet.addModule("common.js") + }) + .then(() => { + ok(true, "Import should load a resource."); + }) + + // 3rd loading - a network error + .then(() => { + return audioContext.audioWorklet.addModule("404.js"); + }) + .then(() => { + ok(false, "The loading should fail."); + }, () => { + ok(true, "The loading should fail."); + }) + + // 4th loading - a network error + .then(() => { + return audioContext.audioWorklet.addModule("404.js"); + }) + .then(() => { + ok(false, "The loading should fail."); + }, () => { + ok(true, "The loading should fail."); + }) + + // done + .then(() => { + SimpleTest.finish(); + }); +} + +</script> +</body> +</html> diff --git a/dom/worklet/tests/test_console.html b/dom/worklet/tests/test_console.html new file mode 100644 index 0000000000..c33b93001f --- /dev/null +++ b/dom/worklet/tests/test_console.html @@ -0,0 +1,54 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for Worklet - Console</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript" src="common.js"></script> +</head> +<body> + +<script type="application/javascript"> +const WORKLET_SCRIPT = "worklet_console.js"; + +function configureTest() { + const ConsoleAPIStorage = SpecialPowers.Cc[ + "@mozilla.org/consoleAPI-storage;1" + ].getService(SpecialPowers.Ci.nsIConsoleAPIStorage); + + function consoleListener() { + this.observe = this.observe.bind(this); + ConsoleAPIStorage.addLogEventListener(this.observe, SpecialPowers.wrap(document).nodePrincipal); + } + + consoleListener.prototype = { + observe(aSubject) { + var obj = aSubject.wrappedJSObject; + if (obj.arguments[0] == "Hello world from a worklet") { + ok(true, "Message received \\o/"); + is(obj.filename, + new URL(WORKLET_SCRIPT, document.baseURI).toString()); + + ConsoleAPIStorage.removeLogEventListener(this.observe); + SimpleTest.finish(); + return; + } + } + } + + var cl = new consoleListener(); + + return SpecialPowers.pushPrefEnv( + {"set": [["dom.audioworklet.enabled", true], + ["dom.worklet.enabled", true]]}); +} + +// This function is called into an iframe. +function runTestInIframe() { + var audioContext = new AudioContext(); + audioContext.audioWorklet.addModule(WORKLET_SCRIPT); +} + +</script> +</body> +</html> diff --git a/dom/worklet/tests/test_dump.html b/dom/worklet/tests/test_dump.html new file mode 100644 index 0000000000..f7885a1e21 --- /dev/null +++ b/dom/worklet/tests/test_dump.html @@ -0,0 +1,30 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for Worklet - Console</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript" src="common.js"></script> +</head> +<body> + +<script type="application/javascript"> + +function configureTest() { + return SpecialPowers.pushPrefEnv( + {"set": [["dom.audioworklet.enabled", true], + ["dom.worklet.enabled", true]]}); +} + +// This function is called into an iframe. +function runTestInIframe() { + var audioContext = new AudioContext(); + audioContext.audioWorklet.addModule("worklet_dump.js") + .then(() => { + ok(true, "All good!"); + SimpleTest.finish(); + }); +} +</script> +</body> +</html> diff --git a/dom/worklet/tests/test_dynamic_import.html b/dom/worklet/tests/test_dynamic_import.html new file mode 100644 index 0000000000..e0326b976c --- /dev/null +++ b/dom/worklet/tests/test_dynamic_import.html @@ -0,0 +1,54 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test import() should throw a TypeError for Worklets</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript" src="common.js"></script> +</head> +<body> + +<script type="application/javascript"> +const WORKLET_SCRIPT = "dynamic_import.js"; + +function configureTest() { + const ConsoleAPIStorage = SpecialPowers.Cc[ + "@mozilla.org/consoleAPI-storage;1" + ].getService(SpecialPowers.Ci.nsIConsoleAPIStorage); + + // We use console API to check if a TypeError has been thrown, as worklets + // have limitations to post the result back to the main document: + // Worklets have a different global, and they don't have postMessage() APIs, + // and static import SimpleTest.js in worklets also don't work. + function consoleListener() { + this.observe = this.observe.bind(this); + ConsoleAPIStorage.addLogEventListener(this.observe, SpecialPowers.wrap(document).nodePrincipal); + } + + consoleListener.prototype = { + observe(aSubject) { + var obj = aSubject.wrappedJSObject; + info("Got console message:" + obj.arguments[0]); + is(TypeError.name + ": Success", obj.arguments[0], "import() should throw"); + + ConsoleAPIStorage.removeLogEventListener(this.observe); + SimpleTest.finish(); + } + } + + var cl = new consoleListener(); + + return SpecialPowers.pushPrefEnv( + {"set": [["dom.audioworklet.enabled", true], + ["dom.worklet.enabled", true]]}); +} + +// This function is called into an iframe. +function runTestInIframe() { + var audioContext = new AudioContext(); + audioContext.audioWorklet.addModule(WORKLET_SCRIPT); +} + +</script> +</body> +</html> diff --git a/dom/worklet/tests/test_exception.html b/dom/worklet/tests/test_exception.html new file mode 100644 index 0000000000..598dc859f3 --- /dev/null +++ b/dom/worklet/tests/test_exception.html @@ -0,0 +1,73 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for Exception in Worklet script</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript" src="common.js"></script> +</head> +<body> + +<script type="application/javascript"> + +function configureTest() { + return SpecialPowers.pushPrefEnv( + {"set": [["dom.audioworklet.enabled", true], + ["dom.worklet.enabled", true]]}); +} + +// This function is called into an iframe. +function runTestInIframe() { + let error; + + // This loading should fail + var audioContext = new AudioContext(); + audioContext.audioWorklet.addModule("404.js") + .then(() => { + ok(false, "We should not be called!"); + }, () => { + ok(true, "The script thrown but we are still here."); + }) + + // This should throw from JS + .then(() => { + return audioContext.audioWorklet.addModule("worklet_exception.js") + }) + .then(() => { + ok(true, "The script threw but we are still here."); + }, () => { + ok(false, "We should not be called!"); + }) + + // invalid_specifier.mjs will throw a TypeError. + .then(() => { + return audioContext.audioWorklet.addModule("invalid_specifier.mjs") + }) + .then(() => { + ok(false, "We should not be called!"); + }, (e) => { + ok(true, "The script thrown but we are still here."); + ok(e instanceof TypeError, "The error should be a TypeError."); + error = e; + }) + + // import "invalid_specifier.mjs" again, this will reuse the response from the + // previous addModule("invalid_specifier.mjs") call. + .then(() => { + return audioContext.audioWorklet.addModule("invalid_specifier.mjs") + }) + .then(() => { + ok(false, "We should not be called!"); + }, (e) => { + ok(true, "The script thrown but we are still here."); + ok (e === error, "The TypeError object should be reused."); + }) + + .then(() => { + SimpleTest.finish(); + }); +} + +</script> +</body> +</html> diff --git a/dom/worklet/tests/test_fetch_failed.html b/dom/worklet/tests/test_fetch_failed.html new file mode 100644 index 0000000000..b5d316805f --- /dev/null +++ b/dom/worklet/tests/test_fetch_failed.html @@ -0,0 +1,39 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test fetch an child module script with an invalid uri for Worklet</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript" src="common.js"></script> +</head> +<body> + +<script type="application/javascript"> + +function configureTest() { + return SpecialPowers.pushPrefEnv( + {"set": [["dom.audioworklet.enabled", true], + ["dom.worklet.enabled", true]]}); +} + +// This function is called into an iframe. +function runTestInIframe() { + var audioContext = new AudioContext(); + ok(!!audioContext.audioWorklet, "audioContext.audioWorklet exists"); + + audioContext.audioWorklet.addModule("specifier_with_user.mjs") + .then(() => { + ok(false, "Error: load shouldn't succeed."); + }, () => { + ok(true, "OK: load should fail."); + }) + + // done + .then(() => { + SimpleTest.finish(); + }); +} + +</script> +</body> +</html> diff --git a/dom/worklet/tests/test_import_with_cache.html b/dom/worklet/tests/test_import_with_cache.html new file mode 100644 index 0000000000..de1744f9cc --- /dev/null +++ b/dom/worklet/tests/test_import_with_cache.html @@ -0,0 +1,49 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for Worklet</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript" src="common.js"></script> +</head> +<body> + +<script type="application/javascript"> + +function configureTest() { + return SpecialPowers.pushPrefEnv( + {"set": [["dom.audioworklet.enabled", true], + ["dom.worklet.enabled", true]]}); +} + +// This function is called into an iframe. +function runTestInIframe() { + var audioContext = new AudioContext(); + function loading() { + audioContext.audioWorklet.addModule("server_import_with_cache.sjs") + .then(() => { + ok(true, "Import should load a resource."); + }, () => { + ok(false, "Import should load a resource."); + }) + .then(() => { + done(); + }); + } + + var count = 0; + const MAX = 10; + + function done() { + if (++count == MAX) { + SimpleTest.finish(); + } + } + + for (var i = 0; i < MAX; ++i) { + loading(); + } +} +</script> +</body> +</html> diff --git a/dom/worklet/tests/test_paintWorklet.html b/dom/worklet/tests/test_paintWorklet.html new file mode 100644 index 0000000000..a02a2757fb --- /dev/null +++ b/dom/worklet/tests/test_paintWorklet.html @@ -0,0 +1,49 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for PaintWorklet</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript" src="common.js"></script> +</head> +<body> + +<script type="application/javascript"> + +function configureTest() { + const ConsoleAPIStorage = SpecialPowers.Cc[ + "@mozilla.org/consoleAPI-storage;1" + ].getService(SpecialPowers.Ci.nsIConsoleAPIStorage); + + function consoleListener() { + this.observe = this.observe.bind(this); + ConsoleAPIStorage.addLogEventListener(this.observe, SpecialPowers.wrap(document).nodePrincipal); + } + + consoleListener.prototype = { + observe(aSubject) { + var obj = aSubject.wrappedJSObject; + if (obj.arguments[0] == "So far so good") { + ok(true, "Message received \\o/"); + + ConsoleAPIStorage.removeLogEventListener(this.observe); + SimpleTest.finish(); + return; + } + } + } + + var cl = new consoleListener(); + + return SpecialPowers.pushPrefEnv( + {"set": [["dom.paintWorklet.enabled", true], + ["dom.worklet.enabled", true]]}); +} + +// This function is called into an iframe. +function runTestInIframe() { + paintWorklet.addModule("worklet_paintWorklet.js") +} +</script> +</body> +</html> diff --git a/dom/worklet/tests/test_promise.html b/dom/worklet/tests/test_promise.html new file mode 100644 index 0000000000..8ea71af9a6 --- /dev/null +++ b/dom/worklet/tests/test_promise.html @@ -0,0 +1,57 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for promise in worklet</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript" src="common.js"></script> +</head> +<body> + +<script type="application/javascript"> + +function configureTest() { + return SpecialPowers.pushPrefEnv( + {"set": [["dom.audioworklet.enabled", true], + ["dom.worklet.enabled", true]]}); +} + +function runTestInIframe() { + if (!SpecialPowers.Cu.getJSTestingFunctions().wasmIsSupported()) { + SimpleTest.finish(); + return; + } + + ok(window.isSecureContext, "Test should run in secure context"); + var audioContext = new AudioContext(); + ok(audioContext.audioWorklet instanceof AudioWorklet, + "AudioContext.audioWorklet should be an instance of AudioWorklet"); + audioContext.audioWorklet.addModule("worklet_promise.js") + .then(() => { + const node = new AudioWorkletNode(audioContext, 'promise'); + node.port.onmessage = e => { + ok(e.data instanceof WebAssembly.Module, "The WasmModule has been compiled into the worklet."); + SimpleTest.finish(); + } + + const wasmTextToBinary = SpecialPowers.unwrap(SpecialPowers.Cu.getJSTestingFunctions().wasmTextToBinary); + /* + js -e ' + t = wasmTextToBinary(` + (module + (func $foo (result i32) (i32.const 42)) + (export "foo" (func $foo)) + ) + `); + print(t) + ' + */ + // eslint-disable-next-line + const fooModuleCode = new Uint8Array([0,97,115,109,1,0,0,0,1,5,1,96,0,1,127,3,2,1,0,7,7,1,3,102,111,111,0,0,10,6,1,4,0,65,42,11,0,13,4,110,97,109,101,1,6,1,0,3,102,111,111]); + + node.port.postMessage(fooModuleCode); + }); +} +</script> +</body> +</html> diff --git a/dom/worklet/tests/worklet_audioWorklet.js b/dom/worklet/tests/worklet_audioWorklet.js new file mode 100644 index 0000000000..fa916d4359 --- /dev/null +++ b/dom/worklet/tests/worklet_audioWorklet.js @@ -0,0 +1,16 @@ +class DummyProcessWorkletProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + process() { + // Do nothing, output silence + } +} + +// We need to pass a valid AudioWorkletProcessor here, otherwise, it will fail, +// and the console.log won't be executed +registerProcessor("sure!", DummyProcessWorkletProcessor); +console.log( + globalThis instanceof AudioWorkletGlobalScope ? "So far so good" : "error" +); diff --git a/dom/worklet/tests/worklet_audioWorklet_WASM.js b/dom/worklet/tests/worklet_audioWorklet_WASM.js new file mode 100644 index 0000000000..1215b4c8d0 --- /dev/null +++ b/dom/worklet/tests/worklet_audioWorklet_WASM.js @@ -0,0 +1,16 @@ +class WasmProcessWorkletProcessor extends AudioWorkletProcessor { + constructor(...args) { + super(...args); + this.port.onmessage = e => { + // Let's send it back. + this.port.postMessage(e.data); + }; + } + + process(inputs, outputs, parameters) { + // Do nothing, output silence + return true; + } +} + +registerProcessor("wasm", WasmProcessWorkletProcessor); diff --git a/dom/worklet/tests/worklet_audioWorklet_options.js b/dom/worklet/tests/worklet_audioWorklet_options.js new file mode 100644 index 0000000000..eb7a704234 --- /dev/null +++ b/dom/worklet/tests/worklet_audioWorklet_options.js @@ -0,0 +1,12 @@ +class OptionsProcessWorkletProcessor extends AudioWorkletProcessor { + constructor(...args) { + super(...args); + this.port.postMessage(args[0].processorOptions); + } + + process(inputs, outputs, parameters) { + return true; + } +} + +registerProcessor("options", OptionsProcessWorkletProcessor); diff --git a/dom/worklet/tests/worklet_console.js b/dom/worklet/tests/worklet_console.js new file mode 100644 index 0000000000..557beb1af2 --- /dev/null +++ b/dom/worklet/tests/worklet_console.js @@ -0,0 +1 @@ +console.log("Hello world from a worklet"); diff --git a/dom/worklet/tests/worklet_dump.js b/dom/worklet/tests/worklet_dump.js new file mode 100644 index 0000000000..439d13f700 --- /dev/null +++ b/dom/worklet/tests/worklet_dump.js @@ -0,0 +1 @@ +dump("Hello world from a worklet"); diff --git a/dom/worklet/tests/worklet_exception.js b/dom/worklet/tests/worklet_exception.js new file mode 100644 index 0000000000..f3b473756e --- /dev/null +++ b/dom/worklet/tests/worklet_exception.js @@ -0,0 +1 @@ +foobar(); diff --git a/dom/worklet/tests/worklet_paintWorklet.js b/dom/worklet/tests/worklet_paintWorklet.js new file mode 100644 index 0000000000..7cf5256e51 --- /dev/null +++ b/dom/worklet/tests/worklet_paintWorklet.js @@ -0,0 +1,5 @@ +// This should work for real... at some point. +registerPaint("sure!", () => {}); +console.log( + globalThis instanceof PaintWorkletGlobalScope ? "So far so good" : "error" +); diff --git a/dom/worklet/tests/worklet_promise.js b/dom/worklet/tests/worklet_promise.js new file mode 100644 index 0000000000..8c593fd001 --- /dev/null +++ b/dom/worklet/tests/worklet_promise.js @@ -0,0 +1,22 @@ +class WasmProcessWorkletProcessor extends AudioWorkletProcessor { + constructor(...args) { + super(...args); + this.port.onmessage = e => { + WebAssembly.compile(e.data).then( + m => { + this.port.postMessage(m); + }, + () => { + this.port.postMessage("error"); + } + ); + }; + } + + process(inputs, outputs, parameters) { + // Do nothing, output silence + return true; + } +} + +registerProcessor("promise", WasmProcessWorkletProcessor); diff --git a/dom/worklet/tests/worklet_test_audioWorkletGlobalScopeRegisterProcessor.js b/dom/worklet/tests/worklet_test_audioWorkletGlobalScopeRegisterProcessor.js new file mode 100644 index 0000000000..cddb9524ec --- /dev/null +++ b/dom/worklet/tests/worklet_test_audioWorkletGlobalScopeRegisterProcessor.js @@ -0,0 +1,384 @@ +// Define several classes. +class EmptyWorkletProcessor extends AudioWorkletProcessor {} + +class NoProcessWorkletProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } +} + +class BadDescriptorsWorkletProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + process() { + // Do nothing, output silence + } + + static get parameterDescriptors() { + return "A string"; + } +} + +class GoodDescriptorsWorkletProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + process() { + // Do nothing, output silence + } + + static get parameterDescriptors() { + return [ + { + name: "myParam", + defaultValue: 0.707, + }, + ]; + } +} + +class DummyProcessWorkletProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + process() { + // Do nothing, output silence + } +} + +class DescriptorsNoNameWorkletProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + process() { + // Do nothing, output silence + } + + static get parameterDescriptors() { + return [ + { + defaultValue: 0.707, + }, + ]; + } +} + +class DescriptorsDefaultValueNotNumberWorkletProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + process() { + // Do nothing, output silence + } + + static get parameterDescriptors() { + return [ + { + name: "test", + defaultValue: "test", + }, + ]; + } +} + +class DescriptorsMinValueNotNumberWorkletProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + process() { + // Do nothing, output silence + } + + static get parameterDescriptors() { + return [ + { + name: "test", + minValue: "test", + }, + ]; + } +} + +class DescriptorsMaxValueNotNumberWorkletProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + process() { + // Do nothing, output silence + } + + static get parameterDescriptors() { + return [ + { + name: "test", + maxValue: "test", + }, + ]; + } +} + +class DescriptorsDuplicatedNameWorkletProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + process() { + // Do nothing, output silence + } + + static get parameterDescriptors() { + return [ + { + name: "test", + }, + { + name: "test", + }, + ]; + } +} + +class DescriptorsNotDictWorkletProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + process() { + // Do nothing, output silence + } + + static get parameterDescriptors() { + return [42]; + } +} + +class DescriptorsOutOfRangeMinWorkletProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + process() { + // Do nothing, output silence + } + + static get parameterDescriptors() { + return [ + { + name: "test", + defaultValue: 0, + minValue: 1, + maxValue: 2, + }, + ]; + } +} + +class DescriptorsOutOfRangeMaxWorkletProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + process() { + // Do nothing, output silence + } + + static get parameterDescriptors() { + return [ + { + name: "test", + defaultValue: 3, + minValue: 1, + maxValue: 2, + }, + ]; + } +} + +class DescriptorsBadRangeMaxWorkletProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + process() { + // Do nothing, output silence + } + + static get parameterDescriptors() { + return [ + { + name: "test", + defaultValue: 1.5, + minValue: 2, + maxValue: 1, + }, + ]; + } +} + +// Test not a constructor +// "TypeError: Argument 2 of AudioWorkletGlobalScope.registerProcessor is not a constructor." +try { + registerProcessor("sure!", () => {}); +} catch (e) { + console.log(e); +} + +// Test empty name +// "NotSupportedError: Argument 1 of AudioWorkletGlobalScope.registerProcessor should not be an empty string." +try { + registerProcessor("", EmptyWorkletProcessor); +} catch (e) { + console.log(e); +} + +// Test not an object +// "TypeError: Argument 2 of AudioWorkletGlobalScope.registerProcessor is not an object." +try { + registerProcessor("my-worklet-processor", ""); +} catch (e) { + console.log(e); +} + +// Test Empty class definition +registerProcessor("empty-worklet-processor", EmptyWorkletProcessor); + +// Test class with constructor but not process function +registerProcessor("no-worklet-processor", NoProcessWorkletProcessor); + +// Test class with parameterDescriptors being iterable, but the elements are not +// dictionaries. +// "TypeError: AudioWorkletGlobalScope.registerProcessor: Element 0 in parameterDescriptors can't be converted to a dictionary.", +try { + registerProcessor( + "bad-descriptors-worklet-processor", + BadDescriptorsWorkletProcessor + ); +} catch (e) { + console.log(e); +} + +// Test class with good parameterDescriptors +// No error expected here +registerProcessor( + "good-descriptors-worklet-processor", + GoodDescriptorsWorkletProcessor +); + +// Test class with constructor and process function +// No error expected here +registerProcessor("dummy-worklet-processor", DummyProcessWorkletProcessor); + +// Test class adding class with the same name twice +// "NotSupportedError: Operation is not supported: Argument 1 of AudioWorkletGlobalScope.registerProcessor is invalid: a class with the same name is already registered." +try { + registerProcessor("dummy-worklet-processor", DummyProcessWorkletProcessor); +} catch (e) { + console.log(e); +} + +// "name" is a mandatory field in descriptors +// "TypeError: Missing required 'name' member of AudioParamDescriptor." +try { + registerProcessor( + "descriptors-no-name-worklet-processor", + DescriptorsNoNameWorkletProcessor + ); +} catch (e) { + console.log(e); +} + +// "defaultValue" should be a number +// "TypeError: 'defaultValue' member of AudioParamDescriptor is not a finite floating-point value." +try { + registerProcessor( + "descriptors-default-value-not-number-worklet-processor", + DescriptorsDefaultValueNotNumberWorkletProcessor + ); +} catch (e) { + console.log(e); +} + +// "min" should be a number +// "TypeError: 'minValue' member of AudioParamDescriptor is not a finite floating-point value." +try { + registerProcessor( + "descriptors-min-value-not-number-worklet-processor", + DescriptorsMinValueNotNumberWorkletProcessor + ); +} catch (e) { + console.log(e); +} + +// "max" should be a number +// "TypeError: 'maxValue' member of AudioParamDescriptor is not a finite floating-point value." +try { + registerProcessor( + "descriptors-max-value-not-number-worklet-processor", + DescriptorsMaxValueNotNumberWorkletProcessor + ); +} catch (e) { + console.log(e); +} + +// Duplicated values are not allowed for "name" +// "NotSupportedError: Duplicated name \"test\" in parameterDescriptors" +try { + registerProcessor( + "descriptors-duplicated-name-worklet-processor", + DescriptorsDuplicatedNameWorkletProcessor + ); +} catch (e) { + console.log(e); +} + +// Descriptors' elements should be dictionnary +// "TypeError: Element 0 in parameterDescriptors can't be converted to a dictionary.", +try { + registerProcessor( + "descriptors-not-dict-worklet-processor", + DescriptorsNotDictWorkletProcessor + ); +} catch (e) { + console.log(e); +} + +// defaultValue value should be in range [minValue, maxValue]. defaultValue < minValue is not allowed +// "NotSupportedError: In parameterDescriptors, test defaultValue is out of the range defined by minValue and maxValue.", +try { + registerProcessor( + "descriptors-out-of-range-min-worklet-processor", + DescriptorsOutOfRangeMinWorkletProcessor + ); +} catch (e) { + console.log(e); +} + +// defaultValue value should be in range [minValue, maxValue]. defaultValue > maxValue is not allowed +// "NotSupportedError: In parameterDescriptors, test defaultValue is out of the range defined by minValue and maxValue.", +try { + registerProcessor( + "descriptors-out-of-range-max-worklet-processor", + DescriptorsOutOfRangeMaxWorkletProcessor + ); +} catch (e) { + console.log(e); +} + +// We should have minValue < maxValue to define a valid range +// "NotSupportedError: In parameterDescriptors, test minValue should be smaller than maxValue.", +try { + registerProcessor( + "descriptors-bad-range-max-worklet-processor", + DescriptorsBadRangeMaxWorkletProcessor + ); +} catch (e) { + console.log(e); +} |