From 0979fea92be2d1610b5d12a4a59e3a7510f2f7b7 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Tue, 23 Jan 2024 10:35:26 +0100 Subject: [PATCH] Add support for testing in more worker types (#3804) Co-authored-by: Liam Murphy <43807659+Liamolucko@users.noreply.github.com> --- .gitignore | 1 + CHANGELOG.md | 8 ++ .../src/bin/wasm-bindgen-test-runner/main.rs | 54 +++++++-- .../bin/wasm-bindgen-test-runner/server.rs | 104 +++++++++++++++--- crates/test/src/lib.rs | 26 ++++- crates/test/src/rt/detect.rs | 4 +- guide/src/wasm-bindgen-test/browsers.md | 21 ++-- tests/worker/dedicated.rs | 18 +++ tests/worker/service.rs | 18 +++ tests/worker/{main.rs => shared.rs} | 2 +- webdriver.json | 8 -- 11 files changed, 217 insertions(+), 47 deletions(-) create mode 100644 tests/worker/dedicated.rs create mode 100644 tests/worker/service.rs rename tests/worker/{main.rs => shared.rs} (84%) delete mode 100644 webdriver.json diff --git a/.gitignore b/.gitignore index 749720c7b..8cdf73b9e 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ yarn.lock /publish /publish.exe .vscode +webdriver.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 160e0822e..209bf11b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ ## Unreleased +### Added + +* Added support for running tests in shared and service workers with ``wasm_bindgen_test_configure!` `run_in_shared_worker` and `run_in_service_worker`. + [#3804](https://github.com/rustwasm/wasm-bindgen/pull/3804) + ### Changed * Stabilize `ClipboardEvent`. @@ -11,6 +16,9 @@ * Use immutable buffers in `SubtleCrypto` methods. [#3797](https://github.com/rustwasm/wasm-bindgen/pull/3797) +* Deprecate `wasm_bindgen_test_configure!`s `run_in_worker` in favor of `run_in_dedicated_worker`. + [#3804](https://github.com/rustwasm/wasm-bindgen/pull/3804) + ## [0.2.90](https://github.com/rustwasm/wasm-bindgen/compare/0.2.89...0.2.90) Released 2024-01-06 diff --git a/crates/cli/src/bin/wasm-bindgen-test-runner/main.rs b/crates/cli/src/bin/wasm-bindgen-test-runner/main.rs index 79382fa2e..fec449bb5 100644 --- a/crates/cli/src/bin/wasm-bindgen-test-runner/main.rs +++ b/crates/cli/src/bin/wasm-bindgen-test-runner/main.rs @@ -30,7 +30,29 @@ enum TestMode { Node, Deno, Browser { no_modules: bool }, - Worker { no_modules: bool }, + DedicatedWorker { no_modules: bool }, + SharedWorker { no_modules: bool }, + ServiceWorker { no_modules: bool }, +} + +impl TestMode { + fn is_worker(self) -> bool { + matches!( + self, + Self::DedicatedWorker { .. } | Self::SharedWorker { .. } | Self::ServiceWorker { .. } + ) + } + + fn no_modules(self) -> bool { + match self { + Self::Node => true, + Self::Deno => true, + Self::Browser { no_modules } + | Self::DedicatedWorker { no_modules } + | Self::SharedWorker { no_modules } + | Self::ServiceWorker { no_modules } => no_modules, + } + } } struct TmpDirDeleteGuard(PathBuf); @@ -120,7 +142,13 @@ fn main() -> anyhow::Result<()> { Some(section) if section.data.contains(&0x01) => TestMode::Browser { no_modules: std::env::var("WASM_BINDGEN_USE_NO_MODULE").is_ok(), }, - Some(section) if section.data.contains(&0x10) => TestMode::Worker { + Some(section) if section.data.contains(&0x02) => TestMode::DedicatedWorker { + no_modules: std::env::var("WASM_BINDGEN_USE_NO_MODULE").is_ok(), + }, + Some(section) if section.data.contains(&0x03) => TestMode::SharedWorker { + no_modules: std::env::var("WASM_BINDGEN_USE_NO_MODULE").is_ok(), + }, + Some(section) if section.data.contains(&0x04) => TestMode::ServiceWorker { no_modules: std::env::var("WASM_BINDGEN_USE_NO_MODULE").is_ok(), }, Some(_) => bail!("invalid __wasm_bingen_test_unstable value"), @@ -175,11 +203,15 @@ fn main() -> anyhow::Result<()> { match test_mode { TestMode::Node => b.nodejs(true)?, TestMode::Deno => b.deno(true)?, - TestMode::Browser { no_modules: false } | TestMode::Worker { no_modules: false } => { - b.web(true)? - } - TestMode::Browser { no_modules: true } | TestMode::Worker { no_modules: true } => { - b.no_modules(true)? + TestMode::Browser { .. } + | TestMode::DedicatedWorker { .. } + | TestMode::SharedWorker { .. } + | TestMode::ServiceWorker { .. } => { + if test_mode.no_modules() { + b.no_modules(true)? + } else { + b.web(true)? + } } }; @@ -200,7 +232,10 @@ fn main() -> anyhow::Result<()> { match test_mode { TestMode::Node => node::execute(module, &tmpdir, &args, &tests)?, TestMode::Deno => deno::execute(module, &tmpdir, &args, &tests)?, - TestMode::Browser { no_modules } | TestMode::Worker { no_modules } => { + TestMode::Browser { .. } + | TestMode::DedicatedWorker { .. } + | TestMode::SharedWorker { .. } + | TestMode::ServiceWorker { .. } => { let srv = server::spawn( &if headless { "127.0.0.1:0".parse().unwrap() @@ -214,8 +249,7 @@ fn main() -> anyhow::Result<()> { &tmpdir, &args, &tests, - no_modules, - matches!(test_mode, TestMode::Worker { no_modules: _ }), + test_mode, ) .context("failed to spawn server")?; let addr = srv.server_addr(); diff --git a/crates/cli/src/bin/wasm-bindgen-test-runner/server.rs b/crates/cli/src/bin/wasm-bindgen-test-runner/server.rs index 6cb0210c2..8c7b8ae40 100644 --- a/crates/cli/src/bin/wasm-bindgen-test-runner/server.rs +++ b/crates/cli/src/bin/wasm-bindgen-test-runner/server.rs @@ -7,19 +7,20 @@ use std::path::Path; use anyhow::{anyhow, Context, Error}; use rouille::{Request, Response, Server}; -pub fn spawn( +use crate::TestMode; + +pub(crate) fn spawn( addr: &SocketAddr, headless: bool, module: &'static str, tmpdir: &Path, args: &[OsString], tests: &[String], - no_module: bool, - worker: bool, + test_mode: TestMode, ) -> Result Response + Send + Sync>, Error> { let mut js_to_execute = String::new(); - let wbg_import_script = if no_module { + let wbg_import_script = if test_mode.no_modules() { String::from( r#" let Context = wasm_bindgen.WasmBindgenTestContext; @@ -48,8 +49,8 @@ pub fn spawn( ) }; - if worker { - let mut worker_script = if no_module { + if test_mode.is_worker() { + let mut worker_script = if test_mode.no_modules() { format!(r#"importScripts("{0}.js");"#, module) } else { String::new() @@ -57,6 +58,25 @@ pub fn spawn( worker_script.push_str(&wbg_import_script); + match test_mode { + TestMode::DedicatedWorker { .. } => worker_script.push_str("const port = self\n"), + TestMode::SharedWorker { .. } => worker_script.push_str( + r#" + addEventListener('connect', (e) => { + const port = e.ports[0] + "#, + ), + TestMode::ServiceWorker { .. } => worker_script.push_str( + r#" + addEventListener('install', (e) => skipWaiting()); + addEventListener('activate', (e) => e.waitUntil(clients.claim())); + addEventListener('message', (e) => { + const port = e.ports[0] + "#, + ), + _ => unreachable!(), + } + worker_script.push_str(&format!( r#" const wrap = method => {{ @@ -65,7 +85,7 @@ pub fn spawn( if (self[on_method]) {{ self[on_method](args); }} - postMessage(["__wbgtest_" + method, args]); + port.postMessage(["__wbgtest_" + method, args]); }}; }}; @@ -73,7 +93,7 @@ pub fn spawn( self.__wbg_test_output = ""; self.__wbg_test_output_writeln = function (line) {{ self.__wbg_test_output += line + "\n"; - postMessage(["__wbgtest_output", self.__wbg_test_output]); + port.postMessage(["__wbgtest_output", self.__wbg_test_output]); }} wrap("debug"); @@ -97,7 +117,7 @@ pub fn spawn( await cx.run(tests.map(s => wasm[s])); }} - onmessage = function(e) {{ + port.onmessage = function(e) {{ let tests = e.data; run_in_worker(tests); }} @@ -105,7 +125,19 @@ pub fn spawn( module, args, )); - let worker_js_path = tmpdir.join("worker.js"); + if matches!( + test_mode, + TestMode::SharedWorker { .. } | TestMode::ServiceWorker { .. } + ) { + worker_script.push_str("})"); + } + + let name = if matches!(test_mode, TestMode::ServiceWorker { .. }) { + "service.js" + } else { + "worker.js" + }; + let worker_js_path = tmpdir.join(name); fs::write(worker_js_path, worker_script).context("failed to write JS file")?; js_to_execute.push_str(&format!( @@ -114,9 +146,9 @@ pub fn spawn( // status text as at this point we should be asynchronously fetching the // wasm module. document.getElementById('output').textContent = "Loading wasm module..."; - const worker = new Worker("worker.js", {{type: "{}"}}); + {} - worker.addEventListener("message", function(e) {{ + port.addEventListener("message", function(e) {{ // Checking the whether the message is from wasm_bindgen_test if( e.data && @@ -141,12 +173,54 @@ pub fn spawn( }}); async function main(test) {{ - worker.postMessage(test) + port.postMessage(test) }} const tests = []; "#, - if no_module { "classic" } else { "module" } + { + let module = if test_mode.no_modules() { + "classic" + } else { + "module" + }; + + match test_mode { + TestMode::DedicatedWorker { .. } => { + format!("const port = new Worker('worker.js', {{type: '{module}'}});\n") + } + TestMode::SharedWorker { .. } => { + format!( + r#" + const worker = new SharedWorker("worker.js?random=" + crypto.randomUUID(), {{type: "{module}"}}); + const port = worker.port; + port.start(); + "# + ) + } + TestMode::ServiceWorker { .. } => { + format!( + r#" + const url = "service.js?random=" + crypto.randomUUID(); + await navigator.serviceWorker.register(url, {{type: "{module}"}}); + await new Promise((resolve) => {{ + navigator.serviceWorker.addEventListener('controllerchange', () => {{ + if (navigator.serviceWorker.controller.scriptURL != location.href + url) {{ + throw "`wasm-bindgen-test-runner` does not support running multiple service worker tests at the same time" + }} + resolve(); + }}); + }}); + const channel = new MessageChannel(); + navigator.serviceWorker.controller.postMessage(undefined, [channel.port2]); + const port = channel.port1; + port.start(); + "# + ) + } + _ => unreachable!(), + } + } )); } else { js_to_execute.push_str(&wbg_import_script); @@ -203,7 +277,7 @@ pub fn spawn( } else { include_str!("index.html") }; - let s = if no_module { + let s = if !test_mode.is_worker() && test_mode.no_modules() { s.replace( "", &format!( diff --git a/crates/test/src/lib.rs b/crates/test/src/lib.rs index 72d3fc9df..6b4174b1d 100644 --- a/crates/test/src/lib.rs +++ b/crates/test/src/lib.rs @@ -35,7 +35,11 @@ macro_rules! console_log { /// /// * `run_in_browser` - requires that this test is run in a browser rather than /// node.js, which is the default for executing tests. -/// * `run_in_worker` - requires that this test is run in a web worker rather than +/// * `run_in_dedicated_worker` - requires that this test is run in a web worker rather than +/// node.js, which is the default for executing tests. +/// * `run_in_shared_worker` - requires that this test is run in a shared worker rather than +/// node.js, which is the default for executing tests. +/// * `run_in_service_worker` - requires that this test is run in a service worker rather than /// node.js, which is the default for executing tests. /// /// This macro may be invoked at most one time per test suite (an entire binary @@ -51,7 +55,25 @@ macro_rules! wasm_bindgen_test_configure { (run_in_worker $($others:tt)*) => ( #[link_section = "__wasm_bindgen_test_unstable"] #[cfg(target_arch = "wasm32")] - pub static __WBG_TEST_RUN_IN_WORKER: [u8; 1] = [0x10]; + pub static __WBG_TEST_RUN_IN_DEDICATED_WORKER: [u8; 1] = [0x02]; + $crate::wasm_bindgen_test_configure!($($others)*); + ); + (run_in_dedicated_worker $($others:tt)*) => ( + #[link_section = "__wasm_bindgen_test_unstable"] + #[cfg(target_arch = "wasm32")] + pub static __WBG_TEST_RUN_IN_DEDICATED_WORKER: [u8; 1] = [0x02]; + $crate::wasm_bindgen_test_configure!($($others)*); + ); + (run_in_shared_worker $($others:tt)*) => ( + #[link_section = "__wasm_bindgen_test_unstable"] + #[cfg(target_arch = "wasm32")] + pub static __WBG_TEST_RUN_IN_SHARED_WORKER: [u8; 1] = [0x03]; + $crate::wasm_bindgen_test_configure!($($others)*); + ); + (run_in_service_worker $($others:tt)*) => ( + #[link_section = "__wasm_bindgen_test_unstable"] + #[cfg(target_arch = "wasm32")] + pub static __WBG_TEST_RUN_IN_SERVICE_WORKER: [u8; 1] = [0x04]; $crate::wasm_bindgen_test_configure!($($others)*); ); () => () diff --git a/crates/test/src/rt/detect.rs b/crates/test/src/rt/detect.rs index 81cb1c704..235b14c67 100644 --- a/crates/test/src/rt/detect.rs +++ b/crates/test/src/rt/detect.rs @@ -24,7 +24,9 @@ pub fn detect() -> Runtime { // only be true in browsers. match js_sys::global().unchecked_into::().self_() { Some(scope) => match scope.constructor().name().as_str() { - "DedicatedWorkerGlobalScope" | "SharedWorkerGlobalScope" => Runtime::Worker, + "DedicatedWorkerGlobalScope" + | "SharedWorkerGlobalScope" + | "ServiceWorkerGlobalScope" => Runtime::Worker, _ => Runtime::Browser, }, None => Runtime::Node, diff --git a/guide/src/wasm-bindgen-test/browsers.md b/guide/src/wasm-bindgen-test/browsers.md index 1df038e32..5477e6b4d 100644 --- a/guide/src/wasm-bindgen-test/browsers.md +++ b/guide/src/wasm-bindgen-test/browsers.md @@ -17,7 +17,12 @@ snippet. ```rust use wasm_bindgen_test::wasm_bindgen_test_configure; -wasm_bindgen_test_configure!(run_in_worker); +// Run in dedicated worker. +wasm_bindgen_test_configure!(run_in_dedicated_worker); +// Or run in shared worker. +wasm_bindgen_test_configure!(run_in_shared_worker); +// Or run in service worker. +wasm_bindgen_test_configure!(run_in_service_worker); ``` Note that although a particular test crate must target either headless browsers @@ -27,9 +32,11 @@ project by using multiple test crates. For example: ``` $MY_CRATE/ `-- tests - |-- node.rs # The tests in this suite use the default Node.js. - |-- worker.rs # The tests in this suite are configured for workers. - `-- web.rs # The tests in this suite are configured for browsers. + |-- node.rs # The tests in this suite use the default Node.js. + |-- dedicated_worker.rs # The tests in this suite are configured for dedicated workers. + |-- shared_worker.rs # The tests in this suite are configured for shared workers. + |-- service_worker.rs # The tests in this suite are configured for service workers. + `-- web.rs # The tests in this suite are configured for browsers. ``` ## Configuring Which Browser is Used @@ -86,12 +93,6 @@ Full list supported capabilities can be found: Note that the `headless` argument is always enabled for both browsers. -You have to enable the special preference `dom.workers.modules.enabled` for -firefox when running the tests in Web Workers without using -`WASM_BINDGEN_USE_NO_MODULE` variable. Because firefox supported -ECMAScript modules in last release (2023-03-14) behind a special -preference. - ### Debugging Headless Browser Tests Omitting the `--headless` flag will disable headless mode, and allow you to diff --git a/tests/worker/dedicated.rs b/tests/worker/dedicated.rs new file mode 100644 index 000000000..f3038db88 --- /dev/null +++ b/tests/worker/dedicated.rs @@ -0,0 +1,18 @@ +#![cfg(target_arch = "wasm32")] + +extern crate js_sys; +extern crate wasm_bindgen; +extern crate wasm_bindgen_test; + +use wasm_bindgen::prelude::*; +use wasm_bindgen_test::wasm_bindgen_test_configure; + +wasm_bindgen_test_configure!(run_in_dedicated_worker); + +pub mod modules; + +// should not be executed +#[wasm_bindgen(start)] +fn start() { + panic!(); +} diff --git a/tests/worker/service.rs b/tests/worker/service.rs new file mode 100644 index 000000000..6ae7de338 --- /dev/null +++ b/tests/worker/service.rs @@ -0,0 +1,18 @@ +#![cfg(target_arch = "wasm32")] + +extern crate js_sys; +extern crate wasm_bindgen; +extern crate wasm_bindgen_test; + +use wasm_bindgen::prelude::*; +use wasm_bindgen_test::wasm_bindgen_test_configure; + +wasm_bindgen_test_configure!(run_in_service_worker); + +pub mod modules; + +// should not be executed +#[wasm_bindgen(start)] +fn start() { + panic!(); +} diff --git a/tests/worker/main.rs b/tests/worker/shared.rs similarity index 84% rename from tests/worker/main.rs rename to tests/worker/shared.rs index 16f358c08..b13c80208 100644 --- a/tests/worker/main.rs +++ b/tests/worker/shared.rs @@ -7,7 +7,7 @@ extern crate wasm_bindgen_test; use wasm_bindgen::prelude::*; use wasm_bindgen_test::wasm_bindgen_test_configure; -wasm_bindgen_test_configure!(run_in_worker); +wasm_bindgen_test_configure!(run_in_shared_worker); pub mod modules; diff --git a/webdriver.json b/webdriver.json deleted file mode 100644 index 84740385c..000000000 --- a/webdriver.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "moz:firefoxOptions": { - "prefs": { - "dom.workers.modules.enabled": true - }, - "args": [] - } -}