diff --git a/cli/main.rs b/cli/main.rs index e3da6ae0f9..ffed7d37a4 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -109,6 +109,7 @@ fn create_web_worker_callback( .log_level .map_or(false, |l| l == log::Level::Debug), unstable: program_state.flags.unstable, + enable_testing_features: program_state.flags.enable_testing_features, unsafely_ignore_certificate_errors: program_state .flags .unsafely_ignore_certificate_errors @@ -120,6 +121,7 @@ fn create_web_worker_callback( create_web_worker_cb, js_error_create_fn: Some(js_error_create_fn), use_deno_namespace: args.use_deno_namespace, + worker_type: args.worker_type, maybe_inspector_server, runtime_version: version::deno(), ts_version: version::TYPESCRIPT.to_string(), @@ -193,6 +195,7 @@ pub fn create_main_worker( .log_level .map_or(false, |l| l == log::Level::Debug), unstable: program_state.flags.unstable, + enable_testing_features: program_state.flags.enable_testing_features, unsafely_ignore_certificate_errors: program_state .flags .unsafely_ignore_certificate_errors diff --git a/cli/standalone.rs b/cli/standalone.rs index 013e2e60fd..800dca4cbe 100644 --- a/cli/standalone.rs +++ b/cli/standalone.rs @@ -253,6 +253,7 @@ pub async fn run( debug_flag: metadata.log_level.map_or(false, |l| l == log::Level::Debug), user_agent: version::get_user_agent(), unstable: metadata.unstable, + enable_testing_features: false, unsafely_ignore_certificate_errors: metadata .unsafely_ignore_certificate_errors, root_cert_store: Some(root_cert_store), diff --git a/ext/fetch/lib.rs b/ext/fetch/lib.rs index eb2fed6831..8f49d88595 100644 --- a/ext/fetch/lib.rs +++ b/ext/fetch/lib.rs @@ -52,7 +52,9 @@ use tokio::sync::mpsc; use tokio_stream::wrappers::ReceiverStream; use tokio_util::io::StreamReader; -pub use reqwest; // Re-export reqwest +// Re-export reqwest and data_url +pub use data_url; +pub use reqwest; pub fn init( user_agent: String, diff --git a/runtime/examples/hello_runtime.rs b/runtime/examples/hello_runtime.rs index 776dc23c3d..9ac1d0a273 100644 --- a/runtime/examples/hello_runtime.rs +++ b/runtime/examples/hello_runtime.rs @@ -27,6 +27,7 @@ async fn main() -> Result<(), AnyError> { args: vec![], debug_flag: false, unstable: false, + enable_testing_features: false, unsafely_ignore_certificate_errors: None, root_cert_store: None, user_agent: "hello_runtime".to_string(), diff --git a/runtime/js/11_workers.js b/runtime/js/11_workers.js index b5a8a9d0c9..2f94131199 100644 --- a/runtime/js/11_workers.js +++ b/runtime/js/11_workers.js @@ -7,7 +7,6 @@ ArrayIsArray, ArrayPrototypeMap, Error, - Uint8Array, StringPrototypeStartsWith, String, SymbolIterator, @@ -28,6 +27,7 @@ useDenoNamespace, permissions, name, + workerType, ) { return core.opSync("op_create_worker", { hasSourceCode, @@ -36,6 +36,7 @@ sourceCode, specifier, useDenoNamespace, + workerType, }); } @@ -183,20 +184,12 @@ } } - if (type !== "module") { - throw new Error( - 'Not yet implemented: only "module" type workers are supported', - ); - } - - this.#name = name; - const hasSourceCode = false; - const sourceCode = core.decode(new Uint8Array()); + const workerType = webidl.converters["WorkerType"](type); if ( StringPrototypeStartsWith(specifier, "./") || StringPrototypeStartsWith(specifier, "../") || - StringPrototypeStartsWith(specifier, "/") || type == "classic" + StringPrototypeStartsWith(specifier, "/") || workerType === "classic" ) { const baseUrl = getLocationHref(); if (baseUrl != null) { @@ -204,6 +197,16 @@ } } + this.#name = name; + let hasSourceCode, sourceCode; + if (workerType === "classic") { + hasSourceCode = true; + sourceCode = `importScripts("#");`; + } else { + hasSourceCode = false; + sourceCode = ""; + } + const id = createWorker( specifier, hasSourceCode, @@ -213,6 +216,7 @@ ? null : parsePermissions(workerDenoAttributes.permissions), options?.name, + workerType, ); this.#id = id; this.#pollControl(); @@ -344,6 +348,11 @@ defineEventHandler(Worker.prototype, "message"); defineEventHandler(Worker.prototype, "messageerror"); + webidl.converters["WorkerType"] = webidl.createEnumConverter("WorkerType", [ + "classic", + "module", + ]); + window.__bootstrap.worker = { parsePermissions, Worker, diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js index 6d5599e71a..b1f7d1473b 100644 --- a/runtime/js/99_main.js +++ b/runtime/js/99_main.js @@ -8,6 +8,7 @@ delete Object.prototype.__proto__; ((window) => { const core = Deno.core; const { + ArrayPrototypeMap, Error, FunctionPrototypeCall, FunctionPrototypeBind, @@ -164,6 +165,44 @@ delete Object.prototype.__proto__; } } + let loadedMainWorkerScript = false; + + function importScripts(...urls) { + if (core.opSync("op_worker_get_type") === "module") { + throw new TypeError("Can't import scripts in a module worker."); + } + + const baseUrl = location.getLocationHref(); + const parsedUrls = ArrayPrototypeMap(urls, (scriptUrl) => { + try { + return new url.URL(scriptUrl, baseUrl ?? undefined).href; + } catch { + throw new domException.DOMException( + "Failed to parse URL.", + "SyntaxError", + ); + } + }); + + // A classic worker's main script has looser MIME type checks than any + // imported scripts, so we use `loadedMainWorkerScript` to distinguish them. + // TODO(andreubotella) Refactor worker creation so the main script isn't + // loaded with `importScripts()`. + const scripts = core.opSync( + "op_worker_sync_fetch", + parsedUrls, + !loadedMainWorkerScript, + ); + loadedMainWorkerScript = true; + + for (const { url, script } of scripts) { + const err = core.evalContext(script, url)[1]; + if (err !== null) { + throw err.thrown; + } + } + } + function opMainModule() { return core.opSync("op_main_module"); } @@ -597,6 +636,13 @@ delete Object.prototype.__proto__; } ObjectDefineProperties(globalThis, workerRuntimeGlobalProperties); ObjectDefineProperties(globalThis, { name: util.readOnly(name) }); + if (runtimeOptions.enableTestingFeaturesFlag) { + ObjectDefineProperty( + globalThis, + "importScripts", + util.writable(importScripts), + ); + } ObjectSetPrototypeOf(globalThis, DedicatedWorkerGlobalScope.prototype); const consoleFromDeno = globalThis.console; diff --git a/runtime/ops/mod.rs b/runtime/ops/mod.rs index e08ddd1c05..ee2bc0a1eb 100644 --- a/runtime/ops/mod.rs +++ b/runtime/ops/mod.rs @@ -84,3 +84,5 @@ pub fn check_unstable2(state: &Rc>, api_name: &str) { let state = state.borrow(); state.borrow::().check_unstable(api_name) } + +pub struct TestingFeaturesEnabled(pub bool); diff --git a/runtime/ops/web_worker.rs b/runtime/ops/web_worker.rs index 026e38157e..8439e43844 100644 --- a/runtime/ops/web_worker.rs +++ b/runtime/ops/web_worker.rs @@ -1,6 +1,9 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. +mod sync_fetch; + use crate::web_worker::WebWorkerInternalHandle; +use crate::web_worker::WebWorkerType; use crate::web_worker::WorkerControlEvent; use deno_core::error::generic_error; use deno_core::error::AnyError; @@ -13,6 +16,8 @@ use deno_web::JsMessageData; use std::cell::RefCell; use std::rc::Rc; +use self::sync_fetch::op_worker_sync_fetch; + pub fn init() -> Extension { Extension::builder() .ops(vec![ @@ -25,6 +30,8 @@ pub fn init() -> Extension { "op_worker_unhandled_error", op_sync(op_worker_unhandled_error), ), + ("op_worker_get_type", op_sync(op_worker_get_type)), + ("op_worker_sync_fetch", op_sync(op_worker_sync_fetch)), ]) .build() } @@ -79,3 +86,12 @@ fn op_worker_unhandled_error( .expect("Failed to propagate error event to parent worker"); Ok(()) } + +fn op_worker_get_type( + state: &mut OpState, + _: (), + _: (), +) -> Result { + let handle = state.borrow::().clone(); + Ok(handle.worker_type) +} diff --git a/runtime/ops/web_worker/sync_fetch.rs b/runtime/ops/web_worker/sync_fetch.rs new file mode 100644 index 0000000000..6ad6edba77 --- /dev/null +++ b/runtime/ops/web_worker/sync_fetch.rs @@ -0,0 +1,155 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +use crate::web_worker::WebWorkerInternalHandle; +use crate::web_worker::WebWorkerType; +use deno_core::error::type_error; +use deno_core::error::AnyError; +use deno_core::url::Url; +use deno_core::OpState; +use deno_fetch::data_url::DataUrl; +use deno_fetch::reqwest; +use deno_web::BlobStore; +use deno_websocket::DomExceptionNetworkError; +use hyper::body::Bytes; +use serde::{Deserialize, Serialize}; +use tokio::task::JoinHandle; + +// TODO(andreubotella) Properly parse the MIME type +fn mime_type_essence(mime_type: &str) -> String { + let essence = match mime_type.split_once(";") { + Some((essence, _)) => essence, + None => mime_type, + }; + essence.trim().to_ascii_lowercase() +} + +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SyncFetchScript { + url: String, + script: String, +} + +pub fn op_worker_sync_fetch( + state: &mut OpState, + scripts: Vec, + mut loose_mime_checks: bool, +) -> Result, AnyError> { + let handle = state.borrow::().clone(); + assert_eq!(handle.worker_type, WebWorkerType::Classic); + + // TODO(andreubotella) Make the runtime into a resource and add a new op to + // block on each request, so a script can run while the next loads. + + let runtime = tokio::runtime::Builder::new_current_thread() + .enable_io() + .enable_time() + .build() + .unwrap(); + + // TODO(andreubotella) It's not good to throw an exception related to blob + // URLs when none of the script URLs use the blob scheme. + // Also, in which contexts are blob URLs not supported? + let blob_store = state.try_borrow::().ok_or_else(|| { + type_error("Blob URLs are not supported in this context.") + })?; + + let handles: Vec<_> = scripts + .into_iter() + .map(|script| -> JoinHandle> { + let blob_store = blob_store.clone(); + runtime.spawn(async move { + let script_url = + Url::parse(&script).map_err(|_| type_error("Invalid script URL"))?; + + let (body, mime_type, res_url) = match script_url.scheme() { + "http" | "https" => { + let resp = reqwest::get(script_url).await?.error_for_status()?; + + let res_url = resp.url().to_string(); + + // TODO(andreubotella) Properly run fetch's "extract a MIME type". + let mime_type = resp + .headers() + .get("Content-Type") + .and_then(|v| v.to_str().ok()) + .map(mime_type_essence); + + // Always check the MIME type with HTTP(S). + loose_mime_checks = false; + + let body = resp.bytes().await?; + + (body, mime_type, res_url) + } + "data" => { + let data_url = DataUrl::process(&script) + .map_err(|e| type_error(format!("{:?}", e)))?; + + let mime_type = { + let mime = data_url.mime_type(); + format!("{}/{}", mime.type_, mime.subtype) + }; + + let (body, _) = data_url + .decode_to_vec() + .map_err(|e| type_error(format!("{:?}", e)))?; + + (Bytes::from(body), Some(mime_type), script) + } + "blob" => { + let blob = blob_store + .get_object_url(script_url)? + .ok_or_else(|| type_error("Blob for the given URL not found."))?; + + let mime_type = mime_type_essence(&blob.media_type); + + let body = blob.read_all().await?; + + (Bytes::from(body), Some(mime_type), script) + } + _ => { + return Err(type_error(format!( + "Classic scripts with scheme {}: are not supported in workers.", + script_url.scheme() + ))) + } + }; + + if !loose_mime_checks { + // TODO(andreubotella) Check properly for a Javascript MIME type. + match mime_type.as_deref() { + Some("application/javascript" | "text/javascript") => {} + Some(mime_type) => { + return Err( + DomExceptionNetworkError { + msg: format!("Invalid MIME type {:?}.", mime_type), + } + .into(), + ) + } + None => { + return Err( + DomExceptionNetworkError::new("Missing MIME type.").into(), + ) + } + } + } + + let (text, _) = encoding_rs::UTF_8.decode_with_bom_removal(&body); + + Ok(SyncFetchScript { + url: res_url, + script: text.into_owned(), + }) + }) + }) + .collect(); + + let mut ret = Vec::with_capacity(handles.len()); + for handle in handles { + let script = runtime.block_on(handle)??; + ret.push(script); + } + Ok(ret) +} diff --git a/runtime/ops/worker_host.rs b/runtime/ops/worker_host.rs index 5315ff5c74..d80a39502e 100644 --- a/runtime/ops/worker_host.rs +++ b/runtime/ops/worker_host.rs @@ -1,5 +1,6 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. +use crate::ops::TestingFeaturesEnabled; use crate::permissions::resolve_read_allowlist; use crate::permissions::resolve_write_allowlist; use crate::permissions::EnvDescriptor; @@ -16,6 +17,7 @@ use crate::web_worker::run_web_worker; use crate::web_worker::SendableWebWorkerHandle; use crate::web_worker::WebWorker; use crate::web_worker::WebWorkerHandle; +use crate::web_worker::WebWorkerType; use crate::web_worker::WorkerControlEvent; use crate::web_worker::WorkerId; use deno_core::error::custom_error; @@ -48,6 +50,7 @@ pub struct CreateWebWorkerArgs { pub permissions: Permissions, pub main_module: ModuleSpecifier, pub use_deno_namespace: bool, + pub worker_type: WebWorkerType, } pub type CreateWebWorkerCb = dyn Fn(CreateWebWorkerArgs) -> (WebWorker, SendableWebWorkerHandle) @@ -460,6 +463,7 @@ pub struct CreateWorkerArgs { source_code: String, specifier: String, use_deno_namespace: bool, + worker_type: WebWorkerType, } /// Create worker as the host @@ -479,6 +483,17 @@ fn op_create_worker( if use_deno_namespace { super::check_unstable(state, "Worker.deno.namespace"); } + let worker_type = args.worker_type; + if let WebWorkerType::Classic = worker_type { + if let TestingFeaturesEnabled(false) = state.borrow() { + return Err( + deno_webstorage::DomExceptionNotSupportedError::new( + "Classic workers are not supported.", + ) + .into(), + ); + } + } let parent_permissions = state.borrow::().clone(); let worker_permissions = if let Some(permissions) = args.permissions { super::check_unstable(state, "Worker.deno.permissions"); @@ -518,6 +533,7 @@ fn op_create_worker( permissions: worker_permissions, main_module: module_specifier.clone(), use_deno_namespace, + worker_type, }); // Send thread safe handle from newly created worker to host thread diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs index 495fedb81a..240d79d1f1 100644 --- a/runtime/web_worker.rs +++ b/runtime/web_worker.rs @@ -44,6 +44,13 @@ use std::sync::Arc; use std::task::Context; use std::task::Poll; +#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum WebWorkerType { + Classic, + Module, +} + #[derive( Debug, Default, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, )] @@ -110,6 +117,7 @@ pub struct WebWorkerInternalHandle { pub cancel: Rc, terminated: Arc, isolate_handle: v8::IsolateHandle, + pub worker_type: WebWorkerType, } impl WebWorkerInternalHandle { @@ -215,6 +223,7 @@ impl WebWorkerHandle { fn create_handles( isolate_handle: v8::IsolateHandle, + worker_type: WebWorkerType, ) -> (WebWorkerInternalHandle, SendableWebWorkerHandle) { let (parent_port, worker_port) = create_entangled_message_port(); let (ctrl_tx, ctrl_rx) = mpsc::channel::(1); @@ -225,6 +234,7 @@ fn create_handles( terminated: terminated.clone(), isolate_handle: isolate_handle.clone(), cancel: CancelHandle::new_rc(), + worker_type, }; let external_handle = SendableWebWorkerHandle { receiver: ctrl_rx, @@ -245,6 +255,7 @@ pub struct WebWorker { pub name: String, internal_handle: WebWorkerInternalHandle, pub use_deno_namespace: bool, + pub worker_type: WebWorkerType, pub main_module: ModuleSpecifier, } @@ -253,6 +264,7 @@ pub struct WebWorkerOptions { pub args: Vec, pub debug_flag: bool, pub unstable: bool, + pub enable_testing_features: bool, pub unsafely_ignore_certificate_errors: Option>, pub root_cert_store: Option, pub user_agent: String, @@ -261,6 +273,7 @@ pub struct WebWorkerOptions { pub create_web_worker_cb: Arc, pub js_error_create_fn: Option>, pub use_deno_namespace: bool, + pub worker_type: WebWorkerType, pub maybe_inspector_server: Option>, pub apply_source_maps: bool, /// Sets `Deno.version.deno` in JS runtime. @@ -286,10 +299,12 @@ impl WebWorker { ) -> (Self, SendableWebWorkerHandle) { // Permissions: many ops depend on this let unstable = options.unstable; + let enable_testing_features = options.enable_testing_features; let perm_ext = Extension::builder() .state(move |state| { state.put::(permissions.clone()); state.put(ops::UnstableChecker { unstable }); + state.put(ops::TestingFeaturesEnabled(enable_testing_features)); Ok(()) }) .build(); @@ -386,7 +401,8 @@ impl WebWorker { let (internal_handle, external_handle) = { let handle = js_runtime.v8_isolate().thread_safe_handle(); - let (internal_handle, external_handle) = create_handles(handle); + let (internal_handle, external_handle) = + create_handles(handle, options.worker_type); let op_state = js_runtime.op_state(); let mut op_state = op_state.borrow_mut(); op_state.put(internal_handle.clone()); @@ -400,6 +416,7 @@ impl WebWorker { name, internal_handle, use_deno_namespace: options.use_deno_namespace, + worker_type: options.worker_type, main_module, }, external_handle, @@ -418,6 +435,7 @@ impl WebWorker { "target": env!("TARGET"), "tsVersion": options.ts_version, "unstableFlag": options.unstable, + "enableTestingFeaturesFlag": options.enable_testing_features, "v8Version": deno_core::v8_version(), "location": self.main_module, "cpuCount": options.cpu_count, diff --git a/runtime/worker.rs b/runtime/worker.rs index b200ef08e0..b1096024b8 100644 --- a/runtime/worker.rs +++ b/runtime/worker.rs @@ -50,6 +50,7 @@ pub struct WorkerOptions { pub args: Vec, pub debug_flag: bool, pub unstable: bool, + pub enable_testing_features: bool, pub unsafely_ignore_certificate_errors: Option>, pub root_cert_store: Option, pub user_agent: String, @@ -84,10 +85,12 @@ impl MainWorker { ) -> Self { // Permissions: many ops depend on this let unstable = options.unstable; + let enable_testing_features = options.enable_testing_features; let perm_ext = Extension::builder() .state(move |state| { state.put::(permissions.clone()); state.put(ops::UnstableChecker { unstable }); + state.put(ops::TestingFeaturesEnabled(enable_testing_features)); Ok(()) }) .build(); @@ -304,6 +307,7 @@ mod tests { args: vec![], debug_flag: false, unstable: false, + enable_testing_features: false, unsafely_ignore_certificate_errors: None, root_cert_store: None, seed: None, diff --git a/tools/wpt.ts b/tools/wpt.ts index a3999a4257..4ebe875c98 100755 --- a/tools/wpt.ts +++ b/tools/wpt.ts @@ -647,7 +647,8 @@ function discoverTestsToRun( const url = new URL(path, "http://web-platform.test:8000"); if ( !url.pathname.endsWith(".any.html") && - !url.pathname.endsWith(".window.html") + !url.pathname.endsWith(".window.html") && + !url.pathname.endsWith(".worker.html") ) { continue; } diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index 0618d6a393..c38b1ad3e5 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -16611,5 +16611,200 @@ "constructor.any.html?wss": true } } + }, + "workers": { + "Worker-base64.any.worker.html": true, + "Worker-call.worker.html": true, + "Worker-constructor-proto.any.worker.html": true, + "Worker-custom-event.any.worker.html": true, + "Worker-formdata.any.worker.html": [ + "Test FormData interface object" + ], + "Worker-location.sub.any.worker.html": [ + "Test WorkerLocation properties." + ], + "Worker-replace-event-handler.any.worker.html": true, + "Worker-replace-global-constructor.any.worker.html": true, + "Worker-replace-self.any.worker.html": true, + "WorkerGlobalScope_requestAnimationFrame.tentative.worker.html": [ + "WorkerGlobalScope_requestAnimationFrame" + ], + "WorkerLocation-origin.sub.window.html": [ + "workerLocation.origin must use ASCII code points" + ], + "WorkerNavigator-hardware-concurrency.any.worker.html": [ + "Test worker navigator hardware concurrency." + ], + "WorkerNavigator.any.worker.html": [ + "Testing Navigator properties on workers." + ], + "constructors": { + "Worker": { + "DedicatedWorkerGlobalScope-members.worker.html": [ + "existence of onoffline", + "existence of ononline" + ], + "expected-self-properties.worker.html": [ + "existence of XMLHttpRequest", + "existence of EventSource", + "existence of SharedWorker" + ], + "unexpected-self-properties.worker.html": true + } + }, + "dedicated-worker-from-blob-url.window.html": [ + "Creating a dedicated worker from a blob URL works immediately before revoking." + ], + "dedicated-worker-in-data-url-context.window.html": [ + "Create a dedicated worker in a data url frame", + "Create a dedicated worker in a data url dedicated worker", + "Create a data url dedicated worker in a data url frame" + ], + "examples": { + "general.any.worker.html": true, + "general.worker.html": true + }, + "importscripts_mime.any.worker.html": [ + "importScripts() requires scripty MIME types: text/ecmascript is allowed." + ], + "interfaces": { + "DedicatedWorkerGlobalScope": { + "EventTarget.worker.html": true, + "onmessage.worker.html": [ + "Setting onmessage to 1", + "Setting onmessage to 1 (again)" + ], + "postMessage": { + "return-value.worker.html": true + } + }, + "WorkerGlobalScope": { + "location": { + "returns-same-object.any.worker.html": true + }, + "self.any.worker.html": true + }, + "WorkerUtils": { + "importScripts": { + "001.worker.html": true, + "002.worker.html": true, + "catch.sub.any.worker.html": [ + "Cross-origin syntax error", + "Cross-origin throw", + "Redirect-to-cross-origin syntax error", + "Redirect-to-Cross-origin throw" + ], + "report-error-cross-origin.sub.any.worker.html": false, + "report-error-redirect-to-cross-origin.sub.any.worker.html": false, + "report-error-same-origin.sub.any.worker.html": false, + "report-error-setTimeout-cross-origin.sub.any.worker.html": false, + "report-error-setTimeout-redirect-to-cross-origin.sub.any.worker.html": false, + "report-error-setTimeout-same-origin.sub.any.worker.html": false + } + } + }, + "modules": { + "dedicated-worker-import-blob-url.any.html": true, + "dedicated-worker-import-blob-url.any.worker.html": true, + "dedicated-worker-import-data-url.any.html": true, + "dedicated-worker-import-data-url.any.worker.html": true, + "dedicated-worker-import.any.html": true, + "dedicated-worker-import.any.worker.html": true, + "shared-worker-import-blob-url.window.html": [ + "Static import.", + "Static import (cross-origin).", + "Static import (redirect).", + "Nested static import.", + "Static import and then dynamic import.", + "Dynamic import.", + "Nested dynamic import.", + "Dynamic import and then static import.", + "eval(import())." + ], + "shared-worker-import-data-url.window.html": [ + "Static import.", + "Static import (cross-origin).", + "Static import (redirect).", + "Nested static import.", + "Static import and then dynamic import.", + "Dynamic import.", + "Nested dynamic import.", + "Dynamic import and then static import.", + "eval(import())." + ], + "shared-worker-import.window.html": [ + "Static import.", + "Static import (cross-origin).", + "Static import (redirect).", + "Nested static import.", + "Static import and then dynamic import.", + "Dynamic import.", + "Nested dynamic import.", + "Dynamic import and then static import.", + "eval(import())." + ] + }, + "nested_worker.worker.html": true, + "nested_worker_close_self.worker.html": true, + "nested_worker_importScripts.worker.html": true, + "nested_worker_sync_xhr.worker.html": [ + "Nested worker that issues a sync XHR" + ], + "semantics": { + "encodings": { + "004.worker.html": true + }, + "interface-objects": { + "001.worker.html": [ + "The SharedWorker interface object should be exposed.", + "The ImageData interface object should be exposed.", + "The ImageBitmap interface object should be exposed.", + "The CanvasGradient interface object should be exposed.", + "The CanvasPattern interface object should be exposed.", + "The CanvasPath interface object should be exposed.", + "The TextMetrics interface object should be exposed.", + "The Path2D interface object should be exposed.", + "The PromiseRejectionEvent interface object should be exposed.", + "The EventSource interface object should be exposed.", + "The XMLHttpRequestEventTarget interface object should be exposed.", + "The XMLHttpRequestUpload interface object should be exposed.", + "The XMLHttpRequest interface object should be exposed.", + "The FileList interface object should be exposed.", + "The FileReaderSync interface object should be exposed.", + "The IDBRequest interface object should be exposed.", + "The IDBOpenDBRequest interface object should be exposed.", + "The IDBVersionChangeEvent interface object should be exposed.", + "The IDBFactory interface object should be exposed.", + "The IDBDatabase interface object should be exposed.", + "The IDBObjectStore interface object should be exposed.", + "The IDBIndex interface object should be exposed.", + "The IDBKeyRange interface object should be exposed.", + "The IDBCursor interface object should be exposed.", + "The IDBCursorWithValue interface object should be exposed.", + "The IDBTransaction interface object should be exposed." + ], + "002.worker.html": true + }, + "multiple-workers": { + "exposure.any.html": [ + "SharedWorker exposure" + ], + "exposure.any.worker.html": true + } + }, + "shared-worker-from-blob-url.window.html": [ + "Creating a shared worker from a blob URL works.", + "Creating a shared worker from a blob URL works immediately before revoking.", + "Connecting to a shared worker on a revoked blob URL works." + ], + "shared-worker-in-data-url-context.window.html": [ + "Create a shared worker in a data url frame", + "Create a data url shared worker in a data url frame" + ], + "worker-performance.worker.html": [ + "Resource timing seems to work in workers", + "performance.clearResourceTimings in workers", + "performance.setResourceTimingBufferSize in workers" + ] } -} \ No newline at end of file +} diff --git a/tools/wpt/runner.ts b/tools/wpt/runner.ts index 07edcec689..27b94da1fa 100644 --- a/tools/wpt/runner.ts +++ b/tools/wpt/runner.ts @@ -94,6 +94,7 @@ export async function runSingleTest( "run", "-A", "--unstable", + "--enable-testing-features-do-not-use", "--location", url.toString(), "--cert",