summaryrefslogtreecommitdiff
path: root/tests/testdata/workers
diff options
context:
space:
mode:
Diffstat (limited to 'tests/testdata/workers')
-rw-r--r--tests/testdata/workers/async_error.ts4
-rw-r--r--tests/testdata/workers/bench_large_message.ts31
-rw-r--r--tests/testdata/workers/bench_round_robin.ts65
-rw-r--r--tests/testdata/workers/bench_startup.ts33
-rw-r--r--tests/testdata/workers/bench_worker.ts21
-rw-r--r--tests/testdata/workers/broadcast_channel.ts5
-rw-r--r--tests/testdata/workers/busy_worker.js8
-rw-r--r--tests/testdata/workers/close_in_wasm_reactions.js21
-rw-r--r--tests/testdata/workers/close_nested_child.js8
-rw-r--r--tests/testdata/workers/close_nested_parent.js13
-rw-r--r--tests/testdata/workers/close_race_worker.js6
-rw-r--r--tests/testdata/workers/custom_inspect/main.out1
-rw-r--r--tests/testdata/workers/custom_inspect/main.ts4
-rw-r--r--tests/testdata/workers/custom_inspect/worker.ts2
-rw-r--r--tests/testdata/workers/deno_worker.ts16
-rw-r--r--tests/testdata/workers/drop_handle_race.js3
-rw-r--r--tests/testdata/workers/dynamic_remote.ts2
-rw-r--r--tests/testdata/workers/env_read_check_worker.js14
-rw-r--r--tests/testdata/workers/error.ts5
-rw-r--r--tests/testdata/workers/error_event.ts11
-rw-r--r--tests/testdata/workers/error_event.ts.out13
-rw-r--r--tests/testdata/workers/error_worker_permissions_local.ts4
-rw-r--r--tests/testdata/workers/error_worker_permissions_local.ts.out2
-rw-r--r--tests/testdata/workers/error_worker_permissions_remote.ts4
-rw-r--r--tests/testdata/workers/error_worker_permissions_remote.ts.out2
-rw-r--r--tests/testdata/workers/event_worker.js7
-rw-r--r--tests/testdata/workers/event_worker_scope.js43
-rw-r--r--tests/testdata/workers/fetching_worker.js6
-rw-r--r--tests/testdata/workers/http_worker.js11
-rw-r--r--tests/testdata/workers/image_data_worker.ts2
-rw-r--r--tests/testdata/workers/immediately_close_worker.js1
-rw-r--r--tests/testdata/workers/message_before_close.js4
-rw-r--r--tests/testdata/workers/message_handler_error.ts4
-rw-r--r--tests/testdata/workers/message_port.ts14
-rw-r--r--tests/testdata/workers/nested_worker.js18
-rw-r--r--tests/testdata/workers/no_permissions_worker.js17
-rw-r--r--tests/testdata/workers/non_deno_worker.js7
-rw-r--r--tests/testdata/workers/nonexistent_worker.out3
-rw-r--r--tests/testdata/workers/nonexistent_worker.ts5
-rw-r--r--tests/testdata/workers/parent_read_check_worker.js12
-rw-r--r--tests/testdata/workers/permission_echo.js19
-rw-r--r--tests/testdata/workers/permissions_blob_local.ts6
-rw-r--r--tests/testdata/workers/permissions_blob_local.ts.out4
-rw-r--r--tests/testdata/workers/permissions_blob_remote.ts4
-rw-r--r--tests/testdata/workers/permissions_blob_remote.ts.out4
-rw-r--r--tests/testdata/workers/permissions_data_local.ts7
-rw-r--r--tests/testdata/workers/permissions_data_local.ts.out4
-rw-r--r--tests/testdata/workers/permissions_data_remote.ts5
-rw-r--r--tests/testdata/workers/permissions_data_remote.ts.out4
-rw-r--r--tests/testdata/workers/permissions_dynamic_remote.ts11
-rw-r--r--tests/testdata/workers/permissions_dynamic_remote.ts.out6
-rw-r--r--tests/testdata/workers/permissions_remote_remote.ts3
-rw-r--r--tests/testdata/workers/permissions_remote_remote.ts.out4
-rw-r--r--tests/testdata/workers/post_undefined.ts5
-rw-r--r--tests/testdata/workers/racy_worker.js25
-rw-r--r--tests/testdata/workers/read_check_granular_worker.js29
-rw-r--r--tests/testdata/workers/read_check_worker.js7
-rw-r--r--tests/testdata/workers/shared_array_buffer.ts9
-rw-r--r--tests/testdata/workers/sibling_worker.js4
-rw-r--r--tests/testdata/workers/static_remote.ts2
-rw-r--r--tests/testdata/workers/terminate_tla_crash.js21
-rw-r--r--tests/testdata/workers/terminate_tla_crash.js.out0
-rw-r--r--tests/testdata/workers/test_worker.js8
-rw-r--r--tests/testdata/workers/test_worker.ts8
-rw-r--r--tests/testdata/workers/throwing_worker.js2
-rw-r--r--tests/testdata/workers/worker_async_error.ts5
-rw-r--r--tests/testdata/workers/worker_async_error.ts.out7
-rw-r--r--tests/testdata/workers/worker_crypto.js5
-rw-r--r--tests/testdata/workers/worker_doest_stall_event_loop.ts29
-rw-r--r--tests/testdata/workers/worker_doest_stall_event_loop.ts.out6
-rw-r--r--tests/testdata/workers/worker_error.ts5
-rw-r--r--tests/testdata/workers/worker_error.ts.out5
-rw-r--r--tests/testdata/workers/worker_event_handlers.js26
-rw-r--r--tests/testdata/workers/worker_globals.ts13
-rw-r--r--tests/testdata/workers/worker_large_message.js14
-rw-r--r--tests/testdata/workers/worker_location.ts6
-rw-r--r--tests/testdata/workers/worker_message_handler_error.ts8
-rw-r--r--tests/testdata/workers/worker_message_handler_error.ts.out7
-rw-r--r--tests/testdata/workers/worker_navigator.ts11
-rw-r--r--tests/testdata/workers/worker_nested_error.ts5
-rw-r--r--tests/testdata/workers/worker_nested_error.ts.out9
-rw-r--r--tests/testdata/workers/worker_structured_cloning.ts15
-rw-r--r--tests/testdata/workers/worker_types.ts4
-rw-r--r--tests/testdata/workers/worker_unstable.ts5
-rw-r--r--tests/testdata/workers/worker_with_top_level_await.ts15
85 files changed, 853 insertions, 0 deletions
diff --git a/tests/testdata/workers/async_error.ts b/tests/testdata/workers/async_error.ts
new file mode 100644
index 000000000..154b957b1
--- /dev/null
+++ b/tests/testdata/workers/async_error.ts
@@ -0,0 +1,4 @@
+// deno-lint-ignore require-await
+(async () => {
+ throw new Error("bar");
+})();
diff --git a/tests/testdata/workers/bench_large_message.ts b/tests/testdata/workers/bench_large_message.ts
new file mode 100644
index 000000000..4bab9fb5c
--- /dev/null
+++ b/tests/testdata/workers/bench_large_message.ts
@@ -0,0 +1,31 @@
+// Copyright 2020 the Deno authors. All rights reserved. MIT license.
+
+function oneWorker(i: number) {
+ return new Promise<void>((resolve) => {
+ let countDown = 10;
+ const worker = new Worker(
+ import.meta.resolve("./worker_large_message.js"),
+ { type: "module" },
+ );
+ worker.onmessage = (_e) => {
+ if (countDown > 0) {
+ countDown--;
+ return;
+ }
+ worker.terminate();
+ resolve();
+ };
+ worker.postMessage("hi " + i);
+ });
+}
+
+function bench() {
+ const promises = [];
+ for (let i = 0; i < 50; i++) {
+ promises.push(oneWorker(i));
+ }
+
+ return Promise.all(promises);
+}
+
+bench();
diff --git a/tests/testdata/workers/bench_round_robin.ts b/tests/testdata/workers/bench_round_robin.ts
new file mode 100644
index 000000000..0380d7979
--- /dev/null
+++ b/tests/testdata/workers/bench_round_robin.ts
@@ -0,0 +1,65 @@
+// Benchmark measures time it takes to send a message to a group of workers one
+// at a time and wait for a response from all of them. Just a general
+// throughput and consistency benchmark.
+const data = "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World\n";
+const workerCount = 4;
+const cmdsPerWorker = 400;
+
+function handleAsyncMsgFromWorker(
+ promiseTable: Map<number, ReturnType<typeof Promise.withResolvers<string>>>,
+ msg: { cmdId: number; data: string },
+) {
+ const promise = promiseTable.get(msg.cmdId);
+ if (promise === null) {
+ throw new Error(`Failed to find promise: cmdId: ${msg.cmdId}, msg: ${msg}`);
+ }
+ promise?.resolve(data);
+}
+
+async function main() {
+ const workers: Array<
+ [Map<number, ReturnType<typeof Promise.withResolvers<string>>>, Worker]
+ > = [];
+ for (let i = 1; i <= workerCount; ++i) {
+ const worker = new Worker(
+ import.meta.resolve("./bench_worker.ts"),
+ { type: "module" },
+ );
+ const { promise, resolve } = Promise.withResolvers<void>();
+ worker.onmessage = (e) => {
+ if (e.data.cmdId === 0) resolve();
+ };
+ worker.postMessage({ cmdId: 0, action: 2 });
+ await promise;
+ workers.push([new Map(), worker]);
+ }
+ // assign callback function
+ for (const [promiseTable, worker] of workers) {
+ worker.onmessage = (e) => {
+ handleAsyncMsgFromWorker(promiseTable, e.data);
+ };
+ }
+ for (const cmdId of Array(cmdsPerWorker).keys()) {
+ const promises: Array<Promise<string>> = [];
+ for (const [promiseTable, worker] of workers) {
+ const deferred = Promise.withResolvers<string>();
+ promiseTable.set(cmdId, deferred);
+ worker.postMessage({ cmdId: cmdId, action: 1, data });
+ promises.push(deferred.promise);
+ }
+ for (const promise of promises) {
+ await promise;
+ }
+ }
+ for (const [, worker] of workers) {
+ const { promise, resolve } = Promise.withResolvers<void>();
+ worker.onmessage = (e) => {
+ if (e.data.cmdId === 3) resolve();
+ };
+ worker.postMessage({ action: 3 });
+ await promise;
+ }
+ console.log("Finished!");
+}
+
+main();
diff --git a/tests/testdata/workers/bench_startup.ts b/tests/testdata/workers/bench_startup.ts
new file mode 100644
index 000000000..a4233d34c
--- /dev/null
+++ b/tests/testdata/workers/bench_startup.ts
@@ -0,0 +1,33 @@
+// Benchmark measures time it takes to start and stop a number of workers.
+const workerCount = 50;
+
+async function bench() {
+ const workers: Worker[] = [];
+ for (let i = 1; i <= workerCount; ++i) {
+ const worker = new Worker(
+ import.meta.resolve("./bench_worker.ts"),
+ { type: "module" },
+ );
+ const promise = new Promise<void>((resolve) => {
+ worker.onmessage = (e) => {
+ if (e.data.cmdId === 0) resolve();
+ };
+ });
+ worker.postMessage({ cmdId: 0, action: 2 });
+ await promise;
+ workers.push(worker);
+ }
+ console.log("Done creating workers closing workers!");
+ for (const worker of workers) {
+ const promise = new Promise<void>((resolve) => {
+ worker.onmessage = (e) => {
+ if (e.data.cmdId === 3) resolve();
+ };
+ });
+ worker.postMessage({ action: 3 });
+ await promise;
+ }
+ console.log("Finished!");
+}
+
+bench();
diff --git a/tests/testdata/workers/bench_worker.ts b/tests/testdata/workers/bench_worker.ts
new file mode 100644
index 000000000..1edd2750f
--- /dev/null
+++ b/tests/testdata/workers/bench_worker.ts
@@ -0,0 +1,21 @@
+onmessage = function (e) {
+ const { cmdId, action, data } = e.data;
+ switch (action) {
+ case 0: // Static response
+ postMessage({
+ cmdId,
+ data: "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World\n",
+ });
+ break;
+ case 1: // Respond with request data
+ postMessage({ cmdId, data });
+ break;
+ case 2: // Ping
+ postMessage({ cmdId });
+ break;
+ case 3: // Close
+ postMessage({ cmdId: 3 });
+ close();
+ break;
+ }
+};
diff --git a/tests/testdata/workers/broadcast_channel.ts b/tests/testdata/workers/broadcast_channel.ts
new file mode 100644
index 000000000..5076e9eb7
--- /dev/null
+++ b/tests/testdata/workers/broadcast_channel.ts
@@ -0,0 +1,5 @@
+new BroadcastChannel("intercom").onmessage = function (e) {
+ this.postMessage(e.data);
+};
+
+self.postMessage("go");
diff --git a/tests/testdata/workers/busy_worker.js b/tests/testdata/workers/busy_worker.js
new file mode 100644
index 000000000..7deba0321
--- /dev/null
+++ b/tests/testdata/workers/busy_worker.js
@@ -0,0 +1,8 @@
+self.onmessage = function (_evt) {
+ // infinite loop
+ for (let i = 0; true; i++) {
+ if (i % 1000 == 0) {
+ postMessage(i);
+ }
+ }
+};
diff --git a/tests/testdata/workers/close_in_wasm_reactions.js b/tests/testdata/workers/close_in_wasm_reactions.js
new file mode 100644
index 000000000..abe573108
--- /dev/null
+++ b/tests/testdata/workers/close_in_wasm_reactions.js
@@ -0,0 +1,21 @@
+// https://github.com/denoland/deno/issues/12263
+// Test for a panic that happens when a worker is closed in the reactions of a
+// WASM async operation.
+
+// The minimum valid wasm module, plus two additional zero bytes.
+const buffer = new Uint8Array([
+ 0x00,
+ 0x61,
+ 0x73,
+ 0x6D,
+ 0x01,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+]);
+WebAssembly.compile(buffer).catch((err) => {
+ console.log("Error:", err);
+ self.close();
+});
diff --git a/tests/testdata/workers/close_nested_child.js b/tests/testdata/workers/close_nested_child.js
new file mode 100644
index 000000000..97980c689
--- /dev/null
+++ b/tests/testdata/workers/close_nested_child.js
@@ -0,0 +1,8 @@
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+
+console.log("Starting the child worker");
+
+setTimeout(() => {
+ console.log("The child worker survived the death of the parent!!!");
+ Deno.exit(1);
+}, 2000);
diff --git a/tests/testdata/workers/close_nested_parent.js b/tests/testdata/workers/close_nested_parent.js
new file mode 100644
index 000000000..d1fe47553
--- /dev/null
+++ b/tests/testdata/workers/close_nested_parent.js
@@ -0,0 +1,13 @@
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+
+console.log("Starting the parent worker");
+
+new Worker(
+ import.meta.resolve("./close_nested_child.js"),
+ { type: "module" },
+);
+
+self.addEventListener("message", () => {
+ console.log("Closing");
+ self.close();
+});
diff --git a/tests/testdata/workers/close_race_worker.js b/tests/testdata/workers/close_race_worker.js
new file mode 100644
index 000000000..6964be34a
--- /dev/null
+++ b/tests/testdata/workers/close_race_worker.js
@@ -0,0 +1,6 @@
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+
+setTimeout(() => {
+ self.postMessage("");
+ self.close();
+}, 500);
diff --git a/tests/testdata/workers/custom_inspect/main.out b/tests/testdata/workers/custom_inspect/main.out
new file mode 100644
index 000000000..40d9b88ad
--- /dev/null
+++ b/tests/testdata/workers/custom_inspect/main.out
@@ -0,0 +1 @@
+ReadableStream { locked: false }
diff --git a/tests/testdata/workers/custom_inspect/main.ts b/tests/testdata/workers/custom_inspect/main.ts
new file mode 100644
index 000000000..93d4eec2d
--- /dev/null
+++ b/tests/testdata/workers/custom_inspect/main.ts
@@ -0,0 +1,4 @@
+new Worker(
+ import.meta.resolve("./worker.ts"),
+ { type: "module" },
+);
diff --git a/tests/testdata/workers/custom_inspect/worker.ts b/tests/testdata/workers/custom_inspect/worker.ts
new file mode 100644
index 000000000..5be82724e
--- /dev/null
+++ b/tests/testdata/workers/custom_inspect/worker.ts
@@ -0,0 +1,2 @@
+console.log(new ReadableStream());
+close();
diff --git a/tests/testdata/workers/deno_worker.ts b/tests/testdata/workers/deno_worker.ts
new file mode 100644
index 000000000..cbebde94a
--- /dev/null
+++ b/tests/testdata/workers/deno_worker.ts
@@ -0,0 +1,16 @@
+import { assert } from "../../../test_util/std/assert/mod.ts";
+
+onmessage = function (e) {
+ if (typeof self.Deno === "undefined") {
+ throw new Error("Deno namespace not available in worker");
+ }
+
+ assert(!Object.isFrozen(self.Deno));
+
+ const desc = Object.getOwnPropertyDescriptor(self, "Deno");
+ assert(desc);
+ assert(desc.configurable);
+ assert(!desc.writable);
+
+ postMessage(e.data);
+};
diff --git a/tests/testdata/workers/drop_handle_race.js b/tests/testdata/workers/drop_handle_race.js
new file mode 100644
index 000000000..30676a600
--- /dev/null
+++ b/tests/testdata/workers/drop_handle_race.js
@@ -0,0 +1,3 @@
+setTimeout(() => {
+ throw new Error();
+}, 1000);
diff --git a/tests/testdata/workers/dynamic_remote.ts b/tests/testdata/workers/dynamic_remote.ts
new file mode 100644
index 000000000..54e4a4714
--- /dev/null
+++ b/tests/testdata/workers/dynamic_remote.ts
@@ -0,0 +1,2 @@
+// This file doesn't really exist, but it doesn't matter, a "PermissionsDenied" error should be thrown.
+await import("" + "https://example.com/some/file.ts");
diff --git a/tests/testdata/workers/env_read_check_worker.js b/tests/testdata/workers/env_read_check_worker.js
new file mode 100644
index 000000000..72ad31df2
--- /dev/null
+++ b/tests/testdata/workers/env_read_check_worker.js
@@ -0,0 +1,14 @@
+onmessage = async ({ data }) => {
+ const permissions = [];
+ for (const name of data.names) {
+ const { state } = await Deno.permissions.query({
+ name: "env",
+ variable: name,
+ });
+ permissions.push(state === "granted");
+ }
+
+ postMessage({
+ permissions,
+ });
+};
diff --git a/tests/testdata/workers/error.ts b/tests/testdata/workers/error.ts
new file mode 100644
index 000000000..495971090
--- /dev/null
+++ b/tests/testdata/workers/error.ts
@@ -0,0 +1,5 @@
+function foo() {
+ throw new Error("foo");
+}
+
+foo();
diff --git a/tests/testdata/workers/error_event.ts b/tests/testdata/workers/error_event.ts
new file mode 100644
index 000000000..70e7728ab
--- /dev/null
+++ b/tests/testdata/workers/error_event.ts
@@ -0,0 +1,11 @@
+const worker = new Worker(import.meta.resolve("./error.ts"), {
+ type: "module",
+});
+worker.addEventListener("error", (e) => {
+ console.log({
+ "message": e.message,
+ "filename": e.filename?.slice?.(-100),
+ "lineno": e.lineno,
+ "colno": e.colno,
+ });
+});
diff --git a/tests/testdata/workers/error_event.ts.out b/tests/testdata/workers/error_event.ts.out
new file mode 100644
index 000000000..833cca8be
--- /dev/null
+++ b/tests/testdata/workers/error_event.ts.out
@@ -0,0 +1,13 @@
+error: Uncaught (in worker "") (in promise) Error: foo
+ throw new Error("foo");
+ ^
+ at foo ([WILDCARD]/error.ts:2:9)
+ at [WILDCARD]/error.ts:5:1
+{
+ message: "Uncaught (in promise) Error: foo",
+ filename: "[WILDCARD]/error.ts",
+ lineno: 2,
+ colno: 9
+}
+error: Uncaught (in promise) Error: Unhandled error in child worker.
+ at [WILDCARD]
diff --git a/tests/testdata/workers/error_worker_permissions_local.ts b/tests/testdata/workers/error_worker_permissions_local.ts
new file mode 100644
index 000000000..1a4b4c0a9
--- /dev/null
+++ b/tests/testdata/workers/error_worker_permissions_local.ts
@@ -0,0 +1,4 @@
+new Worker(
+ import.meta.resolve("../subdir/worker_types.ts"),
+ { type: "module" },
+);
diff --git a/tests/testdata/workers/error_worker_permissions_local.ts.out b/tests/testdata/workers/error_worker_permissions_local.ts.out
new file mode 100644
index 000000000..cacc8ae38
--- /dev/null
+++ b/tests/testdata/workers/error_worker_permissions_local.ts.out
@@ -0,0 +1,2 @@
+error: Uncaught (in worker "") Requires read access to "[WILDCARD]worker_types.ts", run again with the --allow-read flag
+[WILDCARD]
diff --git a/tests/testdata/workers/error_worker_permissions_remote.ts b/tests/testdata/workers/error_worker_permissions_remote.ts
new file mode 100644
index 000000000..878c7080a
--- /dev/null
+++ b/tests/testdata/workers/error_worker_permissions_remote.ts
@@ -0,0 +1,4 @@
+new Worker(
+ "http://localhost:4545/subdir/worker_types.ts",
+ { type: "module" },
+);
diff --git a/tests/testdata/workers/error_worker_permissions_remote.ts.out b/tests/testdata/workers/error_worker_permissions_remote.ts.out
new file mode 100644
index 000000000..afecff0a8
--- /dev/null
+++ b/tests/testdata/workers/error_worker_permissions_remote.ts.out
@@ -0,0 +1,2 @@
+error: Uncaught (in worker "") Requires net access to "localhost:4545", run again with the --allow-net flag
+[WILDCARD]
diff --git a/tests/testdata/workers/event_worker.js b/tests/testdata/workers/event_worker.js
new file mode 100644
index 000000000..849b6026c
--- /dev/null
+++ b/tests/testdata/workers/event_worker.js
@@ -0,0 +1,7 @@
+onmessage = function (e) {
+ if (e.data === "boom") {
+ throw new Error("boom error!");
+ }
+
+ postMessage(e.data);
+};
diff --git a/tests/testdata/workers/event_worker_scope.js b/tests/testdata/workers/event_worker_scope.js
new file mode 100644
index 000000000..0381801a8
--- /dev/null
+++ b/tests/testdata/workers/event_worker_scope.js
@@ -0,0 +1,43 @@
+let messageHandlersCalled = 0;
+let errorHandlersCalled = 0;
+
+onmessage = function (e) {
+ if (e.data === "boom") {
+ throw new Error("boom error!");
+ }
+ messageHandlersCalled++;
+};
+
+self.addEventListener("message", (_e) => {
+ messageHandlersCalled++;
+});
+
+self.addEventListener("message", (_e) => {
+ messageHandlersCalled++;
+});
+
+self.addEventListener("message", (_e) => {
+ messageHandlersCalled++;
+
+ postMessage({
+ messageHandlersCalled,
+ errorHandlersCalled,
+ });
+});
+
+onerror = function (_e) {
+ errorHandlersCalled++;
+};
+
+self.addEventListener("error", (_e) => {
+ errorHandlersCalled++;
+});
+
+self.addEventListener("error", (_e) => {
+ errorHandlersCalled++;
+});
+
+self.addEventListener("error", (e) => {
+ errorHandlersCalled++;
+ e.preventDefault();
+});
diff --git a/tests/testdata/workers/fetching_worker.js b/tests/testdata/workers/fetching_worker.js
new file mode 100644
index 000000000..77ff471d7
--- /dev/null
+++ b/tests/testdata/workers/fetching_worker.js
@@ -0,0 +1,6 @@
+const r = await fetch(
+ "http://localhost:4545/workers/fetching_worker.js",
+);
+await r.text();
+postMessage("Done!");
+close();
diff --git a/tests/testdata/workers/http_worker.js b/tests/testdata/workers/http_worker.js
new file mode 100644
index 000000000..3cd1625ab
--- /dev/null
+++ b/tests/testdata/workers/http_worker.js
@@ -0,0 +1,11 @@
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+const listener = Deno.listen({ hostname: "127.0.0.1", port: 4506 });
+postMessage("ready");
+for await (const conn of listener) {
+ (async () => {
+ const requests = Deno.serveHttp(conn);
+ for await (const { respondWith } of requests) {
+ respondWith(new Response("Hello world"));
+ }
+ })();
+}
diff --git a/tests/testdata/workers/image_data_worker.ts b/tests/testdata/workers/image_data_worker.ts
new file mode 100644
index 000000000..bf920d2f3
--- /dev/null
+++ b/tests/testdata/workers/image_data_worker.ts
@@ -0,0 +1,2 @@
+const data = new ImageData(2, 2, { colorSpace: "display-p3" });
+postMessage(data.data.length);
diff --git a/tests/testdata/workers/immediately_close_worker.js b/tests/testdata/workers/immediately_close_worker.js
new file mode 100644
index 000000000..8fd27343a
--- /dev/null
+++ b/tests/testdata/workers/immediately_close_worker.js
@@ -0,0 +1 @@
+self.close();
diff --git a/tests/testdata/workers/message_before_close.js b/tests/testdata/workers/message_before_close.js
new file mode 100644
index 000000000..9364b6d82
--- /dev/null
+++ b/tests/testdata/workers/message_before_close.js
@@ -0,0 +1,4 @@
+onmessage = () => {
+ postMessage({});
+ close();
+};
diff --git a/tests/testdata/workers/message_handler_error.ts b/tests/testdata/workers/message_handler_error.ts
new file mode 100644
index 000000000..3416faad1
--- /dev/null
+++ b/tests/testdata/workers/message_handler_error.ts
@@ -0,0 +1,4 @@
+postMessage("ready");
+onmessage = () => {
+ throw new Error("bar");
+};
diff --git a/tests/testdata/workers/message_port.ts b/tests/testdata/workers/message_port.ts
new file mode 100644
index 000000000..d78304a39
--- /dev/null
+++ b/tests/testdata/workers/message_port.ts
@@ -0,0 +1,14 @@
+const channel = new MessageChannel();
+
+channel.port2.onmessage = (e) => {
+ channel.port2.postMessage(e.data === "2");
+ channel.port2.close();
+};
+
+self.postMessage("1", [channel.port1]);
+
+self.onmessage = (e) => {
+ const port1 = e.ports[0];
+ port1.postMessage(e.data === "3");
+ port1.close();
+};
diff --git a/tests/testdata/workers/nested_worker.js b/tests/testdata/workers/nested_worker.js
new file mode 100644
index 000000000..2273cdbfa
--- /dev/null
+++ b/tests/testdata/workers/nested_worker.js
@@ -0,0 +1,18 @@
+// Specifier should be resolved relative to current file
+const jsWorker = new Worker(
+ import.meta.resolve("./sibling_worker.js"),
+ { type: "module", name: "sibling" },
+);
+
+jsWorker.onerror = (_e) => {
+ postMessage({ type: "error" });
+};
+
+jsWorker.onmessage = (e) => {
+ postMessage({ type: "msg", text: e.data });
+ close();
+};
+
+onmessage = function (e) {
+ jsWorker.postMessage(e.data);
+};
diff --git a/tests/testdata/workers/no_permissions_worker.js b/tests/testdata/workers/no_permissions_worker.js
new file mode 100644
index 000000000..f49f690ab
--- /dev/null
+++ b/tests/testdata/workers/no_permissions_worker.js
@@ -0,0 +1,17 @@
+self.onmessage = async () => {
+ const hrtime = await Deno.permissions.query({ name: "hrtime" });
+ const net = await Deno.permissions.query({ name: "net" });
+ const ffi = await Deno.permissions.query({ name: "ffi" });
+ const read = await Deno.permissions.query({ name: "read" });
+ const run = await Deno.permissions.query({ name: "run" });
+ const write = await Deno.permissions.query({ name: "write" });
+ self.postMessage(
+ hrtime.state === "prompt" &&
+ net.state === "prompt" &&
+ ffi.state === "prompt" &&
+ read.state === "prompt" &&
+ run.state === "prompt" &&
+ write.state === "prompt",
+ );
+ self.close();
+};
diff --git a/tests/testdata/workers/non_deno_worker.js b/tests/testdata/workers/non_deno_worker.js
new file mode 100644
index 000000000..773721560
--- /dev/null
+++ b/tests/testdata/workers/non_deno_worker.js
@@ -0,0 +1,7 @@
+onmessage = function (e) {
+ if (typeof self.Deno !== "undefined") {
+ throw new Error("Deno namespace unexpectedly available in worker");
+ }
+
+ postMessage(e.data);
+};
diff --git a/tests/testdata/workers/nonexistent_worker.out b/tests/testdata/workers/nonexistent_worker.out
new file mode 100644
index 000000000..a624c0b51
--- /dev/null
+++ b/tests/testdata/workers/nonexistent_worker.out
@@ -0,0 +1,3 @@
+[WILDCARD]error: Uncaught (in worker "") Module not found "file:///[WILDCARD]/workers/doesnt_exist.js".
+error: Uncaught (in promise) Error: Unhandled error in child worker.
+ at Worker.#pollControl[WILDCARD]
diff --git a/tests/testdata/workers/nonexistent_worker.ts b/tests/testdata/workers/nonexistent_worker.ts
new file mode 100644
index 000000000..b30d08636
--- /dev/null
+++ b/tests/testdata/workers/nonexistent_worker.ts
@@ -0,0 +1,5 @@
+const w = new Worker(import.meta.resolve("./doesnt_exist.js"), {
+ type: "module",
+});
+
+w.postMessage("hello");
diff --git a/tests/testdata/workers/parent_read_check_worker.js b/tests/testdata/workers/parent_read_check_worker.js
new file mode 100644
index 000000000..3221fc597
--- /dev/null
+++ b/tests/testdata/workers/parent_read_check_worker.js
@@ -0,0 +1,12 @@
+const worker = new Worker(
+ import.meta.resolve("./read_check_granular_worker.js"),
+ { type: "module", deno: { permissions: "none" } },
+);
+
+onmessage = ({ data }) => {
+ worker.postMessage(data);
+};
+
+worker.onmessage = ({ data }) => {
+ postMessage(data);
+};
diff --git a/tests/testdata/workers/permission_echo.js b/tests/testdata/workers/permission_echo.js
new file mode 100644
index 000000000..f492a25f2
--- /dev/null
+++ b/tests/testdata/workers/permission_echo.js
@@ -0,0 +1,19 @@
+self.onmessage = async () => {
+ const env = await Deno.permissions.query({ name: "env" });
+ const ffi = await Deno.permissions.query({ name: "ffi" });
+ const hrtime = await Deno.permissions.query({ name: "hrtime" });
+ const net = await Deno.permissions.query({ name: "net" });
+ const read = await Deno.permissions.query({ name: "read" });
+ const run = await Deno.permissions.query({ name: "run" });
+ const write = await Deno.permissions.query({ name: "write" });
+ self.postMessage({
+ env: env.state,
+ ffi: ffi.state,
+ hrtime: hrtime.state,
+ net: net.state,
+ read: read.state,
+ run: run.state,
+ write: write.state,
+ });
+ self.close();
+};
diff --git a/tests/testdata/workers/permissions_blob_local.ts b/tests/testdata/workers/permissions_blob_local.ts
new file mode 100644
index 000000000..52f630bd8
--- /dev/null
+++ b/tests/testdata/workers/permissions_blob_local.ts
@@ -0,0 +1,6 @@
+// This file doesn't really exist, but it doesn't matter, a "PermissionsDenied" error should be thrown.
+const code = `import "file:///${
+ Deno.build.os == "windows" ? "C:/" : ""
+}local_file.ts";`;
+const blob = new Blob([code]);
+new Worker(URL.createObjectURL(blob), { type: "module" });
diff --git a/tests/testdata/workers/permissions_blob_local.ts.out b/tests/testdata/workers/permissions_blob_local.ts.out
new file mode 100644
index 000000000..0cd581f7b
--- /dev/null
+++ b/tests/testdata/workers/permissions_blob_local.ts.out
@@ -0,0 +1,4 @@
+error: Uncaught (in worker "") Requires read access to "[WILDCARD]local_file.ts", run again with the --allow-read flag
+ at blob:null/[WILDCARD]:1:8
+error: Uncaught (in promise) Error: Unhandled error in child worker.
+ at Worker.#pollControl [WILDCARD]
diff --git a/tests/testdata/workers/permissions_blob_remote.ts b/tests/testdata/workers/permissions_blob_remote.ts
new file mode 100644
index 000000000..4808bc57b
--- /dev/null
+++ b/tests/testdata/workers/permissions_blob_remote.ts
@@ -0,0 +1,4 @@
+// This file doesn't really exist, but it doesn't matter, a "PermissionsDenied" error should be thrown.
+const code = `import "https://example.com/some/file.ts";`;
+const blob = new Blob([code]);
+new Worker(URL.createObjectURL(blob), { type: "module" });
diff --git a/tests/testdata/workers/permissions_blob_remote.ts.out b/tests/testdata/workers/permissions_blob_remote.ts.out
new file mode 100644
index 000000000..618f552dc
--- /dev/null
+++ b/tests/testdata/workers/permissions_blob_remote.ts.out
@@ -0,0 +1,4 @@
+error: Uncaught (in worker "") Requires net access to "example.com", run again with the --allow-net flag
+ at blob:null/[WILDCARD]:1:8
+error: Uncaught (in promise) Error: Unhandled error in child worker.
+ at Worker.#pollControl[WILDCARD]
diff --git a/tests/testdata/workers/permissions_data_local.ts b/tests/testdata/workers/permissions_data_local.ts
new file mode 100644
index 000000000..cda80bed6
--- /dev/null
+++ b/tests/testdata/workers/permissions_data_local.ts
@@ -0,0 +1,7 @@
+// This file doesn't really exist, but it doesn't matter, a "PermissionsDenied" error should be thrown.
+const code = `import "file:///${
+ Deno.build.os == "windows" ? "C:/" : ""
+}local_file.ts";`;
+new Worker(`data:application/javascript;base64,${btoa(code)}`, {
+ type: "module",
+});
diff --git a/tests/testdata/workers/permissions_data_local.ts.out b/tests/testdata/workers/permissions_data_local.ts.out
new file mode 100644
index 000000000..4e0f72779
--- /dev/null
+++ b/tests/testdata/workers/permissions_data_local.ts.out
@@ -0,0 +1,4 @@
+error: Uncaught (in worker "") Requires read access to "[WILDCARD]local_file.ts", run again with the --allow-read flag
+ at data:application/javascript;base64,[WILDCARD]:1:8
+error: Uncaught (in promise) Error: Unhandled error in child worker.
+ at Worker.#pollControl[WILDCARD]
diff --git a/tests/testdata/workers/permissions_data_remote.ts b/tests/testdata/workers/permissions_data_remote.ts
new file mode 100644
index 000000000..b37bd661d
--- /dev/null
+++ b/tests/testdata/workers/permissions_data_remote.ts
@@ -0,0 +1,5 @@
+// This file doesn't really exist, but it doesn't matter, a "PermissionsDenied" error should be thrown.
+const code = `import "https://example.com/some/file.ts";`;
+new Worker(`data:application/javascript;base64,${btoa(code)}`, {
+ type: "module",
+});
diff --git a/tests/testdata/workers/permissions_data_remote.ts.out b/tests/testdata/workers/permissions_data_remote.ts.out
new file mode 100644
index 000000000..3f7c8cb63
--- /dev/null
+++ b/tests/testdata/workers/permissions_data_remote.ts.out
@@ -0,0 +1,4 @@
+error: Uncaught (in worker "") Requires net access to "example.com", run again with the --allow-net flag
+ at data:application/javascript;base64,aW1wb3J0ICJodHRwczovL2V4YW1wbGUuY29tL3NvbWUvZmlsZS50cyI7:1:8
+error: Uncaught (in promise) Error: Unhandled error in child worker.
+ at Worker.#pollControl[WILDCARD]
diff --git a/tests/testdata/workers/permissions_dynamic_remote.ts b/tests/testdata/workers/permissions_dynamic_remote.ts
new file mode 100644
index 000000000..54a361bc0
--- /dev/null
+++ b/tests/testdata/workers/permissions_dynamic_remote.ts
@@ -0,0 +1,11 @@
+new Worker(
+ "http://localhost:4545/workers/dynamic_remote.ts",
+ {
+ type: "module",
+ deno: {
+ permissions: {
+ net: false,
+ },
+ },
+ },
+);
diff --git a/tests/testdata/workers/permissions_dynamic_remote.ts.out b/tests/testdata/workers/permissions_dynamic_remote.ts.out
new file mode 100644
index 000000000..91f3cc6d5
--- /dev/null
+++ b/tests/testdata/workers/permissions_dynamic_remote.ts.out
@@ -0,0 +1,6 @@
+error: Uncaught (in worker "") (in promise) TypeError: Requires net access to "example.com", run again with the --allow-net flag
+await import("" + "https://example.com/some/file.ts");
+^
+ at async http://localhost:4545/workers/dynamic_remote.ts:2:1
+[WILDCARD]error: Uncaught (in promise) Error: Unhandled error in child worker.
+ at Worker.#pollControl [WILDCARD]
diff --git a/tests/testdata/workers/permissions_remote_remote.ts b/tests/testdata/workers/permissions_remote_remote.ts
new file mode 100644
index 000000000..4df2a8a5d
--- /dev/null
+++ b/tests/testdata/workers/permissions_remote_remote.ts
@@ -0,0 +1,3 @@
+new Worker("http://localhost:4545/workers/static_remote.ts", {
+ type: "module",
+});
diff --git a/tests/testdata/workers/permissions_remote_remote.ts.out b/tests/testdata/workers/permissions_remote_remote.ts.out
new file mode 100644
index 000000000..bb065740a
--- /dev/null
+++ b/tests/testdata/workers/permissions_remote_remote.ts.out
@@ -0,0 +1,4 @@
+error: Uncaught (in worker "") Requires net access to "example.com", run again with the --allow-net flag
+ at http://localhost:4545/workers/static_remote.ts:2:8
+error: Uncaught (in promise) Error: Unhandled error in child worker.
+ at Worker.#pollControl [WILDCARD]
diff --git a/tests/testdata/workers/post_undefined.ts b/tests/testdata/workers/post_undefined.ts
new file mode 100644
index 000000000..1b9b8d6ca
--- /dev/null
+++ b/tests/testdata/workers/post_undefined.ts
@@ -0,0 +1,5 @@
+self.onmessage = (ev: MessageEvent) => {
+ console.log("received in worker", ev.data);
+ self.postMessage(undefined);
+ console.log("posted from worker");
+};
diff --git a/tests/testdata/workers/racy_worker.js b/tests/testdata/workers/racy_worker.js
new file mode 100644
index 000000000..0f66c6278
--- /dev/null
+++ b/tests/testdata/workers/racy_worker.js
@@ -0,0 +1,25 @@
+// See issue for details
+// https://github.com/denoland/deno/issues/4080
+//
+// After first received message, this worker schedules
+// [assert(), close(), assert()] ops on the same turn of microtask queue
+// All tasks after close should not make it
+
+onmessage = async function () {
+ let stage = 0;
+ await new Promise((_) => {
+ setTimeout(() => {
+ if (stage !== 0) throw "Unexpected stage";
+ stage = 1;
+ }, 50);
+ setTimeout(() => {
+ if (stage !== 1) throw "Unexpected stage";
+ stage = 2;
+ postMessage("DONE");
+ close();
+ }, 50);
+ setTimeout(() => {
+ throw "This should not be run";
+ }, 50);
+ });
+};
diff --git a/tests/testdata/workers/read_check_granular_worker.js b/tests/testdata/workers/read_check_granular_worker.js
new file mode 100644
index 000000000..d40fac876
--- /dev/null
+++ b/tests/testdata/workers/read_check_granular_worker.js
@@ -0,0 +1,29 @@
+// deno-fmt-ignore-file
+postMessage({
+ envGlobal: (await Deno.permissions.query({ name: "env" })).state,
+ envFoo: (await Deno.permissions.query({ name: "env", variable: "foo" })).state,
+ envAbsent: (await Deno.permissions.query({ name: "env", variable: "absent" })).state,
+ hrtime: (await Deno.permissions.query({ name: "hrtime" })).state,
+ netGlobal: (await Deno.permissions.query({ name: "net" })).state,
+ netFoo: (await Deno.permissions.query({ name: "net", host: "foo" })).state,
+ netFoo8000: (await Deno.permissions.query({ name: "net", host: "foo:8000" })).state,
+ netBar: (await Deno.permissions.query({ name: "net", host: "bar" })).state,
+ netBar8000: (await Deno.permissions.query({ name: "net", host: "bar:8000" })).state,
+ ffiGlobal: (await Deno.permissions.query({ name: "ffi" })).state,
+ ffiFoo: (await Deno.permissions.query({ name: "ffi", path: new URL("foo", import.meta.url) })).state,
+ ffiBar: (await Deno.permissions.query({ name: "ffi", path: "bar" })).state,
+ ffiAbsent: (await Deno.permissions.query({ name: "ffi", path: "absent" })).state,
+ readGlobal: (await Deno.permissions.query({ name: "read" })).state,
+ readFoo: (await Deno.permissions.query({ name: "read", path: new URL("foo", import.meta.url) })).state,
+ readBar: (await Deno.permissions.query({ name: "read", path: "bar" })).state,
+ readAbsent: (await Deno.permissions.query({ name: "read", path: "absent" })).state,
+ runGlobal: (await Deno.permissions.query({ name: "run" })).state,
+ runFoo: (await Deno.permissions.query({ name: "run", command: new URL("foo", import.meta.url) })).state,
+ runBar: (await Deno.permissions.query({ name: "run", command: "bar" })).state,
+ runBaz: (await Deno.permissions.query({ name: "run", command: "./baz" })).state,
+ runAbsent: (await Deno.permissions.query({ name: "run", command: "absent" })).state,
+ writeGlobal: (await Deno.permissions.query({ name: "write" })).state,
+ writeFoo: (await Deno.permissions.query({ name: "write", path: new URL("foo", import.meta.url) })).state,
+ writeBar: (await Deno.permissions.query({ name: "write", path: "bar" })).state,
+ writeAbsent: (await Deno.permissions.query({ name: "write", path: "absent" })).state,
+});
diff --git a/tests/testdata/workers/read_check_worker.js b/tests/testdata/workers/read_check_worker.js
new file mode 100644
index 000000000..2ad01bf5b
--- /dev/null
+++ b/tests/testdata/workers/read_check_worker.js
@@ -0,0 +1,7 @@
+onmessage = async () => {
+ const { state } = await Deno.permissions.query({
+ name: "read",
+ });
+ postMessage(state === "granted");
+ close();
+};
diff --git a/tests/testdata/workers/shared_array_buffer.ts b/tests/testdata/workers/shared_array_buffer.ts
new file mode 100644
index 000000000..4af95863a
--- /dev/null
+++ b/tests/testdata/workers/shared_array_buffer.ts
@@ -0,0 +1,9 @@
+self.postMessage("ready");
+
+globalThis.addEventListener("message", (e) => {
+ const bytes1 = new Uint8Array(e.data[0]);
+ const bytes2 = new Uint8Array(e.data[1]);
+ bytes1[0] = 1;
+ bytes2[0] = 2;
+ self.postMessage("done");
+});
diff --git a/tests/testdata/workers/sibling_worker.js b/tests/testdata/workers/sibling_worker.js
new file mode 100644
index 000000000..99707e5d6
--- /dev/null
+++ b/tests/testdata/workers/sibling_worker.js
@@ -0,0 +1,4 @@
+onmessage = (e) => {
+ postMessage(e.data);
+ close();
+};
diff --git a/tests/testdata/workers/static_remote.ts b/tests/testdata/workers/static_remote.ts
new file mode 100644
index 000000000..2d6e820fd
--- /dev/null
+++ b/tests/testdata/workers/static_remote.ts
@@ -0,0 +1,2 @@
+// This file doesn't really exist, but it doesn't matter, a "PermissionsDenied" error should be thrown.
+import "https://example.com/some/file.ts";
diff --git a/tests/testdata/workers/terminate_tla_crash.js b/tests/testdata/workers/terminate_tla_crash.js
new file mode 100644
index 000000000..f793b8c8e
--- /dev/null
+++ b/tests/testdata/workers/terminate_tla_crash.js
@@ -0,0 +1,21 @@
+// Test for https://github.com/denoland/deno/issues/12658
+//
+// If a worker is terminated immediately after construction, and the worker's
+// main module uses top-level await, V8 has a chance to crash.
+//
+// These crashes are so rare in debug mode that I've only seen them once. They
+// happen a lot more often in release mode.
+
+const workerModule = `
+ await new Promise(resolve => setTimeout(resolve, 1000));
+`;
+
+// Iterating 10 times to increase the likelihood of triggering the crash, at
+// least in release mode.
+for (let i = 0; i < 10; i++) {
+ const worker = new Worker(
+ `data:application/javascript;base64,${btoa(workerModule)}`,
+ { type: "module" },
+ );
+ worker.terminate();
+}
diff --git a/tests/testdata/workers/terminate_tla_crash.js.out b/tests/testdata/workers/terminate_tla_crash.js.out
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/testdata/workers/terminate_tla_crash.js.out
diff --git a/tests/testdata/workers/test_worker.js b/tests/testdata/workers/test_worker.js
new file mode 100644
index 000000000..2b2d1eeec
--- /dev/null
+++ b/tests/testdata/workers/test_worker.js
@@ -0,0 +1,8 @@
+if (self.name !== "") {
+ throw Error(`Bad worker name: ${self.name}, expected empty string.`);
+}
+
+onmessage = function (e) {
+ postMessage(e.data);
+ close();
+};
diff --git a/tests/testdata/workers/test_worker.ts b/tests/testdata/workers/test_worker.ts
new file mode 100644
index 000000000..996476058
--- /dev/null
+++ b/tests/testdata/workers/test_worker.ts
@@ -0,0 +1,8 @@
+if (self.name !== "tsWorker") {
+ throw Error(`Invalid worker name: ${self.name}, expected tsWorker`);
+}
+
+onmessage = function (e) {
+ postMessage(e.data);
+ close();
+};
diff --git a/tests/testdata/workers/throwing_worker.js b/tests/testdata/workers/throwing_worker.js
new file mode 100644
index 000000000..56ee4ff88
--- /dev/null
+++ b/tests/testdata/workers/throwing_worker.js
@@ -0,0 +1,2 @@
+// This worker just throws error when it's being executed
+throw Error("Thrown error");
diff --git a/tests/testdata/workers/worker_async_error.ts b/tests/testdata/workers/worker_async_error.ts
new file mode 100644
index 000000000..7941a5bbe
--- /dev/null
+++ b/tests/testdata/workers/worker_async_error.ts
@@ -0,0 +1,5 @@
+const worker = new Worker(
+ import.meta.resolve("./async_error.ts"),
+ { type: "module", name: "foo" },
+);
+setTimeout(() => worker.terminate(), 30000);
diff --git a/tests/testdata/workers/worker_async_error.ts.out b/tests/testdata/workers/worker_async_error.ts.out
new file mode 100644
index 000000000..8d017859c
--- /dev/null
+++ b/tests/testdata/workers/worker_async_error.ts.out
@@ -0,0 +1,7 @@
+error: Uncaught (in worker "foo") (in promise) Error: bar
+ throw new Error("bar");
+ ^
+ at [WILDCARD]/async_error.ts:[WILDCARD]
+ at [WILDCARD]/async_error.ts:[WILDCARD]
+error: Uncaught (in promise) Error: Unhandled error in child worker.
+ at Worker.#pollControl [WILDCARD]
diff --git a/tests/testdata/workers/worker_crypto.js b/tests/testdata/workers/worker_crypto.js
new file mode 100644
index 000000000..4398ad068
--- /dev/null
+++ b/tests/testdata/workers/worker_crypto.js
@@ -0,0 +1,5 @@
+self.crypto.getRandomValues(new Uint8Array(16));
+
+onmessage = function () {
+ postMessage(!!self.crypto);
+};
diff --git a/tests/testdata/workers/worker_doest_stall_event_loop.ts b/tests/testdata/workers/worker_doest_stall_event_loop.ts
new file mode 100644
index 000000000..bfddee2ec
--- /dev/null
+++ b/tests/testdata/workers/worker_doest_stall_event_loop.ts
@@ -0,0 +1,29 @@
+const moduleCode = `
+console.log('module start');
+const hash = await crypto.subtle.digest('SHA-1', new TextEncoder().encode('data'));
+const __default = {};
+export { __default as default };
+console.log('module finish');
+`;
+
+const workerCode = `
+ console.log('worker!');
+
+ globalThis.onmessage = (msg) => {
+ const { moduleCode } = msg.data;
+ (async () => {
+ console.log('before import');
+ await import(URL.createObjectURL(new Blob([ moduleCode ])));
+ console.log('after import');
+ self.postMessage('thanks');
+ })();
+ }
+`;
+const worker = new Worker(URL.createObjectURL(new Blob([workerCode])), {
+ type: "module",
+});
+worker.onmessage = () => {
+ console.log("worker.terminate");
+ worker.terminate();
+};
+worker.postMessage({ moduleCode });
diff --git a/tests/testdata/workers/worker_doest_stall_event_loop.ts.out b/tests/testdata/workers/worker_doest_stall_event_loop.ts.out
new file mode 100644
index 000000000..5ed65b02f
--- /dev/null
+++ b/tests/testdata/workers/worker_doest_stall_event_loop.ts.out
@@ -0,0 +1,6 @@
+worker!
+before import
+module start
+module finish
+after import
+worker.terminate
diff --git a/tests/testdata/workers/worker_error.ts b/tests/testdata/workers/worker_error.ts
new file mode 100644
index 000000000..403223d0a
--- /dev/null
+++ b/tests/testdata/workers/worker_error.ts
@@ -0,0 +1,5 @@
+const worker = new Worker(
+ import.meta.resolve("./error.ts"),
+ { type: "module", name: "bar" },
+);
+setTimeout(() => worker.terminate(), 30000);
diff --git a/tests/testdata/workers/worker_error.ts.out b/tests/testdata/workers/worker_error.ts.out
new file mode 100644
index 000000000..1dd017770
--- /dev/null
+++ b/tests/testdata/workers/worker_error.ts.out
@@ -0,0 +1,5 @@
+[WILDCARD]error: Uncaught (in worker "bar") (in promise) Error: foo[WILDCARD]
+ at foo ([WILDCARD])
+ at [WILDCARD]
+error: Uncaught (in promise) Error: Unhandled error in child worker.
+ at Worker.#pollControl [WILDCARD]
diff --git a/tests/testdata/workers/worker_event_handlers.js b/tests/testdata/workers/worker_event_handlers.js
new file mode 100644
index 000000000..5e457cd2e
--- /dev/null
+++ b/tests/testdata/workers/worker_event_handlers.js
@@ -0,0 +1,26 @@
+self.onmessage = (evt) => {
+ console.log("Target from self.onmessage:", String(evt.target));
+};
+
+self.addEventListener("message", (evt) => {
+ console.log("Target from message event listener:", String(evt.target));
+
+ // Throw an error here so the global's error event will fire.
+ throw new Error("Some error message");
+});
+
+self.onerror = (...args) => {
+ // Take the last 100 characters so the filename doesn't get truncated
+ // depending on the dev's FS structure.
+ args = args.map((v) => typeof v == "string" ? v.slice(-100) : v);
+ console.log("Arguments from self.onerror:", args);
+ return true;
+};
+
+self.addEventListener("error", (evt) => {
+ // Returning true from self.onerror means that subsequent event listeners
+ // should see the event as canceled.
+ console.log("Is event canceled?:", evt.defaultPrevented);
+
+ self.close();
+});
diff --git a/tests/testdata/workers/worker_globals.ts b/tests/testdata/workers/worker_globals.ts
new file mode 100644
index 000000000..90e369e41
--- /dev/null
+++ b/tests/testdata/workers/worker_globals.ts
@@ -0,0 +1,13 @@
+onmessage = function () {
+ postMessage(
+ [
+ self instanceof DedicatedWorkerGlobalScope,
+ self instanceof WorkerGlobalScope,
+ self instanceof EventTarget,
+ // TODO(nayeemrmn): Add `WorkerNavigator` to deno_lint globals.
+ // deno-lint-ignore no-undef
+ navigator instanceof WorkerNavigator,
+ ].join(", "),
+ );
+ close();
+};
diff --git a/tests/testdata/workers/worker_large_message.js b/tests/testdata/workers/worker_large_message.js
new file mode 100644
index 000000000..a1ddae4f9
--- /dev/null
+++ b/tests/testdata/workers/worker_large_message.js
@@ -0,0 +1,14 @@
+// Copyright 2020 the Deno authors. All rights reserved. MIT license.
+
+const dataSmall = "";
+const dataLarge = "x".repeat(10 * 1024);
+
+onmessage = function (_e) {
+ for (let i = 0; i <= 10; i++) {
+ if (i % 2 == 0) {
+ postMessage(dataLarge);
+ } else {
+ postMessage(dataSmall);
+ }
+ }
+};
diff --git a/tests/testdata/workers/worker_location.ts b/tests/testdata/workers/worker_location.ts
new file mode 100644
index 000000000..c3c1bb26f
--- /dev/null
+++ b/tests/testdata/workers/worker_location.ts
@@ -0,0 +1,6 @@
+onmessage = function () {
+ postMessage(
+ `${location.href}, ${location instanceof WorkerLocation}`,
+ );
+ close();
+};
diff --git a/tests/testdata/workers/worker_message_handler_error.ts b/tests/testdata/workers/worker_message_handler_error.ts
new file mode 100644
index 000000000..355d86770
--- /dev/null
+++ b/tests/testdata/workers/worker_message_handler_error.ts
@@ -0,0 +1,8 @@
+const worker = new Worker(
+ import.meta.resolve("./message_handler_error.ts"),
+ { type: "module", name: "foo" },
+);
+worker.onmessage = () => {
+ worker.postMessage("ready");
+};
+setTimeout(() => worker.terminate(), 30000);
diff --git a/tests/testdata/workers/worker_message_handler_error.ts.out b/tests/testdata/workers/worker_message_handler_error.ts.out
new file mode 100644
index 000000000..0f97e9703
--- /dev/null
+++ b/tests/testdata/workers/worker_message_handler_error.ts.out
@@ -0,0 +1,7 @@
+error: Uncaught (in worker "foo") Error: bar
+ throw new Error("bar");
+ ^
+ at onmessage ([WILDCARD]/message_handler_error.ts:[WILDCARD])
+ at [WILDCARD]
+error: Uncaught (in promise) Error: Unhandled error in child worker.
+ at Worker.#pollControl [WILDCARD]
diff --git a/tests/testdata/workers/worker_navigator.ts b/tests/testdata/workers/worker_navigator.ts
new file mode 100644
index 000000000..bd364a8f9
--- /dev/null
+++ b/tests/testdata/workers/worker_navigator.ts
@@ -0,0 +1,11 @@
+onmessage = function () {
+ postMessage(
+ [
+ typeof navigator.language,
+ typeof navigator.languages,
+ typeof navigator.userAgent,
+ typeof navigator.hardwareConcurrency,
+ ].join(", "),
+ );
+ close();
+};
diff --git a/tests/testdata/workers/worker_nested_error.ts b/tests/testdata/workers/worker_nested_error.ts
new file mode 100644
index 000000000..48bdea109
--- /dev/null
+++ b/tests/testdata/workers/worker_nested_error.ts
@@ -0,0 +1,5 @@
+const worker = new Worker(
+ import.meta.resolve("./worker_error.ts"),
+ { type: "module", name: "baz" },
+);
+setTimeout(() => worker.terminate(), 30000);
diff --git a/tests/testdata/workers/worker_nested_error.ts.out b/tests/testdata/workers/worker_nested_error.ts.out
new file mode 100644
index 000000000..3622acfb3
--- /dev/null
+++ b/tests/testdata/workers/worker_nested_error.ts.out
@@ -0,0 +1,9 @@
+[WILDCARD]error: Uncaught (in worker "bar") (in promise) Error: foo[WILDCARD]
+ throw new Error("foo");
+ ^
+ at foo ([WILDCARD]/workers/error.ts:[WILDCARD])
+ at [WILDCARD]/workers/error.ts:[WILDCARD]
+error: Uncaught (in worker "baz") (in promise) Error: Unhandled error in child worker.
+ at Worker.#pollControl [WILDCARD]
+error: Uncaught (in promise) Error: Unhandled error in child worker.
+ at Worker.#pollControl [WILDCARD]
diff --git a/tests/testdata/workers/worker_structured_cloning.ts b/tests/testdata/workers/worker_structured_cloning.ts
new file mode 100644
index 000000000..eb1719a9a
--- /dev/null
+++ b/tests/testdata/workers/worker_structured_cloning.ts
@@ -0,0 +1,15 @@
+// More info on structured cloning can be found here:
+// https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
+
+self.onmessage = () => {
+ const arr = ["a", true, 432];
+ const set = new Set([1, 3, 5, 7, 9]);
+ const selfReference = {
+ a: arr,
+ b: arr,
+ c: set,
+ };
+ // deno-lint-ignore no-explicit-any
+ (selfReference as any).self = selfReference;
+ self.postMessage(selfReference);
+};
diff --git a/tests/testdata/workers/worker_types.ts b/tests/testdata/workers/worker_types.ts
new file mode 100644
index 000000000..b67a3b782
--- /dev/null
+++ b/tests/testdata/workers/worker_types.ts
@@ -0,0 +1,4 @@
+// deno-lint-ignore require-await
+self.onmessage = async (_msg: MessageEvent) => {
+ self.postMessage("hello");
+};
diff --git a/tests/testdata/workers/worker_unstable.ts b/tests/testdata/workers/worker_unstable.ts
new file mode 100644
index 000000000..219f34e7b
--- /dev/null
+++ b/tests/testdata/workers/worker_unstable.ts
@@ -0,0 +1,5 @@
+console.log(Deno.permissions.query);
+console.log(Deno.consoleSize);
+self.onmessage = () => {
+ self.close();
+};
diff --git a/tests/testdata/workers/worker_with_top_level_await.ts b/tests/testdata/workers/worker_with_top_level_await.ts
new file mode 100644
index 000000000..1d20bb736
--- /dev/null
+++ b/tests/testdata/workers/worker_with_top_level_await.ts
@@ -0,0 +1,15 @@
+function delay(ms: number) {
+ return new Promise<void>((resolve) => {
+ setTimeout(() => {
+ resolve();
+ }, ms);
+ });
+}
+
+onmessage = (_e: MessageEvent) => {
+ postMessage("triggered worker handler");
+ close();
+};
+postMessage("ready");
+await delay(1000);
+postMessage("never");