summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/workers
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/workers
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/workers')
-rw-r--r--testing/web-platform/tests/workers/META.yml5
-rw-r--r--testing/web-platform/tests/workers/README.md140
-rw-r--r--testing/web-platform/tests/workers/SharedWorker-MessageEvent-source.any.js6
-rw-r--r--testing/web-platform/tests/workers/SharedWorker-constructor.html60
-rw-r--r--testing/web-platform/tests/workers/SharedWorker-detach-frame-in-error-event.html28
-rw-r--r--testing/web-platform/tests/workers/SharedWorker-exception-propagation.html33
-rw-r--r--testing/web-platform/tests/workers/SharedWorker-exception.html22
-rw-r--r--testing/web-platform/tests/workers/SharedWorker-replace-EventHandler.any.js15
-rw-r--r--testing/web-platform/tests/workers/SharedWorker-script-error.html37
-rw-r--r--testing/web-platform/tests/workers/SharedWorker-simple.html17
-rw-r--r--testing/web-platform/tests/workers/SharedWorkerPerformanceNow.html47
-rw-r--r--testing/web-platform/tests/workers/SharedWorker_blobUrl.html30
-rw-r--r--testing/web-platform/tests/workers/SharedWorker_dataUrl.html63
-rw-r--r--testing/web-platform/tests/workers/Worker-base64.any.js5
-rw-r--r--testing/web-platform/tests/workers/Worker-call.worker.js12
-rw-r--r--testing/web-platform/tests/workers/Worker-constructor-proto.any.js7
-rw-r--r--testing/web-platform/tests/workers/Worker-custom-event.any.js8
-rw-r--r--testing/web-platform/tests/workers/Worker-formdata.any.js19
-rw-r--r--testing/web-platform/tests/workers/Worker-location.sub.any.js14
-rw-r--r--testing/web-platform/tests/workers/Worker-messageport.html69
-rw-r--r--testing/web-platform/tests/workers/Worker-multi-port.html86
-rw-r--r--testing/web-platform/tests/workers/Worker-nested-importScripts-error.html18
-rw-r--r--testing/web-platform/tests/workers/Worker-replace-event-handler.any.js11
-rw-r--r--testing/web-platform/tests/workers/Worker-replace-global-constructor.any.js9
-rw-r--r--testing/web-platform/tests/workers/Worker-replace-self.any.js9
-rw-r--r--testing/web-platform/tests/workers/Worker-simultaneous-errors.html33
-rw-r--r--testing/web-platform/tests/workers/Worker-structure-message.html27
-rw-r--r--testing/web-platform/tests/workers/Worker-terminate-forever-during-evaluation.html69
-rw-r--r--testing/web-platform/tests/workers/Worker-terminate-forever.html11
-rw-r--r--testing/web-platform/tests/workers/Worker-termination-with-port-messages.html22
-rw-r--r--testing/web-platform/tests/workers/Worker-timeout-cancel-order.html17
-rw-r--r--testing/web-platform/tests/workers/Worker-timeout-decreasing-order.html23
-rw-r--r--testing/web-platform/tests/workers/Worker-timeout-increasing-order.html23
-rw-r--r--testing/web-platform/tests/workers/WorkerGlobalScope-close.html81
-rw-r--r--testing/web-platform/tests/workers/WorkerGlobalScope_ErrorEvent_colno.htm18
-rw-r--r--testing/web-platform/tests/workers/WorkerGlobalScope_ErrorEvent_filename.htm20
-rw-r--r--testing/web-platform/tests/workers/WorkerGlobalScope_ErrorEvent_lineno.htm18
-rw-r--r--testing/web-platform/tests/workers/WorkerGlobalScope_ErrorEvent_message.htm19
-rw-r--r--testing/web-platform/tests/workers/WorkerGlobalScope_importScripts.htm14
-rw-r--r--testing/web-platform/tests/workers/WorkerGlobalScope_importScripts_NetworkErr.htm13
-rw-r--r--testing/web-platform/tests/workers/WorkerGlobalScope_importScripts_NosniffErr.htm8
-rw-r--r--testing/web-platform/tests/workers/WorkerGlobalScope_requestAnimationFrame.tentative.worker.js19
-rw-r--r--testing/web-platform/tests/workers/WorkerGlobalScope_setInterval.htm20
-rw-r--r--testing/web-platform/tests/workers/WorkerGlobalScope_setTimeout.htm20
-rw-r--r--testing/web-platform/tests/workers/WorkerLocation-origin.sub.window.js11
-rw-r--r--testing/web-platform/tests/workers/WorkerLocation.htm15
-rw-r--r--testing/web-platform/tests/workers/WorkerLocation_hash.htm13
-rw-r--r--testing/web-platform/tests/workers/WorkerLocation_hash_encoding.htm13
-rw-r--r--testing/web-platform/tests/workers/WorkerLocation_hash_nonexist.htm13
-rw-r--r--testing/web-platform/tests/workers/WorkerLocation_host.htm13
-rw-r--r--testing/web-platform/tests/workers/WorkerLocation_hostname.htm13
-rw-r--r--testing/web-platform/tests/workers/WorkerLocation_href.htm15
-rw-r--r--testing/web-platform/tests/workers/WorkerLocation_pathname.htm15
-rw-r--r--testing/web-platform/tests/workers/WorkerLocation_port.htm13
-rw-r--r--testing/web-platform/tests/workers/WorkerLocation_protocol.htm13
-rw-r--r--testing/web-platform/tests/workers/WorkerLocation_search.htm13
-rw-r--r--testing/web-platform/tests/workers/WorkerLocation_search_empty.htm13
-rw-r--r--testing/web-platform/tests/workers/WorkerLocation_search_fragment.htm13
-rw-r--r--testing/web-platform/tests/workers/WorkerLocation_search_nonexist.htm13
-rw-r--r--testing/web-platform/tests/workers/WorkerNavigator-hardware-concurrency.any.js4
-rw-r--r--testing/web-platform/tests/workers/WorkerNavigator.any.js12
-rw-r--r--testing/web-platform/tests/workers/WorkerNavigator_appName.htm13
-rw-r--r--testing/web-platform/tests/workers/WorkerNavigator_appVersion.htm13
-rw-r--r--testing/web-platform/tests/workers/WorkerNavigator_onLine.htm13
-rw-r--r--testing/web-platform/tests/workers/WorkerNavigator_platform.htm13
-rw-r--r--testing/web-platform/tests/workers/WorkerNavigator_userAgent.htm13
-rw-r--r--testing/web-platform/tests/workers/WorkerNavigator_userAgentData.http.html17
-rw-r--r--testing/web-platform/tests/workers/WorkerNavigator_userAgentData.https.html48
-rw-r--r--testing/web-platform/tests/workers/WorkerPerformanceNow.html26
-rw-r--r--testing/web-platform/tests/workers/Worker_ErrorEvent_bubbles_cancelable.htm22
-rw-r--r--testing/web-platform/tests/workers/Worker_ErrorEvent_error.htm32
-rw-r--r--testing/web-platform/tests/workers/Worker_ErrorEvent_filename.htm20
-rw-r--r--testing/web-platform/tests/workers/Worker_ErrorEvent_lineno.htm18
-rw-r--r--testing/web-platform/tests/workers/Worker_ErrorEvent_message.htm19
-rw-r--r--testing/web-platform/tests/workers/Worker_ErrorEvent_type.htm19
-rw-r--r--testing/web-platform/tests/workers/Worker_NosniffErr.htm13
-rw-r--r--testing/web-platform/tests/workers/Worker_basic.htm31
-rw-r--r--testing/web-platform/tests/workers/Worker_cross_origin_security_err.htm21
-rw-r--r--testing/web-platform/tests/workers/Worker_dispatchEvent_ErrorEvent.htm39
-rw-r--r--testing/web-platform/tests/workers/Worker_script_mimetype.htm42
-rw-r--r--testing/web-platform/tests/workers/Worker_terminate_event_queue.htm23
-rw-r--r--testing/web-platform/tests/workers/abrupt-completion.html55
-rw-r--r--testing/web-platform/tests/workers/baseurl/alpha/import-in-moduleworker.html14
-rw-r--r--testing/web-platform/tests/workers/baseurl/alpha/importScripts-in-sharedworker.html8
-rw-r--r--testing/web-platform/tests/workers/baseurl/alpha/importScripts-in-worker.html8
-rw-r--r--testing/web-platform/tests/workers/baseurl/alpha/sharedworker-in-worker.html14
-rw-r--r--testing/web-platform/tests/workers/baseurl/alpha/worker-in-worker.html14
-rw-r--r--testing/web-platform/tests/workers/baseurl/alpha/xhr-in-moduleworker.html14
-rw-r--r--testing/web-platform/tests/workers/baseurl/alpha/xhr-in-sharedworker.html8
-rw-r--r--testing/web-platform/tests/workers/baseurl/alpha/xhr-in-worker.html8
-rw-r--r--testing/web-platform/tests/workers/baseurl/beta/import.py3
-rw-r--r--testing/web-platform/tests/workers/baseurl/beta/importScripts.py3
-rw-r--r--testing/web-platform/tests/workers/baseurl/beta/script.js1
-rw-r--r--testing/web-platform/tests/workers/baseurl/beta/sharedworker.py3
-rw-r--r--testing/web-platform/tests/workers/baseurl/beta/subsharedworker.js3
-rw-r--r--testing/web-platform/tests/workers/baseurl/beta/subworker.js1
-rw-r--r--testing/web-platform/tests/workers/baseurl/beta/test.txt1
-rw-r--r--testing/web-platform/tests/workers/baseurl/beta/worker.py3
-rw-r--r--testing/web-platform/tests/workers/baseurl/beta/xhr-worker.py2
-rw-r--r--testing/web-platform/tests/workers/baseurl/beta/xhr.py3
-rw-r--r--testing/web-platform/tests/workers/baseurl/gamma/import.js2
-rw-r--r--testing/web-platform/tests/workers/baseurl/gamma/importScripts.js6
-rw-r--r--testing/web-platform/tests/workers/baseurl/gamma/script-module.js1
-rw-r--r--testing/web-platform/tests/workers/baseurl/gamma/script.js1
-rw-r--r--testing/web-platform/tests/workers/baseurl/gamma/sharedworker.js4
-rw-r--r--testing/web-platform/tests/workers/baseurl/gamma/subsharedworker.js3
-rw-r--r--testing/web-platform/tests/workers/baseurl/gamma/subworker.js1
-rw-r--r--testing/web-platform/tests/workers/baseurl/gamma/test.txt1
-rw-r--r--testing/web-platform/tests/workers/baseurl/gamma/worker.js4
-rw-r--r--testing/web-platform/tests/workers/baseurl/gamma/xhr-worker.js8
-rw-r--r--testing/web-platform/tests/workers/baseurl/gamma/xhr.js4
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/13
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/1.headers1
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/Infinity3
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/Infinity-arguments.html13
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/Infinity.headers1
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/NaN3
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/NaN-arguments.html13
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/NaN.headers1
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/SharedWorker-constructor.html28
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/URLMismatchError.htm31
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/connect-event.html14
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/connect-event.js3
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/dummy-name.html10
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/dummy-shared-worker.html10
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/dummy-shared-worker.js0
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/empty-name.html10
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/empty.js0
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/global-members.html12
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/global-members.js9
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/interface-objects.html20
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/interface-objects.js13
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/name.html12
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/name.js3
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/no-arguments-ctor.html13
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/null3
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/null-arguments.html13
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/null.headers1
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/number-arguments.html13
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/port-onmessage.html12
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/port-onmessage.js3
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/port-properties.html19
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/port-readonly.html14
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/same-origin.html62
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/setting-port-members.html53
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/shared-worker.js6
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/undefined3
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/undefined-arguments.html13
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/undefined.headers1
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/unexpected-global-properties.html12
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/unexpected-global-properties.js9
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/unresolvable-url.html12
-rw-r--r--testing/web-platform/tests/workers/constructors/Worker/11
-rw-r--r--testing/web-platform/tests/workers/constructors/Worker/1.headers1
-rw-r--r--testing/web-platform/tests/workers/constructors/Worker/AbstractWorker.onerror.html37
-rw-r--r--testing/web-platform/tests/workers/constructors/Worker/AbstractWorker.onerror.js5
-rw-r--r--testing/web-platform/tests/workers/constructors/Worker/Blob-url.html21
-rw-r--r--testing/web-platform/tests/workers/constructors/Worker/DedicatedWorkerGlobalScope-members.worker.js18
-rw-r--r--testing/web-platform/tests/workers/constructors/Worker/Worker-constructor.html60
-rw-r--r--testing/web-platform/tests/workers/constructors/Worker/ctor-1.html23
-rw-r--r--testing/web-platform/tests/workers/constructors/Worker/ctor-null.html23
-rw-r--r--testing/web-platform/tests/workers/constructors/Worker/ctor-undefined.html23
-rw-r--r--testing/web-platform/tests/workers/constructors/Worker/expected-self-properties.worker.js11
-rw-r--r--testing/web-platform/tests/workers/constructors/Worker/null1
-rw-r--r--testing/web-platform/tests/workers/constructors/Worker/null.headers1
-rw-r--r--testing/web-platform/tests/workers/constructors/Worker/same-origin.html65
-rw-r--r--testing/web-platform/tests/workers/constructors/Worker/sample_worker/worker.js1
-rw-r--r--testing/web-platform/tests/workers/constructors/Worker/terminate.html34
-rw-r--r--testing/web-platform/tests/workers/constructors/Worker/terminate.js4
-rw-r--r--testing/web-platform/tests/workers/constructors/Worker/undefined1
-rw-r--r--testing/web-platform/tests/workers/constructors/Worker/undefined.headers1
-rw-r--r--testing/web-platform/tests/workers/constructors/Worker/unexpected-self-properties.worker.js11
-rw-r--r--testing/web-platform/tests/workers/constructors/Worker/use-base-url.html18
-rw-r--r--testing/web-platform/tests/workers/data-url-shared-window.html25
-rw-r--r--testing/web-platform/tests/workers/data-url-shared.html78
-rw-r--r--testing/web-platform/tests/workers/data-url.html67
-rw-r--r--testing/web-platform/tests/workers/dedicated-worker-from-blob-url.window.js29
-rw-r--r--testing/web-platform/tests/workers/dedicated-worker-in-data-url-context.window.js111
-rw-r--r--testing/web-platform/tests/workers/dedicated-worker-parse-error-failure.html27
-rw-r--r--testing/web-platform/tests/workers/examples/fetch_tests_from_worker.html21
-rw-r--r--testing/web-platform/tests/workers/examples/fetch_tests_from_worker.js28
-rw-r--r--testing/web-platform/tests/workers/examples/general.any.js34
-rw-r--r--testing/web-platform/tests/workers/examples/general.worker.js35
-rw-r--r--testing/web-platform/tests/workers/examples/onconnect.any.js4
-rw-r--r--testing/web-platform/tests/workers/importscripts_mime.any.js52
-rw-r--r--testing/web-platform/tests/workers/importscripts_mime_local.any.js66
-rw-r--r--testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/EventTarget.worker.js23
-rw-r--r--testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/onmessage.worker.js40
-rw-r--r--testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/event-ports-dedicated.html15
-rw-r--r--testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/event-ports-dedicated.js3
-rw-r--r--testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/imagedata-cloned-canvas-in-array.html22
-rw-r--r--testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/imagedata-cloned-canvas-in-array.js10
-rw-r--r--testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/message-event.html23
-rw-r--r--testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/message-event.js1
-rw-r--r--testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/return-value.worker.js8
-rw-r--r--testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-dictionary.html16
-rw-r--r--testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-dictionary.js7
-rw-r--r--testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-null-in-array.html14
-rw-r--r--testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-null-in-array.js5
-rw-r--r--testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-null.html14
-rw-r--r--testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-null.js5
-rw-r--r--testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-undefined.html14
-rw-r--r--testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-undefined.js5
-rw-r--r--testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/setting-postMessage.html14
-rw-r--r--testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/setting-postMessage.js3
-rw-r--r--testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/structured-clone-imagedata.html18
-rw-r--r--testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/structured-clone-imagedata.js5
-rw-r--r--testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/structured-clone-message.html38
-rw-r--r--testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/structured-clone-message.js14
-rw-r--r--testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/name/getting.html17
-rw-r--r--testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/name/getting.js9
-rw-r--r--testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/name/setting.html15
-rw-r--r--testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/name/setting.js4
-rw-r--r--testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/onconnect.html14
-rw-r--r--testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/onconnect.js19
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/incoming-message.html18
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/incoming-message.js5
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/sending-messages.html18
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/sending-messages.js3
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/setInterval.html17
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/setInterval.js11
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/setTimeout.html17
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/setTimeout.js7
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/helper-redirect.py3
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/members.html22
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/members.js3
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/post-location-members.js8
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/redirect-module.html20
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/redirect-sharedworker.html9
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/redirect.html28
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/redirect.js7
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/returns-same-object.any.js5
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/setting-members.html23
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/setting-members.js13
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/worker-separate-file.html28
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.html91
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/handled.html22
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/handled.js8
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/message-classic-DOMException.html7
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/message-classic-Error.html7
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/message-helper.js61
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/message-module-DOMException.html7
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/message-module-Error.html7
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/not-handled.html28
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/not-handled.js7
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/propagate-to-window-onerror.html21
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/propagate-to-window-onerror.js4
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/throw.js34
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/self.any.js19
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/001.html14
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/001.js1
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/002.html13
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/002.js2
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/003.html14
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/003.js1
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/004.html13
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/004.js4
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/005.html14
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/005.js3
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/001.worker.js7
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/002.worker.js11
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/003.html14
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/003.js8
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/004.html15
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/004.js13
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/005.html15
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/005.js9
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/006.html17
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/006.js11
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/007.html17
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/007.js2
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/008.html14
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/008.js3
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/009.html20
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/009.js3
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/010.html17
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/010.js11
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/011.html17
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/011.js11
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/012.html17
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/012.js11
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/11
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/1.headers1
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/blob-url.worker.js40
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/catch.sub.any.js47
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/null1
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/null.headers1
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-cross-origin.sub.any.js8
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-helper.js80
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-redirect-to-cross-origin.sub.any.js9
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-same-origin.sub.any.js7
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-cross-origin.sub.any.js8
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-redirect-to-cross-origin.sub.any.js9
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-same-origin.sub.any.js7
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/undefined1
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/undefined.headers1
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/002.html14
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/002.js1
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/003.html14
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/003.js1
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/004.html14
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/004.js1
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/005.html14
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/005.js1
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/006.html14
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/006.js1
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/007.html14
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/007.js11
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/008.worker.js12
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/language.html14
-rw-r--r--testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/language.js1
-rw-r--r--testing/web-platform/tests/workers/modules/dedicated-worker-import-blob-url.any.js26
-rw-r--r--testing/web-platform/tests/workers/modules/dedicated-worker-import-csp.html138
-rw-r--r--testing/web-platform/tests/workers/modules/dedicated-worker-import-data-url-cross-origin.html45
-rw-r--r--testing/web-platform/tests/workers/modules/dedicated-worker-import-data-url.any.js25
-rw-r--r--testing/web-platform/tests/workers/modules/dedicated-worker-import-failure.html57
-rw-r--r--testing/web-platform/tests/workers/modules/dedicated-worker-import-meta.html59
-rw-r--r--testing/web-platform/tests/workers/modules/dedicated-worker-import-referrer.html244
-rw-r--r--testing/web-platform/tests/workers/modules/dedicated-worker-import.any.js22
-rw-r--r--testing/web-platform/tests/workers/modules/dedicated-worker-options-credentials.html304
-rw-r--r--testing/web-platform/tests/workers/modules/dedicated-worker-options-credentials.html.headers2
-rw-r--r--testing/web-platform/tests/workers/modules/dedicated-worker-options-type.html46
-rw-r--r--testing/web-platform/tests/workers/modules/dedicated-worker-parse-error-failure.html51
-rw-r--r--testing/web-platform/tests/workers/modules/resources/dynamic-import-and-then-static-import-worker.js32
-rw-r--r--testing/web-platform/tests/workers/modules/resources/dynamic-import-data-url-block-cross-origin.js24
-rw-r--r--testing/web-platform/tests/workers/modules/resources/dynamic-import-given-url-worker.js21
-rw-r--r--testing/web-platform/tests/workers/modules/resources/dynamic-import-remote-origin-credentials-checker-worker.sub.js15
-rw-r--r--testing/web-platform/tests/workers/modules/resources/dynamic-import-remote-origin-referrer-checker-worker.sub.js16
-rw-r--r--testing/web-platform/tests/workers/modules/resources/dynamic-import-remote-origin-script-worker.sub.js17
-rw-r--r--testing/web-platform/tests/workers/modules/resources/dynamic-import-same-origin-credentials-checker-worker.js13
-rw-r--r--testing/web-platform/tests/workers/modules/resources/dynamic-import-same-origin-referrer-checker-worker.js15
-rw-r--r--testing/web-platform/tests/workers/modules/resources/dynamic-import-script-block-cross-origin.js24
-rw-r--r--testing/web-platform/tests/workers/modules/resources/dynamic-import-worker.js32
-rw-r--r--testing/web-platform/tests/workers/modules/resources/empty-worker.js1
-rw-r--r--testing/web-platform/tests/workers/modules/resources/eval-dynamic-import-worker.js29
-rw-r--r--testing/web-platform/tests/workers/modules/resources/export-block-cross-origin.js1
-rw-r--r--testing/web-platform/tests/workers/modules/resources/export-credentials.py15
-rw-r--r--testing/web-platform/tests/workers/modules/resources/export-on-dynamic-import-script.js8
-rw-r--r--testing/web-platform/tests/workers/modules/resources/export-on-dynamic-import-script.js.headers1
-rw-r--r--testing/web-platform/tests/workers/modules/resources/export-on-load-script.js1
-rw-r--r--testing/web-platform/tests/workers/modules/resources/export-on-load-script.js.headers1
-rw-r--r--testing/web-platform/tests/workers/modules/resources/export-on-load-script.py15
-rw-r--r--testing/web-platform/tests/workers/modules/resources/export-on-static-import-script.js3
-rw-r--r--testing/web-platform/tests/workers/modules/resources/export-on-static-import-script.js.headers1
-rw-r--r--testing/web-platform/tests/workers/modules/resources/export-referrer-checker.py9
-rw-r--r--testing/web-platform/tests/workers/modules/resources/import-meta-url-export.js1
-rw-r--r--testing/web-platform/tests/workers/modules/resources/import-meta-url-worker.js10
-rw-r--r--testing/web-platform/tests/workers/modules/resources/import-scripts-worker.js33
-rw-r--r--testing/web-platform/tests/workers/modules/resources/import-test-cases.js59
-rw-r--r--testing/web-platform/tests/workers/modules/resources/nested-dynamic-import-worker.js34
-rw-r--r--testing/web-platform/tests/workers/modules/resources/nested-static-import-worker.js21
-rw-r--r--testing/web-platform/tests/workers/modules/resources/new-shared-worker-window.html19
-rw-r--r--testing/web-platform/tests/workers/modules/resources/new-worker-window.html19
-rw-r--r--testing/web-platform/tests/workers/modules/resources/post-message-on-load-worker.js10
-rw-r--r--testing/web-platform/tests/workers/modules/resources/postmessage-credentials.py22
-rw-r--r--testing/web-platform/tests/workers/modules/resources/postmessage-referrer-checker.py16
-rw-r--r--testing/web-platform/tests/workers/modules/resources/redirect.py8
-rw-r--r--testing/web-platform/tests/workers/modules/resources/static-import-and-then-dynamic-import-worker.js34
-rw-r--r--testing/web-platform/tests/workers/modules/resources/static-import-data-url-block-cross-origin.js14
-rw-r--r--testing/web-platform/tests/workers/modules/resources/static-import-non-existent-script-worker.js1
-rw-r--r--testing/web-platform/tests/workers/modules/resources/static-import-redirect-worker.js21
-rw-r--r--testing/web-platform/tests/workers/modules/resources/static-import-remote-origin-credentials-checker-worker.sub.js12
-rw-r--r--testing/web-platform/tests/workers/modules/resources/static-import-remote-origin-referrer-checker-worker.sub.js12
-rw-r--r--testing/web-platform/tests/workers/modules/resources/static-import-remote-origin-script-worker.sub.js20
-rw-r--r--testing/web-platform/tests/workers/modules/resources/static-import-same-origin-credentials-checker-worker.js11
-rw-r--r--testing/web-platform/tests/workers/modules/resources/static-import-same-origin-referrer-checker-worker.js11
-rw-r--r--testing/web-platform/tests/workers/modules/resources/static-import-script-block-cross-origin.js14
-rw-r--r--testing/web-platform/tests/workers/modules/resources/static-import-syntax-error.js1
-rw-r--r--testing/web-platform/tests/workers/modules/resources/static-import-worker.js21
-rw-r--r--testing/web-platform/tests/workers/modules/resources/syntax-error.js1
-rw-r--r--testing/web-platform/tests/workers/modules/resources/throw.js1
-rw-r--r--testing/web-platform/tests/workers/modules/shared-worker-import-blob-url.window.js26
-rw-r--r--testing/web-platform/tests/workers/modules/shared-worker-import-csp.html128
-rw-r--r--testing/web-platform/tests/workers/modules/shared-worker-import-data-url-cross-origin.html46
-rw-r--r--testing/web-platform/tests/workers/modules/shared-worker-import-data-url.window.js25
-rw-r--r--testing/web-platform/tests/workers/modules/shared-worker-import-failure.html70
-rw-r--r--testing/web-platform/tests/workers/modules/shared-worker-import-meta.html49
-rw-r--r--testing/web-platform/tests/workers/modules/shared-worker-import-referrer.html259
-rw-r--r--testing/web-platform/tests/workers/modules/shared-worker-import.window.js22
-rw-r--r--testing/web-platform/tests/workers/modules/shared-worker-options-credentials.html309
-rw-r--r--testing/web-platform/tests/workers/modules/shared-worker-options-credentials.html.headers2
-rw-r--r--testing/web-platform/tests/workers/modules/shared-worker-options-type.html48
-rw-r--r--testing/web-platform/tests/workers/modules/shared-worker-parse-error-failure.html53
-rw-r--r--testing/web-platform/tests/workers/multi-globals/current/current.html3
-rw-r--r--testing/web-platform/tests/workers/multi-globals/current/worker.js1
-rw-r--r--testing/web-platform/tests/workers/multi-globals/incumbent/incumbent.html14
-rw-r--r--testing/web-platform/tests/workers/multi-globals/incumbent/worker.js1
-rw-r--r--testing/web-platform/tests/workers/multi-globals/url-parsing.html20
-rw-r--r--testing/web-platform/tests/workers/multi-globals/worker.js1
-rw-r--r--testing/web-platform/tests/workers/name-property.html30
-rw-r--r--testing/web-platform/tests/workers/nested_worker.worker.js11
-rw-r--r--testing/web-platform/tests/workers/nested_worker_close_from_parent_worker.html15
-rw-r--r--testing/web-platform/tests/workers/nested_worker_close_self.worker.js12
-rw-r--r--testing/web-platform/tests/workers/nested_worker_importScripts.worker.js11
-rw-r--r--testing/web-platform/tests/workers/nested_worker_sync_xhr.worker.js11
-rw-r--r--testing/web-platform/tests/workers/nested_worker_terminate_from_document.html14
-rw-r--r--testing/web-platform/tests/workers/non-automated/infinite-nested.html12
-rw-r--r--testing/web-platform/tests/workers/non-automated/infinite-nested.js5
-rw-r--r--testing/web-platform/tests/workers/non-automated/infinite-sibling-and-nested.html12
-rw-r--r--testing/web-platform/tests/workers/non-automated/infinite-sibling-and-nested.js8
-rw-r--r--testing/web-platform/tests/workers/non-automated/infinite-sibling.html12
-rw-r--r--testing/web-platform/tests/workers/non-automated/infinite-sibling.js8
-rw-r--r--testing/web-platform/tests/workers/non-automated/navigator-onLine.html29
-rw-r--r--testing/web-platform/tests/workers/non-automated/navigator-onLine.js11
-rw-r--r--testing/web-platform/tests/workers/non-automated/post-a-1.js1
-rw-r--r--testing/web-platform/tests/workers/opaque-origin.html17
-rw-r--r--testing/web-platform/tests/workers/postMessage_DataCloneErr.htm13
-rw-r--r--testing/web-platform/tests/workers/postMessage_block.https.html18
-rw-r--r--testing/web-platform/tests/workers/postMessage_block.https.html.headers2
-rw-r--r--testing/web-platform/tests/workers/postMessage_clone_port.htm22
-rw-r--r--testing/web-platform/tests/workers/postMessage_clone_port_error.htm14
-rw-r--r--testing/web-platform/tests/workers/postMessage_event_properties.htm24
-rw-r--r--testing/web-platform/tests/workers/postMessage_ports_readonly_array.htm22
-rw-r--r--testing/web-platform/tests/workers/postMessage_target_source.htm18
-rw-r--r--testing/web-platform/tests/workers/same-origin-check.sub.html56
-rw-r--r--testing/web-platform/tests/workers/same-site-cookies/first-party.all.tentative.https.window.js19
-rw-r--r--testing/web-platform/tests/workers/same-site-cookies/first-party.default.tentative.https.window.js19
-rw-r--r--testing/web-platform/tests/workers/same-site-cookies/first-party.none.tentative.https.window.js19
-rw-r--r--testing/web-platform/tests/workers/same-site-cookies/resources/iframe-iframe.html31
-rw-r--r--testing/web-platform/tests/workers/same-site-cookies/resources/iframe.sub.html14
-rw-r--r--testing/web-platform/tests/workers/same-site-cookies/resources/worker.js5
-rw-r--r--testing/web-platform/tests/workers/same-site-cookies/third-party.all.tentative.sub.https.window.js24
-rw-r--r--testing/web-platform/tests/workers/same-site-cookies/third-party.default.tentative.sub.https.window.js24
-rw-r--r--testing/web-platform/tests/workers/same-site-cookies/third-party.none.tentative.sub.https.window.js24
-rw-r--r--testing/web-platform/tests/workers/semantics/encodings/001.html14
-rw-r--r--testing/web-platform/tests/workers/semantics/encodings/001.js1
-rw-r--r--testing/web-platform/tests/workers/semantics/encodings/001.js.headers1
-rw-r--r--testing/web-platform/tests/workers/semantics/encodings/002.html14
-rw-r--r--testing/web-platform/tests/workers/semantics/encodings/002.js3
-rw-r--r--testing/web-platform/tests/workers/semantics/encodings/002.js.headers1
-rw-r--r--testing/web-platform/tests/workers/semantics/encodings/003-1.py4
-rw-r--r--testing/web-platform/tests/workers/semantics/encodings/003.html14
-rw-r--r--testing/web-platform/tests/workers/semantics/encodings/003.js5
-rw-r--r--testing/web-platform/tests/workers/semantics/encodings/004.html14
-rw-r--r--testing/web-platform/tests/workers/semantics/encodings/004.js7
-rw-r--r--testing/web-platform/tests/workers/semantics/encodings/004.worker.js5
-rw-r--r--testing/web-platform/tests/workers/semantics/interface-objects/001.worker.js81
-rw-r--r--testing/web-platform/tests/workers/semantics/interface-objects/002.worker.js45
-rw-r--r--testing/web-platform/tests/workers/semantics/interface-objects/003.any.js81
-rw-r--r--testing/web-platform/tests/workers/semantics/interface-objects/004.any.js41
-rw-r--r--testing/web-platform/tests/workers/semantics/multiple-workers/001.html23
-rw-r--r--testing/web-platform/tests/workers/semantics/multiple-workers/001.js11
-rw-r--r--testing/web-platform/tests/workers/semantics/multiple-workers/002.html21
-rw-r--r--testing/web-platform/tests/workers/semantics/multiple-workers/002.js1
-rw-r--r--testing/web-platform/tests/workers/semantics/multiple-workers/003.html16
-rw-r--r--testing/web-platform/tests/workers/semantics/multiple-workers/003.js13
-rw-r--r--testing/web-platform/tests/workers/semantics/multiple-workers/004-1.html7
-rw-r--r--testing/web-platform/tests/workers/semantics/multiple-workers/004-2.js6
-rw-r--r--testing/web-platform/tests/workers/semantics/multiple-workers/004.html37
-rw-r--r--testing/web-platform/tests/workers/semantics/multiple-workers/008-1.html8
-rw-r--r--testing/web-platform/tests/workers/semantics/multiple-workers/008.html19
-rw-r--r--testing/web-platform/tests/workers/semantics/multiple-workers/008.js6
-rw-r--r--testing/web-platform/tests/workers/semantics/multiple-workers/exposure.any.js11
-rw-r--r--testing/web-platform/tests/workers/semantics/navigation/001-1.html15
-rw-r--r--testing/web-platform/tests/workers/semantics/navigation/001-1.js1
-rw-r--r--testing/web-platform/tests/workers/semantics/navigation/001.html39
-rw-r--r--testing/web-platform/tests/workers/semantics/navigation/002.html38
-rw-r--r--testing/web-platform/tests/workers/semantics/reporting-errors/001.html17
-rw-r--r--testing/web-platform/tests/workers/semantics/reporting-errors/001.js28
-rw-r--r--testing/web-platform/tests/workers/semantics/reporting-errors/002.html17
-rw-r--r--testing/web-platform/tests/workers/semantics/reporting-errors/002.js34
-rw-r--r--testing/web-platform/tests/workers/semantics/reporting-errors/003.html23
-rw-r--r--testing/web-platform/tests/workers/semantics/reporting-errors/003.js8
-rw-r--r--testing/web-platform/tests/workers/semantics/reporting-errors/004-1.html18
-rw-r--r--testing/web-platform/tests/workers/semantics/reporting-errors/004.html26
-rw-r--r--testing/web-platform/tests/workers/semantics/reporting-errors/004.js6
-rw-r--r--testing/web-platform/tests/workers/semantics/run-a-worker/001.html14
-rw-r--r--testing/web-platform/tests/workers/semantics/run-a-worker/001.js1
-rw-r--r--testing/web-platform/tests/workers/semantics/run-a-worker/002.html14
-rw-r--r--testing/web-platform/tests/workers/semantics/run-a-worker/002.js4
-rw-r--r--testing/web-platform/tests/workers/semantics/run-a-worker/003.html15
-rw-r--r--testing/web-platform/tests/workers/semantics/structured-clone/dedicated.html33
-rw-r--r--testing/web-platform/tests/workers/semantics/structured-clone/shared.html37
-rw-r--r--testing/web-platform/tests/workers/semantics/xhr/001-1.xml1
-rw-r--r--testing/web-platform/tests/workers/semantics/xhr/001.html16
-rw-r--r--testing/web-platform/tests/workers/semantics/xhr/001.js13
-rw-r--r--testing/web-platform/tests/workers/semantics/xhr/002.html16
-rw-r--r--testing/web-platform/tests/workers/semantics/xhr/002.js9
-rw-r--r--testing/web-platform/tests/workers/semantics/xhr/003.html16
-rw-r--r--testing/web-platform/tests/workers/semantics/xhr/003.js17
-rw-r--r--testing/web-platform/tests/workers/semantics/xhr/004.html16
-rw-r--r--testing/web-platform/tests/workers/semantics/xhr/004.js11
-rw-r--r--testing/web-platform/tests/workers/semantics/xhr/005.html21
-rw-r--r--testing/web-platform/tests/workers/semantics/xhr/006.html21
-rw-r--r--testing/web-platform/tests/workers/semantics/xhr/support/001-1.xml1
-rw-r--r--testing/web-platform/tests/workers/semantics/xhr/support/005-1.js5
-rw-r--r--testing/web-platform/tests/workers/semantics/xhr/support/006-1.js7
-rw-r--r--testing/web-platform/tests/workers/shared-worker-from-blob-url.window.js53
-rw-r--r--testing/web-platform/tests/workers/shared-worker-in-data-url-context.window.js65
-rw-r--r--testing/web-platform/tests/workers/shared-worker-name-via-options.html38
-rw-r--r--testing/web-platform/tests/workers/shared-worker-options-mismatch.html59
-rw-r--r--testing/web-platform/tests/workers/shared-worker-parse-error-failure.html26
-rw-r--r--testing/web-platform/tests/workers/shared-worker-partitioned-cookies.tentative.https.html62
-rw-r--r--testing/web-platform/tests/workers/shared-worker-partitioned.tentative.html30
-rw-r--r--testing/web-platform/tests/workers/support/ErrorEvent-error.js9
-rw-r--r--testing/web-platform/tests/workers/support/ErrorEvent.js10
-rw-r--r--testing/web-platform/tests/workers/support/ImportScripts.js9
-rw-r--r--testing/web-platform/tests/workers/support/ImportScriptsNetworkErr.js15
-rw-r--r--testing/web-platform/tests/workers/support/ImportScriptsNosniffErr.js9
-rw-r--r--testing/web-platform/tests/workers/support/SharedWorker-common.js32
-rw-r--r--testing/web-platform/tests/workers/support/SharedWorker-create-common.js8
-rw-r--r--testing/web-platform/tests/workers/support/SharedWorker-script-error.js22
-rw-r--r--testing/web-platform/tests/workers/support/Timer.js50
-rw-r--r--testing/web-platform/tests/workers/support/Worker-common.js16
-rw-r--r--testing/web-platform/tests/workers/support/Worker-create-common.js4
-rw-r--r--testing/web-platform/tests/workers/support/Worker-messageport.js40
-rw-r--r--testing/web-platform/tests/workers/support/Worker-run-forever-during-dynamic-import.js3
-rw-r--r--testing/web-platform/tests/workers/support/Worker-run-forever-during-importScripts.js4
-rw-r--r--testing/web-platform/tests/workers/support/Worker-run-forever-during-nested-importScripts.js1
-rw-r--r--testing/web-platform/tests/workers/support/Worker-run-forever-during-top-level-await.js4
-rw-r--r--testing/web-platform/tests/workers/support/Worker-run-forever.js3
-rw-r--r--testing/web-platform/tests/workers/support/Worker-structure-message.js15
-rw-r--r--testing/web-platform/tests/workers/support/Worker-termination-with-port-messages.js10
-rw-r--r--testing/web-platform/tests/workers/support/Worker-thread-multi-port.js43
-rw-r--r--testing/web-platform/tests/workers/support/Worker-timeout-cancel-order.js7
-rw-r--r--testing/web-platform/tests/workers/support/Worker-timeout-decreasing-order.js7
-rw-r--r--testing/web-platform/tests/workers/support/Worker-timeout-increasing-order.js7
-rw-r--r--testing/web-platform/tests/workers/support/WorkerBasic.js7
-rw-r--r--testing/web-platform/tests/workers/support/WorkerClose.js5
-rw-r--r--testing/web-platform/tests/workers/support/WorkerDataCloneErr.js15
-rw-r--r--testing/web-platform/tests/workers/support/WorkerFetchURL.js8
-rw-r--r--testing/web-platform/tests/workers/support/WorkerGlobalScope-close.js43
-rw-r--r--testing/web-platform/tests/workers/support/WorkerLocation-origin.html6
-rw-r--r--testing/web-platform/tests/workers/support/WorkerLocation.js13
-rw-r--r--testing/web-platform/tests/workers/support/WorkerNavigator.js27
-rw-r--r--testing/web-platform/tests/workers/support/WorkerSendingPerformanceNow.js22
-rw-r--r--testing/web-platform/tests/workers/support/WorkerTerminate.js10
-rw-r--r--testing/web-platform/tests/workers/support/WorkerText.txt2
-rw-r--r--testing/web-platform/tests/workers/support/abrupt-completion.js21
-rw-r--r--testing/web-platform/tests/workers/support/check-error-arguments.js4
-rw-r--r--testing/web-platform/tests/workers/support/empty-worker.js1
-rw-r--r--testing/web-platform/tests/workers/support/iframe-sw-shared-name.html19
-rw-r--r--testing/web-platform/tests/workers/support/iframe_sw_dataUrl.html13
-rw-r--r--testing/web-platform/tests/workers/support/importScripts-1.js1
-rw-r--r--testing/web-platform/tests/workers/support/importScripts-2.js1
-rw-r--r--testing/web-platform/tests/workers/support/importScripts-3.js1
-rw-r--r--testing/web-platform/tests/workers/support/imported_script.py2
-rw-r--r--testing/web-platform/tests/workers/support/invalidScript.js1
-rw-r--r--testing/web-platform/tests/workers/support/name-as-accidental-global.js9
-rw-r--r--testing/web-platform/tests/workers/support/name.js18
-rw-r--r--testing/web-platform/tests/workers/support/nosiniff-error-worker.py3
-rw-r--r--testing/web-platform/tests/workers/support/parent_of_nested_worker.js14
-rw-r--r--testing/web-platform/tests/workers/support/post-message-on-load-worker.js10
-rw-r--r--testing/web-platform/tests/workers/support/postMessage_block_worker.js2
-rw-r--r--testing/web-platform/tests/workers/support/postMessage_block_worker.js.headers1
-rw-r--r--testing/web-platform/tests/workers/support/sandboxed-tests.html67
-rw-r--r--testing/web-platform/tests/workers/support/shared-name.js8
-rw-r--r--testing/web-platform/tests/workers/support/shared-worker-echo-cookies.js40
-rw-r--r--testing/web-platform/tests/workers/support/shared-worker-partitioned-cookies-3p-frame.html43
-rw-r--r--testing/web-platform/tests/workers/support/shared-worker-partitioned-cookies-3p-window.html26
-rw-r--r--testing/web-platform/tests/workers/support/shared-worker-partitioned-cookies-helper.js28
-rw-r--r--testing/web-platform/tests/workers/support/sync_xhr.js13
-rw-r--r--testing/web-platform/tests/workers/support/sync_xhr_target.xml1
-rw-r--r--testing/web-platform/tests/workers/support/throw-on-message-Worker.js11
-rw-r--r--testing/web-platform/tests/workers/support/window-sw-shared-name.html22
-rw-r--r--testing/web-platform/tests/workers/support/worker-request-animation-frame.js6
-rw-r--r--testing/web-platform/tests/workers/worker-performance.worker.js129
-rw-r--r--testing/web-platform/tests/workers/worker-request-animation-frame.html27
558 files changed, 11033 insertions, 0 deletions
diff --git a/testing/web-platform/tests/workers/META.yml b/testing/web-platform/tests/workers/META.yml
new file mode 100644
index 0000000000..b5b28235ce
--- /dev/null
+++ b/testing/web-platform/tests/workers/META.yml
@@ -0,0 +1,5 @@
+spec: https://html.spec.whatwg.org/multipage/workers.html
+suggested_reviewers:
+ - caitp
+ - jdm
+ - annevk
diff --git a/testing/web-platform/tests/workers/README.md b/testing/web-platform/tests/workers/README.md
new file mode 100644
index 0000000000..58ee7cca1a
--- /dev/null
+++ b/testing/web-platform/tests/workers/README.md
@@ -0,0 +1,140 @@
+# Worker WPT tests
+
+These are the workers (`Worker`, `SharedWorker`) tests for the
+[Web workers chapter of the HTML Standard](https://html.spec.whatwg.org/multipage/workers.html).
+
+See also
+[testharness.js API > Web Workers](https://web-platform-tests.org/writing-tests/testharness-api.html#web-workers).
+
+Note that because workers are defined in the HTML Standard, the idlharness.js
+tests are in [/html/dom]([/html/dom) instead of here.
+
+## Writing `*.any.js`
+
+The easiest and most recommended way to write tests for workers
+is to create .any.js-style tests.
+
+Official doc:
+[WPT > File Name Flags > Test Features](https://web-platform-tests.org/writing-tests/file-names.html#test-features).
+
+- Standard `testharness.js`-style can be used (and is enforced).
+- The same test can be run on window and many types of workers.
+- All glue code are automatically generated.
+- No need to care about how to create and communicate with each type of workers,
+ thanks to `fetch_tests_from_worker` in `testharness.js`.
+
+Converting existing tests into `.any.js`-style also has benefits:
+
+- Multiple tests can be merged into one.
+- Tests written for window can be run on workers
+ with a very low development cost.
+
+### How to write tests
+
+If you write `testharness.js`-based tests in `foo.any.js` and
+specify types of workers to be tested,
+the test can run on any of dedicated, shared and service workers.
+
+See `examples/general.any.js` for example.
+
+Even for testing specific features in a specific type of workers
+(e.g. shared worker's `onconnect`), `.any.js`-style tests can be used.
+
+See `examples/onconnect.any.js` for example.
+
+### How to debug tests
+
+Whether each individual test passed or failed,
+and its assertion failures (if any) are all reported in the final results.
+
+`console.log()` might not appear in the test results and
+thus might not be useful for printf debugging.
+For example, in Chromium, this message
+
+- Appears (in stderr) on a window or a dedicated worker, but
+- Does NOT appear on a shared worker or a service worker.
+
+### How it works
+
+`.any.js`-style tests use
+`fetch_tests_from_worker` functionality of `testharness.js`.
+
+The WPT test server generates necessary glue code
+(including generated Document HTML and worker top-level scripts).
+See
+[serve.py](https://github.com/web-platform-tests/wpt/blob/master/tools/serve/serve.py)
+for the actual glue code.
+
+Note that `.any.js` file is not the worker top-level script,
+and currently we cannot set response headers to the worker top-level script,
+e.g. to set Referrer Policy of the workers.
+
+## Writing `*.worker.js`
+
+Similar to `.any.js`, you can also write `.worker.js`
+for tests only for dedicated workers.
+Almost the same as `.any.js`, except for the things listed below.
+
+Official doc:
+[WPT > File Name Flags > Test Features](https://web-platform-tests.org/writing-tests/file-names.html#test-features).
+
+### How to write tests
+
+You have to write two things manually (which is generated in `.any.js` tests):
+
+- `importScripts("/resources/testharness.js");` at the beginning.
+- `done();` at the bottom.
+
+Note: Even if you write `async_test()` or `promise_test()`,
+this global `done()` is always needed
+(this is different from async_test's `done()`)
+for dedicated workers and shared workers.
+See official doc:
+[testharness.js API > Determining when all tests are complete](https://web-platform-tests.org/writing-tests/testharness-api.html#determining-when-all-tests-are-complete).
+
+See `examples/general.worker.js` for example.
+
+### How it works
+
+`.worker.js`-style tests also use
+`fetch_tests_from_worker` functionality of `testharness.js`.
+
+The WPT test server generates glue code in Document HTML-side,
+but not for worker top-level scripts.
+This is why you have to manually write `importScripts()` etc.
+See
+[serve.py](https://github.com/web-platform-tests/wpt/blob/master/tools/serve/serve.py)
+for the actual glue code.
+
+Unlike `*.any.js` cases, the `*.worker.js` is the worker top-level script.
+
+## Using `fetch_tests_from_worker`
+
+If you need more flexibility,
+writing tests using `fetch_tests_from_worker` is the way to go.
+For example, when
+
+- Additional processing is needed on the parent Document.
+- Workers should be created in a specific way.
+- You are writing non-WPT tests using `testharness.js`.
+
+You have to write the main HTMLs and the worker scripts,
+but most of the glue code needed for running tests on workers
+are provided by `fetch_tests_from_worker`.
+
+### How to write tests
+
+See
+
+- `examples/fetch_tests_from_worker.html` and
+ `examples/fetch_tests_from_worker.js`.
+
+## Writing the whole tests manually
+
+If `fetch_tests_from_worker` isn't suitable for your specific case
+(which should be rare but might be still possible),
+you have to write the whole tests,
+including the main Document HTML, worker scripts,
+and message passing code between them.
+
+TODO: Supply the templates for writing this kind of tests.
diff --git a/testing/web-platform/tests/workers/SharedWorker-MessageEvent-source.any.js b/testing/web-platform/tests/workers/SharedWorker-MessageEvent-source.any.js
new file mode 100644
index 0000000000..e47fd06535
--- /dev/null
+++ b/testing/web-platform/tests/workers/SharedWorker-MessageEvent-source.any.js
@@ -0,0 +1,6 @@
+// META: global=sharedworker
+const t = async_test("Make sure that MessageEvent.source is properly set in connect event.");
+onconnect = t.step_func_done((event) => {
+ assert_equals(Object.getPrototypeOf(event), MessageEvent.prototype);
+ assert_equals(event.source, event.ports[0]);
+});
diff --git a/testing/web-platform/tests/workers/SharedWorker-constructor.html b/testing/web-platform/tests/workers/SharedWorker-constructor.html
new file mode 100644
index 0000000000..6298dd934e
--- /dev/null
+++ b/testing/web-platform/tests/workers/SharedWorker-constructor.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<title>Test SharedWorker constructor functionality.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+test(() => {
+ assert_throws_js(Error,
+ function() {
+ new SharedWorker({toString:function(){throw new Error()}}, "name") },
+ "toString exception not propagated");
+}, "Test toString exception propagated correctly.");
+
+test(() => {
+ assert_throws_js(RangeError,
+ function() {
+ var foo = {toString:function(){new Worker(foo)}}
+ new SharedWorker(foo, name); },
+ "Trying to create workers recursively did not result in an exception.");
+}, "Test recursive worker creation results in exception.");
+
+test(() => {
+ assert_throws_js(TypeError,
+ function() { new SharedWorker(); },
+ "Invoking SharedWorker constructor without arguments did not result in an exception.");
+}, "Test SharedWorker creation without arguments results in exception.");
+
+test(() => {
+ try {
+ var worker = new SharedWorker("support/SharedWorker-common.js");
+ } catch (ex) {
+ assert_unreached("Constructor failed when no name is passed: (" + ex + ")");
+ }
+}, "Test SharedWorker constructor without a name does not result in an exception.");
+
+test(() => {
+ try {
+ var worker = new SharedWorker("support/SharedWorker-common.js", null);
+ } catch (ex) {
+ assert_unreached("Constructor failed when null name is passed: (" + ex + ")");
+ }
+}, "Test SharedWorker constructor with null name does not result in an exception.");
+
+test(() => {
+ try {
+ var worker = new SharedWorker("support/SharedWorker-common.js", undefined);
+ } catch (ex) {
+ assert_unreached("Constructor failed when undefined name is passed: (" + ex + ")");
+ }
+}, "Test SharedWorker constructor with undefined name does not result in an exception.");
+
+test(() => {
+ try {
+ var worker = new SharedWorker("support/SharedWorker-common.js", "name");
+ } catch (ex) {
+ assert_unreached("Invoking SharedWorker constructor resulted in an exception: (" + ex + ")");
+ }
+}, "Test SharedWorker constructor suceeds.");
+
+</script>
diff --git a/testing/web-platform/tests/workers/SharedWorker-detach-frame-in-error-event.html b/testing/web-platform/tests/workers/SharedWorker-detach-frame-in-error-event.html
new file mode 100644
index 0000000000..7363265fbc
--- /dev/null
+++ b/testing/web-platform/tests/workers/SharedWorker-detach-frame-in-error-event.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>Test frame detach in shared worker's error handler</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<iframe id="frame"></iframe>
+</body>
+<script>
+promise_test(t => {
+ const frame = document.getElementById('frame');
+
+ const promise = new Promise(resolve => {
+ window.detachFrame = () => {
+ frame.remove();
+ resolve();
+ };
+ });
+
+ // Start a new worker with an invalid script in the frame, and detach the
+ // frame in the worker's error handler. This shouldn't crash.
+ const s = frame.contentWindow.document.createElement('script');
+ s.innerHTML = "const worker = new SharedWorker('error');" +
+ "worker.onerror = () => { window.parent.detachFrame(); };";
+ frame.contentWindow.document.body.appendChild(s);
+
+ return promise;
+});
+</script>
diff --git a/testing/web-platform/tests/workers/SharedWorker-exception-propagation.html b/testing/web-platform/tests/workers/SharedWorker-exception-propagation.html
new file mode 100644
index 0000000000..5823a19a4b
--- /dev/null
+++ b/testing/web-platform/tests/workers/SharedWorker-exception-propagation.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<title>Uncaught error in shared worker should not propagate to window</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/workers.html#runtime-script-errors-2">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/SharedWorker-create-common.js"></script>
+<script>
+// Suppress the default handling of the error event so that a failure
+// manifests as a failed test and not a harness error.
+setup({ allow_uncaught_exception: true });
+
+async_test(function(t) {
+ addEventListener("error", t.unreached_func("error event fired"));
+ var worker = createWorker();
+ worker.postMessage("throw");
+ worker.postMessage("ping");
+ var pongs = 0;
+ worker.onmessage = function(evt) {
+ // Wait for response from ping - that's how we know we have thrown the exception.
+ if (evt.data == "PASS: Received ping message") {
+ pongs++;
+ if (pongs == 1) {
+ // Send another "ping" message and wait for the response before
+ // ending the test, so that any error propagation that is now
+ // in flight will have finished.
+ worker.postMessage("ping");
+ } else {
+ t.done();
+ }
+ }
+ };
+});
+</script>
diff --git a/testing/web-platform/tests/workers/SharedWorker-exception.html b/testing/web-platform/tests/workers/SharedWorker-exception.html
new file mode 100644
index 0000000000..28b8584857
--- /dev/null
+++ b/testing/web-platform/tests/workers/SharedWorker-exception.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<title>This test checks whether exceptions in SharedWorkers are logged to the parent document. An exception should be logged to the error console.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/SharedWorker-create-common.js"></script>
+<script>
+// Ignore any error event fired on window in this test. This is tested
+// separately in SharedWorker-exception-propagation.html.
+setup({ allow_uncaught_exception: true });
+
+async_test(function(t) {
+ var worker = createWorker();
+ worker.postMessage("throw");
+ worker.postMessage("ping");
+ worker.onmessage = function(evt) {
+ // Wait for response from ping - that's how we know we have thrown the exception.
+ if (evt.data == "PASS: Received ping message") {
+ t.done();
+ }
+ };
+});
+</script>
diff --git a/testing/web-platform/tests/workers/SharedWorker-replace-EventHandler.any.js b/testing/web-platform/tests/workers/SharedWorker-replace-EventHandler.any.js
new file mode 100644
index 0000000000..90c7d2d08d
--- /dev/null
+++ b/testing/web-platform/tests/workers/SharedWorker-replace-EventHandler.any.js
@@ -0,0 +1,15 @@
+// META: global=sharedworker
+// https://crbug.com/239669
+const t = async_test("Tests that repeatedly setting 'onerror' within a shared worker doesnt crash.");
+onconnect = t.step_func_done((event) => {
+ function update() {
+ onerror = undefined;
+ }
+ try {
+ for (var i = 0; i < 8; ++i) {
+ update();
+ }
+ } catch (ex) {
+ assert_unreached("FAIL: unexpected exception (" + ex + ") received while updating onerror event handler.");
+ }
+});
diff --git a/testing/web-platform/tests/workers/SharedWorker-script-error.html b/testing/web-platform/tests/workers/SharedWorker-script-error.html
new file mode 100644
index 0000000000..3c93cc038f
--- /dev/null
+++ b/testing/web-platform/tests/workers/SharedWorker-script-error.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<title>Test SharedWorker script error handling functionality.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+promise_test(t => {
+ let worker;
+
+ return new Promise((resolve) => {
+ worker = new SharedWorker("support/SharedWorker-script-error.js");
+ // Shared workers should only invoke onerror for loading errors.
+ worker.onerror = function(evt) {
+ assert_unreached("FAIL: onerror invoked for a script error.");
+ };
+ worker.port.postMessage("unhandledError");
+ worker.port.onmessage = resolve;
+ }).then(e => {
+ assert_equals(e.data, "SUCCESS: unhandled error generated");
+ });
+}, 'Test script error unhandled.')
+
+promise_test(t => {
+ let worker;
+
+ return new Promise((resolve) => {
+ worker = new SharedWorker("support/SharedWorker-script-error.js");
+ // Shared workers should only invoke onerror for loading errors.
+ worker.onerror = function(evt) {
+ assert_unreached("FAIL: onerror invoked for a script error.");
+ };
+ worker.port.postMessage("handledError");
+ worker.port.onmessage = resolve;
+ }).then(e => {
+ assert_equals(e.data, "SUCCESS: error handled via onerror");
+ });
+}, 'Test script error handled.')
+</script>
diff --git a/testing/web-platform/tests/workers/SharedWorker-simple.html b/testing/web-platform/tests/workers/SharedWorker-simple.html
new file mode 100644
index 0000000000..7cd3f4f3be
--- /dev/null
+++ b/testing/web-platform/tests/workers/SharedWorker-simple.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>Test simple shared worker construction case.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+promise_test(t => {
+ let worker;
+
+ return new Promise(resolve => {
+ worker = new SharedWorker('support/SharedWorker-common.js', 'name');
+ worker.port.postMessage("ping");
+ worker.port.onmessage = resolve;
+ }).then(e => {
+ assert_equals(e.data, "PASS: Received ping message");
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/SharedWorkerPerformanceNow.html b/testing/web-platform/tests/workers/SharedWorkerPerformanceNow.html
new file mode 100644
index 0000000000..1fd9463294
--- /dev/null
+++ b/testing/web-platform/tests/workers/SharedWorkerPerformanceNow.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>window.performance.now in shared workers</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<script>
+async_test(function(t) {
+ const worker = new SharedWorker('support/WorkerSendingPerformanceNow.js');
+ worker.port.onmessage = t.step_func(event => {
+ const results = event.data;
+ assert_equals(results.length, 4);
+ assert_equals(results[0], 'undefined',
+ 'workerStart not defined on the Worker object');
+ assert_equals(results[1], 'object', 'self.performance is defined');
+ assert_equals(results[2], 'function', 'self.performance.now is defined');
+ assert_greater_than(results[3], 0, 'Time in the worker should be positive');
+ assert_greater_than(window.performance.now(), results[3], 'Time in the worker should be before the current time in the main document');
+ setupIframe();
+ });
+ window.iframeStartTime = 0;
+ window.test_iframe = function(event) {
+ const workerTime = event.data[3];
+ assert_greater_than(workerTime, window.iframeStartTime,
+ 'Time since origin time should be greater in the shared worker than the iframe');
+ t.done();
+ }
+ function setupIframe() {
+ const iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ const script = iframe.contentWindow.document.createElement('script');
+ script.innerHTML =
+ 'window.top.iframeStartTime = window.performance.now();' +
+ 'const worker = new SharedWorker("support/WorkerSendingPerformanceNow.js");' +
+ 'worker.port.onmessage = function(event) {' +
+ ' window.top.test_iframe(event);' +
+ '};' +
+ 'worker.port.postMessage("");';
+ iframe.contentWindow.document.body.appendChild(script);
+ }
+ worker.port.postMessage('');
+}, 'performance.now() exists in shared workers and reports reasonable times');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/workers/SharedWorker_blobUrl.html b/testing/web-platform/tests/workers/SharedWorker_blobUrl.html
new file mode 100644
index 0000000000..e5b1c673c0
--- /dev/null
+++ b/testing/web-platform/tests/workers/SharedWorker_blobUrl.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>Shared Worker: Blob URL passed over message port</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+</body>
+<script>
+
+promise_test(t => {
+ let worker;
+ let blob;
+ let blobUrl;
+ let blobText = 'Blob URL test';
+
+ return new Promise(function(resolve) {
+ worker = new SharedWorker('support/WorkerFetchURL.js');
+ blob = new Blob([blobText]);
+ blobUrl = URL.createObjectURL(blob);
+ worker.port.postMessage(blobUrl);
+ worker.port.onmessage = resolve;
+ })
+ .then(e => {
+ assert_equals(e.data, 'Worker reply:' + blobText);
+ URL.revokeObjectURL(blobUrl);
+ });
+}, 'Blob URL shared by document on SharedWorker');
+
+</script>
+</html>
+
diff --git a/testing/web-platform/tests/workers/SharedWorker_dataUrl.html b/testing/web-platform/tests/workers/SharedWorker_dataUrl.html
new file mode 100644
index 0000000000..c1dec27d49
--- /dev/null
+++ b/testing/web-platform/tests/workers/SharedWorker_dataUrl.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<title>Shared Worker: Data URL cross-origin checks</title>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+</body>
+<script>
+
+function dirname(path) {
+ return path.replace(/\/[^\/]*$/, '/');
+}
+
+promise_test(t => {
+ return new Promise(function(resolve) {
+ let count = 0;
+ onmessage = e => {
+ assert_equals(e.data, 1);
+ if (++count == 2) {
+ resolve(true);
+ }
+ };
+
+ let iframeA = document.createElement('iframe');
+ document.body.appendChild(iframeA);
+ iframeA.src = get_host_info().HTTP_REMOTE_ORIGIN +
+ dirname(location.pathname) +
+ "support/iframe_sw_dataUrl.html";
+
+ let iframeB = document.createElement('iframe');
+ document.body.appendChild(iframeB);
+ iframeB.src = get_host_info().HTTPS_REMOTE_ORIGIN +
+ dirname(location.pathname) +
+ "support/iframe_sw_dataUrl.html";
+ });
+}, 'Data URL not shared by cross-origin SharedWorkers');
+
+promise_test(t => {
+ return new Promise(function(resolve) {
+ let count = 0;
+ onmessage = e => {
+ assert_equals(e.data, ++count);
+ if (count == 2) {
+ resolve(true);
+ }
+ };
+
+ let iframeA = document.createElement('iframe');
+ document.body.appendChild(iframeA);
+ iframeA.src = get_host_info().HTTP_ORIGIN +
+ dirname(location.pathname) +
+ "support/iframe_sw_dataUrl.html";
+
+ let iframeB = document.createElement('iframe');
+ document.body.appendChild(iframeB);
+ iframeB.src = get_host_info().HTTP_ORIGIN +
+ dirname(location.pathname) +
+ "support/iframe_sw_dataUrl.html";
+ });
+}, 'Data URLs shared by same-origin SharedWorkers');
+
+</script>
+</html>
diff --git a/testing/web-platform/tests/workers/Worker-base64.any.js b/testing/web-platform/tests/workers/Worker-base64.any.js
new file mode 100644
index 0000000000..6a46b47784
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker-base64.any.js
@@ -0,0 +1,5 @@
+// META: global=worker
+test(() => {
+ assert_equals(typeof atob, 'function');
+ assert_equals(typeof btoa, 'function');
+}, 'Tests that atob() / btoa() functions are exposed to workers');
diff --git a/testing/web-platform/tests/workers/Worker-call.worker.js b/testing/web-platform/tests/workers/Worker-call.worker.js
new file mode 100644
index 0000000000..ba07498880
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker-call.worker.js
@@ -0,0 +1,12 @@
+importScripts("/resources/testharness.js");
+test(() => {
+ try {
+ postMessage("SUCCESS: postMessage() called directly");
+ postMessage.call(null, "SUCCESS: postMessage() invoked via postMessage.call()");
+ var saved = postMessage;
+ saved("SUCCESS: postMessage() called via intermediate variable");
+ } catch (ex) {
+ assert_unreached("FAIL: unexpected exception (" + ex + ") received while calling functions from the worker context.");
+ }
+}, 'Test calling functions from WorkerContext.');
+done();
diff --git a/testing/web-platform/tests/workers/Worker-constructor-proto.any.js b/testing/web-platform/tests/workers/Worker-constructor-proto.any.js
new file mode 100644
index 0000000000..297fe6c58b
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker-constructor-proto.any.js
@@ -0,0 +1,7 @@
+//META: global=worker
+test(() => {
+ const proto = {};
+ assert_equals(String(Object.getPrototypeOf(WorkerLocation)).replace(/\n/g, " ").replace(/\s\s+/g, " "), "function () { [native code] }");
+ Object.setPrototypeOf(WorkerLocation, proto);
+ assert_equals(Object.getPrototypeOf(WorkerLocation), proto);
+}, 'Tests that setting the proto of a built in constructor is not reset.');
diff --git a/testing/web-platform/tests/workers/Worker-custom-event.any.js b/testing/web-platform/tests/workers/Worker-custom-event.any.js
new file mode 100644
index 0000000000..d7e983aadd
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker-custom-event.any.js
@@ -0,0 +1,8 @@
+// META: global=worker
+async_test(t => {
+ var target = self;
+ target.addEventListener('custom-event', t.step_func_done());
+
+ var event = new Event('custom-event');
+ target.dispatchEvent(event);
+}, 'Test CustomEvents on workers.');
diff --git a/testing/web-platform/tests/workers/Worker-formdata.any.js b/testing/web-platform/tests/workers/Worker-formdata.any.js
new file mode 100644
index 0000000000..a07f194bd2
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker-formdata.any.js
@@ -0,0 +1,19 @@
+// META: global=dedicatedworker
+test(() => {
+ assert_own_property(self, 'FormData');
+ assert_equals(FormData.length, 0);
+
+ var formData = new FormData();
+ assert_not_equals(formData, null);
+ assert_own_property(FormData.prototype, 'append');
+ formData.append('key', 'value');
+
+ var blob = new Blob([]);
+ assert_not_equals(blob, null);
+ formData.append('key', blob);
+ formData.append('key', blob, 'filename');
+
+ assert_throws_dom("DataCloneError",
+ function() { postMessage(formData) },
+ "Trying to clone formdata inside a postMessage results in an exception." );
+},'Test FormData interface object');
diff --git a/testing/web-platform/tests/workers/Worker-location.sub.any.js b/testing/web-platform/tests/workers/Worker-location.sub.any.js
new file mode 100644
index 0000000000..c05bb1750f
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker-location.sub.any.js
@@ -0,0 +1,14 @@
+// META: global=dedicatedworker,sharedworker
+test(() => {
+ assert_equals(String(WorkerLocation).replace(/\n/g, " ").replace(/\s\s+/g, " "), "function WorkerLocation() { [native code] }");
+ assert_true(location instanceof Object);
+ assert_equals(location.href, 'http://{{host}}:{{ports[http][0]}}/workers/Worker-location.sub.any.worker.js');
+ assert_equals(location.origin, "http://{{host}}:{{ports[http][0]}}");
+ assert_equals(location.protocol, "http:");
+ assert_equals(location.host, "{{host}}:{{ports[http][0]}}");
+ assert_equals(location.hostname, "{{host}}");
+ assert_equals(location.port, "{{ports[http][0]}}");
+ assert_equals(location.pathname, "/workers/Worker-location.sub.any.worker.js");
+ assert_equals(location.search, "");
+ assert_equals(location.hash, "");
+}, 'Test WorkerLocation properties.');
diff --git a/testing/web-platform/tests/workers/Worker-messageport.html b/testing/web-platform/tests/workers/Worker-messageport.html
new file mode 100644
index 0000000000..f7734b2543
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker-messageport.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<title>Test that pages and workers can send MessagePorts to one another.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(function(t) {
+ var worker = new Worker("support/Worker-messageport.js");
+
+ // Send messages with and without ports to the worker to make sure it gets them.
+ worker.postMessage("noport");
+ worker.onmessage = t.step_func_done(evt => {
+ assert_equals(evt.data, "PASS: evt.ports = [] as expected");
+ });
+}, 'Test sending messages to workers with no port.');
+
+async_test(function(t) {
+ var worker = new Worker("support/Worker-messageport.js");
+ var channel = new MessageChannel();
+
+ worker.postMessage("port", [channel.port1]);
+ worker.onmessage = t.step_func(evt => {
+ assert_equals(evt.data, "PASS: Received message port");
+ });
+
+ // Send a message on the new port to make sure it gets to the worker.
+ channel.port2.postMessage("ping");
+
+ // Wait for the response.
+ channel.port2.onmessage = t.step_func_done(evt => {
+ assert_equals(evt.data, "pong");
+ });
+ channel.port2.start();
+}, 'Test sending message to a worker on a port.');
+
+async_test(function(t) {
+ var worker = new Worker("support/Worker-messageport.js");
+ var channel = new MessageChannel();
+
+ worker.onmessage = t.step_func(evt => {
+ assert_equals(evt.data, "port");
+ assert_equals(String(evt.ports), "[object MessagePort]");
+ assert_equals(evt.ports.length, 1);
+ evt.ports[0].postMessage("ping");
+ evt.ports[0].onmessage = t.step_func_done(evt => {
+ assert_equals(evt.data, "pong");
+ });
+ evt.ports[0].start();
+ });
+ worker.postMessage("getport");
+}, 'Test getting messages from a worker on a port.');
+
+async_test(function(t) {
+ var worker = new Worker("support/Worker-messageport.js");
+ var channel = new MessageChannel();
+ worker.onmessage = t.step_func(evt => { gotSpam(channel.port1); });
+ worker.postMessage("spam", [channel.port2]);
+
+ function gotSpam(port) {
+ var spamCount = 0;
+ port.onmessage = t.step_func(evt => {
+ assert_equals(evt.data, spamCount);
+ spamCount++;
+ if (spamCount == 1000) {
+ t.done();
+ }
+ });
+ }
+}, 'Test sending many messages to workers using ports.');
+</script>
diff --git a/testing/web-platform/tests/workers/Worker-multi-port.html b/testing/web-platform/tests/workers/Worker-multi-port.html
new file mode 100644
index 0000000000..587176e9fc
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker-multi-port.html
@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+<title>Test sending multiple ports through Worker.postMessage.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(function(t) {
+ var worker = new Worker("support/Worker-thread-multi-port.js");
+ worker.onmessage = t.step_func_done(function(evt) {
+ assert_true(evt.data.startsWith('PASS'));
+ });
+ worker.postMessage("noport");
+}, 'Test postMessage with no port.');
+
+async_test(function(t) {
+ var worker = new Worker("support/Worker-thread-multi-port.js");
+ worker.onmessage = t.step_func_done(function(evt) {
+ assert_true(evt.data.startsWith('PASS'));
+ });
+ worker.postMessage("noargs");
+}, 'Test postMessage with no arguments.');
+
+async_test(function(t) {
+ var worker = new Worker("support/Worker-thread-multi-port.js");
+ worker.onmessage = t.step_func_done(function(evt) {
+ assert_true(evt.data.startsWith('PASS'));
+ });
+ worker.postMessage("zero ports", []);
+}, 'Test postMessage with no ports and empty array.');
+
+async_test(function(t) {
+ var worker = new Worker("support/Worker-thread-multi-port.js");
+ var channel = new MessageChannel();
+ worker.onmessage = t.step_func_done(function(evt) {
+ assert_true(evt.data.startsWith('PASS'));
+ });
+ worker.postMessage("two ports", [channel.port1, channel.port2]);
+}, 'Test postMessage with two ports.');
+
+test(() => {
+ var worker = new Worker("support/Worker-thread-multi-port.js");
+ assert_throws_js(TypeError,
+ function() { worker.postMessage(); },
+ 'Empty postMessage should throw exception.');
+}, 'Test empty postMessage throws exception.');
+
+test(() => {
+ var worker = new Worker("support/Worker-thread-multi-port.js");
+ var channel = new MessageChannel();
+ assert_throws_js(TypeError,
+ function() { worker.postMessage("null port",
+ [channel.port1, null,
+ channel.port2]); },
+ 'postMessage with null ports should throw exception.');
+}, 'Test postMessage with null ports throws exception.');
+
+test(() => {
+ var worker = new Worker("support/Worker-thread-multi-port.js")
+ var channel = new MessageChannel();
+ assert_throws_dom('DataCloneError',
+ function() { worker.postMessage("notAPort",
+ [channel.port1, {},
+ channel.port2]); },
+ 'postMessage with incorrect ports should throw exception.');
+}, 'Test postMessage with incorrect ports throws exception');
+
+test(() => {
+ var worker = new Worker("support/Worker-thread-multi-port.js");
+ assert_throws_dom('DataCloneError',
+ function() { worker.postMessage("notASequence", [{length: 3}]) },
+ 'postMessage without sequence should throw exception.');
+}, 'Test postMessage without sequence throws exception');
+
+async_test(function(t) {
+ var worker = new Worker("support/Worker-thread-multi-port.js");
+ var channel = new MessageChannel();
+ assert_throws_dom('DataCloneError',
+ function() { worker.postMessage("notAPort",
+ [channel.port1, {},
+ channel.port2]); },
+ 'postMessage with incorrect ports should throw exception.');
+ worker.onmessage = t.step_func_done(function(evt) {
+ assert_true(evt.data.startsWith('PASS'));
+ });
+ worker.postMessage("failed ports", [channel.port1, channel.port2]);
+}, 'Test postMessage on channel with previous failed postMessage calls.');
+</script>
diff --git a/testing/web-platform/tests/workers/Worker-nested-importScripts-error.html b/testing/web-platform/tests/workers/Worker-nested-importScripts-error.html
new file mode 100644
index 0000000000..bd96c835df
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker-nested-importScripts-error.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<title>This tests that errors from nested importScripts have the expected provenance.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+promise_test(t => {
+ let worker;
+
+ return new Promise((resolve) => {
+ worker = new Worker("support/importScripts-1.js");
+ worker.onerror = resolve;
+ }).then(e => {
+ assert_equals(e.type, "error");
+ assert_true(e.filename.indexOf('invalidScript.js') >= 0);
+ e.preventDefault();
+ });
+}, 'Tests that errors from the import scripts come from the expected file.')
+</script>
diff --git a/testing/web-platform/tests/workers/Worker-replace-event-handler.any.js b/testing/web-platform/tests/workers/Worker-replace-event-handler.any.js
new file mode 100644
index 0000000000..ff7c764f2b
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker-replace-event-handler.any.js
@@ -0,0 +1,11 @@
+// META: global=worker
+// This is a regression test for a crash bug in Chrome: http://crbug.com/239669
+function update() {
+ onmessage = undefined;
+}
+
+test(() => {
+ for (var i = 0; i < 8; ++i) {
+ update();
+ }
+}, "Tests that repeatedly setting 'onmessage' within a worker doesn't crash.");
diff --git a/testing/web-platform/tests/workers/Worker-replace-global-constructor.any.js b/testing/web-platform/tests/workers/Worker-replace-global-constructor.any.js
new file mode 100644
index 0000000000..d724c6c8ec
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker-replace-global-constructor.any.js
@@ -0,0 +1,9 @@
+// META: global=worker
+test(() => {
+ try {
+ self.MessageEvent = 'PASS';
+ assert_equals(self.MessageEvent, 'PASS');
+ } catch (ex) {
+ assert_unreached("FAIL: unexpected exception (" + ex + ") received while replacing global constructor MessageEvent.");
+ }
+}, 'Test replacing global constructors in a worker context.');
diff --git a/testing/web-platform/tests/workers/Worker-replace-self.any.js b/testing/web-platform/tests/workers/Worker-replace-self.any.js
new file mode 100644
index 0000000000..513fd4a257
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker-replace-self.any.js
@@ -0,0 +1,9 @@
+// META: global=worker
+test(() => {
+ try {
+ self = 'PASS';
+ assert_true(self instanceof WorkerGlobalScope);
+ } catch (ex) {
+ assert_unreached("FAIL: unexpected exception (" + ex + ") received while replacing self.");
+ }
+}, 'Test that self is not replaceable.');
diff --git a/testing/web-platform/tests/workers/Worker-simultaneous-errors.html b/testing/web-platform/tests/workers/Worker-simultaneous-errors.html
new file mode 100644
index 0000000000..4339f2e334
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker-simultaneous-errors.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<title>Test simultaneous errors on workers.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+promise_test(t => {
+ var workers = 4;
+ var promises = [];
+
+ for (i = 0; i < workers; ++i) {
+ var worker = new Worker('support/throw-on-message-Worker.js');
+ promises.push(new Promise(function(resolve, reject) {
+ var error = 0;
+ worker.onmessage = function(event) {
+ if (event.data === 'second')
+ resolve(error);
+ else if (event.data === 'error')
+ ++error;
+ }
+ }));
+ worker.postMessage('first');
+ worker.postMessage('second');
+ }
+
+ return Promise.all(promises).then(e => {
+ var sum = 0;
+ for (var key in e) {
+ sum += e[key]
+ }
+ assert_equals(sum, workers);
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/Worker-structure-message.html b/testing/web-platform/tests/workers/Worker-structure-message.html
new file mode 100644
index 0000000000..9eb12dc6c5
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker-structure-message.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<title>Test that pages and workers can send Structure Message to one another.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+promise_test(t => {
+ let worker;
+
+ return new Promise(resolve => {
+ worker = new Worker("support/Worker-structure-message.js");
+ worker.onmessage = resolve;
+ worker.postMessage({
+ operation: 'find-edges',
+ input: new ArrayBuffer(20),
+ threshold: 0.6
+ });
+ }).then(evt => {
+ assert_false(evt.data.startsWith('FAIL'));
+ return new Promise(resolve => worker.onmessage = resolve);
+ }).then(evt => {
+ assert_equals(evt.data.operation, 'find-edges');
+ assert_true(ArrayBuffer.prototype.isPrototypeOf(evt.data.input));
+ assert_equals(evt.data.input.byteLength, 20);
+ assert_equals(evt.data.threshold, 0.6);
+ });
+}, 'Tests sending structure message to/from worker.');
+</script>
diff --git a/testing/web-platform/tests/workers/Worker-terminate-forever-during-evaluation.html b/testing/web-platform/tests/workers/Worker-terminate-forever-during-evaluation.html
new file mode 100644
index 0000000000..ab66f29289
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker-terminate-forever-during-evaluation.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<title>Test Worker.terminate() for a worker that tries to run forever after top-level script evaluation is started.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+// The tests here are to provide execution coverage for the code paths for
+// forcible worker termination.
+// Expectation here is:
+// - Not to crash, not to cause assertion failures
+// - No WorkerGlobalScope error events and thus Worker error events are fired
+// (#report-the-exception is not called when a script is terminated during
+// #run-a-classic-script/#run-a-module-script according to the spec)
+// - Nothing after infinte loop, promise resolusion/rejection etc. occurs.
+
+for (const test of [
+ {
+ url: 'support/Worker-run-forever.js',
+ description: 'Worker is terminated during top-level script evaluation'
+ },
+ {
+ url: 'support/Worker-run-forever.js',
+ options: {type: 'module'},
+ description: 'Worker is terminated during top-level script evaluation (module)'
+ },
+ {
+ url: 'support/Worker-run-forever-during-importScripts.js',
+ description: 'Worker is terminated during importScripts() call'
+ },
+ {
+ url: 'support/Worker-run-forever-during-nested-importScripts.js',
+ description: 'Worker is terminated during nested importScripts() call'
+ },
+ {
+ url: 'support/Worker-run-forever-during-dynamic-import.js',
+ description: 'Worker is terminated during dynamic import()'
+ },
+ {
+ url: 'support/Worker-run-forever-during-dynamic-import.js',
+ options: {type: 'module'},
+ description: 'Worker is terminated during dynamic import() (module)'
+ },
+ {
+ url: 'support/Worker-run-forever-during-top-level-await.js',
+ options: {type: 'module'},
+ description: 'Worker is terminated during top-level await'
+ }
+]) {
+ async_test((t) => {
+ const worker = new Worker(test.url, test.options);
+ worker.onerror = t.step_func(e => {
+ // Calls preventDefault() to prevent this event from being considered
+ // as an uncaught exception.
+ e.preventDefault();
+ assert_unreached('onerror');
+ });
+ worker.onmessage = t.step_func((e) => {
+ if (e.data === 'start') {
+ worker.terminate();
+ // To make the worker forcibly terminated, because in Chromium worker is
+ // forcibly terminated after 2 seconds.
+ t.step_timeout(function() { t.done(); }, 4000);
+ }
+ else {
+ assert_unreached('Unexpected message received: ' + e.data);
+ }
+ });
+ }, test.description);
+}
+</script>
diff --git a/testing/web-platform/tests/workers/Worker-terminate-forever.html b/testing/web-platform/tests/workers/Worker-terminate-forever.html
new file mode 100644
index 0000000000..3528bb6246
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker-terminate-forever.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<title>Test Worker.terminate() for a worker that tries to run forever.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test((t) => {
+ var worker = new Worker('support/Worker-run-forever.js');
+ worker.terminate();
+ t.step_timeout(function() { t.done(); }, 500);
+}, 'Tests terminating a worker that is trying to run forever.');
+</script>
diff --git a/testing/web-platform/tests/workers/Worker-termination-with-port-messages.html b/testing/web-platform/tests/workers/Worker-termination-with-port-messages.html
new file mode 100644
index 0000000000..bc19784ada
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker-termination-with-port-messages.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<title>This test terminates a worker when there are many undelivered MessagePort messages still waiting to be dispatched into the Worker Context. This causes termination of JS execution and test should not try to dispatch the remaining messages. Test succeeds if it does not hang or crash (if worker thread is running in the separate process, that process could hang or crash).</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(function(t) {
+ var worker = new Worker("support/Worker-termination-with-port-messages.js");
+ var channel = new MessageChannel();
+
+ channel.port2.onmessage = function(evt)
+ {
+ // On first message back from worker, terminate it.
+ worker.terminate();
+ t.done();
+ }
+ channel.port2.start();
+
+ worker.postMessage("", [channel.port1]);
+ for (i = 0; i < 1000; i++)
+ channel.port2.postMessage("message to worker");
+});
+</script>
diff --git a/testing/web-platform/tests/workers/Worker-timeout-cancel-order.html b/testing/web-platform/tests/workers/Worker-timeout-cancel-order.html
new file mode 100644
index 0000000000..78d930df78
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker-timeout-cancel-order.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>Test setTimeOut,cancelTimeout in Web Workers.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+promise_test(t => {
+ let worker
+
+ return new Promise(resolve => {
+ worker = new Worker('support/Worker-timeout-cancel-order.js');
+ worker.postMessage('start');
+ worker.onmessage = resolve;
+ }).then(evt => {
+ assert_equals(evt.data, 2, 'Timeout not canceled');
+ });
+}, 'Tests setting and canceling timeout in workers.');
+</script>
diff --git a/testing/web-platform/tests/workers/Worker-timeout-decreasing-order.html b/testing/web-platform/tests/workers/Worker-timeout-decreasing-order.html
new file mode 100644
index 0000000000..f459461ec0
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker-timeout-decreasing-order.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<title>Test setTimeOut,fired in decreasing order in Web Workers.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+promise_test (t => {
+ let worker;
+
+ return new Promise(resolve => {
+ worker = new Worker('support/Worker-timeout-decreasing-order.js');
+ worker.postMessage('start');
+ worker.onmessage = resolve;
+ }).then(evt => {
+ assert_equals(evt.data, 1);
+ return (new Promise(resolve => worker.onmessage = resolve));
+ }).then(evt => {
+ assert_equals(evt.data, 2);
+ return (new Promise(resolve => worker.onmessage = resolve));
+ }).then(evt => {
+ assert_equals(evt.data, 3);
+ });
+}, 'Tests timeouts on the worker are fired in decreasing order.');
+</script>
diff --git a/testing/web-platform/tests/workers/Worker-timeout-increasing-order.html b/testing/web-platform/tests/workers/Worker-timeout-increasing-order.html
new file mode 100644
index 0000000000..34b029466b
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker-timeout-increasing-order.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<title>Test setTimeOut,fired in increasing order in Web Workers.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+promise_test (t => {
+ let worker;
+
+ return new Promise(resolve => {
+ worker = new Worker('support/Worker-timeout-increasing-order.js');
+ worker.postMessage('start');
+ worker.onmessage = resolve;
+ }).then(evt => {
+ assert_equals(evt.data, 1);
+ return (new Promise(resolve => worker.onmessage = resolve));
+ }).then(evt => {
+ assert_equals(evt.data, 2);
+ return (new Promise(resolve => worker.onmessage = resolve));
+ }).then(evt => {
+ assert_equals(evt.data, 3);
+ });
+}, 'Tests timeouts on the worker are fired in increasing order.');
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerGlobalScope-close.html b/testing/web-platform/tests/workers/WorkerGlobalScope-close.html
new file mode 100644
index 0000000000..08ab1ca515
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerGlobalScope-close.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<title>Test WorkerGlobalScope.close functionality.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+setup({ allow_uncaught_exception: true });
+
+async_test(function(t) {
+ var worker = new Worker('support/WorkerGlobalScope-close.js');
+ worker.postMessage("typeofClose");
+ worker.onmessage = t.step_func_done(function(evt) {
+ assert_equals(evt.data, "typeof close: function");
+ });
+}, 'Test type of close function.');
+
+async_test(function(t) {
+ var worker = new Worker('support/WorkerGlobalScope-close.js');
+ worker.postMessage("ping");
+ worker.onmessage = t.step_func(function(evt) {
+ assert_equals(evt.data, "pong");
+ // Tell the worker to close, then send a followup message.
+ worker.postMessage("close");
+
+ // The worker may or may not be closing/closed by this call. If it is, the
+ // message won't be enqueued on the worker's event loop. If it isn't, the
+ // message will be enqueued but shouldn't be handled by the worker because
+ // the prior postMessage will cause the worker to close. In either case,
+ // the worker shouldn't postMessage back "pong".
+ //
+ // This also means that at this point we can't confidently test
+ // postMessage-ing a worker that will close nor a worker that is already
+ // closing/closed.
+ worker.postMessage("ping");
+
+ worker.onmessage = t.step_func(function(evt) {
+ assert_not_equals(evt.data, "pong");
+
+ // The worker should definitely be closed by now, so we can confidently
+ // test postMessage-ing a closed worker. This postMessage shouldn't throw
+ // or cause the worker to postMessage back "pong" (it shouldn't receive
+ // any events after closing).
+ worker.postMessage("ping");
+
+ t.step_timeout(function() { t.done(); }, 500);
+ });
+ });
+}, 'Test sending a message after closing.');
+
+async_test(function(t) {
+ var worker = new Worker('support/WorkerGlobalScope-close.js');
+ worker.postMessage("closeWithError");
+ worker.onerror = function(event) {
+ t.done()
+ };
+}, 'Test errors are delivered after close.');
+
+async_test(function(t) {
+ var worker = new Worker('support/WorkerGlobalScope-close.js');
+ worker.postMessage("closeWithPendingEvents");
+ worker.onmessage = t.step_func(function(evt) {
+ assert_unreached("Pending events should not fire: " + evt.data);
+ });
+ worker.onerror = t.step_func(function(evt) {
+ assert_unreached("Pending events should not fire:" + evt.message);
+ });
+ t.step_timeout(function() { t.done(); }, 500);
+}, 'Test workers do not deliver pending events.');
+
+async_test(function(t) {
+ var worker = new Worker('support/WorkerGlobalScope-close.js');
+ worker.postMessage("close");
+ worker.onmessage = function(evt) {
+ assert_equals(evt.data, "Should be delivered");
+ // Give worker a chance to close first, then terminate it.
+ t.step_timeout(function() {
+ worker.terminate();
+ t.done();
+ }, 500);
+ };
+}, 'Test terminating a worker after close.');
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerGlobalScope_ErrorEvent_colno.htm b/testing/web-platform/tests/workers/WorkerGlobalScope_ErrorEvent_colno.htm
new file mode 100644
index 0000000000..793d6c1807
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerGlobalScope_ErrorEvent_colno.htm
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<title> WorkerGlobalScope onerror event handler argument: col </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+// The worker events races with the window's load event; if the worker events
+// arrive first, the harness will detect the error event and fail the test.
+setup({ allow_uncaught_exception: true });
+
+async_test(function(t) {
+ var worker = new Worker('./support/ErrorEvent.js');
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(typeof e.data.colno, "number");
+ });
+ worker.postMessage("Error Message");
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerGlobalScope_ErrorEvent_filename.htm b/testing/web-platform/tests/workers/WorkerGlobalScope_ErrorEvent_filename.htm
new file mode 100644
index 0000000000..e165a23f41
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerGlobalScope_ErrorEvent_filename.htm
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<title> WorkerGlobalScope onerror event handler argument: location </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+// The worker events races with the window's load event; if the worker events
+// arrive first, the harness will detect the error event and fail the test.
+setup({ allow_uncaught_exception: true });
+
+async_test(function(t) {
+ var worker = new Worker('./support/ErrorEvent.js');
+ worker.onmessage = t.step_func_done(function(e) {
+ var href = location.href;
+ var expected = href.substring(0, href.lastIndexOf('/')) + '/support/ErrorEvent.js';
+ assert_equals(e.data.filename, expected);
+ });
+ worker.postMessage("Error Message");
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerGlobalScope_ErrorEvent_lineno.htm b/testing/web-platform/tests/workers/WorkerGlobalScope_ErrorEvent_lineno.htm
new file mode 100644
index 0000000000..dfbc51467d
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerGlobalScope_ErrorEvent_lineno.htm
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<title> WorkerGlobalScope onerror event handler argument: line </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+// The worker events races with the window's load event; if the worker events
+// arrive first, the harness will detect the error event and fail the test.
+setup({ allow_uncaught_exception: true });
+
+async_test(function(t) {
+ var worker = new Worker('./support/ErrorEvent.js');
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data.lineno, 3);
+ });
+ worker.postMessage("Error Message");
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerGlobalScope_ErrorEvent_message.htm b/testing/web-platform/tests/workers/WorkerGlobalScope_ErrorEvent_message.htm
new file mode 100644
index 0000000000..bc1d2c45b4
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerGlobalScope_ErrorEvent_message.htm
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title> WorkerGlobalScope onerror event handler argument: message </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+// The worker events races with the window's load event; if the worker events
+// arrive first, the harness will detect the error event and fail the test.
+setup({ allow_uncaught_exception: true });
+
+async_test(function(t) {
+ var message = 'Error Message';
+ var worker = new Worker('./support/ErrorEvent.js');
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_greater_than(e.data.message.indexOf(message), -1);
+ });
+ worker.postMessage(message);
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerGlobalScope_importScripts.htm b/testing/web-platform/tests/workers/WorkerGlobalScope_importScripts.htm
new file mode 100644
index 0000000000..1a3616df98
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerGlobalScope_importScripts.htm
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<title> WorkerGlobalScope API: importScripts() </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var worker = new Worker("./support/ImportScripts.js");
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data, "Pass");
+ });
+ worker.postMessage("ping");
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerGlobalScope_importScripts_NetworkErr.htm b/testing/web-platform/tests/workers/WorkerGlobalScope_importScripts_NetworkErr.htm
new file mode 100644
index 0000000000..36fe6e0b2d
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerGlobalScope_importScripts_NetworkErr.htm
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title> importScripts() with non-existent script file </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var worker = new Worker("./support/ImportScriptsNetworkErr.js");
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data, "Pass");
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerGlobalScope_importScripts_NosniffErr.htm b/testing/web-platform/tests/workers/WorkerGlobalScope_importScripts_NosniffErr.htm
new file mode 100644
index 0000000000..d99cecdc6a
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerGlobalScope_importScripts_NosniffErr.htm
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<title> importScripts() with nosniff X-Content-Type-Options </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+fetch_tests_from_worker(new Worker('./support/ImportScriptsNosniffErr.js'));
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerGlobalScope_requestAnimationFrame.tentative.worker.js b/testing/web-platform/tests/workers/WorkerGlobalScope_requestAnimationFrame.tentative.worker.js
new file mode 100644
index 0000000000..e1b0b9f15a
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerGlobalScope_requestAnimationFrame.tentative.worker.js
@@ -0,0 +1,19 @@
+importScripts("/resources/testharness.js");
+
+async_test(t => {
+ const res = [];
+ requestAnimationFrame(t.step_func(dt => {
+ res.push(dt);
+ requestAnimationFrame(t.step_func(dt => {
+ res.push(dt);
+ requestAnimationFrame(t.step_func_done(dt => {
+ res.push(dt);
+ assert_equals(res.length, 3);
+ assert_less_than(res[0], res[1]);
+ assert_less_than(res[1], res[2]);
+ }));
+ }));
+ }));
+});
+
+done();
diff --git a/testing/web-platform/tests/workers/WorkerGlobalScope_setInterval.htm b/testing/web-platform/tests/workers/WorkerGlobalScope_setInterval.htm
new file mode 100644
index 0000000000..4e147fbf60
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerGlobalScope_setInterval.htm
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<title> WorkerGlobalScope API: setInterval() </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var result = [];
+ var worker = new Worker('./support/Timer.js');
+ worker.onmessage = t.step_func(function(e) {
+ result.push(e.data);
+ if (result.length == 3) {
+ assert_array_equals(result, ["hello", "worker", "worker"]);
+ worker.onmessage = t.unreached_func('Unexpected message event');
+ setTimeout(t.step_func_done(), 100);
+ }
+ });
+ worker.postMessage("IntervalHandler");
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerGlobalScope_setTimeout.htm b/testing/web-platform/tests/workers/WorkerGlobalScope_setTimeout.htm
new file mode 100644
index 0000000000..89fdf3d740
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerGlobalScope_setTimeout.htm
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<title> WorkerGlobalScope API: setTimeout() </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var result = [];
+ var worker = new Worker('./support/Timer.js');
+ worker.onmessage = t.step_func(function(e) {
+ result.push(e.data);
+ if (result.length == 3) {
+ assert_array_equals(result, ["hello", "worker", "worker"]);
+ worker.onmessage = t.unreached_func('Unexpected message event');
+ setTimeout(t.step_func_done(), 100);
+ }
+ });
+ worker.postMessage("TimeoutHandler");
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerLocation-origin.sub.window.js b/testing/web-platform/tests/workers/WorkerLocation-origin.sub.window.js
new file mode 100644
index 0000000000..7e808105dd
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerLocation-origin.sub.window.js
@@ -0,0 +1,11 @@
+async_test(t => {
+ const frame = document.createElement("iframe"),
+ asciiOrigin = location.protocol + "//{{domains[天気ã®è‰¯ã„æ—¥]}}:" + location.port,
+ path = new URL("support/WorkerLocation-origin.html", location).pathname;
+ frame.src = asciiOrigin + path;
+ self.onmessage = t.step_func_done(e => {
+ assert_equals(e.data.origin, asciiOrigin);
+ });
+ document.body.appendChild(frame);
+ t.add_cleanup(() => frame.remove());
+}, "workerLocation.origin must use ASCII code points");
diff --git a/testing/web-platform/tests/workers/WorkerLocation.htm b/testing/web-platform/tests/workers/WorkerLocation.htm
new file mode 100644
index 0000000000..a74f13a8b4
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerLocation.htm
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<title> WorkerLocation object </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var worker = new Worker('./support/WorkerLocation.js');
+ worker.onmessage = t.step_func_done(function(e) {
+ var href = window.location.href;
+ var ExpectedResult = href.substring(0, href.lastIndexOf('/')) + '/support/WorkerLocation.js';
+ assert_equals(e.data.location, ExpectedResult);
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerLocation_hash.htm b/testing/web-platform/tests/workers/WorkerLocation_hash.htm
new file mode 100644
index 0000000000..74a424efc3
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerLocation_hash.htm
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title> WorkerLocation URL decomposition IDL attribute: hash </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var worker = new Worker("./support/WorkerLocation.js#HashString");
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data.hash, "#HashString");
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerLocation_hash_encoding.htm b/testing/web-platform/tests/workers/WorkerLocation_hash_encoding.htm
new file mode 100644
index 0000000000..b2a171a092
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerLocation_hash_encoding.htm
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title> WorkerLocation.hash with url encoding string </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var worker = new Worker("./support/WorkerLocation.js#question%3f");
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data.hash, "#question%3f");
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerLocation_hash_nonexist.htm b/testing/web-platform/tests/workers/WorkerLocation_hash_nonexist.htm
new file mode 100644
index 0000000000..2d898c075c
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerLocation_hash_nonexist.htm
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title> WorkerLocation.hash with no &lt;fragment&gt; component </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var worker = new Worker('./support/WorkerLocation.js');
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data.hash, "");
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerLocation_host.htm b/testing/web-platform/tests/workers/WorkerLocation_host.htm
new file mode 100644
index 0000000000..53286ddfc5
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerLocation_host.htm
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title> WorkerLocation URL decomposition IDL attribute: host </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var worker = new Worker('./support/WorkerLocation.js');
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data.host, location.host);
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerLocation_hostname.htm b/testing/web-platform/tests/workers/WorkerLocation_hostname.htm
new file mode 100644
index 0000000000..97250805c9
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerLocation_hostname.htm
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title> WorkerLocation URL decomposition IDL attribute: hostname </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var worker = new Worker('./support/WorkerLocation.js');
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data.hostname, location.hostname);
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerLocation_href.htm b/testing/web-platform/tests/workers/WorkerLocation_href.htm
new file mode 100644
index 0000000000..3ed1dbd4f5
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerLocation_href.htm
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<title> WorkerLocation href attribute </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var worker = new Worker("./support/WorkerLocation.js?srch%20#hash");
+ worker.onmessage = t.step_func_done(function(e) {
+ var href = location.href;
+ var expected = href.substring(0, href.lastIndexOf('/')) + "/support/WorkerLocation.js?srch%20#hash";
+ assert_equals(e.data.href, expected);
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerLocation_pathname.htm b/testing/web-platform/tests/workers/WorkerLocation_pathname.htm
new file mode 100644
index 0000000000..3469845115
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerLocation_pathname.htm
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<title> WorkerLocation URL decomposition IDL attribute: pathname </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var worker = new Worker('./support/WorkerLocation.js');
+ worker.onmessage = t.step_func_done(function(e) {
+ var pathname = location.pathname;
+ var expected = pathname.substring(0, pathname.lastIndexOf('/')) + '/support/WorkerLocation.js';
+ assert_equals(e.data.pathname, expected);
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerLocation_port.htm b/testing/web-platform/tests/workers/WorkerLocation_port.htm
new file mode 100644
index 0000000000..ef86cfacb6
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerLocation_port.htm
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title> WorkerLocation URL decomposition IDL attribute: port </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var worker = new Worker('./support/WorkerLocation.js');
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data.port, location.port);
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerLocation_protocol.htm b/testing/web-platform/tests/workers/WorkerLocation_protocol.htm
new file mode 100644
index 0000000000..f792dee515
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerLocation_protocol.htm
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title> WorkerLocation URL decomposition IDL attribute: protocol </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var worker = new Worker('./support/WorkerLocation.js');
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data.protocol, location.protocol);
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerLocation_search.htm b/testing/web-platform/tests/workers/WorkerLocation_search.htm
new file mode 100644
index 0000000000..bc6add8768
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerLocation_search.htm
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title> WorkerLocation URL decomposition IDL attribute: search </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var worker = new Worker('./support/WorkerLocation.js?SearchString');
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data.search, '?SearchString');
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerLocation_search_empty.htm b/testing/web-platform/tests/workers/WorkerLocation_search_empty.htm
new file mode 100644
index 0000000000..a32d430912
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerLocation_search_empty.htm
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title> WorkerLocation.search with empty &lt;query&gt; </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var worker = new Worker("./support/WorkerLocation.js?");
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data.search, "");
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerLocation_search_fragment.htm b/testing/web-platform/tests/workers/WorkerLocation_search_fragment.htm
new file mode 100644
index 0000000000..3ec4cffa6b
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerLocation_search_fragment.htm
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title> WorkerLocation.search with &lt;fragment&gt; in &lt;query&gt; </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var worker = new Worker('./support/WorkerLocation.js?test#');
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data.search, "?test");
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerLocation_search_nonexist.htm b/testing/web-platform/tests/workers/WorkerLocation_search_nonexist.htm
new file mode 100644
index 0000000000..9907e6473c
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerLocation_search_nonexist.htm
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title> WorkerLocation.search with no &lt;query&gt; component </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var worker = new Worker('./support/WorkerLocation.js');
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data.search, "");
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerNavigator-hardware-concurrency.any.js b/testing/web-platform/tests/workers/WorkerNavigator-hardware-concurrency.any.js
new file mode 100644
index 0000000000..49db7503ff
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerNavigator-hardware-concurrency.any.js
@@ -0,0 +1,4 @@
+// META: global=worker
+test(() => {
+ assert_true(navigator.hardwareConcurrency > 0);
+}, 'Test worker navigator hardware concurrency.');
diff --git a/testing/web-platform/tests/workers/WorkerNavigator.any.js b/testing/web-platform/tests/workers/WorkerNavigator.any.js
new file mode 100644
index 0000000000..a9542af79a
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerNavigator.any.js
@@ -0,0 +1,12 @@
+// META: global=worker
+test(() => {
+ assert_equals(typeof navigator, "object");
+ assert_true(navigator instanceof WorkerNavigator);
+ assert_equals(navigator.appName, "Netscape");
+ assert_true(navigator.appVersion.indexOf('WebKit') != 0);
+ assert_equals(typeof navigator.platform, "string");
+ assert_true(navigator.userAgent.indexOf('WebKit') != 0);
+ assert_equals(typeof navigator.onLine, "boolean");
+ assert_equals(navigator.appCodeName, 'Mozilla');
+ assert_equals(navigator.product, 'Gecko');
+}, "Testing Navigator properties on workers.");
diff --git a/testing/web-platform/tests/workers/WorkerNavigator_appName.htm b/testing/web-platform/tests/workers/WorkerNavigator_appName.htm
new file mode 100644
index 0000000000..832c46ff5e
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerNavigator_appName.htm
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title> WorkerNavigator appName </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var worker = new Worker("./support/WorkerNavigator.js");
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data.appName, navigator.appName);
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerNavigator_appVersion.htm b/testing/web-platform/tests/workers/WorkerNavigator_appVersion.htm
new file mode 100644
index 0000000000..7deaa4256a
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerNavigator_appVersion.htm
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title> WorkerNavigator appVersion </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var worker = new Worker("./support/WorkerNavigator.js");
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data.appVersion, navigator.appVersion);
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerNavigator_onLine.htm b/testing/web-platform/tests/workers/WorkerNavigator_onLine.htm
new file mode 100644
index 0000000000..f9e819b8aa
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerNavigator_onLine.htm
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title> WorkerNavigator.onLine </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var worker = new Worker("./support/WorkerNavigator.js");
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data.onLine, navigator.onLine);
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerNavigator_platform.htm b/testing/web-platform/tests/workers/WorkerNavigator_platform.htm
new file mode 100644
index 0000000000..3a6de80eb9
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerNavigator_platform.htm
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title> WorkerNavigator.platform </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var worker = new Worker("./support/WorkerNavigator.js");
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data.platform, navigator.platform);
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerNavigator_userAgent.htm b/testing/web-platform/tests/workers/WorkerNavigator_userAgent.htm
new file mode 100644
index 0000000000..8a34fb480a
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerNavigator_userAgent.htm
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title> WorkerNavigator.userAgent </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var worker = new Worker("./support/WorkerNavigator.js");
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data.userAgent, navigator.userAgent);
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerNavigator_userAgentData.http.html b/testing/web-platform/tests/workers/WorkerNavigator_userAgentData.http.html
new file mode 100644
index 0000000000..4e8ca34eeb
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerNavigator_userAgentData.http.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title> WorkerNavigator.userAgentData </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+ promise_test(async () => {
+ const e = await new Promise((resolve, reject) => {
+ const worker = new Worker("./support/WorkerNavigator.js");
+ worker.onmessage = resolve;
+ });
+
+ assert_equals(e.data.brands, undefined);
+ assert_equals(e.data.mobile, undefined);
+ assert_equals(e.data.getHighEntropyValues, undefined);
+ }, "Test that userAgentData is not available in workers in non-secure contexts");
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerNavigator_userAgentData.https.html b/testing/web-platform/tests/workers/WorkerNavigator_userAgentData.https.html
new file mode 100644
index 0000000000..8c22d8f867
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerNavigator_userAgentData.https.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<title> WorkerNavigator.userAgentData </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+ promise_test(async () => {
+ const e = await new Promise((resolve, reject) => {
+ const worker = new Worker("./support/WorkerNavigator.js");
+ worker.onmessage = resolve;
+ });
+
+ assert_equals(e.data.brands.length, navigator.userAgentData.brands.length);
+ for (let i = 0; i < e.data.brands.length; ++i) {
+ const workerUA = e.data.brands[i];
+ const windowUA = navigator.userAgentData.brands[i];
+ assert_equals(workerUA.brand, windowUA.brand);
+ assert_equals(workerUA.version, windowUA.version);
+ }
+ assert_equals(e.data.mobile, navigator.userAgentData.mobile);
+ assert_equals(e.data.platform, navigator.userAgentData.platform);
+ const highEntropyValues = await navigator.userAgentData.getHighEntropyValues([
+ "architecture", "bitness", "fullVersionList", "model",
+ "platformVersion", "uaFullVersion", "wow64", "formFactor",
+ ]);
+
+ assert_equals(e.data.fullVersionList.length,
+ highEntropyValues.fullVersionList.length);
+ for (let i = 0; i < e.data.fullVersionList.length; ++i) {
+ const workerFV = e.data.fullVersionList[i];
+ const windowFV = highEntropyValues.fullVersionList[i];
+ assert_equals(workerFV.brand, windowFV.brand);
+ assert_equals(workerFV.version, windowFV.version);
+ }
+
+ assert_equals(e.data.architecture, highEntropyValues.architecture);
+ assert_equals(e.data.bitness, highEntropyValues.bitness);
+ assert_equals(e.data.model, highEntropyValues.model);
+ assert_equals(e.data.platformVersion, highEntropyValues.platformVersion);
+ assert_equals(e.data.uaFullVersion, highEntropyValues.uaFullVersion);
+ assert_equals(e.data.wow64, highEntropyValues.wow64);
+ assert_equals(e.data.formFactor.join(','), highEntropyValues.formFactor.join(','));
+ assert_equals(e.data.NavigatorUADataExposed, true);
+
+ // Architecture should be one of two permitted values.
+ assert_true(["x86", "arm"].some(arch => arch == e.data.architecture))
+ }, "Test that userAgentData is available in workers in secure contexts");
+</script>
diff --git a/testing/web-platform/tests/workers/WorkerPerformanceNow.html b/testing/web-platform/tests/workers/WorkerPerformanceNow.html
new file mode 100644
index 0000000000..286832fd94
--- /dev/null
+++ b/testing/web-platform/tests/workers/WorkerPerformanceNow.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>performance.now in dedicated workers</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<script>
+async_test(function(t) {
+ const worker = new Worker('support/WorkerSendingPerformanceNow.js');
+ worker.onmessage = t.step_func_done(event => {
+ const results = event.data;
+ assert_equals(results.length, 4);
+ assert_equals(results[0], 'undefined',
+ 'workerStart not defined on the Worker object');
+ assert_equals(results[1], 'object', "self.performance is defined");
+ assert_equals(results[2], 'function', "self.performance.now is defined");
+ assert_greater_than(results[3], 0, "Time in the worker should be positive");
+ assert_greater_than(window.performance.now(), results[3], "Time in the worker should be before the current time in the main document");
+ });
+ worker.postMessage('');
+}, 'performance.now() exists in dedicated workers and reports reasonable times');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/workers/Worker_ErrorEvent_bubbles_cancelable.htm b/testing/web-platform/tests/workers/Worker_ErrorEvent_bubbles_cancelable.htm
new file mode 100644
index 0000000000..4619ee7b53
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker_ErrorEvent_bubbles_cancelable.htm
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Web Workers: Worker ErrorEvent - bubbles, cancelable</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+// The worker events races with the window's load event; if the worker events
+// arrive first, the harness will detect the error event and fail the test.
+setup({ allow_uncaught_exception: true });
+
+async_test(function(t) {
+ var worker = new Worker('./support/ErrorEvent.js');
+ worker.onerror = t.step_func_done(function(e) {
+ assert_false(e.bubbles, "onerror on worker doesn't bubble");
+ assert_true(e.cancelable, "onerror on worker is cancelable");
+ });
+ worker.postMessage("Error Message");
+}, "ErrorEvent on worker doesn't bubble and is cancelable");
+
+</script>
diff --git a/testing/web-platform/tests/workers/Worker_ErrorEvent_error.htm b/testing/web-platform/tests/workers/Worker_ErrorEvent_error.htm
new file mode 100644
index 0000000000..bb7cea12e0
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker_ErrorEvent_error.htm
@@ -0,0 +1,32 @@
+<!doctype html>
+<meta charset=utf-8>
+<title></title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+// The worker events races with the window's load event; if the worker events
+// arrive first, the harness will detect the error event and fail the test.
+setup({ allow_uncaught_exception: true });
+
+var t1 = async_test("Error handler outside the worker should not see the error value");
+var t2 = async_test("Error handlers inside a worker should see the error value");
+
+test(function() {
+ var worker = new Worker("support/ErrorEvent-error.js");
+ worker.onerror = t1.step_func_done(function(e) {
+ assert_true(/hello/.test(e.message));
+ assert_equals(e.error, null);
+ });
+
+ var messages = 0;
+ worker.onmessage = t2.step_func(function(e) {
+ ++messages;
+ var data = e.data;
+ assert_in_array(data.source, ["onerror", "event listener"]);
+ assert_equals(data.value, "hello");
+ if (messages == 2) {
+ t2.done();
+ }
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/Worker_ErrorEvent_filename.htm b/testing/web-platform/tests/workers/Worker_ErrorEvent_filename.htm
new file mode 100644
index 0000000000..0faef6fea2
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker_ErrorEvent_filename.htm
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<title> AbstractWorker ErrorEvent.filename </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+// The worker events races with the window's load event; if the worker events
+// arrive first, the harness will detect the error event and fail the test.
+setup({ allow_uncaught_exception: true });
+
+async_test(function(t) {
+ var worker = new Worker('./support/ErrorEvent.js');
+ worker.onerror = t.step_func_done(function(e) {
+ var href = location.href;
+ var expected = href.substring(0, href.lastIndexOf('/')) + '/support/ErrorEvent.js';
+ assert_equals(e.filename, expected);
+ });
+ worker.postMessage("Error Message");
+});
+</script>
diff --git a/testing/web-platform/tests/workers/Worker_ErrorEvent_lineno.htm b/testing/web-platform/tests/workers/Worker_ErrorEvent_lineno.htm
new file mode 100644
index 0000000000..ad98172960
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker_ErrorEvent_lineno.htm
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<title> AbstractWorker ErrorEvent.lineno </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+// The worker events races with the window's load event; if the worker events
+// arrive first, the harness will detect the error event and fail the test.
+setup({ allow_uncaught_exception: true });
+
+async_test(function(t) {
+ var worker = new Worker('./support/ErrorEvent.js');
+ worker.onerror = t.step_func_done(function(e) {
+ assert_equals(e.lineno, 3);
+ });
+ worker.postMessage("Error Message");
+});
+</script>
diff --git a/testing/web-platform/tests/workers/Worker_ErrorEvent_message.htm b/testing/web-platform/tests/workers/Worker_ErrorEvent_message.htm
new file mode 100644
index 0000000000..5602d9bc02
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker_ErrorEvent_message.htm
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title> AbstractWorker ErrorEvent.message </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+// The worker events races with the window's load event; if the worker events
+// arrive first, the harness will detect the error event and fail the test.
+setup({ allow_uncaught_exception: true });
+
+async_test(function(t) {
+ var message = 'Error Message';
+ var worker = new Worker('./support/ErrorEvent.js');
+ worker.onerror = t.step_func_done(function(e) {
+ assert_greater_than(e.message.indexOf(message), -1);
+ });
+ worker.postMessage(message);
+});
+</script>
diff --git a/testing/web-platform/tests/workers/Worker_ErrorEvent_type.htm b/testing/web-platform/tests/workers/Worker_ErrorEvent_type.htm
new file mode 100644
index 0000000000..3a0f85ad9b
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker_ErrorEvent_type.htm
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title> AbstractWorker ErrorEvent.type </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+// The worker events races with the window's load event; if the worker events
+// arrive first, the harness will detect the error event and fail the test.
+setup({ allow_uncaught_exception: true });
+
+async_test(function(t) {
+ var worker = new Worker('./support/ErrorEvent.js');
+ worker.onerror = t.step_func_done(function(e) {
+ assert_class_string(e, 'ErrorEvent');
+ assert_equals(e.type, 'error');
+ });
+ worker.postMessage("Error Message");
+});
+</script>
diff --git a/testing/web-platform/tests/workers/Worker_NosniffErr.htm b/testing/web-platform/tests/workers/Worker_NosniffErr.htm
new file mode 100644
index 0000000000..11d4b7c290
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker_NosniffErr.htm
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title> Worker with nosniff X-Content-Type-Options header </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var worker = new Worker("./support/nosiniff-error-worker.py");
+ worker.onerror = t.step_func_done(function(e) {
+ assert_equals(e.type, 'error');
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/Worker_basic.htm b/testing/web-platform/tests/workers/Worker_basic.htm
new file mode 100644
index 0000000000..d2b57b4918
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker_basic.htm
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<title> Web Workers Basic Tests </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+function create_worker() {
+ return new Worker('./support/WorkerBasic.js');
+}
+
+test(function() {
+ var worker = create_worker();
+ assert_class_string(worker, "Worker");
+}, "Worker constructor");
+
+async_test(function(t) {
+ var worker = create_worker();
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data, "Pass");
+ });
+ worker.postMessage("start");
+}, "MessageEvent.data");
+
+async_test(function(t) {
+ var worker = create_worker();
+ worker.addEventListener("message", t.step_func_done(function(e) {
+ assert_equals(e.type, "message");
+ }), true);
+ worker.postMessage("start");
+}, "MessageEvent.type");
+</script>
diff --git a/testing/web-platform/tests/workers/Worker_cross_origin_security_err.htm b/testing/web-platform/tests/workers/Worker_cross_origin_security_err.htm
new file mode 100644
index 0000000000..a3e49df79a
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker_cross_origin_security_err.htm
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<title>Worker cross-origin URL</title>
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var w = new Worker("ftp://example.org/support/WorkerBasic.js");
+ w.onerror = t.step_func_done(function(e) {
+ assert_true(e instanceof Event);
+ });
+ }, "Cross-origin classic workers should fail to fetch");
+
+async_test(function(t) {
+ var w = new Worker("ftp://example.org/support/WorkerBasic.js", {type: "module"});
+ w.onerror = t.step_func_done(function(e) {
+ assert_true(e instanceof Event);
+ });
+}, "Cross-origin module workers should fail to fetch");
+</script>
diff --git a/testing/web-platform/tests/workers/Worker_dispatchEvent_ErrorEvent.htm b/testing/web-platform/tests/workers/Worker_dispatchEvent_ErrorEvent.htm
new file mode 100644
index 0000000000..7ba56b89ec
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker_dispatchEvent_ErrorEvent.htm
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<title> ErrorEvent and Worker.dispatchEvent() </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var event = "error";
+ var filename = './support/ErrorEvent.js';
+ var message = 'Hello Worker';
+ var lineno = 5;
+ var colno = 6;
+ var error = new Error("test");
+ var worker = new Worker(filename);
+ worker.addEventListener(event, t.step_func_done(function(e) {
+ assert_equals(e.type, event, 'type');
+ assert_equals(e.message, message, 'message');
+ assert_equals(e.filename, filename, 'filename');
+ assert_equals(e.lineno, lineno, 'lineno');
+ assert_equals(e.colno, colno, 'colno');
+ assert_equals(e.error, error, 'error');
+ }), true);
+ var e = new ErrorEvent(event, {bubbles:true, cancelable:true, message:message, filename:filename, lineno:lineno, colno:colno, error:error});
+ worker.dispatchEvent(e);
+});
+
+test(function() {
+ var e = new ErrorEvent("error");
+ assert_false("initErrorEvent" in e, "should not be supported");
+}, "initErrorEvent");
+
+test(function() {
+ assert_throws_js(
+ TypeError,
+ () => ErrorEvent(''),
+ "Calling ErrorEvent constructor without 'new' must throw"
+ );
+}, "ErrorEvent constructor called as normal function");
+</script>
diff --git a/testing/web-platform/tests/workers/Worker_script_mimetype.htm b/testing/web-platform/tests/workers/Worker_script_mimetype.htm
new file mode 100644
index 0000000000..d2278d3717
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker_script_mimetype.htm
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<title>Worker constructor with wrong MIME type scripts</title>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+async_test(t => {
+ const worker = new Worker('./support/WorkerText.txt');
+ worker.onmessage = t.unreached_func("Worker should not receive messages");
+ worker.onerror = () => t.done();
+}, "HTTP(S) URLs which respond with text/plain MIME type must not work");
+
+async_test(t => {
+ const worker = new SharedWorker('./support/WorkerText.txt');
+ worker.onmessage = t.unreached_func("Worker should not receive messages");
+ worker.onerror = () => t.done();
+}, "HTTP(S) URLs which respond with text/plain MIME type must not work on SharedWorkers");
+
+async_test(t => {
+ const url = URL.createObjectURL(new Blob(['postMessage("PASS")'])); // no MIME type parameter
+ const worker = new Worker(url);
+ worker.onmessage = () => t.done();
+ worker.onerror = t.unreached_func("Worker should not error");
+}, "blob: URLs should load, despite no MIME type for the backing Blob");
+
+async_test(t => {
+ const url = URL.createObjectURL(new Blob(['postMessage("PASS")'], { type: 'text/plain' }));
+ const worker = new Worker(url);
+ worker.onmessage = () => t.done();
+ worker.onerror = t.unreached_func("Worker should not error");
+}, "blob: URLs should load, despite the wrong MIME type for the backing Blob");
+
+async_test(t => {
+ const url = `data:text/plain,postMessage("PASS");`
+ const worker = new Worker(url);
+ worker.onmessage = () => t.done();
+ worker.onerror = t.unreached_func("Worker should not error");
+}, "data: URLs should load, despite the wrong MIME type");
+
+</script>
diff --git a/testing/web-platform/tests/workers/Worker_terminate_event_queue.htm b/testing/web-platform/tests/workers/Worker_terminate_event_queue.htm
new file mode 100644
index 0000000000..e4f106ad3a
--- /dev/null
+++ b/testing/web-platform/tests/workers/Worker_terminate_event_queue.htm
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<title> AbstractWorker terminate(): clear event queue </title>
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var testResult;
+ var worker = new Worker('./support/WorkerTerminate.js');
+ worker.onmessage = this.step_func(function(e) {
+ testResult = e.data;
+ if (testResult >= 10000) {
+ worker.terminate();
+ worker.onmessage = this.unreached_func('Unexpected message event');
+ setTimeout(this.step_func_done(function() {
+ assert_equals(testResult, 10000);
+ }), 100);
+ }
+ });
+ worker.postMessage("ping");
+});
+</script>
diff --git a/testing/web-platform/tests/workers/abrupt-completion.html b/testing/web-platform/tests/workers/abrupt-completion.html
new file mode 100644
index 0000000000..3f2c70b6a3
--- /dev/null
+++ b/testing/web-platform/tests/workers/abrupt-completion.html
@@ -0,0 +1,55 @@
+<!doctype html>
+<meta charset=utf-8>
+<title></title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+
+// Tests that a {Dedicated,Shared}Worker keeps running even if its script
+// evaluation results in an abrupt completion. This corresponds to the "run a
+// worker" algorithm disregarding the return value of "run the {classic,module}
+// script" in its step 24:
+//
+// "If script is a classic script, then run the classic script script.
+// Otherwise, it is a module script; run the module script script."
+
+async function testWorker(worker) {
+ await new Promise(resolve => {
+ worker.onerror = e => {
+ assert_not_equals(e.message.search("uncaught-exception"), -1,
+ "Correct uncaught exception thrown by worker");
+
+ // Suppress the exception.
+ e.preventDefault();
+
+ resolve();
+ }
+ });
+
+ return new Promise(resolve => {
+ const channel = new MessageChannel();
+
+ channel.port1.onmessage = e => {
+ assert_equals(e.data, "handler-before-throw", "Correct message handler.");
+ resolve();
+ };
+
+ if (worker instanceof SharedWorker) {
+ worker.port.postMessage("", [channel.port2]);
+ } else {
+ worker.postMessage("", [channel.port2]);
+ }
+ });
+}
+
+promise_test(async t => {
+ const worker = new Worker("support/abrupt-completion.js");
+ return testWorker(worker);
+}, "DedicatedWorker should correctly handle abrupt completion");
+
+promise_test(async t => {
+ const worker = new SharedWorker("support/abrupt-completion.js");
+ return testWorker(worker);
+}, "SharedWorker should correctly handle abrupt completion");
+
+</script>
diff --git a/testing/web-platform/tests/workers/baseurl/alpha/import-in-moduleworker.html b/testing/web-platform/tests/workers/baseurl/alpha/import-in-moduleworker.html
new file mode 100644
index 0000000000..2c75dec9ce
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/alpha/import-in-moduleworker.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Base URL in module dedicated workers: import</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(function() {
+ var worker = new Worker("../beta/import.py", {type: "module"});
+ worker.onmessage = this.step_func_done(function(e) {
+ assert_equals(e.data, "gamma/script-module.js");
+ });
+ worker.onerror = this.unreached_func("Got error event");
+});
+</script>
diff --git a/testing/web-platform/tests/workers/baseurl/alpha/importScripts-in-sharedworker.html b/testing/web-platform/tests/workers/baseurl/alpha/importScripts-in-sharedworker.html
new file mode 100644
index 0000000000..6a4111c6c0
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/alpha/importScripts-in-sharedworker.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Base URL in classic shared workers: importScripts</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+fetch_tests_from_worker(new SharedWorker("../beta/importScripts.py"));
+</script>
diff --git a/testing/web-platform/tests/workers/baseurl/alpha/importScripts-in-worker.html b/testing/web-platform/tests/workers/baseurl/alpha/importScripts-in-worker.html
new file mode 100644
index 0000000000..55907bf423
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/alpha/importScripts-in-worker.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Base URL in classic dedicated workers: importScripts</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+fetch_tests_from_worker(new Worker("../beta/importScripts.py"));
+</script>
diff --git a/testing/web-platform/tests/workers/baseurl/alpha/sharedworker-in-worker.html b/testing/web-platform/tests/workers/baseurl/alpha/sharedworker-in-worker.html
new file mode 100644
index 0000000000..25d2582366
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/alpha/sharedworker-in-worker.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Base URL in workers: new SharedWorker()</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(function() {
+ var worker = new Worker("../beta/sharedworker.py");
+ worker.onmessage = this.step_func_done(function(e) {
+ assert_equals(e.data, "gamma");
+ });
+ worker.onerror = this.unreached_func("Got error event");
+});
+</script>
diff --git a/testing/web-platform/tests/workers/baseurl/alpha/worker-in-worker.html b/testing/web-platform/tests/workers/baseurl/alpha/worker-in-worker.html
new file mode 100644
index 0000000000..284425ed34
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/alpha/worker-in-worker.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Base URL in workers: new Worker()</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(function() {
+ var worker = new Worker("../beta/worker.py");
+ worker.onmessage = this.step_func_done(function(e) {
+ assert_equals(e.data, "gamma");
+ });
+ worker.onerror = this.unreached_func("Got error event");
+});
+</script>
diff --git a/testing/web-platform/tests/workers/baseurl/alpha/xhr-in-moduleworker.html b/testing/web-platform/tests/workers/baseurl/alpha/xhr-in-moduleworker.html
new file mode 100644
index 0000000000..7597a1357d
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/alpha/xhr-in-moduleworker.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Base URL in module dedicated workers: XHR</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(function() {
+ var worker = new Worker("../beta/xhr.py", {type: "module"});
+ worker.onmessage = this.step_func_done(function(e) {
+ assert_equals(e.data, "gamma\n");
+ });
+ worker.onerror = this.unreached_func("Got error event");
+});
+</script>
diff --git a/testing/web-platform/tests/workers/baseurl/alpha/xhr-in-sharedworker.html b/testing/web-platform/tests/workers/baseurl/alpha/xhr-in-sharedworker.html
new file mode 100644
index 0000000000..43921b898d
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/alpha/xhr-in-sharedworker.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Base URL in classic shared workers: XHR</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+fetch_tests_from_worker(new SharedWorker("../beta/xhr-worker.py"));
+</script>
diff --git a/testing/web-platform/tests/workers/baseurl/alpha/xhr-in-worker.html b/testing/web-platform/tests/workers/baseurl/alpha/xhr-in-worker.html
new file mode 100644
index 0000000000..bc58b9b2dd
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/alpha/xhr-in-worker.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Base URL in classic dedicated workers: XHR</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+fetch_tests_from_worker(new Worker("../beta/xhr-worker.py"));
+</script>
diff --git a/testing/web-platform/tests/workers/baseurl/beta/import.py b/testing/web-platform/tests/workers/baseurl/beta/import.py
new file mode 100644
index 0000000000..cea229dbf3
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/beta/import.py
@@ -0,0 +1,3 @@
+def main(request, response):
+ return (302, b"Moved"), [(b"Location", b"../gamma/import.js")], u"postMessage('executed redirecting script');"
+
diff --git a/testing/web-platform/tests/workers/baseurl/beta/importScripts.py b/testing/web-platform/tests/workers/baseurl/beta/importScripts.py
new file mode 100644
index 0000000000..688427d59d
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/beta/importScripts.py
@@ -0,0 +1,3 @@
+def main(request, response):
+ return (302, b"Moved"), [(b"Location", b"../gamma/importScripts.js")], u"postMessage('executed redirecting script');"
+
diff --git a/testing/web-platform/tests/workers/baseurl/beta/script.js b/testing/web-platform/tests/workers/baseurl/beta/script.js
new file mode 100644
index 0000000000..bef771ff9e
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/beta/script.js
@@ -0,0 +1 @@
+var result = 'beta/script.js';
diff --git a/testing/web-platform/tests/workers/baseurl/beta/sharedworker.py b/testing/web-platform/tests/workers/baseurl/beta/sharedworker.py
new file mode 100644
index 0000000000..bd6f70e7d9
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/beta/sharedworker.py
@@ -0,0 +1,3 @@
+def main(request, response):
+ return (302, b"Moved"), [(b"Location", b"../gamma/sharedworker.js")], u"postMessage('executed redirecting script');"
+
diff --git a/testing/web-platform/tests/workers/baseurl/beta/subsharedworker.js b/testing/web-platform/tests/workers/baseurl/beta/subsharedworker.js
new file mode 100644
index 0000000000..de6a8cacaf
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/beta/subsharedworker.js
@@ -0,0 +1,3 @@
+onconnect = function(e) {
+ e.source.postMessage('beta');
+}
diff --git a/testing/web-platform/tests/workers/baseurl/beta/subworker.js b/testing/web-platform/tests/workers/baseurl/beta/subworker.js
new file mode 100644
index 0000000000..997cecd6ce
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/beta/subworker.js
@@ -0,0 +1 @@
+postMessage("beta");
diff --git a/testing/web-platform/tests/workers/baseurl/beta/test.txt b/testing/web-platform/tests/workers/baseurl/beta/test.txt
new file mode 100644
index 0000000000..65b2df87f7
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/beta/test.txt
@@ -0,0 +1 @@
+beta
diff --git a/testing/web-platform/tests/workers/baseurl/beta/worker.py b/testing/web-platform/tests/workers/baseurl/beta/worker.py
new file mode 100644
index 0000000000..46db05efe5
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/beta/worker.py
@@ -0,0 +1,3 @@
+def main(request, response):
+ return (302, b"Moved"), [(b"Location", b"../gamma/worker.js")], u"postMessage('executed redirecting script');"
+
diff --git a/testing/web-platform/tests/workers/baseurl/beta/xhr-worker.py b/testing/web-platform/tests/workers/baseurl/beta/xhr-worker.py
new file mode 100644
index 0000000000..86c033b985
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/beta/xhr-worker.py
@@ -0,0 +1,2 @@
+def main(request, response):
+ return (302, b"Moved"), [(b"Location", b"../gamma/xhr-worker.js")], u"postMessage('executed redirecting script');"
diff --git a/testing/web-platform/tests/workers/baseurl/beta/xhr.py b/testing/web-platform/tests/workers/baseurl/beta/xhr.py
new file mode 100644
index 0000000000..11d6eb776a
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/beta/xhr.py
@@ -0,0 +1,3 @@
+def main(request, response):
+ return (302, b"Moved"), [(b"Location", b"../gamma/xhr.js")], u"postMessage('executed redirecting script');"
+
diff --git a/testing/web-platform/tests/workers/baseurl/gamma/import.js b/testing/web-platform/tests/workers/baseurl/gamma/import.js
new file mode 100644
index 0000000000..1246913a84
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/gamma/import.js
@@ -0,0 +1,2 @@
+import r from "./script-module.js";
+postMessage(r);
diff --git a/testing/web-platform/tests/workers/baseurl/gamma/importScripts.js b/testing/web-platform/tests/workers/baseurl/gamma/importScripts.js
new file mode 100644
index 0000000000..13820380a8
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/gamma/importScripts.js
@@ -0,0 +1,6 @@
+importScripts('/resources/testharness.js');
+importScripts("script.js");
+test(() => {
+ assert_equals(result, "gamma/script.js");
+});
+done();
diff --git a/testing/web-platform/tests/workers/baseurl/gamma/script-module.js b/testing/web-platform/tests/workers/baseurl/gamma/script-module.js
new file mode 100644
index 0000000000..88d5f82db3
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/gamma/script-module.js
@@ -0,0 +1 @@
+export default 'gamma/script-module.js';
diff --git a/testing/web-platform/tests/workers/baseurl/gamma/script.js b/testing/web-platform/tests/workers/baseurl/gamma/script.js
new file mode 100644
index 0000000000..0f9ce8eacf
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/gamma/script.js
@@ -0,0 +1 @@
+var result = 'gamma/script.js';
diff --git a/testing/web-platform/tests/workers/baseurl/gamma/sharedworker.js b/testing/web-platform/tests/workers/baseurl/gamma/sharedworker.js
new file mode 100644
index 0000000000..d0718cfdef
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/gamma/sharedworker.js
@@ -0,0 +1,4 @@
+var worker = new SharedWorker("subsharedworker.js");
+worker.port.onmessage = function(e) {
+ postMessage(e.data);
+}
diff --git a/testing/web-platform/tests/workers/baseurl/gamma/subsharedworker.js b/testing/web-platform/tests/workers/baseurl/gamma/subsharedworker.js
new file mode 100644
index 0000000000..e23602ff9c
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/gamma/subsharedworker.js
@@ -0,0 +1,3 @@
+onconnect = function(e) {
+ e.source.postMessage('gamma');
+}
diff --git a/testing/web-platform/tests/workers/baseurl/gamma/subworker.js b/testing/web-platform/tests/workers/baseurl/gamma/subworker.js
new file mode 100644
index 0000000000..44407358e6
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/gamma/subworker.js
@@ -0,0 +1 @@
+postMessage("gamma");
diff --git a/testing/web-platform/tests/workers/baseurl/gamma/test.txt b/testing/web-platform/tests/workers/baseurl/gamma/test.txt
new file mode 100644
index 0000000000..af17f6cc87
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/gamma/test.txt
@@ -0,0 +1 @@
+gamma
diff --git a/testing/web-platform/tests/workers/baseurl/gamma/worker.js b/testing/web-platform/tests/workers/baseurl/gamma/worker.js
new file mode 100644
index 0000000000..8cfbcaef31
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/gamma/worker.js
@@ -0,0 +1,4 @@
+var worker = new Worker("subworker.js");
+worker.onmessage = function(e) {
+ postMessage(e.data);
+}
diff --git a/testing/web-platform/tests/workers/baseurl/gamma/xhr-worker.js b/testing/web-platform/tests/workers/baseurl/gamma/xhr-worker.js
new file mode 100644
index 0000000000..a9d77827d9
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/gamma/xhr-worker.js
@@ -0,0 +1,8 @@
+importScripts('/resources/testharness.js');
+test(t => {
+ var x = new XMLHttpRequest();
+ x.open("GET", "test.txt", false);
+ x.send();
+ assert_equals(x.response, "gamma\n");
+});
+done();
diff --git a/testing/web-platform/tests/workers/baseurl/gamma/xhr.js b/testing/web-platform/tests/workers/baseurl/gamma/xhr.js
new file mode 100644
index 0000000000..70f331565a
--- /dev/null
+++ b/testing/web-platform/tests/workers/baseurl/gamma/xhr.js
@@ -0,0 +1,4 @@
+var x = new XMLHttpRequest();
+x.open("GET", "test.txt", false);
+x.send();
+postMessage(x.response);
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/1 b/testing/web-platform/tests/workers/constructors/SharedWorker/1
new file mode 100644
index 0000000000..831434e639
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/1
@@ -0,0 +1,3 @@
+onconnect = e => {
+ e.ports[0].postMessage(['1', self.name]);
+};
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/1.headers b/testing/web-platform/tests/workers/constructors/SharedWorker/1.headers
new file mode 100644
index 0000000000..e7ec0d6699
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/1.headers
@@ -0,0 +1 @@
+Content-Type: text/javascript
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/Infinity b/testing/web-platform/tests/workers/constructors/SharedWorker/Infinity
new file mode 100644
index 0000000000..d4c921c565
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/Infinity
@@ -0,0 +1,3 @@
+onconnect = e => {
+ e.ports[0].postMessage(['Infinity', self.name]);
+};
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/Infinity-arguments.html b/testing/web-platform/tests/workers/constructors/SharedWorker/Infinity-arguments.html
new file mode 100644
index 0000000000..b38e55dc6b
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/Infinity-arguments.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<title>Infinity as arguments</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ const worker = new SharedWorker(Infinity, Infinity);
+ worker.port.onmessage = t.step_func_done(e => {
+ assert_equals(e.data[0], 'Infinity', 'first arg (script name)');
+ assert_equals(e.data[1], 'Infinity', 'second arg (worker name)');
+ });
+}, 'Test constructing a shared worker with Infinity');
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/Infinity.headers b/testing/web-platform/tests/workers/constructors/SharedWorker/Infinity.headers
new file mode 100644
index 0000000000..6805c323df
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/Infinity.headers
@@ -0,0 +1 @@
+Content-Type: text/javascript; charset=utf-8
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/NaN b/testing/web-platform/tests/workers/constructors/SharedWorker/NaN
new file mode 100644
index 0000000000..1d06329788
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/NaN
@@ -0,0 +1,3 @@
+onconnect = e => {
+ e.ports[0].postMessage(['NaN', self.name]);
+};
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/NaN-arguments.html b/testing/web-platform/tests/workers/constructors/SharedWorker/NaN-arguments.html
new file mode 100644
index 0000000000..8a4578a965
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/NaN-arguments.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<title>NaN as arguments</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ const worker = new SharedWorker(NaN, NaN);
+ worker.port.onmessage = t.step_func_done(e => {
+ assert_equals(e.data[0], 'NaN', 'first arg (script name)');
+ assert_equals(e.data[1], 'NaN', 'second arg (worker name)');
+ });
+}, 'Test constructing a shared worker with NaN');
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/NaN.headers b/testing/web-platform/tests/workers/constructors/SharedWorker/NaN.headers
new file mode 100644
index 0000000000..6805c323df
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/NaN.headers
@@ -0,0 +1 @@
+Content-Type: text/javascript; charset=utf-8
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/SharedWorker-constructor.html b/testing/web-platform/tests/workers/constructors/SharedWorker/SharedWorker-constructor.html
new file mode 100644
index 0000000000..7909eb5369
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/SharedWorker-constructor.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>Test SharedWorker constructor functionality.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(() => {
+ assert_throws_js(Error,
+ function() {
+ new SharedWorker({toString:function(){throw new Error()}})},
+ 'toString exception should be propagated');
+}, 'Test toString propagation exception.');
+
+test(() => {
+ assert_throws_js(TypeError,
+ function() { new SharedWorker(); },
+ 'invoking SharedWorker constructor without arguments should result ' +
+ 'in an exception.')
+}, 'Test Sharedworker creation with no arguments');
+
+
+test(() => {
+ assert_throws_dom("SyntaxError",
+ function() { var Sharedworker = new SharedWorker('http://invalid:123$'); },
+ 'Invoking SharedWorker constructor with invalid script URL should ' +
+ 'result in an exception.');
+}, 'Test invalid script URL.');
+
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/URLMismatchError.htm b/testing/web-platform/tests/workers/constructors/SharedWorker/URLMismatchError.htm
new file mode 100644
index 0000000000..683d201ad3
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/URLMismatchError.htm
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Web Workers: SharedWorker - same name, different URL</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+setup({ single_test: true });
+
+let counter = 0
+const maybeDone = () => {
+ if(counter) {
+ done()
+ }
+ counter++
+}
+
+const worker = new SharedWorker('shared-worker.js', 'name');
+worker.port.postMessage("trigger a response")
+worker.port.onmessage = e => {
+ assert_equals(e.data, "ping")
+ maybeDone()
+}
+
+// This used to throw "URLMismatchError", but the standard changed
+const worker2 = new SharedWorker('1', 'name');
+worker2.port.onmessage = e => {
+ assert_array_equals(e.data, ["1", "name"])
+ maybeDone()
+}
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/connect-event.html b/testing/web-platform/tests/workers/constructors/SharedWorker/connect-event.html
new file mode 100644
index 0000000000..0ab41d25c9
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/connect-event.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>connect event</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ const worker = new SharedWorker('connect-event.js');
+ worker.port.onmessage = t.step_func_done(e => {
+ assert_true(e.data[0], "e.data === ''");
+ assert_true(e.data[1], "e instanceof MessageEvent");
+ assert_true(e.data[2], "e.ports.length == 1");
+ });
+}, 'Test connect event for a shared worker');
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/connect-event.js b/testing/web-platform/tests/workers/constructors/SharedWorker/connect-event.js
new file mode 100644
index 0000000000..2cf26a723e
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/connect-event.js
@@ -0,0 +1,3 @@
+onconnect = e => {
+ e.ports[0].postMessage([e.data === '', e instanceof MessageEvent, e.ports.length == 1]);
+};
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/dummy-name.html b/testing/web-platform/tests/workers/constructors/SharedWorker/dummy-name.html
new file mode 100644
index 0000000000..25277042e2
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/dummy-name.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<title>creating a dummy shared worker with name "foo"</title>
+<link rel=help href="http://www.whatwg.org/html/#dom-sharedworker">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(() => {
+ const worker = new SharedWorker('empty.js', 'foo');
+});
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/dummy-shared-worker.html b/testing/web-platform/tests/workers/constructors/SharedWorker/dummy-shared-worker.html
new file mode 100644
index 0000000000..59a449ad7d
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/dummy-shared-worker.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<title>creating a dummy shared worker</title>
+<link rel=help href="http://www.whatwg.org/html/#dom-sharedworker">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(() => {
+ const worker = new SharedWorker('dummy-shared-worker.js');
+});
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/dummy-shared-worker.js b/testing/web-platform/tests/workers/constructors/SharedWorker/dummy-shared-worker.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/dummy-shared-worker.js
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/empty-name.html b/testing/web-platform/tests/workers/constructors/SharedWorker/empty-name.html
new file mode 100644
index 0000000000..94771d27c9
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/empty-name.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<title>creating a dummy shared worker with explicit name ""</title>
+<link rel=help href="http://www.whatwg.org/html/#dom-sharedworker">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(() => {
+ const worker = new SharedWorker('empty.js', '');
+});
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/empty.js b/testing/web-platform/tests/workers/constructors/SharedWorker/empty.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/empty.js
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/global-members.html b/testing/web-platform/tests/workers/constructors/SharedWorker/global-members.html
new file mode 100644
index 0000000000..2da4fc1cee
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/global-members.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>members of SharedWorkerGlobalScope</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ const worker = new SharedWorker('global-members.js');
+ worker.port.onmessage = t.step_func_done(e => {
+ assert_equals(e.data, '');
+ });
+}, 'Test if global members exist in a shared worker');
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/global-members.js b/testing/web-platform/tests/workers/constructors/SharedWorker/global-members.js
new file mode 100644
index 0000000000..453da6aae5
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/global-members.js
@@ -0,0 +1,9 @@
+const expected = 'self location close onerror importScripts navigator addEventListener removeEventListener dispatchEvent name onconnect setTimeout clearTimeout setInterval clearInterval'.split(' ');
+let log = '';
+for (let i = 0; i < expected.length; ++i) {
+ if (!(expected[i] in self))
+ log += expected[i] + ' did not exist\n';
+}
+onconnect = e => {
+ e.ports[0].postMessage(log);
+};
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/interface-objects.html b/testing/web-platform/tests/workers/constructors/SharedWorker/interface-objects.html
new file mode 100644
index 0000000000..a8f6998168
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/interface-objects.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>expected interface objects/constructors</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ const expected = 'XMLHttpRequest WebSocket EventSource MessageChannel Worker'.split(' ');
+ const supported = [];
+ for (let i = 0; i < expected.length; ++i) {
+ if (expected[i] in window)
+ supported.push(expected[i]);
+ }
+ const worker = new SharedWorker('interface-objects.js');
+ worker.port.start();
+ worker.port.postMessage(supported);
+ worker.port.onmessage = t.step_func_done(e => {
+ assert_equals(e.data, 'These were missing: ');
+ });
+}, 'Test if interface objects exist in a shared worker');
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/interface-objects.js b/testing/web-platform/tests/workers/constructors/SharedWorker/interface-objects.js
new file mode 100644
index 0000000000..2a7aaee687
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/interface-objects.js
@@ -0,0 +1,13 @@
+let prt;
+const handleCall = e => {
+ const log = [];
+ for (let i = 0; i < e.data.length; ++i) {
+ if (!(e.data[i] in self))
+ log.push(e.data[i]);
+ }
+ prt.postMessage('These were missing: '+log.join(', '));
+};
+onconnect = e => {
+ prt = e.ports[0];
+ prt.onmessage = handleCall;
+};
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/name.html b/testing/web-platform/tests/workers/constructors/SharedWorker/name.html
new file mode 100644
index 0000000000..4531cb1b80
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/name.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>self.name</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ const worker = new SharedWorker('name.js', 'hello');
+ worker.port.onmessage = t.step_func_done(e => {
+ assert_equals(e.data, 'hello');
+ });
+}, 'Test self.name in a shared worker');
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/name.js b/testing/web-platform/tests/workers/constructors/SharedWorker/name.js
new file mode 100644
index 0000000000..2bc2a4b18b
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/name.js
@@ -0,0 +1,3 @@
+onconnect = e => {
+ e.ports[0].postMessage(self.name);
+};
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/no-arguments-ctor.html b/testing/web-platform/tests/workers/constructors/SharedWorker/no-arguments-ctor.html
new file mode 100644
index 0000000000..5a1231d7b5
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/no-arguments-ctor.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<title>no arguments</title>
+<link rel=help href="http://www.whatwg.org/html/#sharedworker">
+<link rel=help href="http://dev.w3.org/2006/webapi/WebIDL/#es-interface-call">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(() => {
+ assert_throws_js(TypeError, () => {
+ const worker = new SharedWorker();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/null b/testing/web-platform/tests/workers/constructors/SharedWorker/null
new file mode 100644
index 0000000000..16f02d5131
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/null
@@ -0,0 +1,3 @@
+onconnect = e => {
+ e.ports[0].postMessage(['null', self.name]);
+};
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/null-arguments.html b/testing/web-platform/tests/workers/constructors/SharedWorker/null-arguments.html
new file mode 100644
index 0000000000..dd5e5773ed
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/null-arguments.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<title>null as arguments</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ const worker = new SharedWorker(null, null);
+ worker.port.onmessage = t.step_func_done(e => {
+ assert_equals(e.data[0], 'null', 'first arg (script name)');
+ assert_equals(e.data[1], '', 'second arg (worker name)');
+ });
+}, 'Test constructing a shared worker with null');
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/null.headers b/testing/web-platform/tests/workers/constructors/SharedWorker/null.headers
new file mode 100644
index 0000000000..e7ec0d6699
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/null.headers
@@ -0,0 +1 @@
+Content-Type: text/javascript
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/number-arguments.html b/testing/web-platform/tests/workers/constructors/SharedWorker/number-arguments.html
new file mode 100644
index 0000000000..8f90baa898
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/number-arguments.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<title>1 as arguments</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ const worker = new SharedWorker(1, 1);
+ worker.port.onmessage = t.step_func_done(e => {
+ assert_equals(e.data[0], '1', 'first arg (script name)');
+ assert_equals(e.data[1], '1', 'second arg (worker name)');
+ });
+}, 'Test constructing a shared worker with 1');
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/port-onmessage.html b/testing/web-platform/tests/workers/constructors/SharedWorker/port-onmessage.html
new file mode 100644
index 0000000000..706420c5e4
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/port-onmessage.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>worker.port.onmessage</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ const worker = new SharedWorker('port-onmessage.js', '');
+ worker.port.onmessage = t.step_func_done(e => {
+ assert_true(e.data);
+ });
+}, 'Test SharedWorker.port.onmessage');
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/port-onmessage.js b/testing/web-platform/tests/workers/constructors/SharedWorker/port-onmessage.js
new file mode 100644
index 0000000000..64ef84df15
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/port-onmessage.js
@@ -0,0 +1,3 @@
+onconnect = e => {
+ e.ports[0].postMessage(true);
+};
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/port-properties.html b/testing/web-platform/tests/workers/constructors/SharedWorker/port-properties.html
new file mode 100644
index 0000000000..e2a1d5b2a8
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/port-properties.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>worker.port</title>
+<link rel=help href="http://www.whatwg.org/html/#sharedworker">
+<link rel=help href="http://www.whatwg.org/html/#messageport">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(() => {
+ const worker = new SharedWorker('empty.js', '');
+ assert_true('port' in worker, "port");
+ assert_true('postMessage' in worker.port, "postMessage");
+ assert_true('start' in worker.port, "start");
+ assert_true('close' in worker.port, "close");
+ assert_true('onmessage' in worker.port, "onmessage");
+ assert_true('addEventListener' in worker.port, "addEventListener");
+ assert_true('removeEventListener' in worker.port, "removeEventListener");
+ assert_true('dispatchEvent' in worker.port, "dispatchEvent");
+});
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/port-readonly.html b/testing/web-platform/tests/workers/constructors/SharedWorker/port-readonly.html
new file mode 100644
index 0000000000..cfb5f3afa5
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/port-readonly.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>setting worker.port</title>
+<link rel=help href="http://www.whatwg.org/html/#sharedworker">
+<link rel=help href="http://dev.w3.org/2006/webapi/WebIDL/#dfn-attribute-setter">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(() => {
+ const worker = new SharedWorker('empty.js', '');
+ const x = worker.port;
+ worker.port = 1;
+ assert_equals(worker.port, x);
+});
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/same-origin.html b/testing/web-platform/tests/workers/constructors/SharedWorker/same-origin.html
new file mode 100644
index 0000000000..4f1b62a660
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/same-origin.html
@@ -0,0 +1,62 @@
+<!doctype html>
+<title>same-origin checks</title>
+<meta name="timeout" content="long">
+<link rel=help href="https://html.spec.whatwg.org/multipage/workers.html#dom-sharedworker">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+// Needed to prevent a race condition if a worker throws an exception that may or may
+// not propogate to the window before the tests finish
+setup({allow_uncaught_exception: true});
+
+testSharedWorkerHelper = (t, script) => {
+ const worker = new SharedWorker(script, '');
+ worker.onerror = t.step_func_done(e => {
+ assert_true(e instanceof Event);
+ });
+}
+
+test(() => {
+ assert_throws_dom("SyntaxError", () => { new SharedWorker('https://test:test', ''); });
+}, "non-parsable URL");
+
+async_test(t => {
+ // Parses fine as a URL, fails to fetch according to Fetch
+ testSharedWorkerHelper(t, 'unsupported:');
+}, "unsupported_scheme");
+
+async_test(t => {
+ const worker = new SharedWorker('data:,onconnect = e => { e.ports[0].postMessage(1); }', '');
+ worker.port.onmessage = t.step_func_done(e => {
+ assert_equals(e.data, 1);
+ });
+}, "data_url");
+
+async_test(t => {
+ testSharedWorkerHelper(t, 'javascript:""');
+}, "javascript_url");
+
+async_test(t => {
+ testSharedWorkerHelper(t, 'about:blank');
+}, "about_blank");
+
+async_test(t => {
+ testSharedWorkerHelper(t, 'http://www.opera.com/');
+}, "opera_com");
+
+async_test(t => {
+ testSharedWorkerHelper(t, location.protocol+'//'+location.hostname+':81/');
+}, "port_81");
+
+async_test(t => {
+ testSharedWorkerHelper(t, 'https://'+location.hostname+':80/');
+}, "https_port_80");
+
+async_test(t => {
+ testSharedWorkerHelper(t, 'https://'+location.hostname+':8000/');
+}, "https_port_8000");
+
+async_test(t => {
+ testSharedWorkerHelper(t, 'http://'+location.hostname+':8012/');
+}, "http_port_8012");
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/setting-port-members.html b/testing/web-platform/tests/workers/constructors/SharedWorker/setting-port-members.html
new file mode 100644
index 0000000000..0c53474ff0
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/setting-port-members.html
@@ -0,0 +1,53 @@
+<!doctype html>
+<title>setting members of worker.port</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+setup(() => {
+ window.worker = new SharedWorker('#', '');
+});
+test(() => {
+ worker.port.postMessage = 1;
+ assert_equals(worker.port.postMessage, 1);
+}, 'postMessage');
+test(() => {
+ worker.port.start = 1;
+ assert_equals(worker.port.start, 1);
+}, 'start');
+test(() => {
+ worker.port.close = 1;
+ assert_equals(worker.port.close, 1);
+}, 'close');
+test(() => {
+ const f = () => {};
+ worker.port.onmessage = f;
+ assert_equals(worker.port.onmessage, f, '() => {}');
+ worker.port.onmessage = 1;
+ assert_equals(worker.port.onmessage, null, '1');
+ worker.port.onmessage = f;
+ worker.port.onmessage = ';';
+ assert_equals(worker.port.onmessage, null, '";"');
+ worker.port.onmessage = f;
+ const handler = {handleEvent:() => {}};
+ worker.port.onmessage = handler;
+ assert_equals(worker.port.onmessage, handler, '{handleEvent:() => {}}');
+ worker.port.onmessage = f;
+ worker.port.onmessage = null;
+ assert_equals(worker.port.onmessage, null, 'null');
+ worker.port.onmessage = f;
+ worker.port.onmessage = undefined;
+ assert_equals(worker.port.onmessage, null, 'undefined');
+}, 'onmessage');
+test(() => {
+ worker.port.addEventListener = 1;
+ assert_equals(worker.port.addEventListener, 1);
+}, 'addEventListener');
+test(() => {
+ worker.port.removeEventListener = 1;
+ assert_equals(worker.port.removeEventListener, 1);
+}, 'removeEventListener');
+test(() => {
+ worker.port.despatchEvent = 1;
+ assert_equals(worker.port.despatchEvent, 1);
+}, 'despatchEvent');
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/shared-worker.js b/testing/web-platform/tests/workers/constructors/SharedWorker/shared-worker.js
new file mode 100644
index 0000000000..b6d18855da
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/shared-worker.js
@@ -0,0 +1,6 @@
+onconnect = e => {
+ const port = e.ports[0];
+ port.onmessage = e => {
+ port.postMessage('ping');
+ }
+}
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/undefined b/testing/web-platform/tests/workers/constructors/SharedWorker/undefined
new file mode 100644
index 0000000000..b8462f1911
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/undefined
@@ -0,0 +1,3 @@
+onconnect = e => {
+ e.ports[0].postMessage(['undefined', self.name]);
+};
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/undefined-arguments.html b/testing/web-platform/tests/workers/constructors/SharedWorker/undefined-arguments.html
new file mode 100644
index 0000000000..cd4c86e84a
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/undefined-arguments.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<title>undefined as arguments</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ const worker = new SharedWorker(undefined, undefined);
+ worker.port.onmessage = t.step_func_done(e => {
+ assert_equals(e.data[0], 'undefined', 'first arg (script name)');
+ assert_equals(e.data[1], '', 'second arg (worker name)');
+ });
+}, 'Test constructing a shared worker with undefined');
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/undefined.headers b/testing/web-platform/tests/workers/constructors/SharedWorker/undefined.headers
new file mode 100644
index 0000000000..e7ec0d6699
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/undefined.headers
@@ -0,0 +1 @@
+Content-Type: text/javascript
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/unexpected-global-properties.html b/testing/web-platform/tests/workers/constructors/SharedWorker/unexpected-global-properties.html
new file mode 100644
index 0000000000..522d31ff56
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/unexpected-global-properties.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>unexpected members/interface objects/constructors</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ const worker = new SharedWorker('unexpected-global-properties.js');
+ worker.port.onmessage = t.step_func_done(e => {
+ assert_equals(e.data, '');
+ });
+}, 'Test unexpected properties are not in global scope');
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/unexpected-global-properties.js b/testing/web-platform/tests/workers/constructors/SharedWorker/unexpected-global-properties.js
new file mode 100644
index 0000000000..0af8935821
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/unexpected-global-properties.js
@@ -0,0 +1,9 @@
+const unexpected = 'open print stop getComputedStyle getSelection releaseEvents captureEvents alert confirm prompt addEventStream removeEventStream back forward attachEvent detachEvent navigate DOMParser XMLSerializer XPathEvaluator XSLTProcessor opera Image Option frames Audio SVGUnitTypes SVGZoomAndPan java netscape sun Packages ByteArray closed defaultStatus document event frameElement history innerHeight innerWidth opener outerHeight outerWidth pageXOffset pageYOffset parent screen screenLeft screenTop screenX screenY status top window length'.split(' '); // iterated window in opera and removed expected ones
+let log = '';
+for (let i = 0; i < unexpected.length; ++i) {
+ if (unexpected[i] in self)
+ log += unexpected[i] + ' ';
+}
+onconnect = e => {
+ e.ports[0].postMessage(log);
+};
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/unresolvable-url.html b/testing/web-platform/tests/workers/constructors/SharedWorker/unresolvable-url.html
new file mode 100644
index 0000000000..c68968d77d
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/unresolvable-url.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>resolving broken url</title>
+<link rel=help href="http://www.whatwg.org/html/#dom-sharedworker">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(() => {
+ assert_throws_dom("SyntaxError", () => {
+ const worker = new SharedWorker('http://foo bar');
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/Worker/1 b/testing/web-platform/tests/workers/constructors/Worker/1
new file mode 100644
index 0000000000..ea0b7c8f4c
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/Worker/1
@@ -0,0 +1 @@
+postMessage('1');
diff --git a/testing/web-platform/tests/workers/constructors/Worker/1.headers b/testing/web-platform/tests/workers/constructors/Worker/1.headers
new file mode 100644
index 0000000000..e7ec0d6699
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/Worker/1.headers
@@ -0,0 +1 @@
+Content-Type: text/javascript
diff --git a/testing/web-platform/tests/workers/constructors/Worker/AbstractWorker.onerror.html b/testing/web-platform/tests/workers/constructors/Worker/AbstractWorker.onerror.html
new file mode 100644
index 0000000000..b27f278bff
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/Worker/AbstractWorker.onerror.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<title>AbstractWorker.onerror</title>
+<link rel=help href="https://html.spec.whatwg.org/multipage/#runtime-script-errors-2">
+<link rel=help href="https://html.spec.whatwg.org/multipage/#report-the-error">
+<link rel=help href="https://html.spec.whatwg.org/multipage/#the-event-handler-processing-algorithm">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+setup({allow_uncaught_exception:true});
+async_test(function() {
+ var worker = new Worker('AbstractWorker.onerror.js');
+ var error;
+ worker.onerror = this.step_func(function(a, b, c) {
+ error = a;
+ assert_equals('' + a, '[object ErrorEvent]');
+ assert_true("message" in a, 'ErrorEvent.message');
+ assert_equals(typeof a.message, "string", 'ErrorEvent.message');
+ assert_equals(a.filename, document.URL.replace('.html', '.js'), 'ErrorEvent.filename');
+ assert_true("lineno" in a, 'ErrorEvent.lineno');
+ assert_equals(typeof a.lineno, "number", 'ErrorEvent.lineno');
+ assert_equals(b, undefined, 'unexpected second argument to onerror');
+ assert_equals(c, undefined, 'unexpected third argument to onerror');
+ });
+ worker.onmessage = this.step_func(function(e) {
+ assert_unreached('onmessage was invoked but worker script shouldn\'t have compiled');
+ });
+ window.onerror = this.step_func_done(function(a, b, c, d, e, f) {
+ assert_equals(a, error.message, 'message');
+ assert_equals(b, error.filename, 'filename');
+ assert_equals(c, error.lineno, 'lineno');
+ assert_equals(d, error.colno, 'colno');
+ assert_equals(e, error.error, 'error');
+ assert_equals(f, undefined, 'unexpected sixth argument to onerror');
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/constructors/Worker/AbstractWorker.onerror.js b/testing/web-platform/tests/workers/constructors/Worker/AbstractWorker.onerror.js
new file mode 100644
index 0000000000..1594decd37
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/Worker/AbstractWorker.onerror.js
@@ -0,0 +1,5 @@
+// Throw a runtime error, the UA must report the error for that script.
+// https://html.spec.whatwg.org/#runtime-script-errors-2
+for (;;)
+ throw new Error("error from onerror.js");
+postMessage(1); // shouldn't do anything since the script doesn't compile
diff --git a/testing/web-platform/tests/workers/constructors/Worker/Blob-url.html b/testing/web-platform/tests/workers/constructors/Worker/Blob-url.html
new file mode 100644
index 0000000000..168fc91ae1
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/Worker/Blob-url.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Web Workers: Worker - Blob url</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+
+ async_test(function(t) {
+ var blob = new Blob(["onmessage = function(event) { postMessage(event.data); }"], {type: "text/plain"});
+ var worker = new Worker(window.URL.createObjectURL(blob));
+ var data = "Blob URL";
+ worker.postMessage(data);
+ worker.onmessage = t.step_func(function(event) {
+ assert_equals(event.data, data, "event.data");
+ t.done();
+ });
+ }, "Worker supports Blob url");
+
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/Worker/DedicatedWorkerGlobalScope-members.worker.js b/testing/web-platform/tests/workers/constructors/Worker/DedicatedWorkerGlobalScope-members.worker.js
new file mode 100644
index 0000000000..2ef466ccdc
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/Worker/DedicatedWorkerGlobalScope-members.worker.js
@@ -0,0 +1,18 @@
+importScripts("/resources/testharness.js");
+
+var expected = [
+ 'postMessage', 'onmessage', /* DedicatedWorkerGlobalScope */
+ 'self', 'location', 'close', 'onerror', 'onoffline', 'ononline', /* WorkerGlobalScope */
+ 'addEventListener', 'removeEventListener', 'dispatchEvent', /* EventListener */
+ 'importScripts', 'navigator', /* WorkerUtils */
+ 'setTimeout', 'clearTimeout', 'setInterval', 'clearInterval', /* WindowTimers */
+ 'btoa', 'atob' /* WindowBase64 */
+];
+for (var i = 0; i < expected.length; ++i) {
+ var property = expected[i];
+ test(function() {
+ assert_true(property in self);
+ }, "existence of " + property);
+}
+
+done();
diff --git a/testing/web-platform/tests/workers/constructors/Worker/Worker-constructor.html b/testing/web-platform/tests/workers/constructors/Worker/Worker-constructor.html
new file mode 100644
index 0000000000..6d6843b77b
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/Worker/Worker-constructor.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<title>Test Worker constructor functionality.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+test(() => {
+ assert_throws_js(Error,
+ function() {
+ new Worker({toString:function(){throw new Error()}})},
+ 'toString exception should be propagated');
+}, 'Test toString propagation exception.');
+
+test(() => {
+ try {
+ var foo = {toString:function(){new Worker(foo)}};
+ new Worker(foo);
+ } catch(ex) {
+ assert_true(true, 'trying to create workers recursively should result in an: ' +
+ ex + 'exception.')
+ }
+}, 'Test recursive Worker creation.');
+
+test(() => {
+ assert_throws_js(TypeError,
+ function() { new Worker(); },
+ 'invoking Worker constructor without arguments should result ' +
+ 'in an exception.')
+}, 'Test worker creation with no arguments');
+
+async_test(t => {
+ var worker = new Worker('');
+ worker.onerror = function(e) {
+ e.preventDefault();
+ t.done();
+ }
+}, 'Test Worker creation with empty script URL.');
+
+test(() => {
+ assert_throws_dom("SyntaxError",
+ function() { var worker = new Worker('http://invalid:123$'); },
+ 'Invoking Worker constructor with invalid script URL should ' +
+ 'result in an exception.');
+}, 'Test invalid script URL.');
+
+async_test(t => {
+ var worker = new Worker('does-not-exist.js');
+ worker.onerror = function(e) {
+ t.done();
+ }
+}, 'Test not existent script URL.');
+
+test(() => {
+ var worker = new Worker('../../support/Worker-common.js');
+ assert_true('postMessage' in worker,
+ 'worker.postMessage did not exist.');
+ assert_true('addEventListener' in worker,
+ 'worker.addEventListener did not exist.');
+}, 'Test the Worker object defines postMessage() and addEventListener().');
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/Worker/ctor-1.html b/testing/web-platform/tests/workers/constructors/Worker/ctor-1.html
new file mode 100644
index 0000000000..bd865261fc
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/Worker/ctor-1.html
@@ -0,0 +1,23 @@
+<!--
+postMessage('FAIL');
+/*
+-->
+<!doctype html>
+<title>1 as argument</title>
+<link rel=help href="http://www.whatwg.org/html/#dom-worker">
+<link rel=help href="http://dev.w3.org/2006/webapi/WebIDL/#es-DOMString">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+var t = async_test();
+t.step(function() {
+ var worker = new Worker(1);
+ worker.addEventListener('message', t.step_func_done(function(e) {
+ assert_equals(e.data, '1')
+ }), false);
+});
+</script>
+<!--
+*/
+//-->
diff --git a/testing/web-platform/tests/workers/constructors/Worker/ctor-null.html b/testing/web-platform/tests/workers/constructors/Worker/ctor-null.html
new file mode 100644
index 0000000000..94ab71aeff
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/Worker/ctor-null.html
@@ -0,0 +1,23 @@
+<!--
+postMessage('FAIL');
+/*
+-->
+<!doctype html>
+<title>null as argument</title>
+<link rel=help href="http://www.whatwg.org/html/#dom-worker">
+<link rel=help href="http://dev.w3.org/2006/webapi/WebIDL/#es-DOMString">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+var t = async_test();
+t.step(function() {
+ var worker = new Worker(null);
+ worker.addEventListener('message', t.step_func_done(function(e) {
+ assert_equals(e.data, 'null')
+ }), false);
+});
+</script>
+<!--
+*/
+//-->
diff --git a/testing/web-platform/tests/workers/constructors/Worker/ctor-undefined.html b/testing/web-platform/tests/workers/constructors/Worker/ctor-undefined.html
new file mode 100644
index 0000000000..2d9eb6e656
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/Worker/ctor-undefined.html
@@ -0,0 +1,23 @@
+<!--
+postMessage('FAIL');
+/*
+-->
+<!doctype html>
+<title>undefined as argument</title>
+<link rel=help href="http://www.whatwg.org/html/#dom-worker">
+<link rel=help href="http://dev.w3.org/2006/webapi/WebIDL/#es-DOMString">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+var t = async_test();
+t.step(function() {
+ var worker = new Worker(undefined);
+ worker.addEventListener('message', t.step_func_done(function(e) {
+ assert_equals(e.data, 'undefined')
+ }), false);
+});
+</script>
+<!--
+*/
+//-->
diff --git a/testing/web-platform/tests/workers/constructors/Worker/expected-self-properties.worker.js b/testing/web-platform/tests/workers/constructors/Worker/expected-self-properties.worker.js
new file mode 100644
index 0000000000..0ce41b59e7
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/Worker/expected-self-properties.worker.js
@@ -0,0 +1,11 @@
+importScripts("/resources/testharness.js");
+
+var expected = ['XMLHttpRequest', 'WebSocket', 'EventSource', 'MessageChannel', 'Worker', 'SharedWorker'];
+for (var i = 0; i < expected.length; ++i) {
+ var property = expected[i];
+ test(function() {
+ assert_true(property in self);
+ }, "existence of " + property);
+}
+
+done();
diff --git a/testing/web-platform/tests/workers/constructors/Worker/null b/testing/web-platform/tests/workers/constructors/Worker/null
new file mode 100644
index 0000000000..6d079b514c
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/Worker/null
@@ -0,0 +1 @@
+postMessage('null');
diff --git a/testing/web-platform/tests/workers/constructors/Worker/null.headers b/testing/web-platform/tests/workers/constructors/Worker/null.headers
new file mode 100644
index 0000000000..e7ec0d6699
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/Worker/null.headers
@@ -0,0 +1 @@
+Content-Type: text/javascript
diff --git a/testing/web-platform/tests/workers/constructors/Worker/same-origin.html b/testing/web-platform/tests/workers/constructors/Worker/same-origin.html
new file mode 100644
index 0000000000..56dbfe3b3f
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/Worker/same-origin.html
@@ -0,0 +1,65 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>same-origin checks; the script is in a script element</title>
+<meta name="timeout" content="long">
+<link rel=help href="https://html.spec.whatwg.org/multipage/workers.html#dom-worker">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+// Needed to prevent a race condition if a worker throws an exception that may or may
+// not propogate to the window before the tests finish
+setup({allow_uncaught_exception: true});
+
+function testWorkerHelper(t, script) {
+ var worker = new Worker(script);
+ worker.onerror = t.step_func_done(function(e) {
+ assert_true(e instanceof Event);
+ });
+}
+
+test(function() {
+ assert_throws_dom("SyntaxError", function() { new Worker('https://test:test'); });
+}, "non-parsable URL");
+
+async_test(function(t) {
+ // Parses fine as a URL, fails to fetch according to Fetch
+ testWorkerHelper(t, 'unsupported:');
+}, "unsupported_scheme");
+
+async_test(function() {
+ var worker = new Worker('data:,postMessage(1);');
+ worker.onmessage = this.step_func_done(function(e) {
+ assert_equals(e.data, 1);
+ });
+}, "data_url");
+
+async_test(function(t) {
+ testWorkerHelper(t, 'about:blank');
+}, "about_blank");
+
+async_test(function(t) {
+ testWorkerHelper(t, 'http://www.example.invalid/');
+}, "example_invalid");
+
+async_test(function(t) {
+ testWorkerHelper(t, location.protocol+'//'+location.hostname+':81/');
+}, "port_81");
+
+async_test(function(t) {
+ testWorkerHelper(t, 'https://'+location.hostname+':80/');
+}, "https_port_80");
+
+async_test(function(t) {
+ testWorkerHelper(t, 'https://'+location.hostname+':8000/');
+}, "https_port_8000");
+
+async_test(function(t) {
+ testWorkerHelper(t, 'http://'+location.hostname+':8012/');
+}, "http_post_8012");
+
+async_test(function(t) {
+ testWorkerHelper(t,'javascript:""');
+}, "javascript_url");
+
+</script>
diff --git a/testing/web-platform/tests/workers/constructors/Worker/sample_worker/worker.js b/testing/web-platform/tests/workers/constructors/Worker/sample_worker/worker.js
new file mode 100644
index 0000000000..19bbea58e7
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/Worker/sample_worker/worker.js
@@ -0,0 +1 @@
+onmessage = function(event) { postMessage(event.data); }
diff --git a/testing/web-platform/tests/workers/constructors/Worker/terminate.html b/testing/web-platform/tests/workers/constructors/Worker/terminate.html
new file mode 100644
index 0000000000..b9af76e2fb
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/Worker/terminate.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<title>terminate()</title>
+<link rel=help href="http://www.whatwg.org/html/#dom-worker-terminate">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+var t = async_test();
+t.step(function() {
+ var worker = new Worker('terminate.js');
+ var i = 0;
+ var expected;
+
+ worker.onmessage = t.step_func(function() {
+ i++;
+ });
+
+ setTimeout(t.step_func(function() {
+ expected = i;
+ start_time = Date.now();
+ //Hang the main thread for a bit to give the worker the chance to post some more messages
+ while(Date.now() - start_time < 500) {
+ //pass
+ }
+ worker.terminate();
+
+ setTimeout(t.step_func(function() {
+ assert_equals(i, expected);
+ t.done();
+ }), 100);
+
+ }), 100);
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/constructors/Worker/terminate.js b/testing/web-platform/tests/workers/constructors/Worker/terminate.js
new file mode 100644
index 0000000000..e6349c3320
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/Worker/terminate.js
@@ -0,0 +1,4 @@
+(function f() {
+ postMessage(1);
+ setTimeout(f, 0);
+})(); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/constructors/Worker/undefined b/testing/web-platform/tests/workers/constructors/Worker/undefined
new file mode 100644
index 0000000000..bc7f482e94
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/Worker/undefined
@@ -0,0 +1 @@
+postMessage('undefined');
diff --git a/testing/web-platform/tests/workers/constructors/Worker/undefined.headers b/testing/web-platform/tests/workers/constructors/Worker/undefined.headers
new file mode 100644
index 0000000000..e7ec0d6699
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/Worker/undefined.headers
@@ -0,0 +1 @@
+Content-Type: text/javascript
diff --git a/testing/web-platform/tests/workers/constructors/Worker/unexpected-self-properties.worker.js b/testing/web-platform/tests/workers/constructors/Worker/unexpected-self-properties.worker.js
new file mode 100644
index 0000000000..69d29b2297
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/Worker/unexpected-self-properties.worker.js
@@ -0,0 +1,11 @@
+importScripts("/resources/testharness.js");
+
+var unexpected = ['open', 'print', 'stop', 'getComputedStyle', 'getSelection', 'releaseEvents', 'captureEvents', 'alert', 'confirm', 'prompt', 'addEventStream', 'removeEventStream', 'back', 'forward', 'attachEvent', 'detachEvent', 'navigate', 'DOMParser', 'XMLSerializer', 'XPathEvaluator', 'XSLTProcessor', 'opera', 'Image', 'Option', 'frames', 'Audio', 'SVGUnitTypes', 'SVGZoomAndPan', 'java', 'netscape', 'sun', 'Packages', 'ByteArray', 'closed', 'defaultStatus', 'document', 'event', 'frameElement', 'history', 'innerHeight', 'innerWidth', 'opener', 'outerHeight', 'outerWidth', 'pageXOffset', 'pageYOffset', 'parent', 'screen', 'screenLeft', 'screenTop', 'screenX', 'screenY', 'status', 'top', 'window', 'length']; // iterated window in opera and removed expected ones
+for (var i = 0; i < unexpected.length; ++i) {
+ var property = unexpected[i];
+ test(function() {
+ assert_false(property in self);
+ }, "existence of " + property);
+}
+
+done();
diff --git a/testing/web-platform/tests/workers/constructors/Worker/use-base-url.html b/testing/web-platform/tests/workers/constructors/Worker/use-base-url.html
new file mode 100644
index 0000000000..94ce2a71f1
--- /dev/null
+++ b/testing/web-platform/tests/workers/constructors/Worker/use-base-url.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Use the document base url when resolving worker URLs</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<base href="/workers/constructors/Worker/sample_worker/">
+<script>
+ async_test(function(t) {
+ var worker = new Worker('worker.js');
+ var data = "foo";
+ worker.postMessage(data);
+ worker.onmessage = t.step_func_done(function(event) {
+ assert_equals(event.data, data, "event.data does not match expected data");
+ });
+ worker.onerror = t.unreached_func("received error event");
+ }, "Use the document base url when resolving worker URLs");
+</script>
diff --git a/testing/web-platform/tests/workers/data-url-shared-window.html b/testing/web-platform/tests/workers/data-url-shared-window.html
new file mode 100644
index 0000000000..7459f59286
--- /dev/null
+++ b/testing/web-platform/tests/workers/data-url-shared-window.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<head>
+<title>data URL shared worker</title>
+</head>
+<body>
+<script>
+onmessage = event => {
+ const port = event.ports[0];
+ // This shared worker counts the total number of connected documents and
+ // notifies the connector of it.
+ const kScript =
+ "onconnect = e => {" +
+ " if (self.count === undefined)" +
+ " self.count = 0;" +
+ " self.count++;" +
+ " e.ports[0].postMessage(self.count);" +
+ "};";
+ const worker = new SharedWorker('data:application/javascript,' + kScript);
+ worker.port.onmessage = e => port.postMessage(e.data);
+};
+
+window.opener.postMessage('LOADED', '*');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/workers/data-url-shared.html b/testing/web-platform/tests/workers/data-url-shared.html
new file mode 100644
index 0000000000..aae76d46cd
--- /dev/null
+++ b/testing/web-platform/tests/workers/data-url-shared.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<title>data URL shared workers</title>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+function assert_worker_sends_pass(test_desc, mime_type, worker_code) {
+ async_test(function(t) {
+ var w = new SharedWorker(`data:${mime_type},onconnect = function(e) { port = e.ports[0]; ${worker_code}}`);
+ w.port.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data, 'PASS');
+ });
+ w.port.postMessage('SEND_PASS');
+ }, test_desc);
+}
+
+function assert_worker_throws(test_desc, worker_code) {
+ assert_worker_sends_pass(test_desc, '', `try { ${worker_code}; port.postMessage("FAIL"); } catch (e) { port.postMessage("PASS"); }`);
+}
+
+// Any MIME type allowed
+assert_worker_sends_pass('application/javascript MIME allowed', 'application/javascript', 'port.postMessage("PASS")');
+assert_worker_sends_pass('text/plain MIME allowed', 'text/plain', 'port.postMessage("PASS")');
+assert_worker_sends_pass('empty MIME allowed', '', 'port.postMessage("PASS")');
+
+// Communications goes both ways
+assert_worker_sends_pass('communication goes both ways', 'application/javascript', 'port.onmessage = function(e) { port.postMessage("PASS"); }');
+
+// test access to storage APIs
+
+// https://w3c.github.io/IndexedDB/#dom-idbfactory-open
+assert_worker_sends_pass('indexedDB is present', '', 'port.postMessage("indexedDB" in self ? "PASS" : "FAIL")');
+assert_worker_throws('indexedDB is inaccessible', 'self.indexedDB.open("someDBName")');
+// Other standardized storage APIs are either not exposed to workers
+// (e.g. window.localStorage, window.sessionStorage), or are [SecureContext]
+// (e.g. self.caches).
+
+// 'data:' workers are cross-origin
+assert_worker_sends_pass('cross-origin worker', '', 'fetch("/").then(() => port.postMessage("FAIL"), () => port.postMessage("PASS"))');
+
+// 'data:' workers have opaque origin
+assert_worker_sends_pass('worker has opaque origin', 'application/javascript', 'port.postMessage(self.location.origin == "null" ? "PASS" : "FAIL")');
+
+function openWindow(url) {
+ return new Promise(resolve => {
+ const win = window.open(url, '_blank');
+ add_completion_callback(() => win.close());
+ window.onmessage = e => {
+ assert_equals(e.data, 'LOADED');
+ resolve(win);
+ };
+ });
+}
+
+promise_test(() => {
+ const kWindowURL = 'data-url-shared-window.html';
+ const kRemoteWindowURL = get_host_info().HTTP_REMOTE_ORIGIN +
+ '/workers/data-url-shared-window.html';
+ return openWindow(kWindowURL)
+ .then(win => {
+ const channel = new MessageChannel;
+ win.postMessage(channel.port1, '*', [channel.port1]);
+ return new Promise(resolve => channel.port2.onmessage = resolve);
+ })
+ .then(msg_event => {
+ assert_equals(msg_event.data, 1);
+ return openWindow(kRemoteWindowURL);
+ })
+ .then(win => {
+ const channel = new MessageChannel;
+ win.postMessage(channel.port1, '*', [channel.port1]);
+ return new Promise(resolve => channel.port2.onmessage = resolve);
+ })
+ .then(msg_event => assert_equals(msg_event.data, 1));
+}, 'A data: URL shared worker should not be shared among origins.');
+
+</script>
diff --git a/testing/web-platform/tests/workers/data-url.html b/testing/web-platform/tests/workers/data-url.html
new file mode 100644
index 0000000000..f8fe65e520
--- /dev/null
+++ b/testing/web-platform/tests/workers/data-url.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<title>data URL dedicated workers</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+// Helper assert functions -START-
+function assert_worker_sends_pass(test_desc, mime_type, worker_code) {
+ async_test(function(t) {
+ var w = new Worker(`data:${mime_type},${worker_code}`);
+ w.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data, 'PASS');
+ });
+ w.postMessage('SEND_PASS');
+ }, test_desc);
+}
+
+function assert_worker_throws(test_desc, worker_code) {
+ assert_worker_sends_pass(test_desc, '', `try { ${worker_code}; self.postMessage("FAIL"); } catch (e) { self.postMessage("PASS"); }`);
+}
+
+function assert_worker_construction_fails(test_desc, mime_type, worker_code) {
+ async_test(function(t) {
+ var w = new Worker(`data:${mime_type},${worker_code};postMessage("PASS")`);
+ w.onmessage = t.step_func_done(function(e) {
+ assert_unreached('Should not receive any message back.');
+ });
+ w.onerror = t.step_func_done(function(e) {
+ assert_true(true, 'Should throw ' + e.message);
+ // Stop the error from being propagated to the WPT test harness
+ e.preventDefault();
+ });
+ }, test_desc);
+}
+// Helper assert functions -END-
+
+// Actual tests -START-
+
+// Any MIME type allowed
+assert_worker_sends_pass('application/javascript MIME allowed', 'application/javascript', 'self.postMessage("PASS")');
+assert_worker_sends_pass('text/plain MIME allowed', 'text/plain', 'self.postMessage("PASS")');
+assert_worker_sends_pass('empty MIME allowed', '', 'self.postMessage("PASS")');
+
+// Communications goes both ways
+assert_worker_sends_pass('communication goes both ways', 'application/javascript', 'onmessage = function(e) { self.postMessage("PASS"); }');
+
+// test access to storage APIs
+
+// https://w3c.github.io/IndexedDB/#dom-idbfactory-open
+assert_worker_sends_pass('indexedDB is present', '', 'self.postMessage("indexedDB" in self ? "PASS" : "FAIL")');
+assert_worker_throws('indexedDB is inaccessible', 'self.indexedDB.open("someDBName")');
+
+// Other standardized storage APIs are either not exposed to workers
+// (e.g. window.localStorage, window.sessionStorage), or are [SecureContext]
+// (e.g. self.caches).
+
+// 'data:' workers are cross-origin
+assert_worker_sends_pass('cross-origin worker', '', 'fetch("/").then(() => self.postMessage("FAIL"), () => self.postMessage("PASS"))');
+
+// 'data:' workers have opaque origin
+assert_worker_sends_pass('worker has opaque origin', 'application/javascript', 'if (self.location.origin == "null") {postMessage("PASS");} else {postMessage("FAIL");}');
+
+setup({allow_uncaught_exception:true});
+// invalid javascript will trigger an ErrorEvent
+assert_worker_construction_fails('invalid javascript produces error', 'application/javascript', '}x=3');
+
+// Actual tests -END-
+</script>
diff --git a/testing/web-platform/tests/workers/dedicated-worker-from-blob-url.window.js b/testing/web-platform/tests/workers/dedicated-worker-from-blob-url.window.js
new file mode 100644
index 0000000000..8455285571
--- /dev/null
+++ b/testing/web-platform/tests/workers/dedicated-worker-from-blob-url.window.js
@@ -0,0 +1,29 @@
+function message_from_port(port) {
+ return new Promise((resolve, reject) => {
+ port.onmessage = e => resolve(e.data);
+ port.onerror = e => reject(e);
+ });
+}
+
+promise_test(async t => {
+ const run_result = 'worker_OK';
+ const blob_contents = 'self.postMessage("' + run_result + '");';
+ const blob = new Blob([blob_contents]);
+ const url = URL.createObjectURL(blob);
+
+ const worker = new Worker(url);
+ const reply = await message_from_port(worker);
+ assert_equals(reply, run_result);
+}, 'Creating a dedicated worker from a blob URL works.');
+
+promise_test(async t => {
+ const run_result = 'worker_OK';
+ const blob_contents = 'self.postMessage("' + run_result + '");';
+ const blob = new Blob([blob_contents]);
+ const url = URL.createObjectURL(blob);
+
+ const worker = new Worker(url);
+ URL.revokeObjectURL(url);
+ const reply = await message_from_port(worker);
+ assert_equals(reply, run_result);
+}, 'Creating a dedicated worker from a blob URL works immediately before revoking.');
diff --git a/testing/web-platform/tests/workers/dedicated-worker-in-data-url-context.window.js b/testing/web-platform/tests/workers/dedicated-worker-in-data-url-context.window.js
new file mode 100644
index 0000000000..124914012d
--- /dev/null
+++ b/testing/web-platform/tests/workers/dedicated-worker-in-data-url-context.window.js
@@ -0,0 +1,111 @@
+// META: title=data URL dedicated worker in data URL context
+// META: script=/service-workers/service-worker/resources/test-helpers.sub.js
+const mimeType = 'application/javascript';
+
+// Tests creating a dedicated worker in a data URL iframe.
+promise_test(async t => {
+ const nestedWorkerScriptURL =
+ new URL('/workers/support/post-message-on-load-worker.js', location.href);
+
+ // This code will be executed in a data URL iframe. The iframe tries to create
+ // a dedicated worker from |nestedWorkerScriptURL|, but that should result in
+ // a failure. This is because the data URL iframe has an opaque origin, and
+ // script fetch is handled as a cross-origin request.
+ const frameCode = `
+ <script>
+ try {
+ const worker = new Worker('${nestedWorkerScriptURL}');
+ worker.onmessage = e => {
+ window.parent.postMessage(
+ 'Worker construction unexpectedly succeeded', '*');
+ };
+ worker.onerror = e => window.parent.postMessage('PASS', '*');
+ } catch (e) {
+ // Cross-origin request should asynchronously fail during worker script
+ // fetch because its request mode is 'same-origin'.
+ window.parent.postMessage(
+ 'Worker construction unexpectedly synchronously failed', '*');
+ }
+ </script>
+ `;
+
+ const p = new Promise(r => window.onmessage = e => r(e.data));
+ const frame = await with_iframe(`data:text/html;base64,${btoa(frameCode)}`);
+ const result = await p;
+ assert_equals(result, 'PASS');
+}, 'Create a dedicated worker in a data url frame');
+
+// Tests creating a dedicated worker in a data URL dedicated worker (i.e.,
+// nested dedicated worker).
+promise_test(async t => {
+ const nestedWorkerScriptURL =
+ new URL('/workers/support/post-message-on-load-worker.js', location.href);
+
+ // This code will be executed in a data URL dedicated worker. The worker tries
+ // to create a nested dedicated worker from |nestedWorkerScriptURL|, but that
+ // should result in a failure. This is because the data URL dedicated worker
+ // has an opaque origin, and script fetch is handled as a cross-origin
+ // request.
+ const workerCode = `
+ try {
+ const worker = new Worker('${nestedWorkerScriptURL}');
+ worker.onmessage =
+ e => postMessage('Worker construction unexpectedly succeeded');
+ worker.onerror = e => postMessage('PASS');
+ } catch (e) {
+ // Cross-origin request should asynchronously fail during worker script
+ // fetch because its request mode is 'same-origin'.
+ postMessage('Worker construction unexpectedly synchronously failed');
+ }
+ `;
+
+ const result = await new Promise((resolve, reject) => {
+ const worker = new Worker(`data:${mimeType};base64,${btoa(workerCode)}`);
+ worker.onmessage = e => resolve(e.data);
+ worker.onerror = e => reject(e.message);
+ });
+ assert_equals(result, 'PASS');
+}, 'Create a dedicated worker in a data url dedicated worker');
+
+// Tests creating a data URL dedicated worker in a data URL iframe.
+promise_test(async t => {
+ // This code will be executed in a data URL iframe. The iframe tries to create
+ // a data URL dedicated worker. Fetching a data URL from the data URL iframe
+ // whose origin is opaque is allowed, so the worker construction should
+ // succeed. The iframe posts the result to the parent frame.
+ const frameCode = `
+ <script>
+ const worker = new Worker('data:${mimeType},postMessage("PASS");');
+ worker.onmessage = e => window.parent.postMessage(e.data, '*');
+ worker.onerror = e => {
+ window.parent.postMessage('FAIL: ' + e.message, '*');
+ };
+ </script>
+ `;
+
+ const p = new Promise(r => window.onmessage = e => r(e.data));
+ const frame = await with_iframe(`data:text/html;base64,${btoa(frameCode)}`);
+ const result = await p;
+ assert_equals(result, 'PASS');
+}, 'Create a data url dedicated worker in a data url frame');
+
+// Tests creating a data URL dedicated worker in a data URL dedicated worker
+// (i.e., nested dedicated worker).
+promise_test(async t => {
+ // This code will be executed in a data URL dedicated worker. The worker tries
+ // to create a nested data URL dedicated worker. Fetching a data URL from the
+ // data URL dedicated worker is allowed, so the worker construction should
+ // succeed. The worker posts the result to the parent frame.
+ const workerCode = `
+ const worker = new Worker('data:${mimeType},postMessage("PASS");');
+ worker.onmessage = e => postMessage(e.data);
+ worker.onerror = e => postMessage('FAIL: ' + e.message);
+ `;
+
+ const result = await new Promise((resolve, reject) => {
+ const worker = new Worker(`data:${mimeType};base64,${btoa(workerCode)}`);
+ worker.onmessage = e => resolve(e.data);
+ worker.onerror = e => reject(e.message);
+ });
+ assert_equals(result, 'PASS');
+}, 'Create a data url dedicated worker in a data url dedicated worker');
diff --git a/testing/web-platform/tests/workers/dedicated-worker-parse-error-failure.html b/testing/web-platform/tests/workers/dedicated-worker-parse-error-failure.html
new file mode 100644
index 0000000000..ed475dab10
--- /dev/null
+++ b/testing/web-platform/tests/workers/dedicated-worker-parse-error-failure.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<title>DedicatedWorker: parse error failure</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script> setup({allow_uncaught_exception: true}); </script>
+<script src="./support/check-error-arguments.js"></script>
+<script>
+
+promise_test(async () => {
+ const scriptURL = 'modules/resources/syntax-error.js';
+ const worker = new Worker(scriptURL, { type: 'classic' });
+ const args = await new Promise(resolve =>
+ worker.onerror = (...args) => resolve(args));
+ window.checkErrorArguments(args);
+}, 'Classic worker construction for script with syntax error should dispatch ' +
+ 'an event named error.');
+
+promise_test(async () => {
+ const scriptURL = 'modules/resources/static-import-worker.js';
+ const worker = new Worker(scriptURL, { type: 'classic' });
+ worker.postMessage('Send message for tests from main script.');
+ const args = await new Promise(resolve =>
+ worker.onerror = (...args) => resolve(args));
+ window.checkErrorArguments(args);
+}, 'Static import on classic worker should dispatch an event named error.');
+
+</script>
diff --git a/testing/web-platform/tests/workers/examples/fetch_tests_from_worker.html b/testing/web-platform/tests/workers/examples/fetch_tests_from_worker.html
new file mode 100644
index 0000000000..5ac765c7ee
--- /dev/null
+++ b/testing/web-platform/tests/workers/examples/fetch_tests_from_worker.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<!--
+ This file is an example of a hand-written test using
+ fetch_tests_from_worker().
+ Unlike *.any.js or *.worker.js tests, fetch_tests_from_worker.html/js files
+ are manually written and no generated glue code are involved.
+-->
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+fetch_tests_from_worker(new Worker("fetch_tests_from_worker.js"));
+
+// If you want to test on SharedWorker,
+// fetch_tests_from_worker(new SharedWorker("fetch_tests_from_worker.js"));
+
+// See ServiceWorkersHandler in
+// https://github.com/web-platform-tests/wpt/blob/master/tools/serve/serve.py
+// for the generated snippet used in .any.js for service workers.
+// Note: when testing service workers, also add ".https." file flag in the
+// main HTML's file name to run the test on HTTPS.
+</script>
diff --git a/testing/web-platform/tests/workers/examples/fetch_tests_from_worker.js b/testing/web-platform/tests/workers/examples/fetch_tests_from_worker.js
new file mode 100644
index 0000000000..01ba12a622
--- /dev/null
+++ b/testing/web-platform/tests/workers/examples/fetch_tests_from_worker.js
@@ -0,0 +1,28 @@
+// This file is an example of a hand-written test using
+// fetch_tests_from_worker().
+// Unlike *.any.js or *.worker.js tests, fetch_tests_from_worker.html/js files
+// are manually written and no generated glue code are involved.
+
+// fetch_tests_from_worker() requires testharness.js both on the parent
+// document and on the worker.
+importScripts("/resources/testharness.js");
+
+// ============================================================================
+
+// Test body.
+test(() => {
+ assert_equals(1, 1, "1 == 1");
+ },
+ "Test that should pass"
+);
+
+// ============================================================================
+
+// `done()` is always needed at the bottom for dedicated workers and shared
+// workers, even if you write `async_test()` or `promise_test()`.
+// `async_test()` and `promise_test()` called before this `done()`
+// will continue and assertions/failures after this `done()` are not ignored.
+// See
+// https://web-platform-tests.org/writing-tests/testharness-api.html#determining-when-all-tests-are-complete
+// for details.
+done();
diff --git a/testing/web-platform/tests/workers/examples/general.any.js b/testing/web-platform/tests/workers/examples/general.any.js
new file mode 100644
index 0000000000..cb5d61eafb
--- /dev/null
+++ b/testing/web-platform/tests/workers/examples/general.any.js
@@ -0,0 +1,34 @@
+// META: global=worker
+
+// See
+// https://web-platform-tests.org/writing-tests/testharness.html#multi-global-tests
+// for how to specify in which global scopes to run this tests,
+// how to specify additional scripts needed, etc.
+
+// testharness.js is imported (via importScripts()) by generated glue code by
+// WPT server.
+// See ClassicWorkerHandler in
+// https://github.com/web-platform-tests/wpt/blob/master/tools/serve/serve.py.
+
+// ============================================================================
+
+// Test body.
+// .any.js tests are always testharness.js-based.
+test(() => {
+ assert_equals(1, 1, "1 == 1");
+ },
+ "Test that should pass"
+);
+
+test(() => {
+ // This file is "general.any.js" but the worker top-level script is
+ // "general.any.worker.js", which is generated by the WPT server.
+ assert_equals(location.pathname, "/workers/examples/general.any.worker.js");
+ },
+ "Worker top-level script is a generated script."
+);
+
+// done() is NOT needed in .any.js tests, as it is called by generated
+// glue code by the WPT server.
+// See ClassicWorkerHandler in
+// https://github.com/web-platform-tests/wpt/blob/master/tools/serve/serve.py.
diff --git a/testing/web-platform/tests/workers/examples/general.worker.js b/testing/web-platform/tests/workers/examples/general.worker.js
new file mode 100644
index 0000000000..aeca236781
--- /dev/null
+++ b/testing/web-platform/tests/workers/examples/general.worker.js
@@ -0,0 +1,35 @@
+// This file is an example of a test using *.worker.js mechanism.
+// The parent document that calls fetch_tests_from_worker() is auto-generated
+// but there are no generated code in the worker side.
+
+// fetch_tests_from_worker() requires testharness.js both on the parent
+// document and on the worker.
+importScripts("/resources/testharness.js");
+
+// ============================================================================
+
+// Test body.
+test(() => {
+ assert_equals(1, 1, "1 == 1");
+ },
+ "Test that should pass"
+);
+
+test(() => {
+ // This file is "general.worker.js" and this file itself is the worker
+ // top-level script (which is different from the .any.js case).
+ assert_equals(location.pathname, "/workers/examples/general.worker.js");
+ },
+ "Worker top-level script is the .worker.js file itself."
+);
+
+// ============================================================================
+
+// `done()` is always needed at the bottom for dedicated workers and shared
+// workers, even if you write `async_test()` or `promise_test()`.
+// `async_test()` and `promise_test()` called before this `done()`
+// will continue and assertions/failures after this `done()` are not ignored.
+// See
+// https://web-platform-tests.org/writing-tests/testharness-api.html#determining-when-all-tests-are-complete
+// for details.
+done();
diff --git a/testing/web-platform/tests/workers/examples/onconnect.any.js b/testing/web-platform/tests/workers/examples/onconnect.any.js
new file mode 100644
index 0000000000..d43a992183
--- /dev/null
+++ b/testing/web-platform/tests/workers/examples/onconnect.any.js
@@ -0,0 +1,4 @@
+// META: global=sharedworker
+const t = async_test("onconnect is called");
+onconnect = t.step_func_done((event) => {
+});
diff --git a/testing/web-platform/tests/workers/importscripts_mime.any.js b/testing/web-platform/tests/workers/importscripts_mime.any.js
new file mode 100644
index 0000000000..bfdfc191fd
--- /dev/null
+++ b/testing/web-platform/tests/workers/importscripts_mime.any.js
@@ -0,0 +1,52 @@
+// META: global=worker
+//
+// Tentative test for https://github.com/whatwg/html/issues/3255
+
+let test_cases = [
+ // Supported mimetypes:
+ ["text/javascript", true],
+ ["application/javascript", true],
+ ["text/ecmascript", true],
+
+ // Blocked mimetpyes:
+ ["image/png", false],
+ ["text/csv", false],
+ ["video/mpeg", false],
+
+ // Legacy mimetypes:
+ ["text/html", false],
+ ["text/plain", false],
+ ["application/xml", false],
+ ["application/octet-stream", false],
+
+ // Potato mimetypes:
+ ["text/potato", false],
+ ["potato/text", false],
+ ["aaa/aaa", false],
+ ["zzz/zzz", false],
+
+ // Parameterized mime types:
+ ["text/javascript; charset=utf-8", true],
+ ["text/javascript;charset=utf-8", true],
+ ["text/javascript;bla;bla", true],
+ ["text/csv; charset=utf-8", false],
+ ["text/csv;charset=utf-8", false],
+ ["text/csv;bla;bla", false],
+
+ // Funky capitalization:
+ ["Text/html", false],
+ ["text/Html", false],
+ ["TeXt/HtMl", false],
+ ["TEXT/HTML", false],
+];
+
+for (const [mimeType, isScriptType] of test_cases) {
+ test(t => {
+ let import_url = "/workers/support/imported_script.py?mime=" + mimeType;
+ if (isScriptType) {
+ assert_equals(undefined, importScripts(import_url));
+ } else {
+ assert_throws_dom("NetworkError", _ => { importScripts(import_url) })
+ }
+ }, "importScripts() requires scripty MIME types: " + mimeType + " is " + (isScriptType ? "allowed" : "blocked") + ".");
+}
diff --git a/testing/web-platform/tests/workers/importscripts_mime_local.any.js b/testing/web-platform/tests/workers/importscripts_mime_local.any.js
new file mode 100644
index 0000000000..62d690d8af
--- /dev/null
+++ b/testing/web-platform/tests/workers/importscripts_mime_local.any.js
@@ -0,0 +1,66 @@
+// META: global=dedicatedworker,sharedworker
+//
+// Tests for https://github.com/whatwg/html/issues/8869
+
+importScripts("/resources/testharness.js");
+
+let test_cases = [
+ // Supported mimetypes:
+ ["text/javascript", true],
+ ["application/javascript", true],
+ ["text/ecmascript", true],
+
+ // Blocked mimetpyes:
+ ["image/png", false],
+ ["text/csv", false],
+ ["video/mpeg", false],
+
+ // Legacy mimetypes:
+ ["text/html", false],
+ ["text/plain", false],
+ ["application/xml", false],
+ ["application/octet-stream", false],
+
+ // Potato mimetypes:
+ ["text/potato", false],
+ ["potato/text", false],
+ ["aaa/aaa", false],
+ ["zzz/zzz", false],
+
+ // Parameterized mime types:
+ ["text/javascript; charset=utf-8", true],
+ ["text/javascript;charset=utf-8", true],
+ ["text/javascript;bla;bla", true],
+ ["text/csv; charset=utf-8", false],
+ ["text/csv;charset=utf-8", false],
+ ["text/csv;bla;bla", false],
+
+ // Funky capitalization:
+ ["Text/html", false],
+ ["text/Html", false],
+ ["TeXt/HtMl", false],
+ ["TEXT/HTML", false],
+];
+
+for (const [mimeType, isScriptType] of test_cases) {
+ test(t => {
+ let import_url = `data:${ mimeType },`;
+ if (isScriptType) {
+ assert_equals(undefined, importScripts(import_url));
+ } else {
+ assert_throws_dom("NetworkError", _ => { importScripts(import_url) })
+ }
+ }, "importScripts() requires scripty MIME types for data: URLs: " + mimeType + " is " + (isScriptType ? "allowed" : "blocked") + ".");
+}
+
+for (const [mimeType, isScriptType] of test_cases) {
+ test(t => {
+ let import_url = URL.createObjectURL(new Blob([""], { type: mimeType }));
+ if (isScriptType) {
+ assert_equals(undefined, importScripts(import_url));
+ } else {
+ assert_throws_dom("NetworkError", _ => { importScripts(import_url) })
+ }
+ }, "importScripts() requires scripty MIME types for blob: URLs: " + mimeType + " is " + (isScriptType ? "allowed" : "blocked") + ".");
+}
+done();
diff --git a/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/EventTarget.worker.js b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/EventTarget.worker.js
new file mode 100644
index 0000000000..954c46c07e
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/EventTarget.worker.js
@@ -0,0 +1,23 @@
+importScripts("/resources/testharness.js");
+
+test(function(t) {
+ var i = 0;
+ addEventListener("message", function listener(evt) {
+ t.step(function() {
+ ++i;
+ removeEventListener("message", listener, true);
+ });
+ }, true);
+ self.dispatchEvent(new Event("message"));
+ self.dispatchEvent(new Event("message"));
+ assert_equals(i, 1);
+}, "removeEventListener");
+
+test(function() {
+ addEventListener("message", this.step_func(function(evt) {
+ assert_equals(evt.target, self);
+ }), true);
+ self.dispatchEvent(new Event("message"));
+}, "target");
+
+done();
diff --git a/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/onmessage.worker.js b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/onmessage.worker.js
new file mode 100644
index 0000000000..6f285caac3
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/onmessage.worker.js
@@ -0,0 +1,40 @@
+importScripts("/resources/testharness.js");
+
+test(function() {
+ self.onmessage = 1;
+ assert_equals(self.onmessage, null,
+ "attribute should return null after being set to a primitive");
+}, "Setting onmessage to 1");
+
+test(function() {
+ var object = {
+ handleEvent: this.unreached_func()
+ };
+ self.onmessage = object;
+ assert_equals(self.onmessage, object,
+ "attribute should return the object it was set to.");
+
+ self.dispatchEvent(new Event("message"));
+}, "Setting onmessage to an object");
+
+test(function() {
+ var triggered = false;
+ var f = function(e) { triggered = true; };
+ self.onmessage = f;
+ assert_equals(self.onmessage, f,
+ "attribute should return the function it was set to.");
+
+ self.dispatchEvent(new Event("message"));
+ assert_true(triggered, "event handler should have been triggered");
+}, "Setting onmessage to a function");
+
+
+test(function() {
+ assert_not_equals(self.onmessage, null,
+ "attribute should not return null after being set to a function");
+ self.onmessage = 1;
+ assert_equals(self.onmessage, null,
+ "attribute should return null after being set to a primitive");
+}, "Setting onmessage to 1 (again)");
+
+done();
diff --git a/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/event-ports-dedicated.html b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/event-ports-dedicated.html
new file mode 100644
index 0000000000..be89478786
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/event-ports-dedicated.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>e.ports in dedicated worker</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+(async_test()).step(function() {
+ var worker = new Worker('event-ports-dedicated.js');
+ worker.postMessage(1);
+ worker.onmessage = this.step_func(function(e) {
+ assert_true(e.data);
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/event-ports-dedicated.js b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/event-ports-dedicated.js
new file mode 100644
index 0000000000..c5cc9f8d9f
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/event-ports-dedicated.js
@@ -0,0 +1,3 @@
+onmessage = function(e) {
+ postMessage(e.ports instanceof Array && e.ports.length === 0);
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/imagedata-cloned-canvas-in-array.html b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/imagedata-cloned-canvas-in-array.html
new file mode 100644
index 0000000000..7c019a9993
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/imagedata-cloned-canvas-in-array.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<title>posting an imagedata (from a cloned canvas) in an array</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+(async_test()).step(function() {
+ var worker = new Worker('imagedata-cloned-canvas-in-array.js');
+ var canvas = document.createElement('canvas');
+ var clone = canvas.cloneNode(true);
+ var ctx = clone.getContext('2d');
+ var imagedata = ctx.getImageData(0, 0, 300, 150);
+ worker.postMessage([imagedata]);
+ worker.onmessage = this.step_func(function(e) {
+ var pixeldata = e.data.data;
+ for (var i = 0; i < pixeldata.length; i++) {
+ assert_equals(pixeldata[i], (i % 4 == 0) ? 128 : 0);
+ }
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/imagedata-cloned-canvas-in-array.js b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/imagedata-cloned-canvas-in-array.js
new file mode 100644
index 0000000000..76eaee366c
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/imagedata-cloned-canvas-in-array.js
@@ -0,0 +1,10 @@
+onmessage = function(e) {
+ function processPixels(imagedata) {
+ var pixeldata = imagedata.data;
+ for (var i = 0; i < pixeldata.length; i = i+4) {
+ pixeldata[i] = 128;
+ }
+ postMessage(imagedata);
+ }
+ processPixels(e.data[0]);
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/message-event.html b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/message-event.html
new file mode 100644
index 0000000000..91ec632685
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/message-event.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>'message' event properties</title>
+<link rel=help href="http://www.whatwg.org/html/#dom-dedicatedworkerglobalscope-postmessage">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<div id=log></div>
+<script>
+async_test("Properties of the 'message' event").step(function() {
+ var worker = new Worker("message-event.js");
+ worker.onmessage = this.step_func_done(function (evt) {
+ assert_class_string(evt, "MessageEvent");
+ assert_equals(evt.type, "message");
+ assert_false(evt.bubbles, "bubbles should be false");
+ assert_false(evt.cancelable, "cancelable should be false");
+ assert_equals(evt.data, "test");
+ assert_equals(evt.origin, "", "origin");
+ assert_equals(evt.lastEventId, "", "lastEventId");
+ assert_equals(evt.source, null, "source");
+ assert_array_equals(evt.ports, [], "ports");
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/message-event.js b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/message-event.js
new file mode 100644
index 0000000000..54a250005e
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/message-event.js
@@ -0,0 +1 @@
+postMessage("test");
diff --git a/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/return-value.worker.js b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/return-value.worker.js
new file mode 100644
index 0000000000..521251699a
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/return-value.worker.js
@@ -0,0 +1,8 @@
+importScripts("/resources/testharness.js");
+
+test(function() {
+ var rv = postMessage(1);
+ assert_equals(rv, undefined);
+}, "return value of postMessage");
+
+done();
diff --git a/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-dictionary.html b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-dictionary.html
new file mode 100644
index 0000000000..1749644908
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-dictionary.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<title>Using dictionary as postMessage's second argument</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+(async_test()).step(function() {
+ var worker = new Worker('second-argument-dictionary.js');
+ var ab = new ArrayBuffer(1);
+ worker.postMessage(ab, {transfer: [ab]});
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data.byteLength, 1);
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-dictionary.js b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-dictionary.js
new file mode 100644
index 0000000000..0cb80f8fae
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-dictionary.js
@@ -0,0 +1,7 @@
+onmessage = (event) => {
+ try {
+ postMessage(event.data, {transfer: [event.data]});
+ } catch(e) {
+ postMessage(''+e);
+ }
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-null-in-array.html b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-null-in-array.html
new file mode 100644
index 0000000000..8db06b4116
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-null-in-array.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>Using [null] in postMessage's second argument</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+(async_test()).step(function() {
+ var worker = new Worker('second-argument-null-in-array.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_true(e.data);
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-null-in-array.js b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-null-in-array.js
new file mode 100644
index 0000000000..95a094234b
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-null-in-array.js
@@ -0,0 +1,5 @@
+try {
+ postMessage(false, [null]);
+} catch(e) {
+ postMessage(e instanceof TypeError);
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-null.html b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-null.html
new file mode 100644
index 0000000000..68d9caabc5
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-null.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>Using null in postMessage's second argument</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+(async_test()).step(function() {
+ var worker = new Worker('second-argument-null.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(1, e.data);
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-null.js b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-null.js
new file mode 100644
index 0000000000..6f6f9e799f
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-null.js
@@ -0,0 +1,5 @@
+try {
+ postMessage(1, null);
+} catch(e) {
+ postMessage(e instanceof TypeError);
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-undefined.html b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-undefined.html
new file mode 100644
index 0000000000..c7dcb3c5c0
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-undefined.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>Using undefined in postMessage's second argument</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+(async_test()).step(function() {
+ var worker = new Worker('second-argument-undefined.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, 1);
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-undefined.js b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-undefined.js
new file mode 100644
index 0000000000..6f11443c4a
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/second-argument-undefined.js
@@ -0,0 +1,5 @@
+try {
+ postMessage(1, undefined);
+} catch(e) {
+ postMessage(''+e);
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/setting-postMessage.html b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/setting-postMessage.html
new file mode 100644
index 0000000000..5b3e014e1e
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/setting-postMessage.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>setting postMessage</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+(async_test()).step(function() {
+ var worker = new Worker('setting-postMessage.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_true(e.data);
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/setting-postMessage.js b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/setting-postMessage.js
new file mode 100644
index 0000000000..5426ebde0d
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/setting-postMessage.js
@@ -0,0 +1,3 @@
+var x = postMessage;
+postMessage = 1;
+x(postMessage == 1); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/structured-clone-imagedata.html b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/structured-clone-imagedata.html
new file mode 100644
index 0000000000..c7fbb0f956
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/structured-clone-imagedata.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<title>structured clone of ImageData</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+(async_test()).step(function() {
+ var worker = new Worker('structured-clone-imagedata.js');
+ var ctx = document.createElement('canvas').getContext('2d');
+ var imagedata = ctx.getImageData(0, 0, 300, 150);
+ worker.postMessage(imagedata);
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(''+e.data, '[object ImageData]');
+ assert_equals(e.data.data[0], 128);
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/structured-clone-imagedata.js b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/structured-clone-imagedata.js
new file mode 100644
index 0000000000..04cd7eea5b
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/structured-clone-imagedata.js
@@ -0,0 +1,5 @@
+onmessage = function(e) {
+ var imagedata = e.data;
+ imagedata.data[0] = 128;
+ postMessage(imagedata);
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/structured-clone-message.html b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/structured-clone-message.html
new file mode 100644
index 0000000000..edf4fb7e0e
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/structured-clone-message.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<title>structured clone of message</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+var wrapper_test = async_test();
+var tests = [
+ {test:async_test('undefined'), check:function(e) { assert_equals(e.data, undefined); }},
+ {test:async_test('null'), check:function(e) { assert_equals(e.data, null); }},
+ {test:async_test('false'), check:function(e) { assert_false(e.data); }},
+ {test:async_test('true'), check:function(e) { assert_true(e.data); }},
+ {test:async_test('1'), check:function(e) { assert_equals(e.data, 1); }},
+ {test:async_test('NaN'), check:function(e) { assert_equals(e.data, NaN); }},
+ {test:async_test('Infinity'), check:function(e) { assert_equals(e.data, Infinity); }},
+ {test:async_test('string'), check:function(e) { assert_equals(e.data, 'foo'); }},
+ {test:async_test('date'), check:function(e) { assert_equals(e.data instanceof Date, true); }},
+ {test:async_test('regexp'), check:function(e) { assert_equals('' + e.data, '/foo/'); assert_equals(e.data instanceof RegExp, true, 'e.data instanceof RegExp'); }},
+ {test:async_test('self'), check:function(e) { assert_equals(e.data, null); }},
+ {test:async_test('array'), check:function(e) { assert_array_equals(e.data, [undefined, null, false, true, 1, NaN, Infinity, 'foo', null, null]); }},
+ {test:async_test('object'), check:function(e) { assert_object_equals(e.data, {a:undefined, b:null, c:false, d:true, e:1, f:NaN, g:Infinity, h:'foo', k:null, n:null}); }},
+ {test:async_test('error'), check:function(e) { assert_equals(e.data, null, 'new Error()'); }},
+ {test:wrapper_test, check:function(e) { assert_unreached(); }}
+];
+// make wrapper_test pass after 500ms
+setTimeout(tests[tests.length-1].test.step_func(function() {
+ this.done();
+}), 500);
+
+wrapper_test.step(function() {
+ var worker = new Worker('structured-clone-message.js');
+ var i = 0;
+ worker.onmessage = function(e) {
+ tests[i].test.step(function() { tests[i].check(e); this.done(); });
+ i++;
+ };
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/structured-clone-message.js b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/structured-clone-message.js
new file mode 100644
index 0000000000..db456e1fba
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/structured-clone-message.js
@@ -0,0 +1,14 @@
+var err = new Error('foo');
+var date = new Date();
+// commented out bits are either tested elsewhere or not supported yet. or uncloneable.
+var tests = [undefined, null, false, true, 1, NaN, Infinity, 'foo', date, /foo/, /* ImageData, File, FileData, FileList,*/ null/*self*/,
+ [undefined, null, false, true, 1, NaN, Infinity, 'foo', /*date, /foo/,*/ null/*self*/, /*[], {},*/ null/*err*/],
+ {a:undefined, b:null, c:false, d:true, e:1, f:NaN, g:Infinity, h:'foo', /*i:date, j:/foo/,*/ k:null/*self*/, /*l:[], m:{},*/ n:null/*err*/},
+ null/*err*/];
+for (var i = 0; i < tests.length; ++i) {
+ try {
+ postMessage(tests[i]);
+ } catch(e) {
+ postMessage(''+e);
+ }
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/name/getting.html b/testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/name/getting.html
new file mode 100644
index 0000000000..c3a52d12e8
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/name/getting.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<title>getting name</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+var tests = [['getting.js#1', ''], ['getting.js#2', 'a'], ['getting.js#3', -0]];
+tests.forEach(function(t) {
+ async_test(function() {
+ var w = new SharedWorker(t[0], t[1]);
+ w.port.onmessage = this.step_func(function(e) {
+ assert_true(e.data);
+ this.done();
+ });
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/name/getting.js b/testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/name/getting.js
new file mode 100644
index 0000000000..acf89ca6f6
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/name/getting.js
@@ -0,0 +1,9 @@
+addEventListener('connect', function(e) {
+ var passed;
+ switch (location.hash) {
+ case '#1': passed = name == ''; break;
+ case '#2': passed = name == 'a'; break;
+ case '#3': passed = name == '0'; break;
+ }
+ e.ports[0].postMessage(passed);
+}, false);
diff --git a/testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/name/setting.html b/testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/name/setting.html
new file mode 100644
index 0000000000..ddd8569710
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/name/setting.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>setting name</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ var w1 = new SharedWorker('setting.js#1', 'x');
+ w1.port.addEventListener('message', this.step_func(function(e) {
+ assert_equals(e.data, 1);
+ this.done();
+ }), false);
+ w1.port.start();
+});
+</script>
diff --git a/testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/name/setting.js b/testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/name/setting.js
new file mode 100644
index 0000000000..c705e9c40a
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/name/setting.js
@@ -0,0 +1,4 @@
+addEventListener('connect', function(e) {
+ name = 1;
+ e.ports[0].postMessage(name);
+}, false);
diff --git a/testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/onconnect.html b/testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/onconnect.html
new file mode 100644
index 0000000000..8a0f103d40
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/onconnect.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>onconnect</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ var w1 = new SharedWorker('onconnect.js', '');
+ w1.port.addEventListener('message', this.step_func(function(e) {
+ assert_array_equals(e.data, ['null', 'null', 'function', '']);
+ }), false);
+ w1.port.start();
+});
+</script>
diff --git a/testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/onconnect.js b/testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/onconnect.js
new file mode 100644
index 0000000000..34a2be51fc
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/SharedWorkerGlobalScope/onconnect.js
@@ -0,0 +1,19 @@
+var results = [];
+try {
+ self.onconnect = 1;
+ results.push(String(onconnect));
+} catch(e) {
+ results.push(''+e);
+}
+try {
+ self.onconnect = {handleEvent:function(){}};
+ results.push(String(onconnect));
+} catch(e) {
+ results.push(''+e);
+}
+var f = function(e) {
+ results.push(e.data);
+ e.ports[0].postMessage(results);
+};
+onconnect = f;
+results.push(typeof onconnect);
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/incoming-message.html b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/incoming-message.html
new file mode 100644
index 0000000000..0905d07661
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/incoming-message.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<title>close() and incoming message</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+setup({ single_test: true });
+
+var worker = new Worker('incoming-message.js');
+worker.onmessage = function(e) {
+ assert_unreached("Got message");
+};
+worker.onerror = function(e) {
+ assert_unreached("Got error");
+};
+worker.postMessage(1);
+setTimeout(done, 2000);
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/incoming-message.js b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/incoming-message.js
new file mode 100644
index 0000000000..b4f7e7fc05
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/incoming-message.js
@@ -0,0 +1,5 @@
+onmessage = function(e) {
+ postMessage(1);
+ throw new Error();
+}
+close(); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/sending-messages.html b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/sending-messages.html
new file mode 100644
index 0000000000..da7da66d25
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/sending-messages.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<title>close() and sending messages</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ var worker = new Worker('sending-messages.js');
+ var i = 0;
+ worker.onmessage = this.step_func(function(e) {
+ i++;
+ assert_equals(e.data, i);
+ if (i == 2) {
+ this.done();
+ }
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/sending-messages.js b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/sending-messages.js
new file mode 100644
index 0000000000..2e0a898288
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/sending-messages.js
@@ -0,0 +1,3 @@
+postMessage(1);
+close();
+postMessage(2); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/setInterval.html b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/setInterval.html
new file mode 100644
index 0000000000..2f0ba176d4
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/setInterval.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<title>close() and setInterval</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+setup({ single_test: true });
+
+var worker = new Worker('setInterval.js');
+worker.onmessage = function(e) {
+ assert_unreached("Got message");
+};
+worker.onerror = function(e) {
+ assert_unreached("Got error");
+};
+setTimeout(done, 2000);
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/setInterval.js b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/setInterval.js
new file mode 100644
index 0000000000..d165d20eab
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/setInterval.js
@@ -0,0 +1,11 @@
+var interval1 = setInterval(function() {
+ clearInterval(interval1);
+ postMessage(1);
+ throw new Error();
+}, 10);
+close();
+var interval2 = setInterval(function() {
+ clearInterval(interval2);
+ postMessage(1);
+ throw new Error();
+}, 10); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/setTimeout.html b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/setTimeout.html
new file mode 100644
index 0000000000..2bddc0947f
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/setTimeout.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<title>close() and setTimeout</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+setup({ single_test: true });
+
+var worker = new Worker('setTimeout.js');
+worker.onmessage = function(e) {
+ assert_unreached("Got message");
+};
+worker.onerror = function(e) {
+ assert_unreached("Got error");
+};
+setTimeout(done, 2000);
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/setTimeout.js b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/setTimeout.js
new file mode 100644
index 0000000000..55eecb0557
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/close/setTimeout.js
@@ -0,0 +1,7 @@
+function x() {
+ postMessage(1);
+ throw new Error();
+}
+setTimeout(x, 0);
+close();
+setTimeout(x, 0); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/helper-redirect.py b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/helper-redirect.py
new file mode 100644
index 0000000000..c8cd354348
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/helper-redirect.py
@@ -0,0 +1,3 @@
+def main(request, response):
+ response.status = 302
+ response.headers.append(b"Location", b"post-location-members.js?a")
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/members.html b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/members.html
new file mode 100644
index 0000000000..3da6b7484d
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/members.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<title>members of WorkerLocation</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ var worker = new Worker('members.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data[0], null);
+ assert_equals(e.data[1], location.href.replace('.html', '.js'), 'href');
+ assert_equals(e.data[2], location.protocol, 'protocol');
+ assert_equals(e.data[3], location.host, 'host');
+ assert_equals(e.data[4], location.hostname, 'hostname');
+ assert_equals(e.data[5], location.port, 'port');
+ assert_equals(e.data[6], location.pathname.replace('.html', '.js'), 'pathname');
+ assert_equals(e.data[7], location.search, 'search');
+ assert_equals(e.data[8], '', 'hash');
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/members.js b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/members.js
new file mode 100644
index 0000000000..37235eac83
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/members.js
@@ -0,0 +1,3 @@
+postMessage([null, location.href, location.protocol, location.host,
+ location.hostname, location.port, location.pathname,
+ location.search, location.hash]); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/post-location-members.js b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/post-location-members.js
new file mode 100644
index 0000000000..e850b76b6e
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/post-location-members.js
@@ -0,0 +1,8 @@
+postMessage([location.href,
+ location.protocol,
+ location.host,
+ location.hostname,
+ location.port,
+ location.pathname,
+ location.search,
+ location.hash]); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/redirect-module.html b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/redirect-module.html
new file mode 100644
index 0000000000..b1a14be8f7
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/redirect-module.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>WorkerLocation with redirects: module dedicated workers</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ var worker = new Worker('helper-redirect.py?fail', {type: 'module'});
+ worker.onmessage = this.step_func_done(function(e) {
+ assert_equals(e.data[0], location.href.replace(/\/[^\/]+$/, '/post-location-members.js?a'));
+ assert_equals(e.data[1], location.protocol);
+ assert_equals(e.data[2], location.host);
+ assert_equals(e.data[3], location.hostname);
+ assert_equals(e.data[4], location.port);
+ assert_equals(e.data[5], location.pathname.replace(/\/[^\/]+$/, '/post-location-members.js'));
+ assert_equals(e.data[6], '?a');
+ assert_equals(e.data[7], '');
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/redirect-sharedworker.html b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/redirect-sharedworker.html
new file mode 100644
index 0000000000..978a99ac8c
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/redirect-sharedworker.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<title>WorkerLocation with redirects: classic shared workers</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+fetch_tests_from_worker(
+ new SharedWorker('/common/redirect.py?location=/workers/interfaces/WorkerGlobalScope/location/redirect.js?a'));
+</script>
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/redirect.html b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/redirect.html
new file mode 100644
index 0000000000..98a0e54760
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/redirect.html
@@ -0,0 +1,28 @@
+<!--
+/*
+-->
+<!doctype html>
+<title>WorkerLocation with redirects: classic dedicated workers</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ var worker = new Worker('helper-redirect.py?fail');
+ worker.onmessage = this.step_func_done(function(e) {
+ assert_equals(e.data[0], location.href.replace(/\/[^\/]+$/, '/post-location-members.js?a'));
+ assert_equals(e.data[1], location.protocol);
+ assert_equals(e.data[2], location.host);
+ assert_equals(e.data[3], location.hostname);
+ assert_equals(e.data[4], location.port);
+ assert_equals(e.data[5], location.pathname.replace(/\/[^\/]+$/, '/post-location-members.js'));
+ assert_equals(e.data[6], '?a');
+ assert_equals(e.data[7], '');
+ });
+});
+</script>
+<!--
+*/
+//-->
+
+
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/redirect.js b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/redirect.js
new file mode 100644
index 0000000000..2db48544a2
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/redirect.js
@@ -0,0 +1,7 @@
+importScripts('/resources/testharness.js');
+test(t => {
+ assert_equals(location.pathname, '/workers/interfaces/WorkerGlobalScope/location/redirect.js');
+ assert_equals(location.search, '?a');
+ assert_equals(location.hash, '');
+});
+done();
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/returns-same-object.any.js b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/returns-same-object.any.js
new file mode 100644
index 0000000000..dd3560f040
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/returns-same-object.any.js
@@ -0,0 +1,5 @@
+// META: global=worker
+
+test(function() {
+ assert_equals(location, location);
+}, 'location === location');
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/setting-members.html b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/setting-members.html
new file mode 100644
index 0000000000..7ea79b6897
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/setting-members.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<title>setting members of WorkerLocation</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ var worker = new Worker('setting-members.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data[0], null);
+ assert_equals(e.data[1], location.href.replace('.html', '.js'), 'href');
+ assert_equals(e.data[2], location.protocol, 'protocol');
+ assert_equals(e.data[3], location.host, 'host');
+ assert_equals(e.data[4], location.hostname, 'hostname');
+ assert_equals(e.data[5], location.port, 'port');
+ assert_equals(e.data[6], location.pathname.replace('.html', '.js'), 'pathname');
+ assert_equals(e.data[7], location.search, 'search');
+ assert_equals(e.data[8], '', 'hash');
+ assert_array_equals(e.data[9], [], 'number of exceptions');
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/setting-members.js b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/setting-members.js
new file mode 100644
index 0000000000..4c5c8a35ae
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/setting-members.js
@@ -0,0 +1,13 @@
+var exceptions = [];
+try { location.href = 1; } catch(e) { exceptions.push('href'); }
+try { location.protocol = 1; } catch(e) { exceptions.push('protocol'); }
+try { location.host = 1; } catch(e) { exceptions.push('host'); }
+try { location.hostname = 1; } catch(e) { exceptions.push('hostname');}
+try { location.port = 1; } catch(e) { exceptions.push('port'); }
+try { location.pathname = 1; } catch(e) { exceptions.push('pathname'); }
+try { location.search = 1; } catch(e) { exceptions.push('search'); }
+try { location.hash = 1; } catch(e) { exceptions.push('hash'); }
+
+postMessage([null, location.href, location.protocol, location.host,
+ location.hostname, location.port, location.pathname,
+ location.search, location.hash, exceptions]); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/worker-separate-file.html b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/worker-separate-file.html
new file mode 100644
index 0000000000..ac8e64dcc8
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/location/worker-separate-file.html
@@ -0,0 +1,28 @@
+<!--
+/*
+-->
+<!doctype html>
+<title>location with a worker in separate file</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ var worker = new Worker('post-location-members.js?a#b?c');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data[0], location.href.replace(/\/[^\/]+$/, '/post-location-members.js?a#b?c'));
+ assert_equals(e.data[1], location.protocol);
+ assert_equals(e.data[2], location.host);
+ assert_equals(e.data[3], location.hostname);
+ assert_equals(e.data[4], location.port);
+ assert_equals(e.data[5], location.pathname.replace(/\/[^\/]+$/, '/post-location-members.js'));
+ assert_equals(e.data[6], '?a');
+ assert_equals(e.data[7], '#b?c');
+ this.done();
+ });
+});
+</script>
+<!--
+*/
+//-->
+
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.html b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.html
new file mode 100644
index 0000000000..5f3999db66
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.html
@@ -0,0 +1,91 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+// 1. Exception is thrown somewhere in a Worker.
+// Various contexts are tested: from worker initialization,
+// from setTimeout, from event handlers, etc.
+// 2. WorkerGlobalScope.onerror event handler is called.
+// (i.e. `onerror` in the worker script)
+// 3. From the event handler, another exception is thrown.
+// 4. Each of Worker.onerror handler (on the parent Document) and
+// Worker error event listener should be called twice:
+// once for each of the exceptions thrown in Step 1 and 2, respectively.
+// (We don't check the ordering of two Worker.onerror calls, because
+// browsers fires them in different orders)
+
+function prepareHandler(t, messages) {
+ const fired = {};
+ let fired_count = 0;
+ t.step_timeout(() => {
+ if (fired_count < messages.length) {
+ let error_description = 'Worker.onerror not fired for:';
+ for (const message of messages) {
+ if (!fired[message]) {
+ error_description += ' ';
+ error_description += message;
+ }
+ }
+ assert_unreached(error_description);
+ }
+ }, 2000);
+ return t.step_func(e => {
+ e.preventDefault();
+ for (const message of messages) {
+ if (!fired[message] && e.message.indexOf(message) >= 0) {
+ fired[message] = true;
+ ++fired_count;
+ if (fired_count === messages.length) {
+ // Worker.onerror is fired for all messages.
+ t.done();
+ }
+ return;
+ }
+ }
+ assert_unreached("Unexpected worker.onerror message: " + e.message);
+ });
+}
+
+function expectErrors(worker, title, messages) {
+ async_test(t => {
+ worker.addEventListener('error', prepareHandler(t, messages));
+ }, title+ ': listener');
+ async_test(t => {
+ worker.onerror = prepareHandler(t, messages);
+ }, title + ': handler');
+}
+
+for (const type of ['classic', 'module']) {
+ const workerOptions = type === 'module' ? {type: 'module'}: {};
+
+ const worker1 = new Worker(
+ 'throw.js?throw-in-toplevel&throw-in-onerror',
+ workerOptions);
+ expectErrors(
+ worker1,
+ 'Throw in worker initialization: ' + type,
+ ['Throw in toplevel', 'Throw in error handler']);
+
+ const worker2 = new Worker(
+ 'throw.js?throw-in-setTimeout-function&throw-in-onerror', workerOptions);
+ expectErrors(
+ worker2,
+ 'Throw in setTimeout(function): ' + type,
+ ['Throw in setTimeout function', 'Throw in error handler']);
+
+ const worker3 = new Worker(
+ 'throw.js?throw-in-setTimeout-string&throw-in-onerror', workerOptions);
+ expectErrors(
+ worker3,
+ 'Throw in setTimeout(string): ' + type,
+ ['Throw in setTimeout string', 'Throw in error handler']);
+
+ const worker4 = new Worker('throw.js?throw-in-onerror', workerOptions);
+ worker4.postMessage('foo');
+ expectErrors(
+ worker4,
+ 'Throw in message handler: ' + type,
+ ['Throw in message handler', 'Throw in error handler']);
+
+}
+</script>
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/handled.html b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/handled.html
new file mode 100644
index 0000000000..7d4b03c6cd
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/handled.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<title>onerror, "handled"</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ var worker = new Worker('handled.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(typeof e.data[0], 'string', 'first argument');
+ assert_equals(e.data[1], document.URL.replace('.html', '.js'), 'second argument');
+ assert_equals(typeof e.data[2], 'number', 'third argument');
+ assert_equals(typeof e.data[3], 'number', 'fourth argument');
+ setTimeout(this.step_func(function() {
+ this.done();
+ }), 100);
+ });
+ worker.onerror = this.step_func(function(e) {
+ assert_unreached();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/handled.js b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/handled.js
new file mode 100644
index 0000000000..e58fa4a515
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/handled.js
@@ -0,0 +1,8 @@
+onerror = function(a, b, c, d) {
+ postMessage([a, b, c, d]);
+ return true; // the error is "handled"
+}
+function x() {
+ y();
+}
+x(); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/message-classic-DOMException.html b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/message-classic-DOMException.html
new file mode 100644
index 0000000000..df8c851475
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/message-classic-DOMException.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./message-helper.js"></script>
+<script>
+runTest('classic', 'DOMException-TypeError');
+</script>
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/message-classic-Error.html b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/message-classic-Error.html
new file mode 100644
index 0000000000..e026b6ebf0
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/message-classic-Error.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./message-helper.js"></script>
+<script>
+runTest('classic', 'Error');
+</script>
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/message-helper.js b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/message-helper.js
new file mode 100644
index 0000000000..6271329b03
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/message-helper.js
@@ -0,0 +1,61 @@
+// The error's `message` values in Worker error event handlers are tested.
+// While not explicitly specified in the HTML spec, we expect some information
+// about thrown errors (e.g. original message, the string "TypeError", etc.)
+// to appear in the `message`.
+
+function prepareHandler(t, error, expectedCount) {
+ let count = 0;
+ return t.step_func(e => {
+ e.preventDefault();
+
+ assert_regexp_match(
+ e.message,
+ /Throw in/,
+ 'e.message should contain the message of the thrown error');
+
+ if (error === 'DOMException-TypeError') {
+ assert_regexp_match(e.message, /TypeError/);
+ }
+
+ ++count;
+ if (count >= expectedCount) {
+ t.done();
+ }
+ });
+}
+
+function expectErrors(worker, error, expectedCount, title) {
+ async_test(t => {
+ worker.addEventListener('error',
+ prepareHandler(t, error, expectedCount));
+ }, title+ ': listener');
+ async_test(t => {
+ worker.onerror = prepareHandler(t, error, expectedCount);
+ }, title + ': handler');
+}
+
+function runTest(type, error) {
+ for (const location of ['toplevel',
+ 'setTimeout-function',
+ 'setTimeout-string',
+ 'onmessage',
+ 'onerror']) {
+ const worker = new Worker(
+ 'throw.js?throw-in-' + location + '&error=' + error,
+ {type});
+ let expectedCount = 1;
+ if (location === 'onmessage') {
+ // This makes the worker's message handler to throw an error.
+ worker.postMessage('foo');
+ }
+ if (location === 'onerror') {
+ // This makes the worker's message handler to throw an error,
+ // AND worker's error handler to throw another error.
+ // Therefore we expect two errors here.
+ worker.postMessage('foo');
+ expectedCount = 2;
+ }
+ expectErrors(worker, error, expectedCount,
+ 'Throw ' + error + ' in ' + location + ': ' + type);
+ }
+}
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/message-module-DOMException.html b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/message-module-DOMException.html
new file mode 100644
index 0000000000..8ed873bc32
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/message-module-DOMException.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./message-helper.js"></script>
+<script>
+runTest('module', 'DOMException-TypeError');
+</script>
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/message-module-Error.html b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/message-module-Error.html
new file mode 100644
index 0000000000..046ff969d6
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/message-module-Error.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./message-helper.js"></script>
+<script>
+runTest('module', 'Error');
+</script>
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/not-handled.html b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/not-handled.html
new file mode 100644
index 0000000000..11d03d728b
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/not-handled.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<title>onerror, "not handled"</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+function createHandler(t) {
+ return t.step_func(function(e) {
+ assert_true(e instanceof ErrorEvent, 'e instanceof ErrorEvent');
+ assert_equals(typeof e.message, 'string', 'typeof e.message');
+ assert_equals(e.filename, document.URL.replace('.html', '.js'), 'e.filename');
+ assert_equals(typeof e.lineno, 'number', 'typeof e.lineno');
+ assert_equals(typeof e.colno, 'number', 'typeof e.column');
+ e.preventDefault(); // "handled"
+ t.done();
+ });
+}
+
+async_test(function(t) {
+ var worker = new Worker('not-handled.js');
+ worker.onerror = createHandler(t);
+}, 'Not handled evaluation error => Worker.onerror handler');
+
+async_test(function(t) {
+ var worker = new Worker('not-handled.js');
+ worker.addEventListener('error', createHandler(t));
+}, 'Not handled evaluation error => Worker error listener');
+</script>
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/not-handled.js b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/not-handled.js
new file mode 100644
index 0000000000..c3254b0ba7
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/not-handled.js
@@ -0,0 +1,7 @@
+onerror = function(a, b, c, d) {
+ return false; // the error is "not handled"
+}
+function x() {
+ y();
+}
+x(); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/propagate-to-window-onerror.html b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/propagate-to-window-onerror.html
new file mode 100644
index 0000000000..b3be772679
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/propagate-to-window-onerror.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<title>onerror, "not handled" with only window.onerror defined</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+setup({
+ allow_uncaught_exception: true,
+});
+async_test(function() {
+ var worker = new Worker('propagate-to-window-onerror.js');
+ window.onerror = this.step_func(function(a, b, c, d) {
+ assert_equals(typeof a, 'string', 'first argument');
+ assert_equals(b, document.URL.replace('.html', '.js'), 'second argument');
+ assert_equals(typeof c, 'number', 'third argument');
+ assert_equals(typeof d, 'number', 'fourth argument');
+ this.done();
+ return true; // "handled"
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/propagate-to-window-onerror.js b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/propagate-to-window-onerror.js
new file mode 100644
index 0000000000..0daf488d6f
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/propagate-to-window-onerror.js
@@ -0,0 +1,4 @@
+function x() {
+ y();
+}
+x(); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/throw.js b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/throw.js
new file mode 100644
index 0000000000..704098a6d8
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/onerror/throw.js
@@ -0,0 +1,34 @@
+const params = new URL(self.location.href).searchParams;
+
+self.createError = (message) => {
+ if (params.get('error') === 'DOMException-TypeError') {
+ return new DOMException(message, 'TypeError');
+ } else {
+ return new Error(message);
+ }
+};
+
+onerror = function() {
+ if (params.has('throw-in-onerror')) {
+ throw createError('Throw in error handler');
+ }
+ return false;
+};
+onmessage = function() {
+ throw createError('Throw in message handler');
+ return false;
+};
+
+if (params.has('throw-in-toplevel')) {
+ throw createError('Throw in toplevel');
+}
+
+// We don't use step_timeout() here, because we have to test the behavior of
+// setTimeout() without wrappers.
+if (params.has('throw-in-setTimeout-function')) {
+ setTimeout(() => { throw createError('Throw in setTimeout function') }, 0);
+}
+
+if (params.has('throw-in-setTimeout-string')) {
+ setTimeout("throw createError('Throw in setTimeout string')", 0);
+}
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/self.any.js b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/self.any.js
new file mode 100644
index 0000000000..64b4ee2fae
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerGlobalScope/self.any.js
@@ -0,0 +1,19 @@
+// META: global=worker
+
+test(function() {
+ assert_equals(self, self);
+}, 'self === self');
+
+test(function() {
+ assert_true(self instanceof WorkerGlobalScope);
+}, 'self instanceof WorkerGlobalScope');
+
+test(function() {
+ assert_true('self' in self);
+}, '\'self\' in self');
+
+test(function() {
+ var x = self;
+ self = 1;
+ assert_equals(self, x);
+}, 'self = 1');
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/001.html b/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/001.html
new file mode 100644
index 0000000000..9fe5e2b1bc
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/001.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>setTimeout</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var worker = new Worker('001.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, 1);
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/001.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/001.js
new file mode 100644
index 0000000000..bd5b7c4071
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/001.js
@@ -0,0 +1 @@
+setTimeout(function() { postMessage(1) }, 10); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/002.html b/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/002.html
new file mode 100644
index 0000000000..1a10b3d0bb
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/002.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<title>clearTimeout</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var worker = new Worker('002.js');
+ var gotMessage = false;
+ worker.onmessage = function() { gotMessage = true; };
+ setTimeout(this.step_func(function() { assert_false(gotMessage); this.done(); }), 100);
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/002.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/002.js
new file mode 100644
index 0000000000..a96c088442
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/002.js
@@ -0,0 +1,2 @@
+var t = setTimeout(function() { postMessage(1); }, 10);
+clearTimeout(t); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/003.html b/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/003.html
new file mode 100644
index 0000000000..119d109b5f
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/003.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>setInterval</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var worker = new Worker('003.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, 1);
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/003.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/003.js
new file mode 100644
index 0000000000..e64e4e2179
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/003.js
@@ -0,0 +1 @@
+setInterval(function() { postMessage(1); }, 10); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/004.html b/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/004.html
new file mode 100644
index 0000000000..83d7bf915f
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/004.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<title>clearInterval</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var worker = new Worker('004.js');
+ var i = 0;
+ worker.onmessage = function() { i++; }
+ setTimeout(this.step_func(function() { assert_equals(i, 0); this.done(); }), 100);
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/004.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/004.js
new file mode 100644
index 0000000000..e80d79a8e5
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/004.js
@@ -0,0 +1,4 @@
+var t = setInterval(function() {
+ postMessage(1);
+}, 10);
+clearInterval(t); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/005.html b/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/005.html
new file mode 100644
index 0000000000..2a181d55d0
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/005.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>setInterval when closing</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var worker = new Worker('005.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, 1);
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/005.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/005.js
new file mode 100644
index 0000000000..125c224e7b
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/WindowTimers/005.js
@@ -0,0 +1,3 @@
+self.close();
+var t = setInterval(function() {}, 10);
+postMessage(t); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/001.worker.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/001.worker.js
new file mode 100644
index 0000000000..aa86c8ef17
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/001.worker.js
@@ -0,0 +1,7 @@
+importScripts("/resources/testharness.js");
+
+test(function() {
+ importScripts();
+});
+
+done();
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/002.worker.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/002.worker.js
new file mode 100644
index 0000000000..1cacee5ccb
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/002.worker.js
@@ -0,0 +1,11 @@
+importScripts("/resources/testharness.js");
+
+test(function() {
+ var ran = false;
+ assert_throws_dom("SyntaxError", function() {
+ importScripts('data:text/javascript,ran=true','http://foo bar');
+ });
+ assert_false(ran, 'first argument to importScripts ran');
+});
+
+done();
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/003.html b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/003.html
new file mode 100644
index 0000000000..5dcd08aa15
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/003.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>importScripts running scripts</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ var worker = new Worker('003.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, "abc");
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/003.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/003.js
new file mode 100644
index 0000000000..6e378ef20f
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/003.js
@@ -0,0 +1,8 @@
+var x = 'a';
+try {
+ importScripts('data:text/javascript,x+="b"',
+ 'data:text/javascript,x+="c"');
+} catch(e) {
+ x += "d"
+}
+postMessage(x); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/004.html b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/004.html
new file mode 100644
index 0000000000..62537e0888
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/004.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>importScripts broken script</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ var worker = new Worker('004.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data[0], "first script successful. ");
+ assert_true(e.data[1], 'expected SyntaxError');
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/004.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/004.js
new file mode 100644
index 0000000000..98040d0d48
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/004.js
@@ -0,0 +1,13 @@
+var x = '';
+var exception;
+try {
+ importScripts('data:text/javascript,x+="first script successful. "',
+ 'data:text/javascript,x+="FAIL (second script). "; for(;) break;', // doesn't compile
+ 'data:text/javascript,x+="FAIL (third script)"');
+} catch(ex) {
+ if (ex instanceof SyntaxError)
+ exception = true;
+ else
+ exception = String(ex);
+}
+postMessage([x, exception]); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/005.html b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/005.html
new file mode 100644
index 0000000000..7ebbc1be55
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/005.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>importScripts separate scripts</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ var worker = new Worker('005.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data[0], undefined);
+ assert_true(e.data[1]);
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/005.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/005.js
new file mode 100644
index 0000000000..18c534efa9
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/005.js
@@ -0,0 +1,9 @@
+var x;
+var y;
+try {
+ importScripts('data:text/javascript,x={',
+ 'data:text/javascript,}');
+} catch(e) {
+ y = true;
+}
+postMessage([x, y]); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/006.html b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/006.html
new file mode 100644
index 0000000000..aec2fb1483
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/006.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<title>importScripts uncaught exception</title>
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ var worker = new Worker('006.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data[0], 1);
+ assert_equals(e.data[1], 2);
+ assert_equals(e.data[2], undefined);
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/006.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/006.js
new file mode 100644
index 0000000000..fc170f790c
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/006.js
@@ -0,0 +1,11 @@
+var x;
+var y;
+var z;
+try {
+ importScripts('data:text/javascript,x=1',
+ 'data:text/javascript,throw 2',
+ 'data:text/javascript,z=3');
+} catch(e) {
+ y = e;
+}
+postMessage([x, y, z]); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/007.html b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/007.html
new file mode 100644
index 0000000000..37e888365f
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/007.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<title>postMessage in importScripts</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ var worker = new Worker('007.js');
+ var i = 0;
+ worker.onmessage = this.step_func(function(e) {
+ i++;
+ assert_equals(e.data, i);
+ if (i == 2)
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/007.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/007.js
new file mode 100644
index 0000000000..dc85216f3d
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/007.js
@@ -0,0 +1,2 @@
+importScripts('data:text/javascript,postMessage(1)');
+postMessage(2); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/008.html b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/008.html
new file mode 100644
index 0000000000..f72b79939c
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/008.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>variables and functions crossing importScripts boundary</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ var worker = new Worker('008.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_true(e.data);
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/008.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/008.js
new file mode 100644
index 0000000000..c957fcd635
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/008.js
@@ -0,0 +1,3 @@
+var log = postMessage;
+importScripts('data:text/javascript,function run() { log(true) }');
+run(); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/009.html b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/009.html
new file mode 100644
index 0000000000..e0eb5488c2
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/009.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>variables and functions crossing importScripts boundary, take 2</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ var worker = new Worker('009.js');
+ var i = 0;
+ worker.onmessage = this.step_func(function(e) {
+ i++;
+ if (i == 1) {
+ assert_true(e.data);
+ } else {
+ assert_equals(e.data, 1);
+ this.done();
+ }
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/009.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/009.js
new file mode 100644
index 0000000000..4b86f8c303
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/009.js
@@ -0,0 +1,3 @@
+var log = postMessage;
+importScripts('data:text/javascript,function run() { for(var i = 0; i < 1000; ++i) { if (i == 500) log(true); } return 1; }');
+postMessage(run()); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/010.html b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/010.html
new file mode 100644
index 0000000000..a6db49c4be
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/010.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<title>importScripts(undefined)</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ var worker = new Worker('010.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, 'undefined');
+ this.done();
+ })
+ worker.onerror = this.step_func(function(e) {
+ assert_unreached(e.message);
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/010.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/010.js
new file mode 100644
index 0000000000..4ec4a3b8c7
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/010.js
@@ -0,0 +1,11 @@
+// prevent recursion
+if ('beenThere' in self) {
+ throw 'undefined stringified to the empty string';
+}
+beenThere = true;
+try {
+ importScripts(undefined);
+ postMessage(got);
+} catch(ex) {
+ postMessage(String(ex));
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/011.html b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/011.html
new file mode 100644
index 0000000000..1bfb233497
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/011.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<title>importScripts(null)</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ var worker = new Worker('011.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, 'null');
+ this.done();
+ });
+ worker.onerror = this.step_func(function(e) {
+ assert_unreached(e.message);
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/011.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/011.js
new file mode 100644
index 0000000000..bd6fed5c0a
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/011.js
@@ -0,0 +1,11 @@
+// prevent recursion
+if ('beenThere' in self) {
+ throw 'null stringified to the empty string';
+}
+beenThere = true;
+try {
+ importScripts(null);
+ postMessage(got);
+} catch(ex) {
+ postMessage(String(ex));
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/012.html b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/012.html
new file mode 100644
index 0000000000..ab0778d0c7
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/012.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<title>importScripts(1)</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ var worker = new Worker('012.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, '1');
+ this.done();
+ });
+ worker.onerror = this.step_func(function(e) {
+ assert_unreached(e.message);
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/012.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/012.js
new file mode 100644
index 0000000000..f4c887f7df
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/012.js
@@ -0,0 +1,11 @@
+// prevent recursion
+if ('beenThere' in self) {
+ throw '1 stringified to the empty string';
+}
+beenThere = true;
+try {
+ importScripts(1);
+ postMessage(got);
+} catch(ex) {
+ postMessage(String(ex));
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/1 b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/1
new file mode 100644
index 0000000000..18cea4ff0f
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/1
@@ -0,0 +1 @@
+var got = '1'; \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/1.headers b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/1.headers
new file mode 100644
index 0000000000..a17a9a3a12
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/1.headers
@@ -0,0 +1 @@
+Content-Type: application/javascript
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/blob-url.worker.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/blob-url.worker.js
new file mode 100644
index 0000000000..71603bf314
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/blob-url.worker.js
@@ -0,0 +1,40 @@
+importScripts("/resources/testharness.js");
+
+function objectUrlFromScript(script) {
+ const blob = new Blob([script], { type: "text/javascript" });
+ return URL.createObjectURL(blob);
+}
+
+test((t) => {
+ self.run = false;
+ const blobScriptUrl = objectUrlFromScript(`self.run = true;`);
+ t.add_cleanup(() => URL.revokeObjectURL(blobScriptUrl));
+
+ importScripts(blobScriptUrl);
+ assert_true(self.run);
+}, "Blob URLs work on importScripts");
+
+test(() => {
+ self.run = false;
+ const blobScriptUrl = objectUrlFromScript(`self.run = true;`);
+
+ URL.revokeObjectURL(blobScriptUrl);
+
+ assert_throws_dom("NetworkError", () => {
+ importScripts(blobScriptUrl);
+ });
+ assert_false(self.run);
+}, "A revoked blob URL will fail");
+
+test(() => {
+ self.run = false;
+ const runScriptUrl = objectUrlFromScript(`self.run = true;`);
+ const revokeScriptUrl = objectUrlFromScript(
+ `URL.revokeObjectURL(${JSON.stringify(runScriptUrl)});`
+ );
+
+ importScripts(revokeScriptUrl, runScriptUrl);
+ assert_true(self.run);
+}, "Revoking a blob URL in an earlier script will not fail");
+
+done();
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/catch.sub.any.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/catch.sub.any.js
new file mode 100644
index 0000000000..52da60be91
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/catch.sub.any.js
@@ -0,0 +1,47 @@
+// META: global=worker
+
+const crossOrigin = "https://{{hosts[alt][]}}:{{ports[https][0]}}";
+const redirectToCrossOrigin = "/common/redirect.py?location=" + crossOrigin;
+
+test(function() {
+ assert_throws_js(SyntaxError, function() {
+ importScripts("/workers/modules/resources/syntax-error.js");
+ });
+}, "Same-origin syntax error");
+
+test(function() {
+ assert_throws_js(Error, function() {
+ importScripts("/workers/modules/resources/throw.js");
+ });
+}, "Same-origin throw");
+
+// https://html.spec.whatwg.org/C/#run-a-classic-script
+// Step 8.2. If rethrow errors is true and script's muted errors is true, then:
+// Step 8.2.2. Throw a "NetworkError" DOMException.
+test(function() {
+ assert_throws_dom("NetworkError", function() {
+ importScripts(crossOrigin +
+ "/workers/modules/resources/syntax-error.js");
+ });
+}, "Cross-origin syntax error");
+
+test(function() {
+ assert_throws_dom("NetworkError", function() {
+ importScripts(crossOrigin +
+ "/workers/modules/resources/throw.js");
+ });
+}, "Cross-origin throw");
+
+test(function() {
+ assert_throws_dom("NetworkError", function() {
+ importScripts(redirectToCrossOrigin +
+ "/workers/modules/resources/syntax-error.js");
+ });
+}, "Redirect-to-cross-origin syntax error");
+
+test(function() {
+ assert_throws_dom("NetworkError", function() {
+ importScripts(redirectToCrossOrigin +
+ "/workers/modules/resources/throw.js");
+ });
+}, "Redirect-to-Cross-origin throw");
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/null b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/null
new file mode 100644
index 0000000000..8e54b66c50
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/null
@@ -0,0 +1 @@
+var got = 'null'; \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/null.headers b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/null.headers
new file mode 100644
index 0000000000..a17a9a3a12
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/null.headers
@@ -0,0 +1 @@
+Content-Type: application/javascript
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-cross-origin.sub.any.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-cross-origin.sub.any.js
new file mode 100644
index 0000000000..4fd8914856
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-cross-origin.sub.any.js
@@ -0,0 +1,8 @@
+// META: global=dedicatedworker,sharedworker
+// META: script=report-error-helper.js
+const crossOrigin = "https://{{hosts[alt][]}}:{{ports[https][0]}}";
+runTest(
+ crossOrigin + "/workers/modules/resources/syntax-error.js",
+ false,
+ "NetworkError"
+);
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-helper.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-helper.js
new file mode 100644
index 0000000000..7fc6d0dd64
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-helper.js
@@ -0,0 +1,80 @@
+setup({ allow_uncaught_exception:true });
+
+// For SyntaxError, the line in doImportScripts() is expected to be reported
+// as `e.lineno` etc. below.
+// doImportScripts() is introduced here to prevent the line number from being
+// affected by changes in runTest(), use of setTimeout(), etc.
+function doImportScripts(url) {
+ importScripts(url);
+}
+
+const t0 = async_test("WorkerGlobalScope error event: error");
+const t1 = async_test("WorkerGlobalScope error event: message");
+const t2 = async_test("WorkerGlobalScope error event: filename");
+const t3 = async_test("WorkerGlobalScope error event: lineno");
+
+function runTest(importScriptUrl, shouldUseSetTimeout, expected) {
+ self.addEventListener("error", e => {
+ if (expected === "NetworkError") {
+ t0.step_func_done(() => {
+ assert_equals(e.error.constructor, DOMException,
+ "e.error should be a DOMException")
+ assert_equals(e.error.name, "NetworkError");
+ })();
+
+ t1.step_func_done(() => {
+ assert_not_equals(e.message, "Script error.",
+ "e.message should not be muted to 'Script error.'");
+ })();
+
+ // filename, lineno etc. should NOT point to the location within
+ // `syntax-error.js` (otherwise parse errors to be muted are
+ // leaked to JavaScript).
+ // we expect they point to the caller of `importScripts()`,
+ // while this is not explicitly stated in the spec.
+ t2.step_func_done(() => {
+ assert_equals(e.filename, self.location.origin +
+ '/workers/interfaces/WorkerUtils/importScripts/report-error-helper.js');
+ })();
+ t3.step_func_done(() => {
+ assert_equals(e.lineno, 8);
+ })();
+ // We don't check `e.colno` for now, because browsers set different
+ // `colno` values.
+ } else if (expected === "SyntaxError") {
+ t0.step_func_done(() => {
+ assert_equals(e.error.constructor, SyntaxError);
+ assert_equals(e.error.name, "SyntaxError");
+ })();
+
+ t1.step_func_done(() => {
+ assert_not_equals(e.message, "Script error.",
+ "e.message should not be muted to 'Script error.'");
+ })();
+
+ // filename, lineno etc. are expected to point to the location within
+ // `syntax-error.js` because it is same-origin,
+ // while this is not explicitly stated in the spec.
+ t2.step_func_done(() => {
+ assert_equals(e.filename, self.location.origin +
+ '/workers/modules/resources/syntax-error.js');
+ })();
+ t3.step_func_done(() => {
+ assert_equals(e.lineno, 1);
+ })();
+ // We don't check `e.colno` for now, because browsers set different
+ // `colno` values.
+ }
+
+ // Because importScripts() throws, we call done() here.
+ done();
+ });
+
+ if (shouldUseSetTimeout) {
+ setTimeout(
+ () => doImportScripts(importScriptUrl),
+ 0);
+ } else {
+ doImportScripts(importScriptUrl);
+ }
+}
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-redirect-to-cross-origin.sub.any.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-redirect-to-cross-origin.sub.any.js
new file mode 100644
index 0000000000..2b9600973f
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-redirect-to-cross-origin.sub.any.js
@@ -0,0 +1,9 @@
+// META: global=dedicatedworker,sharedworker
+// META: script=report-error-helper.js
+const crossOrigin = "https://{{hosts[alt][]}}:{{ports[https][0]}}";
+runTest(
+ "/common/redirect.py?location=" + crossOrigin +
+ "/workers/modules/resources/syntax-error.js",
+ false,
+ "NetworkError"
+);
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-same-origin.sub.any.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-same-origin.sub.any.js
new file mode 100644
index 0000000000..f7de416e11
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-same-origin.sub.any.js
@@ -0,0 +1,7 @@
+// META: global=dedicatedworker,sharedworker
+// META: script=report-error-helper.js
+runTest(
+ "/workers/modules/resources/syntax-error.js",
+ false,
+ "SyntaxError"
+);
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-cross-origin.sub.any.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-cross-origin.sub.any.js
new file mode 100644
index 0000000000..a1bbef7bc4
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-cross-origin.sub.any.js
@@ -0,0 +1,8 @@
+// META: global=dedicatedworker,sharedworker
+// META: script=report-error-helper.js
+const crossOrigin = "https://{{hosts[alt][]}}:{{ports[https][0]}}";
+runTest(
+ crossOrigin + "/workers/modules/resources/syntax-error.js",
+ true,
+ "NetworkError"
+);
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-redirect-to-cross-origin.sub.any.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-redirect-to-cross-origin.sub.any.js
new file mode 100644
index 0000000000..2755b337d3
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-redirect-to-cross-origin.sub.any.js
@@ -0,0 +1,9 @@
+// META: global=dedicatedworker,sharedworker
+// META: script=report-error-helper.js
+const crossOrigin = "https://{{hosts[alt][]}}:{{ports[https][0]}}";
+runTest(
+ "/common/redirect.py?location=" + crossOrigin +
+ "/workers/modules/resources/syntax-error.js",
+ true,
+ "NetworkError"
+);
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-same-origin.sub.any.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-same-origin.sub.any.js
new file mode 100644
index 0000000000..c4f70ebec9
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-same-origin.sub.any.js
@@ -0,0 +1,7 @@
+// META: global=dedicatedworker,sharedworker
+// META: script=report-error-helper.js
+runTest(
+ "/workers/modules/resources/syntax-error.js",
+ true,
+ "SyntaxError"
+);
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/undefined b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/undefined
new file mode 100644
index 0000000000..f99ba4be74
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/undefined
@@ -0,0 +1 @@
+var got = 'undefined'; \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/undefined.headers b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/undefined.headers
new file mode 100644
index 0000000000..a17a9a3a12
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/undefined.headers
@@ -0,0 +1 @@
+Content-Type: application/javascript
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/002.html b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/002.html
new file mode 100644
index 0000000000..4c76e2b699
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/002.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>navigator.appName</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var worker = new Worker('002.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, navigator.appName);
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/002.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/002.js
new file mode 100644
index 0000000000..a5af348ef1
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/002.js
@@ -0,0 +1 @@
+postMessage(navigator.appName); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/003.html b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/003.html
new file mode 100644
index 0000000000..86ab5aee48
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/003.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>navigator.appVersion</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var worker = new Worker('003.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, navigator.appVersion);
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/003.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/003.js
new file mode 100644
index 0000000000..ff92f8aadb
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/003.js
@@ -0,0 +1 @@
+postMessage(navigator.appVersion); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/004.html b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/004.html
new file mode 100644
index 0000000000..93eee00957
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/004.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>navigator.platform</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var worker = new Worker('004.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, navigator.platform);
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/004.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/004.js
new file mode 100644
index 0000000000..c1b575e43c
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/004.js
@@ -0,0 +1 @@
+postMessage(navigator.platform); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/005.html b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/005.html
new file mode 100644
index 0000000000..ad2899e62e
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/005.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>navigator.userAgent</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var worker = new Worker('005.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, navigator.userAgent);
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/005.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/005.js
new file mode 100644
index 0000000000..d62252d39b
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/005.js
@@ -0,0 +1 @@
+postMessage(navigator.userAgent); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/006.html b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/006.html
new file mode 100644
index 0000000000..e0f7386af3
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/006.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>navigator.onLine</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var worker = new Worker('006.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, navigator.onLine);
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/006.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/006.js
new file mode 100644
index 0000000000..325fd0fbde
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/006.js
@@ -0,0 +1 @@
+postMessage(navigator.onLine); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/007.html b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/007.html
new file mode 100644
index 0000000000..8f9d38dd85
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/007.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>readonlyness of members of Navigator</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var worker = new Worker('007.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, '');
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/007.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/007.js
new file mode 100644
index 0000000000..38849bc8ab
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/007.js
@@ -0,0 +1,11 @@
+var log = [];
+var neverEncounteredValue = "This is not the value you are looking for.";
+for (x in navigator) {
+ // skip functions, as they are writable
+ if (typeof navigator[x] === 'function') continue;
+ // this should silently fail and not throw per webidl
+ navigator[x] = neverEncounteredValue;
+ if (navigator[x] === neverEncounteredValue)
+ log.push(x);
+}
+postMessage(log.join(', ')); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/008.worker.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/008.worker.js
new file mode 100644
index 0000000000..e539d85d76
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/008.worker.js
@@ -0,0 +1,12 @@
+"use strict";
+importScripts("/resources/testharness.js");
+test(function () {
+ for (const x in navigator) {
+ // skip functions, as they are settable
+ if (typeof navigator[x] === "function") continue;
+ assert_throws_js(TypeError, () => {
+ navigator[x] = "";
+ }, `navigator.${x} is read-only`);
+ }
+}, "navigator properties are read-only");
+done();
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/language.html b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/language.html
new file mode 100644
index 0000000000..535ab3a7cb
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/language.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>navigator.language</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var worker = new Worker('language.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, navigator.language);
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/language.js b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/language.js
new file mode 100644
index 0000000000..e94ba4dfcf
--- /dev/null
+++ b/testing/web-platform/tests/workers/interfaces/WorkerUtils/navigator/language.js
@@ -0,0 +1 @@
+postMessage(navigator.language); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/modules/dedicated-worker-import-blob-url.any.js b/testing/web-platform/tests/workers/modules/dedicated-worker-import-blob-url.any.js
new file mode 100644
index 0000000000..e5d79add73
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/dedicated-worker-import-blob-url.any.js
@@ -0,0 +1,26 @@
+// META: script=/workers/modules/resources/import-test-cases.js
+
+// Imports |testCase.scriptURL| on a dedicated worker loaded from a blob URL,
+// and waits until the list of imported modules is sent from the worker. Passes
+// if the list is equal to |testCase.expectation|.
+function import_blob_url_test(testCase) {
+ promise_test(async () => {
+ const importURL = new URL(testCase.scriptURL, location.href);
+ const blob = new Blob([`import "${importURL}";`],
+ { type: 'text/javascript' });
+ const blobURL = URL.createObjectURL(blob);
+ const worker = new Worker(blobURL, { type: 'module'});
+ worker.postMessage('Send message for tests from main script.');
+ const msgEvent = await new Promise((resolve, reject) => {
+ worker.onmessage = resolve;
+ worker.onerror = error => {
+ const msg = error instanceof ErrorEvent ? error.message
+ : 'unknown error';
+ reject(msg);
+ };
+ });
+ assert_array_equals(msgEvent.data, testCase.expectation);
+ }, testCase.description);
+}
+
+testCases.forEach(import_blob_url_test);
diff --git a/testing/web-platform/tests/workers/modules/dedicated-worker-import-csp.html b/testing/web-platform/tests/workers/modules/dedicated-worker-import-csp.html
new file mode 100644
index 0000000000..6e0051aa14
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/dedicated-worker-import-csp.html
@@ -0,0 +1,138 @@
+<!DOCTYPE html>
+<title>DedicatedWorker: CSP for ES Modules</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+async function openWindow(url) {
+ const win = window.open(url, '_blank');
+ add_result_callback(() => win.close());
+ const msg_event = await new Promise(resolve => window.onmessage = resolve);
+ assert_equals(msg_event.data, 'LOADED');
+ return win;
+}
+
+function import_csp_test(
+ cspHeader, importType, expectedImportedModules, description) {
+ // Append CSP header to windowURL for static import tests since static import
+ // scripts should obey Window's CSP.
+ const windowURL = `resources/new-worker-window.html` +
+ `${importType === 'static'
+ ? '?pipe=header(Content-Security-Policy, ' + cspHeader + ')'
+ : ''}`;
+ // Append CSP header to scriptURL for dynamic import tests since dynamic
+ // import scripts should obey Worker script's response's CSP.
+ const scriptURL = `${importType}-import-remote-origin-script-worker.sub.js` +
+ `${importType === 'dynamic'
+ ? '?pipe=header(Content-Security-Policy, ' + cspHeader + ')'
+ : ''}`;
+ promise_test(async () => {
+ const win = await openWindow(windowURL);
+ // Ask the window to start a dedicated worker.
+ win.postMessage(scriptURL, '*');
+ const msg_event = await new Promise(resolve => window.onmessage = resolve);
+ assert_array_equals(msg_event.data, expectedImportedModules);
+ }, description);
+}
+
+// Tests for static import.
+//
+// Static import should obey the worker-src directive and the script-src
+// directive. If the both directives are specified, the worker-src directive
+// should be prioritized.
+//
+// Step 1: "If the result of executing 6.6.1.11 Get the effective directive for
+// request on request is "worker-src", and policy contains a directive whose
+// name is "worker-src", return "Allowed"."
+// "Note: If worker-src is present, we’ll defer to it when handling worker
+// requests."
+// https://w3c.github.io/webappsec-csp/#script-src-pre-request
+
+import_csp_test(
+ "worker-src 'self' 'unsafe-inline'",
+ "static",
+ ['ERROR'],
+ "worker-src 'self' directive should disallow cross origin static import.");
+
+import_csp_test(
+ "worker-src * 'unsafe-inline'",
+ "static",
+ ["export-on-load-script.js"],
+ "worker-src * directive should allow cross origin static import.")
+
+import_csp_test(
+ "script-src 'self' 'unsafe-inline'",
+ "static",
+ ['ERROR'],
+ "script-src 'self' directive should disallow cross origin static import.");
+
+import_csp_test(
+ "script-src * 'unsafe-inline'",
+ "static",
+ ["export-on-load-script.js"],
+ "script-src * directive should allow cross origin static import.")
+
+import_csp_test(
+ "worker-src *; script-src 'self' 'unsafe-inline'",
+ "static",
+ ["export-on-load-script.js"],
+ "worker-src * directive should override script-src 'self' directive and " +
+ "allow cross origin static import.");
+
+import_csp_test(
+ "worker-src 'self'; script-src * 'unsafe-inline'",
+ "static",
+ ['ERROR'],
+ "worker-src 'self' directive should override script-src * directive and " +
+ "disallow cross origin static import.");
+
+// For static imports on workers, the effective directive should be 'worker-src'.
+// https://w3c.github.io/webappsec-csp/#effective-directive-for-a-request
+//
+// The directive fallback list of 'worker-src' doesn't contain 'script-src-elem'
+// https://w3c.github.io/webappsec-csp/#directive-fallback-list
+import_csp_test(
+ "script-src-elem 'self' 'unsafe-inline'",
+ "static",
+ ["export-on-load-script.js"],
+ "script-src-elem 'self' directive should not take effect on static import.");
+
+// Tests for dynamic import.
+//
+// Dynamic import should obey the script-src directive instead of the worker-src
+// directive according to the specs:
+//
+// Dynamic import has the "script" destination.
+// Step 2.4: "Fetch a module script graph given url, ..., "script", ..."
+// https://html.spec.whatwg.org/multipage/webappapis.html#hostimportmoduledynamically(referencingscriptormodule,-specifier,-promisecapability)
+//
+// The "script" destination should obey the script-src CSP directive.
+// Step 2: "If request's destination is script-like:"
+// https://w3c.github.io/webappsec-csp/#script-src-pre-request
+
+import_csp_test(
+ "script-src 'self' 'unsafe-inline'",
+ "dynamic",
+ ['ERROR'],
+ "script-src 'self' directive should disallow cross origin dynamic import.");
+
+// For dynamic imports, the effective directive should be 'script-src-elem'.
+// https://w3c.github.io/webappsec-csp/#effective-directive-for-a-request
+import_csp_test(
+ "script-src-elem 'self' 'unsafe-inline'",
+ "dynamic",
+ ['ERROR'],
+ "script-src-elem 'self' directive should disallow cross origin dynamic import.");
+
+import_csp_test(
+ "script-src * 'unsafe-inline'",
+ "dynamic",
+ ["export-on-load-script.js"],
+ "script-src * directive should allow cross origin dynamic import.")
+
+import_csp_test(
+ "worker-src 'self' 'unsafe-inline'",
+ "dynamic",
+ ["export-on-load-script.js"],
+ "worker-src 'self' directive should not take effect on dynamic import.");
+</script>
diff --git a/testing/web-platform/tests/workers/modules/dedicated-worker-import-data-url-cross-origin.html b/testing/web-platform/tests/workers/modules/dedicated-worker-import-data-url-cross-origin.html
new file mode 100644
index 0000000000..2f790a06a5
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/dedicated-worker-import-data-url-cross-origin.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<title>DedicatedWorker: ES modules for data URL workers</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+const import_from_data_url_worker_test = (importType, isDataURL, expectation) => {
+ promise_test(async () => {
+ const importURL = new URL(`resources/${importType}-import-` +
+ `${isDataURL ? 'data-url' : 'script'}-block-cross-origin.js`,
+ location.href) + '?pipe=header(Access-Control-Allow-Origin, *)';
+ const dataURL = `data:text/javascript,import "${importURL}";`;
+ const worker = new Worker(dataURL, { type: 'module' });
+ worker.postMessage('Send message for tests from main script.');
+ const msgEvent = await new Promise((resolve, reject) =>{
+ worker.onmessage = resolve;
+ worker.onerror = reject;
+ }).catch(e => assert_true(false));
+ assert_array_equals(msgEvent.data,
+ expectation === 'blocked' ? ['ERROR']
+ : ['export-block-cross-origin.js']);
+ }, `${importType} import ${isDataURL ? 'data url' : 'script'} from data: ` +
+ `URL should be ${expectation}.`);
+}
+
+// Static import should obey the outside settings.
+// SecurityOrigin of the outside settings is decided by Window.
+import_from_data_url_worker_test('static', true, 'allowed');
+import_from_data_url_worker_test('static', false, 'allowed');
+
+
+// Dynamic import should obey the inside settings.
+// SecurityOrigin of the inside settings is a unique opaque origin.
+//
+// Data url script is cross-origin to the inside settings' SecurityOrigin, but
+// dynamic importing it is allowed.
+// https://fetch.spec.whatwg.org/#concept-main-fetch
+// Step 5: request’s current URL’s scheme is "data" [spec text]
+import_from_data_url_worker_test('dynamic', true, 'allowed');
+
+// Non-data url script is cross-origin to the inside settings' SecurityOrigin.
+// It should be blocked.
+import_from_data_url_worker_test('dynamic', false, 'blocked');
+
+</script>
diff --git a/testing/web-platform/tests/workers/modules/dedicated-worker-import-data-url.any.js b/testing/web-platform/tests/workers/modules/dedicated-worker-import-data-url.any.js
new file mode 100644
index 0000000000..b837ad67da
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/dedicated-worker-import-data-url.any.js
@@ -0,0 +1,25 @@
+// META: script=/workers/modules/resources/import-test-cases.js
+
+// Imports |testCase.scriptURL| on a dedicated worker loaded from a data URL,
+// and waits until the list of imported modules is sent from the worker. Passes
+// if the list is equal to |testCase.expectation|.
+function import_data_url_test(testCase) {
+ promise_test(async () => {
+ // The Access-Control-Allow-Origin header is necessary because a worker
+ // loaded from a data URL has a null origin and import() on the worker
+ // without the header is blocked.
+ const importURL = new URL(testCase.scriptURL, location.href) +
+ '?pipe=header(Access-Control-Allow-Origin, *)';
+ const dataURL = `data:text/javascript,import "${importURL}";`;
+
+ const worker = new Worker(dataURL, { type: 'module'});
+ worker.postMessage('Send message for tests from main script.');
+ const msgEvent = await new Promise((resolve, reject) =>{
+ worker.onmessage = resolve;
+ worker.onerror = reject;
+ }).catch(e => assert_true(false));
+ assert_array_equals(msgEvent.data, testCase.expectation);
+ }, testCase.description);
+}
+
+testCases.forEach(import_data_url_test);
diff --git a/testing/web-platform/tests/workers/modules/dedicated-worker-import-failure.html b/testing/web-platform/tests/workers/modules/dedicated-worker-import-failure.html
new file mode 100644
index 0000000000..8c6beb35d3
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/dedicated-worker-import-failure.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<title>DedicatedWorker: import failure</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script> setup({allow_uncaught_exception: true}); </script>
+<script>
+
+promise_test(async () => {
+ const scriptURL = 'resources/import-scripts-worker.js';
+ const worker = new Worker(scriptURL, { type: 'module' });
+ const msg_event = await new Promise(resolve => worker.onmessage = resolve);
+ assert_equals(msg_event.data, 'TypeError');
+}, 'importScripts() on module worker should throw an exception.');
+
+promise_test(() => {
+ const scriptURL = 'resources/non-existent-worker.js';
+ const worker = new Worker(scriptURL, { type: 'module' });
+ return new Promise(resolve => worker.onerror = resolve);
+}, 'Worker construction for non-existent script should dispatch an ' +
+ 'ErrorEvent.');
+
+promise_test(() => {
+ const scriptURL = 'resources/static-import-non-existent-script-worker.js';
+ const worker = new Worker(scriptURL, { type: 'module' });
+ return new Promise(resolve => worker.onerror = resolve);
+}, 'Static import for non-existent script should dispatch an ErrorEvent.');
+
+promise_test(async () => {
+ const scriptURL = './non-existent-worker.js';
+ const worker = new Worker('resources/dynamic-import-given-url-worker.js',
+ { type: 'module' });
+ worker.postMessage(scriptURL);
+ const msg_event = await new Promise((resolve, reject) => {
+ worker.onmessage = resolve;
+ worker.onerror = error => {
+ const msg = error instanceof ErrorEvent ? error.message
+ : 'unknown error';
+ reject(msg);
+ };
+ });
+ assert_equals(msg_event.data, 'TypeError');
+}, 'Dynamic import for non-existent script should throw an exception.');
+
+test(() => {
+ const scriptURL = 'http://invalid:123$';
+ assert_throws_dom('SyntaxError', () => new Worker(scriptURL, { type: 'module' }));
+}, 'Worker construction for an invalid URL should throw an exception.');
+
+async_test((t) => {
+ const scriptURL = 'file:///static-import-worker.js';
+ const worker = new Worker(scriptURL, { type: 'module' });
+ worker.onerror = t.step_func_done(function(e) {
+ assert_true(e instanceof Event);
+ });
+}, 'Worker construction for a file URL should fail');
+
+</script>
diff --git a/testing/web-platform/tests/workers/modules/dedicated-worker-import-meta.html b/testing/web-platform/tests/workers/modules/dedicated-worker-import-meta.html
new file mode 100644
index 0000000000..97a5da870f
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/dedicated-worker-import-meta.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<title>DedicatedWorker: import.meta</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+promise_test(() => {
+ const script_url = 'resources/import-meta-url-worker.js';
+ const worker = new Worker(script_url, { type: 'module' });
+ return new Promise((resolve, reject) => {
+ worker.onmessage = resolve;
+ worker.onerror = error => {
+ const msg = error instanceof ErrorEvent ? error.message
+ : 'unknown error';
+ reject(msg);
+ };
+ })
+ .then(msg_event => assert_true(msg_event.data.endsWith(script_url)));
+}, 'Test import.meta.url on the top-level module script.');
+
+promise_test(() => {
+ const script_url = 'import-meta-url-export.js';
+ const worker = new Worker('resources/dynamic-import-given-url-worker.js',
+ { type: 'module' });
+ worker.postMessage('./' + script_url);
+ return new Promise((resolve, reject) => {
+ worker.onmessage = resolve;
+ worker.onerror = error => {
+ const msg = error instanceof ErrorEvent ? error.message
+ : 'unknown error';
+ reject(msg);
+ };
+ })
+ .then(msg_event => assert_true(msg_event.data.endsWith(script_url)));
+}, 'Test import.meta.url on the imported module script.');
+
+promise_test(() => {
+ const script_url = 'import-meta-url-export.js';
+ const worker = new Worker('resources/dynamic-import-given-url-worker.js',
+ { type: 'module' });
+ worker.postMessage('./' + script_url);
+
+ return new Promise((resolve, reject) => {
+ worker.onmessage = resolve;
+ worker.onerror = error => {
+ const msg = error instanceof ErrorEvent ? error.message
+ : 'unknown error';
+ reject(msg);
+ };
+ })
+ .then(msg_event => assert_true(msg_event.data.endsWith(script_url)))
+ .then(() => {
+ worker.postMessage('./' + script_url + '#1');
+ return new Promise(resolve => worker.onmessage = resolve);
+ })
+ .then(msg_event => assert_true(msg_event.data.endsWith(script_url + "#1")));
+}, 'Test import.meta.url on the imported module script with a fragment.');
+
+</script>
diff --git a/testing/web-platform/tests/workers/modules/dedicated-worker-import-referrer.html b/testing/web-platform/tests/workers/modules/dedicated-worker-import-referrer.html
new file mode 100644
index 0000000000..855df62194
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/dedicated-worker-import-referrer.html
@@ -0,0 +1,244 @@
+<!DOCTYPE html>
+<title>DedicatedWorker: Referrer</title>
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+async function openWindow(url) {
+ const win = window.open(url, '_blank');
+ add_result_callback(() => win.close());
+ const msg_event = await new Promise(resolve => window.onmessage = resolve);
+ assert_equals(msg_event.data, 'LOADED');
+ return win;
+}
+
+// Removes URL parameters from the given URL string and returns it.
+function removeParams(url_string) {
+ if (!url_string)
+ return url_string;
+ let url = new URL(url_string);
+ for (var key of url.searchParams.keys())
+ url.searchParams.delete(key);
+ return url.href;
+}
+
+// Generates a referrer given a fetchType, referrer policy, and a request URL
+// (used to determine whether request is remote-origin or not). This function
+// is used to generate expected referrers.
+function generateExpectedReferrer(referrerURL, referrerPolicy, requestURL) {
+ let generatedReferrer = "";
+ if (referrerPolicy === 'no-referrer')
+ generatedReferrer = "";
+ else if (referrerPolicy === 'origin')
+ generatedReferrer = new URL('resources/' + referrerURL, location.href).origin + '/';
+ else if (referrerPolicy === 'same-origin')
+ generatedReferrer = requestURL.includes('remote') ? "" : new URL('resources/' + referrerURL, location.href).href;
+ else
+ generatedReferrer = new URL('resources/' + referrerURL, location.href).href;
+
+ return generatedReferrer;
+}
+
+// Runs a referrer policy test with the given settings. This opens a new window
+// that starts a dedicated worker.
+//
+// |settings| has options as follows:
+//
+// settings = {
+// scriptURL: 'resources/referrer-checker.sub.js',
+// windowReferrerPolicy: 'no-referrer',
+// workerReferrerPolicy: 'same-origin',
+// fetchType: 'top-level' or 'descendant-static' or 'descendant-dynamic'
+// };
+//
+// - |scriptURL| is used for starting a new worker.
+// - |windowReferrerPolicy| is to set the ReferrerPolicy HTTP header of the
+// window. This policy should be applied to top-level worker module script
+// loading and static imports.
+// - |workerReferrerPolicy| is to set the ReferrerPolicy HTTP header of the
+// worker. This policy should be applied to dynamic imports.
+// - |fetchType| indicates a script whose referrer will be tested.
+function import_referrer_test(settings, description) {
+ promise_test(async () => {
+ let windowURL = 'resources/new-worker-window.html';
+ if (settings.windowReferrerPolicy) {
+ windowURL +=
+ `?pipe=header(Referrer-Policy, ${settings.windowReferrerPolicy})`;
+ }
+
+ let scriptURL = settings.scriptURL;
+ if (settings.workerReferrerPolicy) {
+ // 'sub' is necessary even if the |scriptURL| contains the '.sub'
+ // extension because the extension doesn't work with the 'pipe' parameter.
+ // See an issue on the WPT's repository:
+ // https://github.com/web-platform-tests/wpt/issues/9345
+ scriptURL +=
+ `?pipe=sub|header(Referrer-Policy, ${settings.workerReferrerPolicy})`;
+ }
+
+ const win = await openWindow(windowURL);
+ win.postMessage(scriptURL, '*');
+ const msgEvent = await new Promise(resolve => window.onmessage = resolve);
+
+ // Generate the expected referrer, given:
+ // - The fetchType of the test
+ // - Referrer URL to be used
+ // - Relevant referrer policy
+ // - Request URL
+ let expectedReferrer;
+ if (settings.fetchType === 'top-level') {
+ // Top-level worker requests have their outgoing referrers set given their
+ // containing window's URL and referrer policy.
+ expectedReferrer = generateExpectedReferrer('new-worker-window.html', settings.windowReferrerPolicy, settings.scriptURL);
+ } else if (settings.fetchType === 'descendant-static') {
+ // Static descendant script requests from a worker have their outgoing
+ // referrer set given their containing script's URL and containing
+ // window's referrer policy.
+
+ // In the below cases, the referrer URL and the request URLs are the same
+ // because the initial request (for the top-level worker script) should
+ // act as the referrer for future descendant requests.
+ expectedReferrer = generateExpectedReferrer(settings.scriptURL, settings.windowReferrerPolicy, settings.scriptURL);
+ } else if (settings.fetchType === 'descendant-dynamic') {
+ // Dynamic descendant script requests from a worker have their outgoing
+ // referrer set given their containing script's URL and referrer policy.
+ expectedReferrer = generateExpectedReferrer(settings.scriptURL, settings.workerReferrerPolicy, settings.scriptURL);
+ }
+
+ // Delete query parameters from the actual referrer to make it easy to match
+ // it with the expected referrer.
+ const actualReferrer = removeParams(msgEvent.data);
+
+ assert_equals(actualReferrer, expectedReferrer);
+ }, description);
+}
+
+// Tests for top-level worker module script loading.
+//
+// Top-level worker module scripts should inherit the containing window's
+// referrer policy when using the containing window's URL as the referrer.
+//
+// [Current document]
+// --(open)--> [Window] whose referrer policy is |windowReferrerPolicy|.
+// --(new Worker)--> [Worker] should respect [windowReferrerPolicy| when
+// using [Window]'s URL as the referrer.
+
+import_referrer_test(
+ { scriptURL: 'postmessage-referrer-checker.py',
+ windowReferrerPolicy: 'no-referrer',
+ fetchType: 'top-level' },
+ 'Same-origin top-level module script loading with "no-referrer" referrer ' +
+ 'policy');
+
+import_referrer_test(
+ { scriptURL: 'postmessage-referrer-checker.py',
+ windowReferrerPolicy: 'origin',
+ fetchType: 'top-level' },
+ 'Same-origin top-level module script loading with "origin" referrer ' +
+ 'policy');
+
+import_referrer_test(
+ { scriptURL: 'postmessage-referrer-checker.py',
+ windowReferrerPolicy: 'same-origin',
+ fetchType: 'top-level' },
+ 'Same-origin top-level module script loading with "same-origin" referrer ' +
+ 'policy');
+
+// Tests for static imports.
+//
+// Static imports should inherit the containing window's referrer policy when
+// using the containing module script's URL as the referrer.
+// Note: This is subject to change in the future; see
+// https://github.com/w3c/webappsec-referrer-policy/issues/111.
+//
+// [Current document]
+// --(open)--> [Window] whose referrer policy is |windowReferrerPolicy|.
+// --(new Worker)--> [Worker]
+// --(static import)--> [Script] should respect |windowReferrerPolicy| when
+// using [Worker]'s URL as the referrer.
+
+import_referrer_test(
+ { scriptURL: 'static-import-same-origin-referrer-checker-worker.js',
+ windowReferrerPolicy: 'no-referrer',
+ fetchType: 'descendant-static' },
+ 'Same-origin static import with "no-referrer" referrer policy.');
+
+import_referrer_test(
+ { scriptURL: 'static-import-same-origin-referrer-checker-worker.js',
+ windowReferrerPolicy: 'origin',
+ fetchType: 'descendant-static' },
+ 'Same-origin static import with "origin" referrer policy.');
+
+import_referrer_test(
+ { scriptURL: 'static-import-same-origin-referrer-checker-worker.js',
+ windowReferrerPolicy: 'same-origin',
+ fetchType: 'descendant-static' },
+ 'Same-origin static import with "same-origin" referrer policy.');
+
+import_referrer_test(
+ { scriptURL: 'static-import-remote-origin-referrer-checker-worker.sub.js',
+ windowReferrerPolicy: 'no-referrer',
+ fetchType: 'descendant-static' },
+ 'Cross-origin static import with "no-referrer" referrer policy.');
+
+import_referrer_test(
+ { scriptURL: 'static-import-remote-origin-referrer-checker-worker.sub.js',
+ windowReferrerPolicy: 'origin',
+ fetchType: 'descendant-static' },
+ 'Cross-origin static import with "origin" referrer policy.');
+
+import_referrer_test(
+ { scriptURL: 'static-import-remote-origin-referrer-checker-worker.sub.js',
+ windowReferrerPolicy: 'same-origin',
+ fetchType: 'descendant-static' },
+ 'Cross-origin static import with "same-origin" referrer policy.');
+
+// Tests for dynamic imports.
+//
+// Dynamic imports should inherit the containing script's referrer policy if
+// set, and use the default referrer policy otherwise, when using the
+// containing script's URL as the referrer.
+//
+// [Current document]
+// --(open)--> [Window]
+// --(new Worker)--> [Worker] whose referrer policy is |workerReferrerPolicy|.
+// --(dynamic import)--> [Script] should respect |workerReferrerPolicy| when
+// using [Worker]'s URL as the referrer.
+
+import_referrer_test(
+ { scriptURL: 'dynamic-import-same-origin-referrer-checker-worker.js',
+ workerReferrerPolicy: 'no-referrer',
+ fetchType: 'descendant-dynamic' },
+ 'Same-origin dynamic import with "no-referrer" referrer policy.');
+
+import_referrer_test(
+ { scriptURL: 'dynamic-import-same-origin-referrer-checker-worker.js',
+ workerReferrerPolicy: 'origin',
+ fetchType: 'descendant-dynamic' },
+ 'Same-origin dynamic import with "origin" referrer policy.');
+
+import_referrer_test(
+ { scriptURL: 'dynamic-import-same-origin-referrer-checker-worker.js',
+ workerReferrerPolicy: 'same-origin',
+ fetchType: 'descendant-dynamic' },
+ 'Same-origin dynamic import with "same-origin" referrer policy.');
+
+import_referrer_test(
+ { scriptURL: 'dynamic-import-remote-origin-referrer-checker-worker.sub.js',
+ workerReferrerPolicy: 'no-referrer',
+ fetchType: 'descendant-dynamic' },
+ 'Cross-origin dynamic import with "no-referrer" referrer policy.');
+
+import_referrer_test(
+ { scriptURL: 'dynamic-import-remote-origin-referrer-checker-worker.sub.js',
+ workerReferrerPolicy: 'origin',
+ fetchType: 'descendant-dynamic' },
+ 'Cross-origin dynamic import with "origin" referrer policy.');
+
+import_referrer_test(
+ { scriptURL: 'dynamic-import-remote-origin-referrer-checker-worker.sub.js',
+ workerReferrerPolicy: 'same-origin',
+ fetchType: 'descendant-dynamic' },
+ 'Cross-origin dynamic import with "same-origin" referrer policy.');
+</script>
diff --git a/testing/web-platform/tests/workers/modules/dedicated-worker-import.any.js b/testing/web-platform/tests/workers/modules/dedicated-worker-import.any.js
new file mode 100644
index 0000000000..d5bb6cccbe
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/dedicated-worker-import.any.js
@@ -0,0 +1,22 @@
+// META: script=/workers/modules/resources/import-test-cases.js
+
+// Starts a dedicated worker for |testCase.scriptURL| and waits until the list
+// of imported modules is sent from the worker. Passes if the list is equal to
+// |testCase.expectation|.
+function import_test(testCase) {
+ promise_test(async () => {
+ const worker = new Worker(testCase.scriptURL, { type: 'module' });
+ worker.postMessage('Send message for tests from main script.');
+ const msgEvent = await new Promise((resolve, reject) => {
+ worker.onmessage = resolve;
+ worker.onerror = error => {
+ const msg = error instanceof ErrorEvent ? error.message
+ : 'unknown error';
+ reject(msg);
+ };
+ });
+ assert_array_equals(msgEvent.data, testCase.expectation);
+ }, testCase.description);
+}
+
+testCases.forEach(import_test);
diff --git a/testing/web-platform/tests/workers/modules/dedicated-worker-options-credentials.html b/testing/web-platform/tests/workers/modules/dedicated-worker-options-credentials.html
new file mode 100644
index 0000000000..94916d7ff5
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/dedicated-worker-options-credentials.html
@@ -0,0 +1,304 @@
+<!DOCTYPE html>
+<title>DedicatedWorker: WorkerOptions 'credentials'</title>
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script>
+host_info = get_host_info();
+
+// Determines the expected cookie value to be reported by a dedicated worker
+// based on the given option. The worker reports an empty string as the actual
+// cookie value if the cookie wasn't sent to the server. Otherwise, it's the
+// value set by the headers file:
+// "dedicated-worker-options-credentials.html.headers"
+function DetermineExpectedCookieValue(options, config) {
+ // Valid WorkerOptions and test config checking.
+ if (config.origin !== 'same' && config.origin !== 'remote')
+ assert_unreached('Invalid config.origin was specified: ' + config.origin);
+ if (options.credentials && options.credentials !== 'omit' &&
+ options.credentials !== 'same-origin' &&
+ options.credentials !== 'include') {
+ assert_unreached('Invalid credentials option was specified: ' +
+ options.credentials);
+ }
+ if (options.type !== 'classic' && options.type !== 'module')
+ assert_unreached('Invalid type option was specified: ' + options.type);
+
+ if (options.type === 'classic')
+ return (config.origin === 'same') ? '1' : '';
+
+ if (options.credentials === 'omit')
+ return '';
+ else if (options.credentials === 'include')
+ return '1';
+ else
+ return (config.origin === 'same') ? '1' : '';
+}
+
+// Runs a credentials test with the given WorkerOptions.
+//
+// |options| is a WorkerOptions dict.
+// |config| has options as follows:
+//
+// config = {
+// fetchType: 'top-level' or 'descendant-static' or 'descendant-dynamic'
+// origin: 'remote' or 'same'
+// };
+//
+// - |config.fetchType| indicates the type of script to load for the test.
+// - |config.origin| indicates same-origin-ness of the script to load.
+function credentials_test(options, config, description) {
+ promise_test(async () => {
+ let workerURL, origin = config.origin;
+ if (config.fetchType === 'top-level') {
+ workerURL = 'resources/postmessage-credentials.py';
+ } else if (config.fetchType === 'descendant-static') {
+ workerURL =
+ `resources/static-import-${origin}-origin-credentials-checker-worker.${origin === 'same' ? '' : 'sub.'}js`;
+ } else if (config.fetchType === 'descendant-dynamic') {
+ workerURL =
+ `resources/dynamic-import-${origin}-origin-credentials-checker-worker.${origin === 'same' ? '' : 'sub.'}js`;
+ } else {
+ assert_unreached('Invalid config.fetchType: ' + config.fetchType);
+ }
+
+ const worker = new Worker(workerURL, options);
+
+ // Wait until the worker sends the actual cookie value.
+ const msg_event = await new Promise(resolve => worker.onmessage = resolve);
+
+ const expectedCookieValue = DetermineExpectedCookieValue(options, config);
+ assert_equals(msg_event.data, expectedCookieValue);
+ }, description);
+}
+
+function init() {
+ // Same-origin cookie is set up in the .headers file in this directory.
+ promise_test(async () => {
+ return fetch(
+ `${host_info.HTTP_REMOTE_ORIGIN}/cookies/resources/set-cookie.py?name=COOKIE_NAME&path=/workers/modules/`,
+ {
+ mode: 'no-cors',
+ credentials: 'include'
+ });
+ }, 'Test initialization: setting up cross-origin cookie');
+}
+
+init();
+
+// Tests for module workers.
+
+credentials_test(
+ { type: 'module' },
+ { fetchType: 'top-level', origin: 'same' },
+ 'new Worker() with type=module and default credentials option should ' +
+ 'behave as credentials=same-origin and send the credentials');
+
+credentials_test(
+ { credentials: 'omit', type: 'module' },
+ { fetchType: 'top-level', origin: 'same' },
+ 'new Worker() with type=module and credentials=omit should not send the ' +
+ 'credentials');
+
+credentials_test(
+ { credentials: 'same-origin', type: 'module' },
+ { fetchType: 'top-level', origin: 'same' },
+ 'new Worker() with type=module and credentials=same-origin should send ' +
+ 'the credentials');
+
+credentials_test(
+ { credentials: 'include', type: 'module' },
+ { fetchType: 'top-level', origin: 'same' },
+ 'new Worker() with type=module and credentials=include should send the ' +
+ 'credentials');
+
+// Tests for module worker static imports.
+
+credentials_test(
+ { type: 'module' },
+ { fetchType: 'descendant-static', origin: 'same' },
+ 'new Worker() with type=module and default credentials option should ' +
+ 'behave as credentials=same-origin and send the credentials for ' +
+ 'same-origin static imports');
+
+credentials_test(
+ { credentials: 'omit', type: 'module' },
+ { fetchType: 'descendant-static', origin: 'same' },
+ 'new Worker() with type=module and credentials=omit should not send the ' +
+ 'credentials for same-origin static imports');
+
+credentials_test(
+ { credentials: 'same-origin', type: 'module' },
+ { fetchType: 'descendant-static', origin: 'same' },
+ 'new Worker() with type=module and credentials=same-origin should send ' +
+ 'the credentials for same-origin static imports');
+
+credentials_test(
+ { credentials: 'include', type: 'module' },
+ { fetchType: 'descendant-static', origin: 'same' },
+ 'new Worker() with type=module and credentials=include should send the ' +
+ 'credentials for same-origin static imports');
+
+credentials_test(
+ { type: 'module' },
+ { fetchType: 'descendant-static', origin: 'remote' },
+ 'new Worker() with type=module and default credentials option should ' +
+ 'behave as credentials=same-origin and not send the credentials for ' +
+ 'cross-origin static imports');
+
+credentials_test(
+ { credentials: 'omit', type: 'module' },
+ { fetchType: 'descendant-static', origin: 'remote' },
+ 'new Worker() with type-module credentials=omit should not send the ' +
+ 'credentials for cross-origin static imports');
+
+credentials_test(
+ { credentials: 'same-origin', type: 'module' },
+ { fetchType: 'descendant-static', origin: 'remote' },
+ 'new Worker() with type=module and credentials=same-origin should not ' +
+ 'send the credentials for cross-origin static imports');
+
+credentials_test(
+ { credentials: 'include', type: 'module' },
+ { fetchType: 'descendant-static', origin: 'remote' },
+ 'new Worker() with type=module and credentials=include should send the ' +
+ 'credentials for cross-origin static imports');
+
+// Tests for module worker dynamic imports.
+
+credentials_test(
+ { type: 'module' },
+ { fetchType: 'descendant-dynamic', origin: 'same' },
+ 'new Worker() with type=module and default credentials option should ' +
+ 'behave as credentials=same-origin and send the credentials for ' +
+ 'same-origin dynamic imports');
+
+credentials_test(
+ { credentials: 'omit', type: 'module' },
+ { fetchType: 'descendant-dynamic', origin: 'same' },
+ 'new Worker() with type=module and credentials=omit should not send the ' +
+ 'credentials for same-origin dynamic imports');
+
+credentials_test(
+ { credentials: 'same-origin', type: 'module' },
+ { fetchType: 'descendant-dynamic', origin: 'same' },
+ 'new Worker() with type=module and credentials=same-origin should send ' +
+ 'the credentials for same-origin dynamic imports');
+
+credentials_test(
+ { credentials: 'include', type: 'module' },
+ { fetchType: 'descendant-dynamic', origin: 'same' },
+ 'new Worker() with type=module and credentials=include should send the ' +
+ 'credentials for same-origin dynamic imports');
+
+credentials_test(
+ { type: 'module'},
+ { fetchType: 'descendant-dynamic', origin: 'remote' },
+ 'new Worker() with type=module and default credentials option should ' +
+ 'behave as credentials=same-origin and not send the credentials for ' +
+ 'cross-origin dynamic imports');
+
+credentials_test(
+ { credentials: 'omit', type: 'module' },
+ { fetchType: 'descendant-dynamic', origin: 'remote' },
+ 'new Worker() with type-module credentials=omit should not send the ' +
+ 'credentials for cross-origin dynamic imports');
+
+credentials_test(
+ { credentials: 'same-origin', type: 'module' },
+ { fetchType: 'descendant-dynamic', origin: 'remote' },
+ 'new Worker() with type=module and credentials=same-origin should not ' +
+ 'send the credentials for cross-origin dynamic imports');
+
+credentials_test(
+ { credentials: 'include', type: 'module' },
+ { fetchType: 'descendant-dynamic', origin: 'remote' },
+ 'new Worker() with type=module and credentials=include should send the ' +
+ 'credentials for cross-origin dynamic imports');
+
+// Tests for classic workers.
+// TODO(domfarolino): Maybe move classic worker tests up a directory?
+
+credentials_test(
+ { type: 'classic' },
+ { fetchType: 'top-level', origin: 'same' },
+ 'new Worker() with type=classic should always send the credentials ' +
+ 'regardless of the credentials option (default).');
+
+credentials_test(
+ { credentials: 'omit', type: 'classic' },
+ { fetchType: 'top-level', origin: 'same' },
+ 'new Worker() with type=classic should always send the credentials ' +
+ 'regardless of the credentials option (omit).');
+
+credentials_test(
+ { credentials: 'same-origin', type: 'classic' },
+ { fetchType: 'top-level', origin: 'same' },
+ 'new Worker() with type=classic should always send the credentials ' +
+ 'regardless of the credentials option (same-origin).');
+
+credentials_test(
+ { credentials: 'include', type: 'classic' },
+ { fetchType: 'top-level', origin: 'same' },
+ 'new Worker() with type=classic should always send the credentials ' +
+ 'regardless of the credentials option (include).');
+
+// Tests for classic worker dynamic imports.
+
+credentials_test(
+ { type: 'classic' },
+ { fetchType: 'descendant-dynamic', origin: 'same' },
+ 'new Worker() with type=classic should always send the credentials for ' +
+ 'same-origin dynamic imports regardless of the credentials option ' +
+ '(default).');
+
+credentials_test(
+ { credentials: 'omit', type: 'classic' },
+ { fetchType: 'descendant-dynamic', origin: 'same' },
+ 'new Worker() with type=classic should always send the credentials for ' +
+ 'same-origin dynamic imports regardless of the credentials option (omit).');
+
+credentials_test(
+ { credentials: 'same-origin', type: 'classic' },
+ { fetchType: 'descendant-dynamic', origin: 'same' },
+ 'new Worker() with type=classic should always send the credentials for ' +
+ 'same-origin dynamic imports regardless of the credentials option ' +
+ '(same-origin).');
+
+credentials_test(
+ { credentials: 'include', type: 'classic' },
+ { fetchType: 'descendant-dynamic', origin: 'same' },
+ 'new Worker() with type=classic should always send the credentials for ' +
+ 'same-origin dynamic imports regardless of the credentials option ' +
+ '(include).');
+
+credentials_test(
+ { type: 'classic' },
+ { fetchType: 'descendant-dynamic', origin: 'remote' },
+ 'new Worker() with type=classic should never send the credentials for ' +
+ 'cross-origin dynamic imports regardless of the credentials option ' +
+ '(default).');
+
+credentials_test(
+ { credentials: 'omit', type: 'classic' },
+ { fetchType: 'descendant-dynamic', origin: 'remote' },
+ 'new Worker() with type=classic should never send the credentials for ' +
+ 'cross-origin dynamic imports regardless of the credentials option ' +
+ '(omit).');
+
+credentials_test(
+ { credentials: 'same-origin', type: 'classic' },
+ { fetchType: 'descendant-dynamic', origin: 'remote' },
+ 'new Worker() with type=classic should never send the credentials for ' +
+ 'cross-origin dynamic imports regardless of the credentials option ' +
+ '(same-origin).');
+
+credentials_test(
+ { credentials: 'include', type: 'classic' },
+ { fetchType: 'descendant-dynamic', origin: 'remote' },
+ 'new Worker() with type=classic should never send the credentials for ' +
+ 'cross-origin dynamic imports regardless of the credentials option ' +
+ '(include).');
+
+</script>
diff --git a/testing/web-platform/tests/workers/modules/dedicated-worker-options-credentials.html.headers b/testing/web-platform/tests/workers/modules/dedicated-worker-options-credentials.html.headers
new file mode 100644
index 0000000000..8da851ab73
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/dedicated-worker-options-credentials.html.headers
@@ -0,0 +1,2 @@
+Set-Cookie: COOKIE_NAME=1
+Access-Control-Allow-Credentials: true
diff --git a/testing/web-platform/tests/workers/modules/dedicated-worker-options-type.html b/testing/web-platform/tests/workers/modules/dedicated-worker-options-type.html
new file mode 100644
index 0000000000..bb37a18f2c
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/dedicated-worker-options-type.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<title>DedicatedWorker: WorkerOptions 'type'</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+promise_test(() => {
+ const worker = new Worker('resources/post-message-on-load-worker.js');
+ return new Promise(resolve => worker.onmessage = resolve)
+ .then(msg_event => assert_equals(msg_event.data, 'LOADED'));
+}, 'Test worker construction with the default worker type.');
+
+promise_test(() => {
+ const worker = new Worker('resources/post-message-on-load-worker.js',
+ { type: 'classic' });
+ return new Promise(resolve => worker.onmessage = resolve)
+ .then(msg_event => assert_equals(msg_event.data, 'LOADED'));
+}, 'Test worker construction with the "classic" worker type.');
+
+promise_test(() => {
+ const worker = new Worker('resources/post-message-on-load-worker.js',
+ { type: 'module' });
+ return new Promise(resolve => worker.onmessage = resolve)
+ .then(msg_event => assert_equals(msg_event.data, 'LOADED'));
+}, 'Test worker construction with the "module" worker type.');
+
+test(() => {
+ assert_throws_js(
+ TypeError,
+ () => {
+ new Worker('resources/post-message-on-load-worker.js', { type: '' });
+ },
+ 'Worker construction with an empty type should throw an exception');
+}, 'Test worker construction with an empty worker type.');
+
+test(() => {
+ assert_throws_js(
+ TypeError,
+ () => {
+ new Worker('resources/post-message-on-load-worker.js',
+ { type: 'unknown' });
+ },
+ 'Worker construction with an unknown type should throw an exception');
+}, 'Test worker construction with an unknown worker type.');
+
+</script>
diff --git a/testing/web-platform/tests/workers/modules/dedicated-worker-parse-error-failure.html b/testing/web-platform/tests/workers/modules/dedicated-worker-parse-error-failure.html
new file mode 100644
index 0000000000..343bfe289f
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/dedicated-worker-parse-error-failure.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<title>DedicatedWorker: parse error failure</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script> setup({allow_uncaught_exception: true}); </script>
+<script src="../support/check-error-arguments.js"></script>
+<script>
+
+// Check if module scripts are supported on dedicated workers. There is no
+// direct way to detect it, so we assume it's supported when static import is
+// available on the workers.
+//
+// This check is necessary to appropriately test parse error handling because
+// we need to distinguish the parse error invoked by unsupported "import" in
+// the top-level script from the parse error invoked by the statically imported
+// script which is the one we want to check in this test.
+promise_setup(async () => {
+ const scriptURL = 'resources/static-import-worker.js';
+ const worker = new Worker(scriptURL, { type: 'module' });
+ worker.postMessage('Send message for tests from main script.');
+ const supportsModuleWorkers = await new Promise((resolve, reject) => {
+ worker.onmessage = e => {
+ resolve(e.data.length == 1 && e.data[0] == 'export-on-load-script.js');
+ };
+ worker.onerror = () => resolve(false);
+ });
+ assert_implements(
+ supportsModuleWorkers,
+ "Static import must be supported on module dedicated worker to run this test."
+ );
+});
+
+promise_test(async () => {
+ const scriptURL = 'resources/syntax-error.js';
+ const worker = new Worker(scriptURL, { type: 'module' });
+ const args = await new Promise(resolve =>
+ worker.onerror = (...args) => resolve(args));
+ window.checkErrorArguments(args);
+}, 'Module worker construction for script with syntax error should dispatch ' +
+ 'an event named error.');
+
+promise_test(async () => {
+ const scriptURL = 'resources/static-import-syntax-error.js';
+ const worker = new Worker(scriptURL, { type: 'module' });
+ const args = await new Promise(resolve =>
+ worker.onerror = (...args) => resolve(args));
+ window.checkErrorArguments(args);
+}, 'Static import on module worker for script with syntax error should ' +
+ 'dispatch an event named error.');
+
+</script>
diff --git a/testing/web-platform/tests/workers/modules/resources/dynamic-import-and-then-static-import-worker.js b/testing/web-platform/tests/workers/modules/resources/dynamic-import-and-then-static-import-worker.js
new file mode 100644
index 0000000000..527702f551
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/dynamic-import-and-then-static-import-worker.js
@@ -0,0 +1,32 @@
+// This script is meant to be imported by a module worker. It receives a
+// message from the worker and responds with the list of imported modules.
+const sourcePromise = new Promise(resolve => {
+ if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ self.onmessage = e => {
+ resolve(e.target);
+ };
+ } else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ self.onconnect = e => {
+ resolve(e.ports[0]);
+ };
+ } else if (
+ 'ServiceWorkerGlobalScope' in self &&
+ self instanceof ServiceWorkerGlobalScope) {
+ self.onmessage = e => {
+ resolve(e.source);
+ };
+ }
+});
+
+const importedModulesPromise =
+ import('./export-on-static-import-script.js')
+ .then(module => module.importedModules)
+ .catch(error => `Failed to do dynamic import: ${error}`);
+
+Promise.all([sourcePromise, importedModulesPromise]).then(results => {
+ const [source, importedModules] = results;
+ source.postMessage(importedModules);
+});
diff --git a/testing/web-platform/tests/workers/modules/resources/dynamic-import-data-url-block-cross-origin.js b/testing/web-platform/tests/workers/modules/resources/dynamic-import-data-url-block-cross-origin.js
new file mode 100644
index 0000000000..caa15319c5
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/dynamic-import-data-url-block-cross-origin.js
@@ -0,0 +1,24 @@
+const sourcePromise = new Promise(resolve => {
+ if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ self.onmessage = e => {
+ resolve(e.target);
+ };
+ } else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ self.onconnect = e => {
+ resolve(e.ports[0]);
+ };
+ }
+});
+
+const importedModulesPromise =
+ import("data:text/javascript, export const importedModules = ['export-block-cross-origin.js'];")
+ .then(module => module.importedModules)
+ .catch(() => ['ERROR']);
+
+Promise.all([sourcePromise, importedModulesPromise]).then(results => {
+ const [source, importedModules] = results;
+ source.postMessage(importedModules);
+});
diff --git a/testing/web-platform/tests/workers/modules/resources/dynamic-import-given-url-worker.js b/testing/web-platform/tests/workers/modules/resources/dynamic-import-given-url-worker.js
new file mode 100644
index 0000000000..5510275935
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/dynamic-import-given-url-worker.js
@@ -0,0 +1,21 @@
+// This worker dynamically imports the script URL sent by postMessage(), and
+// sends back an error name if the dynamic import fails.
+if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ self.onmessage = msg_event => {
+ import(msg_event.data)
+ .then(module => postMessage(module.meta_url))
+ .catch(e => postMessage(e.name));
+ };
+} else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ self.onconnect = connect_event => {
+ const port = connect_event.ports[0];
+ port.onmessage = msg_event => {
+ import(msg_event.data)
+ .then(module => port.postMessage(module.meta_url))
+ .catch(e => port.postMessage(e.name));
+ };
+ };
+}
diff --git a/testing/web-platform/tests/workers/modules/resources/dynamic-import-remote-origin-credentials-checker-worker.sub.js b/testing/web-platform/tests/workers/modules/resources/dynamic-import-remote-origin-credentials-checker-worker.sub.js
new file mode 100644
index 0000000000..3cfbe7c6e4
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/dynamic-import-remote-origin-credentials-checker-worker.sub.js
@@ -0,0 +1,15 @@
+// Import a remote origin script.
+const import_url =
+ 'http://{{domains[www1]}}:{{ports[http][0]}}/workers/modules/resources/export-credentials.py';
+if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ import(import_url)
+ .then(module => postMessage(module.cookie));
+} else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ onconnect = e => {
+ import(import_url)
+ .then(module => e.ports[0].postMessage(module.cookie));
+ };
+}
diff --git a/testing/web-platform/tests/workers/modules/resources/dynamic-import-remote-origin-referrer-checker-worker.sub.js b/testing/web-platform/tests/workers/modules/resources/dynamic-import-remote-origin-referrer-checker-worker.sub.js
new file mode 100644
index 0000000000..014a3467e8
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/dynamic-import-remote-origin-referrer-checker-worker.sub.js
@@ -0,0 +1,16 @@
+// Import a remote origin script.
+const import_url = 'https://{{hosts[alt][]}}:{{ports[https][0]}}/workers/modules/resources/export-referrer-checker.py';
+if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ import(import_url)
+ .then(module => postMessage(module.referrer))
+ .catch(error => postMessage(`Import failed: ${error}`));
+} else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ onconnect = e => {
+ import(import_url)
+ .then(module => e.ports[0].postMessage(module.referrer))
+ .catch(error => e.ports[0].postMessage(`Import failed: ${error}`));
+ };
+}
diff --git a/testing/web-platform/tests/workers/modules/resources/dynamic-import-remote-origin-script-worker.sub.js b/testing/web-platform/tests/workers/modules/resources/dynamic-import-remote-origin-script-worker.sub.js
new file mode 100644
index 0000000000..7ed6543890
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/dynamic-import-remote-origin-script-worker.sub.js
@@ -0,0 +1,17 @@
+// Import a remote origin script.
+const importUrl =
+ 'https://{{domains[www1]}}:{{ports[https][0]}}/workers/modules/resources/export-on-load-script.js';
+if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ import(importUrl)
+ .then(module => postMessage(module.importedModules))
+ .catch(e => postMessage(['ERROR']));
+} else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ onconnect = e => {
+ import(importUrl)
+ .then(module => e.ports[0].postMessage(module.importedModules))
+ .catch(error => e.ports[0].postMessage(['ERROR']));
+ };
+}
diff --git a/testing/web-platform/tests/workers/modules/resources/dynamic-import-same-origin-credentials-checker-worker.js b/testing/web-platform/tests/workers/modules/resources/dynamic-import-same-origin-credentials-checker-worker.js
new file mode 100644
index 0000000000..24dbd55128
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/dynamic-import-same-origin-credentials-checker-worker.js
@@ -0,0 +1,13 @@
+const import_url = './export-credentials.py';
+if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ import(import_url)
+ .then(module => postMessage(module.cookie));
+} else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ onconnect = e => {
+ import(import_url)
+ .then(module => e.ports[0].postMessage(module.cookie));
+ };
+}
diff --git a/testing/web-platform/tests/workers/modules/resources/dynamic-import-same-origin-referrer-checker-worker.js b/testing/web-platform/tests/workers/modules/resources/dynamic-import-same-origin-referrer-checker-worker.js
new file mode 100644
index 0000000000..56f8a6ffe8
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/dynamic-import-same-origin-referrer-checker-worker.js
@@ -0,0 +1,15 @@
+const import_url = './export-referrer-checker.py';
+if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ import(import_url)
+ .then(module => postMessage(module.referrer))
+ .catch(error => postMessage(`Import failed: ${error}`));
+} else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ onconnect = e => {
+ import(import_url)
+ .then(module => e.ports[0].postMessage(module.referrer))
+ .catch(error => e.ports[0].postMessage(`Import failed: ${error}`));
+ };
+}
diff --git a/testing/web-platform/tests/workers/modules/resources/dynamic-import-script-block-cross-origin.js b/testing/web-platform/tests/workers/modules/resources/dynamic-import-script-block-cross-origin.js
new file mode 100644
index 0000000000..52ec530663
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/dynamic-import-script-block-cross-origin.js
@@ -0,0 +1,24 @@
+const sourcePromise = new Promise(resolve => {
+ if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ self.onmessage = e => {
+ resolve(e.target);
+ };
+ } else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ self.onconnect = e => {
+ resolve(e.ports[0]);
+ };
+ }
+});
+
+const importedModulesPromise =
+ import('./export-block-cross-origin.js')
+ .then(module => module.importedModules)
+ .catch(() => ['ERROR']);
+
+Promise.all([sourcePromise, importedModulesPromise]).then(results => {
+ const [source, importedModules] = results;
+ source.postMessage(importedModules);
+});
diff --git a/testing/web-platform/tests/workers/modules/resources/dynamic-import-worker.js b/testing/web-platform/tests/workers/modules/resources/dynamic-import-worker.js
new file mode 100644
index 0000000000..2e756fe055
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/dynamic-import-worker.js
@@ -0,0 +1,32 @@
+// This script is meant to be imported by a module worker. It receives a
+// message from the worker and responds with the list of imported modules.
+const sourcePromise = new Promise(resolve => {
+ if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ self.onmessage = e => {
+ resolve(e.target);
+ };
+ } else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ self.onconnect = e => {
+ resolve(e.ports[0]);
+ };
+ } else if (
+ 'ServiceWorkerGlobalScope' in self &&
+ self instanceof ServiceWorkerGlobalScope) {
+ self.onmessage = e => {
+ resolve(e.source);
+ };
+ }
+});
+
+const importedModulesPromise =
+ import('./export-on-load-script.js')
+ .then(module => module.importedModules)
+ .catch(error => `Failed to do dynamic import: ${error}`);
+
+Promise.all([sourcePromise, importedModulesPromise]).then(results => {
+ const [source, importedModules] = results;
+ source.postMessage(importedModules);
+});
diff --git a/testing/web-platform/tests/workers/modules/resources/empty-worker.js b/testing/web-platform/tests/workers/modules/resources/empty-worker.js
new file mode 100644
index 0000000000..49ceb2648a
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/empty-worker.js
@@ -0,0 +1 @@
+// Do nothing.
diff --git a/testing/web-platform/tests/workers/modules/resources/eval-dynamic-import-worker.js b/testing/web-platform/tests/workers/modules/resources/eval-dynamic-import-worker.js
new file mode 100644
index 0000000000..60080d4292
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/eval-dynamic-import-worker.js
@@ -0,0 +1,29 @@
+// This script is meant to be imported by a module worker. It receives a
+// message from the worker and responds with the list of imported modules.
+const code = 'const sourcePromise = new Promise(resolve => {' +
+ ' if (\'DedicatedWorkerGlobalScope\' in self &&' +
+ ' self instanceof DedicatedWorkerGlobalScope) {' +
+ ' self.onmessage = e => {' +
+ ' resolve(e.target);' +
+ ' };' +
+ ' } else if (\'SharedWorkerGlobalScope\' in self &&' +
+ ' self instanceof SharedWorkerGlobalScope) {' +
+ ' self.onconnect = e => {' +
+ ' resolve(e.ports[0]);' +
+ ' };' +
+ ' } else if (\'ServiceWorkerGlobalScope\' in self &&' +
+ ' self instanceof ServiceWorkerGlobalScope) {' +
+ ' self.onmessage = e => {' +
+ ' resolve(e.source);' +
+ ' };' +
+ ' }' +
+ '});' +
+ 'const importedModulesPromise =' +
+ ' import(\'./export-on-load-script.js\')' +
+ ' .then(module => module.importedModules)' +
+ ' .catch(error => `Failed to do dynamic import: ${error}`);' +
+ 'Promise.all([sourcePromise, importedModulesPromise]).then(results => {' +
+ ' const [source, importedModules] = results;' +
+ ' source.postMessage(importedModules);' +
+ '});';
+eval(code);
diff --git a/testing/web-platform/tests/workers/modules/resources/export-block-cross-origin.js b/testing/web-platform/tests/workers/modules/resources/export-block-cross-origin.js
new file mode 100644
index 0000000000..a4b513d280
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/export-block-cross-origin.js
@@ -0,0 +1 @@
+export const importedModules = ['export-block-cross-origin.js'];
diff --git a/testing/web-platform/tests/workers/modules/resources/export-credentials.py b/testing/web-platform/tests/workers/modules/resources/export-credentials.py
new file mode 100644
index 0000000000..3d0ba778d1
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/export-credentials.py
@@ -0,0 +1,15 @@
+def main(request, response):
+ cookie = request.cookies.first(b"COOKIE_NAME", None)
+
+ response_headers = [(b"Content-Type", b"text/javascript"),
+ (b"Access-Control-Allow-Credentials", b"true")]
+
+ origin = request.headers.get(b"Origin", None)
+ if origin:
+ response_headers.append((b"Access-Control-Allow-Origin", origin))
+
+ cookie_value = b'';
+ if cookie:
+ cookie_value = cookie.value;
+ return (200, response_headers,
+ b"export const cookie = '"+cookie_value+b"';")
diff --git a/testing/web-platform/tests/workers/modules/resources/export-on-dynamic-import-script.js b/testing/web-platform/tests/workers/modules/resources/export-on-dynamic-import-script.js
new file mode 100644
index 0000000000..bab7cb48d2
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/export-on-dynamic-import-script.js
@@ -0,0 +1,8 @@
+// Export the list of imported modules. It's available after the |ready| promise
+// is resolved.
+export let importedModules = ['export-on-dynamic-import-script.js'];
+export let ready = import('./export-on-load-script.js')
+ .then(module => {
+ Array.prototype.push.apply(importedModules, module.importedModules);
+ return importedModules;
+ });
diff --git a/testing/web-platform/tests/workers/modules/resources/export-on-dynamic-import-script.js.headers b/testing/web-platform/tests/workers/modules/resources/export-on-dynamic-import-script.js.headers
new file mode 100644
index 0000000000..cb762eff80
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/export-on-dynamic-import-script.js.headers
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: *
diff --git a/testing/web-platform/tests/workers/modules/resources/export-on-load-script.js b/testing/web-platform/tests/workers/modules/resources/export-on-load-script.js
new file mode 100644
index 0000000000..7d1b122c32
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/export-on-load-script.js
@@ -0,0 +1 @@
+export const importedModules = ['export-on-load-script.js'];
diff --git a/testing/web-platform/tests/workers/modules/resources/export-on-load-script.js.headers b/testing/web-platform/tests/workers/modules/resources/export-on-load-script.js.headers
new file mode 100644
index 0000000000..cb762eff80
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/export-on-load-script.js.headers
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: *
diff --git a/testing/web-platform/tests/workers/modules/resources/export-on-load-script.py b/testing/web-platform/tests/workers/modules/resources/export-on-load-script.py
new file mode 100644
index 0000000000..9014341915
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/export-on-load-script.py
@@ -0,0 +1,15 @@
+import datetime
+
+def main(request, response):
+ # This script serves both preflight and main GET request for cross-origin
+ # static imports from module service workers.
+ # According to https://w3c.github.io/ServiceWorker/#update-algorithm,
+ # `Service-Worker: script` request header is added, which triggers CORS
+ # preflight.
+ response_headers = [(b"Content-Type", b"text/javascript"),
+ (b"Access-Control-Allow-Origin", b"*"),
+ (b"Access-Control-Allow-Headers", b"Service-Worker")]
+
+ body = b"export const importedModules = ['export-on-load-script.js'];"
+ body += b"// %d" % datetime.datetime.now().timestamp()
+ return (200, response_headers, body)
diff --git a/testing/web-platform/tests/workers/modules/resources/export-on-static-import-script.js b/testing/web-platform/tests/workers/modules/resources/export-on-static-import-script.js
new file mode 100644
index 0000000000..3f7174eef0
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/export-on-static-import-script.js
@@ -0,0 +1,3 @@
+import * as module from './export-on-load-script.js';
+const filename = 'export-on-static-import-script.js';
+export const importedModules = [filename].concat(module.importedModules);
diff --git a/testing/web-platform/tests/workers/modules/resources/export-on-static-import-script.js.headers b/testing/web-platform/tests/workers/modules/resources/export-on-static-import-script.js.headers
new file mode 100644
index 0000000000..cb762eff80
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/export-on-static-import-script.js.headers
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: *
diff --git a/testing/web-platform/tests/workers/modules/resources/export-referrer-checker.py b/testing/web-platform/tests/workers/modules/resources/export-referrer-checker.py
new file mode 100644
index 0000000000..3b0fda1aa6
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/export-referrer-checker.py
@@ -0,0 +1,9 @@
+# Returns a worker script that posts the request's referrer header.
+def main(request, response):
+ referrer = request.headers.get(b"referer", b"")
+
+ response_headers = [(b"Content-Type", b"text/javascript"),
+ (b"Access-Control-Allow-Origin", b"*")]
+
+ return (200, response_headers,
+ b"export const referrer = '"+referrer+b"';")
diff --git a/testing/web-platform/tests/workers/modules/resources/import-meta-url-export.js b/testing/web-platform/tests/workers/modules/resources/import-meta-url-export.js
new file mode 100644
index 0000000000..5287b2e9e8
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/import-meta-url-export.js
@@ -0,0 +1 @@
+export const meta_url = import.meta.url;
diff --git a/testing/web-platform/tests/workers/modules/resources/import-meta-url-worker.js b/testing/web-platform/tests/workers/modules/resources/import-meta-url-worker.js
new file mode 100644
index 0000000000..7887836a6c
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/import-meta-url-worker.js
@@ -0,0 +1,10 @@
+if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ postMessage(import.meta.url);
+} else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ self.onconnect = e => {
+ e.ports[0].postMessage(import.meta.url);
+ };
+}
diff --git a/testing/web-platform/tests/workers/modules/resources/import-scripts-worker.js b/testing/web-platform/tests/workers/modules/resources/import-scripts-worker.js
new file mode 100644
index 0000000000..d85f573ffe
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/import-scripts-worker.js
@@ -0,0 +1,33 @@
+try {
+ importScripts('empty-worker.js');
+ if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ postMessage('LOADED');
+ } else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ onconnect = e => {
+ e.ports[0].postMessage('LOADED');
+ };
+ }
+} catch (e) {
+ // Post a message instead of propagating an ErrorEvent to the page because
+ // propagated event loses an error name.
+ //
+ // Step 1. "Let notHandled be the result of firing an event named error at the
+ // Worker object associated with the worker, using ErrorEvent, with the
+ // cancelable attribute initialized to true, the message, filename, lineno,
+ // and colno attributes initialized appropriately, and the error attribute
+ // initialized to null."
+ // https://html.spec.whatwg.org/multipage/workers.html#runtime-script-errors-2
+ if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ postMessage(e.name);
+ } else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ onconnect = connectEvent => {
+ connectEvent.ports[0].postMessage(e.name);
+ };
+ }
+}
diff --git a/testing/web-platform/tests/workers/modules/resources/import-test-cases.js b/testing/web-platform/tests/workers/modules/resources/import-test-cases.js
new file mode 100644
index 0000000000..8ad89e8fda
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/import-test-cases.js
@@ -0,0 +1,59 @@
+const testCases = [
+ {
+ scriptURL: '/workers/modules/resources/static-import-worker.js',
+ expectation: ['export-on-load-script.js'],
+ description: 'Static import.'
+ },
+ {
+ scriptURL: '/workers/modules/resources/static-import-remote-origin-script-worker.sub.js',
+ expectation: ['export-on-load-script.js'],
+ description: 'Static import (cross-origin).'
+ },
+ {
+ scriptURL: '/workers/modules/resources/static-import-redirect-worker.js',
+ expectation: ['export-on-load-script.js'],
+ description: 'Static import (redirect).'
+ },
+ {
+ scriptURL: '/workers/modules/resources/nested-static-import-worker.js',
+ expectation: [
+ 'export-on-static-import-script.js',
+ 'export-on-load-script.js'
+ ],
+ description: 'Nested static import.'
+ },
+ {
+ scriptURL: '/workers/modules/resources/static-import-and-then-dynamic-import-worker.js',
+ expectation: [
+ 'export-on-dynamic-import-script.js',
+ 'export-on-load-script.js'
+ ],
+ description: 'Static import and then dynamic import.'
+ },
+ {
+ scriptURL: '/workers/modules/resources/dynamic-import-worker.js',
+ expectation: ['export-on-load-script.js'],
+ description: 'Dynamic import.'
+ },
+ {
+ scriptURL: '/workers/modules/resources/nested-dynamic-import-worker.js',
+ expectation: [
+ 'export-on-dynamic-import-script.js',
+ 'export-on-load-script.js'
+ ],
+ description: 'Nested dynamic import.'
+ },
+ {
+ scriptURL: '/workers/modules/resources/dynamic-import-and-then-static-import-worker.js',
+ expectation: [
+ 'export-on-static-import-script.js',
+ 'export-on-load-script.js'
+ ],
+ description: 'Dynamic import and then static import.'
+ },
+ {
+ scriptURL: '/workers/modules/resources/eval-dynamic-import-worker.js',
+ expectation: ['export-on-load-script.js'],
+ description: 'eval(import()).'
+ }
+];
diff --git a/testing/web-platform/tests/workers/modules/resources/nested-dynamic-import-worker.js b/testing/web-platform/tests/workers/modules/resources/nested-dynamic-import-worker.js
new file mode 100644
index 0000000000..00da43c5f0
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/nested-dynamic-import-worker.js
@@ -0,0 +1,34 @@
+// This script is meant to be imported by a module worker. It receives a
+// message from the worker and responds with the list of imported modules.
+
+const sourcePromise = new Promise(resolve => {
+ if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ self.onmessage = e => {
+ resolve(e.target);
+ };
+ } else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ self.onconnect = e => {
+ resolve(e.ports[0]);
+ };
+ } else if (
+ 'ServiceWorkerGlobalScope' in self &&
+ self instanceof ServiceWorkerGlobalScope) {
+ self.onmessage = e => {
+ resolve(e.source);
+ };
+ }
+});
+
+const importedModulesPromise =
+ import('./export-on-dynamic-import-script.js')
+ .then(module => module.ready)
+ .then(importedModules => importedModules)
+ .catch(error => `Failed to do dynamic import: ${error}`);
+
+Promise.all([sourcePromise, importedModulesPromise]).then(results => {
+ const [source, importedModules] = results;
+ source.postMessage(importedModules);
+});
diff --git a/testing/web-platform/tests/workers/modules/resources/nested-static-import-worker.js b/testing/web-platform/tests/workers/modules/resources/nested-static-import-worker.js
new file mode 100644
index 0000000000..c3a9ff0b79
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/nested-static-import-worker.js
@@ -0,0 +1,21 @@
+// This script is meant to be imported by a module worker. It receives a
+// message from the worker and responds with the list of imported modules.
+import * as module from './export-on-static-import-script.js';
+if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ self.onmessage = e => {
+ e.target.postMessage(module.importedModules);
+ };
+} else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ self.onconnect = e => {
+ e.ports[0].postMessage(module.importedModules);
+ };
+} else if (
+ 'ServiceWorkerGlobalScope' in self &&
+ self instanceof ServiceWorkerGlobalScope) {
+ self.onmessage = e => {
+ e.source.postMessage(module.importedModules);
+ };
+}
diff --git a/testing/web-platform/tests/workers/modules/resources/new-shared-worker-window.html b/testing/web-platform/tests/workers/modules/resources/new-shared-worker-window.html
new file mode 100644
index 0000000000..84564fd7b6
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/new-shared-worker-window.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title>SharedWorker: new SharedWorker()</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+let worker;
+
+// Create a new shared worker for a given script url.
+window.onmessage = e => {
+ worker = new SharedWorker(e.data.scriptURL,
+ { name: e.data.name, type: 'module' });
+ worker.port.onmessage = msg => window.opener.postMessage(msg.data, '*');
+ worker.onerror = err => {
+ window.opener.postMessage(['ERROR'], '*');
+ err.preventDefault();
+ };
+}
+window.opener.postMessage('LOADED', '*');
+</script>
diff --git a/testing/web-platform/tests/workers/modules/resources/new-worker-window.html b/testing/web-platform/tests/workers/modules/resources/new-worker-window.html
new file mode 100644
index 0000000000..32a89fae0e
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/new-worker-window.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title>DedicatedWorker: new Worker()</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+let worker;
+
+// Creates a new dedicated worker for a given script url.
+window.onmessage = e => {
+ worker = new Worker(e.data, { type: 'module' });
+ worker.postMessage('start');
+ worker.onmessage = msg => window.opener.postMessage(msg.data, '*');
+ worker.onerror = err => {
+ window.opener.postMessage(['ERROR'], '*');
+ err.preventDefault();
+ };
+};
+window.opener.postMessage('LOADED', '*');
+</script>
diff --git a/testing/web-platform/tests/workers/modules/resources/post-message-on-load-worker.js b/testing/web-platform/tests/workers/modules/resources/post-message-on-load-worker.js
new file mode 100644
index 0000000000..e1c547ab6a
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/post-message-on-load-worker.js
@@ -0,0 +1,10 @@
+if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ postMessage('LOADED');
+} else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ self.onconnect = e => {
+ e.ports[0].postMessage('LOADED');
+ };
+}
diff --git a/testing/web-platform/tests/workers/modules/resources/postmessage-credentials.py b/testing/web-platform/tests/workers/modules/resources/postmessage-credentials.py
new file mode 100644
index 0000000000..a054a1a923
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/postmessage-credentials.py
@@ -0,0 +1,22 @@
+def main(request, response):
+ cookie = request.cookies.first(b"COOKIE_NAME", None)
+
+ response_headers = [(b"Content-Type", b"text/javascript"),
+ (b"Access-Control-Allow-Credentials", b"true")]
+
+ origin = request.headers.get(b"Origin", None)
+ if origin:
+ response_headers.append((b"Access-Control-Allow-Origin", origin))
+
+ cookie_value = b'';
+ if cookie:
+ cookie_value = cookie.value;
+ return (200, response_headers,
+ b"if ('DedicatedWorkerGlobalScope' in self &&" +
+ b" self instanceof DedicatedWorkerGlobalScope) {" +
+ b" postMessage('"+cookie_value+b"');" +
+ b"} else if (" +
+ b" 'SharedWorkerGlobalScope' in self &&" +
+ b" self instanceof SharedWorkerGlobalScope) {" +
+ b" onconnect = e => e.ports[0].postMessage('"+cookie_value+b"');" +
+ b"}")
diff --git a/testing/web-platform/tests/workers/modules/resources/postmessage-referrer-checker.py b/testing/web-platform/tests/workers/modules/resources/postmessage-referrer-checker.py
new file mode 100644
index 0000000000..699af684a2
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/postmessage-referrer-checker.py
@@ -0,0 +1,16 @@
+# Returns a worker script that posts the request's referrer header.
+def main(request, response):
+ referrer = request.headers.get(b"referer", b"")
+
+ response_headers = [(b"Content-Type", b"text/javascript"),
+ (b"Access-Control-Allow-Origin", b"*")]
+
+ return (200, response_headers,
+ b"if ('DedicatedWorkerGlobalScope' in self &&" +
+ b" self instanceof DedicatedWorkerGlobalScope) {" +
+ b" postMessage('"+referrer+b"');" +
+ b"} else if (" +
+ b" 'SharedWorkerGlobalScope' in self &&" +
+ b" self instanceof SharedWorkerGlobalScope) {" +
+ b" onconnect = e => e.ports[0].postMessage('"+referrer+b"');" +
+ b"}")
diff --git a/testing/web-platform/tests/workers/modules/resources/redirect.py b/testing/web-platform/tests/workers/modules/resources/redirect.py
new file mode 100644
index 0000000000..396bd4c4b2
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/redirect.py
@@ -0,0 +1,8 @@
+def main(request, response):
+ """Simple handler that causes redirection.
+ This is placed here to stay within the same directory during redirects,
+ to avoid issues like https://crbug.com/1136775.
+ """
+ response.status = 302
+ location = request.GET.first(b"location")
+ response.headers.set(b"Location", location)
diff --git a/testing/web-platform/tests/workers/modules/resources/static-import-and-then-dynamic-import-worker.js b/testing/web-platform/tests/workers/modules/resources/static-import-and-then-dynamic-import-worker.js
new file mode 100644
index 0000000000..2d857a2e90
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/static-import-and-then-dynamic-import-worker.js
@@ -0,0 +1,34 @@
+// This script is meant to be imported by a module worker. It receives a
+// message from the worker and responds with the list of imported modules.
+import * as module from './export-on-dynamic-import-script.js';
+
+const sourcePromise = new Promise(resolve => {
+ if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ self.onmessage = e => {
+ resolve(e.target);
+ };
+ } else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ self.onconnect = e => {
+ resolve(e.ports[0]);
+ };
+ } else if (
+ 'ServiceWorkerGlobalScope' in self &&
+ self instanceof ServiceWorkerGlobalScope) {
+ self.onmessage = e => {
+ resolve(e.source);
+ };
+ }
+});
+
+export let importedModules = ['export-on-dynamic-import-script.js'];
+const importedModulesPromise = module.ready
+ .then(importedModules => importedModules)
+ .catch(error => `Failed to do dynamic import: ${error}`);
+
+Promise.all([sourcePromise, importedModulesPromise]).then(results => {
+ const [source, importedModules] = results;
+ source.postMessage(importedModules);
+});
diff --git a/testing/web-platform/tests/workers/modules/resources/static-import-data-url-block-cross-origin.js b/testing/web-platform/tests/workers/modules/resources/static-import-data-url-block-cross-origin.js
new file mode 100644
index 0000000000..833348d66c
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/static-import-data-url-block-cross-origin.js
@@ -0,0 +1,14 @@
+import * as module from "data:text/javascript, export const importedModules = ['export-block-cross-origin.js'];";
+
+if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ self.onmessage = e => {
+ e.target.postMessage(module.importedModules);
+ };
+} else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ self.onconnect = e => {
+ e.ports[0].postMessage(module.importedModules);
+ };
+}
diff --git a/testing/web-platform/tests/workers/modules/resources/static-import-non-existent-script-worker.js b/testing/web-platform/tests/workers/modules/resources/static-import-non-existent-script-worker.js
new file mode 100644
index 0000000000..16f70e9daf
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/static-import-non-existent-script-worker.js
@@ -0,0 +1 @@
+import './non-existent-script.js';
diff --git a/testing/web-platform/tests/workers/modules/resources/static-import-redirect-worker.js b/testing/web-platform/tests/workers/modules/resources/static-import-redirect-worker.js
new file mode 100644
index 0000000000..8434c1a34e
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/static-import-redirect-worker.js
@@ -0,0 +1,21 @@
+// This script is meant to be imported by a module worker. It receives a
+// message from the worker and responds with the list of imported modules.
+import * as module from './redirect.py?location=/workers/modules/resources/export-on-load-script.js';
+if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ self.onmessage = e => {
+ e.target.postMessage(module.importedModules);
+ };
+} else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ self.onconnect = e => {
+ e.ports[0].postMessage(module.importedModules);
+ };
+} else if (
+ 'ServiceWorkerGlobalScope' in self &&
+ self instanceof ServiceWorkerGlobalScope) {
+ self.onmessage = e => {
+ e.source.postMessage(module.importedModules);
+ };
+}
diff --git a/testing/web-platform/tests/workers/modules/resources/static-import-remote-origin-credentials-checker-worker.sub.js b/testing/web-platform/tests/workers/modules/resources/static-import-remote-origin-credentials-checker-worker.sub.js
new file mode 100644
index 0000000000..c543cb4961
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/static-import-remote-origin-credentials-checker-worker.sub.js
@@ -0,0 +1,12 @@
+// Import a remote origin script.
+import * as module from 'http://{{domains[www1]}}:{{ports[http][0]}}/workers/modules/resources/export-credentials.py';
+if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ postMessage(module.cookie);
+} else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ onconnect = e => {
+ e.ports[0].postMessage(module.cookie);
+ };
+}
diff --git a/testing/web-platform/tests/workers/modules/resources/static-import-remote-origin-referrer-checker-worker.sub.js b/testing/web-platform/tests/workers/modules/resources/static-import-remote-origin-referrer-checker-worker.sub.js
new file mode 100644
index 0000000000..c1f8340f36
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/static-import-remote-origin-referrer-checker-worker.sub.js
@@ -0,0 +1,12 @@
+// Import a remote origin script.
+import * as module from 'https://{{hosts[alt][]}}:{{ports[https][0]}}/workers/modules/resources/export-referrer-checker.py';
+if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ postMessage(module.referrer);
+} else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ onconnect = e => {
+ e.ports[0].postMessage(module.referrer);
+ };
+}
diff --git a/testing/web-platform/tests/workers/modules/resources/static-import-remote-origin-script-worker.sub.js b/testing/web-platform/tests/workers/modules/resources/static-import-remote-origin-script-worker.sub.js
new file mode 100644
index 0000000000..6432dd5d80
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/static-import-remote-origin-script-worker.sub.js
@@ -0,0 +1,20 @@
+// Import a remote origin script.
+import * as module from 'https://{{domains[www1]}}:{{ports[https][0]}}/workers/modules/resources/export-on-load-script.py';
+if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ self.onmessage = e => {
+ e.target.postMessage(module.importedModules);
+ };
+} else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ self.onconnect = e => {
+ e.ports[0].postMessage(module.importedModules);
+ };
+} else if (
+ 'ServiceWorkerGlobalScope' in self &&
+ self instanceof ServiceWorkerGlobalScope) {
+ self.onmessage = e => {
+ e.source.postMessage(module.importedModules);
+ };
+}
diff --git a/testing/web-platform/tests/workers/modules/resources/static-import-same-origin-credentials-checker-worker.js b/testing/web-platform/tests/workers/modules/resources/static-import-same-origin-credentials-checker-worker.js
new file mode 100644
index 0000000000..e83dc92070
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/static-import-same-origin-credentials-checker-worker.js
@@ -0,0 +1,11 @@
+import * as module from './export-credentials.py';
+if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ postMessage(module.cookie);
+} else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ onconnect = e => {
+ e.ports[0].postMessage(module.cookie);
+ };
+}
diff --git a/testing/web-platform/tests/workers/modules/resources/static-import-same-origin-referrer-checker-worker.js b/testing/web-platform/tests/workers/modules/resources/static-import-same-origin-referrer-checker-worker.js
new file mode 100644
index 0000000000..ffcab9e45f
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/static-import-same-origin-referrer-checker-worker.js
@@ -0,0 +1,11 @@
+import * as module from './export-referrer-checker.py';
+if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ postMessage(module.referrer);
+} else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ onconnect = e => {
+ e.ports[0].postMessage(module.referrer);
+ };
+}
diff --git a/testing/web-platform/tests/workers/modules/resources/static-import-script-block-cross-origin.js b/testing/web-platform/tests/workers/modules/resources/static-import-script-block-cross-origin.js
new file mode 100644
index 0000000000..82be8e7ce7
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/static-import-script-block-cross-origin.js
@@ -0,0 +1,14 @@
+import * as module from './export-block-cross-origin.js';
+
+if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ self.onmessage = e => {
+ e.target.postMessage(module.importedModules);
+ };
+} else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ self.onconnect = e => {
+ e.ports[0].postMessage(module.importedModules);
+ };
+}
diff --git a/testing/web-platform/tests/workers/modules/resources/static-import-syntax-error.js b/testing/web-platform/tests/workers/modules/resources/static-import-syntax-error.js
new file mode 100644
index 0000000000..3a20e792c4
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/static-import-syntax-error.js
@@ -0,0 +1 @@
+import * as module from './syntax-error.js';
diff --git a/testing/web-platform/tests/workers/modules/resources/static-import-worker.js b/testing/web-platform/tests/workers/modules/resources/static-import-worker.js
new file mode 100644
index 0000000000..19a347999d
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/static-import-worker.js
@@ -0,0 +1,21 @@
+// This script is meant to be imported by a module worker. It receives a
+// message from the worker and responds with the list of imported modules.
+import * as module from './export-on-load-script.js';
+if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ self.onmessage = e => {
+ e.target.postMessage(module.importedModules);
+ };
+} else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ self.onconnect = e => {
+ e.ports[0].postMessage(module.importedModules);
+ };
+} else if (
+ 'ServiceWorkerGlobalScope' in self &&
+ self instanceof ServiceWorkerGlobalScope) {
+ self.onmessage = e => {
+ e.source.postMessage(module.importedModules);
+ };
+}
diff --git a/testing/web-platform/tests/workers/modules/resources/syntax-error.js b/testing/web-platform/tests/workers/modules/resources/syntax-error.js
new file mode 100644
index 0000000000..8c5c4df671
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/syntax-error.js
@@ -0,0 +1 @@
+1 + ;
diff --git a/testing/web-platform/tests/workers/modules/resources/throw.js b/testing/web-platform/tests/workers/modules/resources/throw.js
new file mode 100644
index 0000000000..3d876d43d9
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/resources/throw.js
@@ -0,0 +1 @@
+throw new Error('custom message');
diff --git a/testing/web-platform/tests/workers/modules/shared-worker-import-blob-url.window.js b/testing/web-platform/tests/workers/modules/shared-worker-import-blob-url.window.js
new file mode 100644
index 0000000000..a79d5725ad
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/shared-worker-import-blob-url.window.js
@@ -0,0 +1,26 @@
+// META: script=/workers/modules/resources/import-test-cases.js
+
+// Imports |testCase.scriptURL| on a shared worker loaded from a blob URL,
+// and waits until the list of imported modules is sent from the worker. Passes
+// if the list is equal to |testCase.expectation|.
+function import_blob_url_test(testCase) {
+ promise_test(async () => {
+ const importURL = new URL(testCase.scriptURL, location.href);
+ const blob =
+ new Blob([`import "${importURL}";`], {type: 'text/javascript'});
+ const blobURL = URL.createObjectURL(blob);
+ const worker = new SharedWorker(blobURL, {type: 'module'});
+ worker.port.postMessage('Send message for tests from main script.');
+ const msgEvent = await new Promise((resolve, reject) => {
+ worker.port.onmessage = resolve;
+ worker.onerror = error => {
+ const msg = error instanceof ErrorEvent ? error.message
+ : 'unknown error';
+ reject(msg);
+ };
+ });
+ assert_array_equals(msgEvent.data, testCase.expectation);
+ }, testCase.description);
+}
+
+testCases.forEach(import_blob_url_test);
diff --git a/testing/web-platform/tests/workers/modules/shared-worker-import-csp.html b/testing/web-platform/tests/workers/modules/shared-worker-import-csp.html
new file mode 100644
index 0000000000..c7ca37557a
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/shared-worker-import-csp.html
@@ -0,0 +1,128 @@
+<!DOCTYPE html>
+<title>SharedWorker: CSP for ES Modules</title>
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+// This Set is for checking a shared worker in each test is newly created.
+const existingWorkers = new Set();
+
+async function openWindow(url) {
+ const win = window.open(url, '_blank');
+ add_result_callback(() => win.close());
+ const msgEvent = await new Promise(resolve => window.onmessage = resolve);
+ assert_equals(msgEvent.data, 'LOADED');
+ return win;
+}
+
+function import_csp_test(
+ cspHeader, importType, expectedImportedModules, description) {
+ // Append CSP header to windowURL for static import tests since static import
+ // scripts should obey Window's CSP.
+ const windowURL = `resources/new-shared-worker-window.html` +
+ `${importType === 'static'
+ ? '?pipe=header(Content-Security-Policy, ' + cspHeader + ')'
+ : ''}`;
+ // Append CSP header to scriptURL for dynamic import tests since dynamic
+ // import scripts should obey SharedWorker script's responce's CSP.
+ const scriptURL = `${importType}-import-remote-origin-script-worker.sub.js` +
+ `${importType === 'dynamic'
+ ? '?pipe=header(Content-Security-Policy, ' + cspHeader + ')'
+ : ''}`;
+ promise_test(async () => {
+ // Open a window that has the given CSP header.
+ const win = await openWindow(windowURL);
+ // Construct a unique name for SharedWorker.
+ const name = `${cspHeader}_${importType}`;
+ const workerProperties = { scriptURL, name };
+ // Check if this shared worker is newly created.
+ assert_false(existingWorkers.has(workerProperties));
+ existingWorkers.add(workerProperties);
+
+ // Ask the window to start a shared worker with the given CSP header.
+ // The shared worker doesn't inherits the window's CSP header.
+ // https://w3c.github.io/webappsec-csp/#initialize-global-object-csp
+ win.postMessage(workerProperties, '*');
+ const msg_event = await new Promise(resolve => window.onmessage = resolve);
+ assert_array_equals(msg_event.data, expectedImportedModules);
+ }, description);
+}
+
+// Tests for static import.
+//
+// Static import should obey the worker-src directive and the script-src
+// directive. If the both directives are specified, the worker-src directive
+// should be prioritized.
+//
+// "The script-src directive acts as a default fallback for all script-like
+// destinations (including worker-specific destinations if worker-src is not
+// present)."
+// https://w3c.github.io/webappsec-csp/#directive-script-src
+
+import_csp_test(
+ "worker-src 'self' 'unsafe-inline'", "static",
+ ['ERROR'],
+ "worker-src 'self' directive should disallow cross origin static import.");
+
+import_csp_test(
+ "worker-src * 'unsafe-inline'", "static",
+ ["export-on-load-script.js"],
+ "worker-src * directive should allow cross origin static import.");
+
+import_csp_test(
+ "script-src 'self' 'unsafe-inline'", "static",
+ ['ERROR'],
+ "script-src 'self' directive should disallow cross origin static import.");
+
+import_csp_test(
+ "script-src * 'unsafe-inline'", "static",
+ ["export-on-load-script.js"],
+ "script-src * directive should allow cross origin static import.");
+
+import_csp_test(
+ "worker-src *; script-src 'self' 'unsafe-inline'", "static",
+ ["export-on-load-script.js"],
+ "worker-src * directive should override script-src 'self' directive and " +
+ "allow cross origin static import.");
+
+import_csp_test(
+ "worker-src 'self'; script-src * 'unsafe-inline'", "static",
+ ['ERROR'],
+ "worker-src 'self' directive should override script-src * directive and " +
+ "disallow cross origin static import.");
+
+// Tests for dynamic import.
+//
+// Dynamic import should obey SharedWorker script's CSP instead of parent
+// Window's CSP.
+//
+// Dynamic import should obey the script-src directive instead of the worker-src
+// directive according to the specs:
+//
+// Dynamic import has the "script" destination.
+// Step 3: "Fetch a single module script graph given url, ..., "script", ..."
+// https://html.spec.whatwg.org/multipage/webappapis.html#fetch-an-import()-module-script-graph
+//
+// The "script" destination should obey the script-src CSP directive.
+// "The script-src directive acts as a default fallback for all script-like
+// destinations (including worker-specific destinations if worker-src is not
+// present)."
+// https://w3c.github.io/webappsec-csp/#directive-script-src
+
+import_csp_test(
+ "script-src 'self' 'unsafe-inline'", "dynamic",
+ ['ERROR'],
+ "script-src 'self' directive should disallow cross origin dynamic import.");
+
+import_csp_test(
+ "script-src * 'unsafe-inline'", "dynamic",
+ ["export-on-load-script.js"],
+ "script-src * directive should allow cross origin dynamic import.");
+
+import_csp_test(
+ "worker-src 'self' 'unsafe-inline'", "dynamic",
+ ["export-on-load-script.js"],
+ "worker-src 'self' directive should not take effect on dynamic import.");
+
+</script>
diff --git a/testing/web-platform/tests/workers/modules/shared-worker-import-data-url-cross-origin.html b/testing/web-platform/tests/workers/modules/shared-worker-import-data-url-cross-origin.html
new file mode 100644
index 0000000000..06724a2b9e
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/shared-worker-import-data-url-cross-origin.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<title>SharedWorker: ES modules for data URL workers</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+const import_from_data_url_worker_test = (importType, isDataURL, expectation) => {
+ promise_test(async () => {
+ const importURL = new URL(`resources/${importType}-import-` +
+ `${isDataURL ? 'data-url' : 'script'}-block-cross-origin.js`,
+ location.href) + '?pipe=header(Access-Control-Allow-Origin, *)';
+ const dataURL = `data:text/javascript,import "${importURL}";`;
+ const worker = new SharedWorker(dataURL, { type: 'module' });
+ worker.port.postMessage('Send message for tests from main script.');
+ const msgEvent = await new Promise((resolve, reject) =>{
+ worker.port.onmessage = resolve;
+ worker.onerror = reject;
+ }).catch(e => assert_true(false));
+
+ assert_array_equals(msgEvent.data,
+ expectation === 'blocked' ? ['ERROR']
+ : ['export-block-cross-origin.js']);
+ }, `${importType} import ${isDataURL ? 'data url' : 'script'} from data: ` +
+ `URL should be ${expectation}.`);
+}
+
+// Static import should obey the outside settings.
+// SecurityOrigin of the outside settings is decided by Window.
+import_from_data_url_worker_test('static', true, 'allowed');
+import_from_data_url_worker_test('static', false, 'allowed');
+
+
+// Dynamic import should obey the inside settings.
+// SecurityOrigin of the inside settings is a unique opaque origin.
+//
+// Data url script is cross-origin to the inside settings' SecurityOrigin, but
+// dynamic importing it is allowed.
+// https://fetch.spec.whatwg.org/#concept-main-fetch
+// Step 5: request’s current URL’s scheme is "data" [spec text]
+import_from_data_url_worker_test('dynamic', true, 'allowed');
+
+// Non-data url script is cross-origin to the inside settings' SecurityOrigin.
+// It should be blocked.
+import_from_data_url_worker_test('dynamic', false, 'blocked');
+
+</script>
diff --git a/testing/web-platform/tests/workers/modules/shared-worker-import-data-url.window.js b/testing/web-platform/tests/workers/modules/shared-worker-import-data-url.window.js
new file mode 100644
index 0000000000..5c77f6d936
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/shared-worker-import-data-url.window.js
@@ -0,0 +1,25 @@
+// META: script=/workers/modules/resources/import-test-cases.js
+
+// Imports |testCase.scriptURL| on a shared worker loaded from a data URL,
+// and waits until the list of imported modules is sent from the worker. Passes
+// if the list is equal to |testCase.expectation|.
+function import_data_url_test(testCase) {
+ promise_test(async () => {
+ // The Access-Control-Allow-Origin header is necessary because a worker
+ // loaded from a data URL has a null origin and import() on the worker
+ // without the header is blocked.
+ const importURL = new URL(testCase.scriptURL, location.href) +
+ '?pipe=header(Access-Control-Allow-Origin, *)';
+ const dataURL = `data:text/javascript,import "${importURL}";`;
+
+ const worker = new SharedWorker(dataURL, { type: 'module'});
+ worker.port.postMessage('Send message for tests from main script.');
+ const msgEvent = await new Promise((resolve, reject) =>{
+ worker.port.onmessage = resolve;
+ worker.onerror = reject;
+ }).catch(e => assert_true(false));
+ assert_array_equals(msgEvent.data, testCase.expectation);
+ }, testCase.description);
+}
+
+testCases.forEach(import_data_url_test);
diff --git a/testing/web-platform/tests/workers/modules/shared-worker-import-failure.html b/testing/web-platform/tests/workers/modules/shared-worker-import-failure.html
new file mode 100644
index 0000000000..c9d166c4fe
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/shared-worker-import-failure.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<title>SharedWorker: import failure</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script> setup({allow_uncaught_exception: true}); </script>
+<script>
+
+// TODO: Factor out the test cases into a separate file.
+// (like import-test-cases.js)
+
+// SharedWorkers doesn't fire error events when runtime script errors occur.
+//
+// "For shared workers, if the error is still not handled afterwards, the error
+// may be reported to a developer console." [spec text]
+// https://html.spec.whatwg.org/C/#runtime-script-errors-2
+
+promise_test(async () => {
+ const scriptURL = 'resources/import-scripts-worker.js';
+ const worker = new SharedWorker(scriptURL, { type: 'module' });
+ const msg_event =
+ await new Promise(resolve => worker.port.onmessage = resolve);
+ assert_equals(msg_event.data, 'TypeError');
+}, 'importScripts() on module worker should throw an exception.');
+
+promise_test(() => {
+ const scriptURL = 'resources/non-existent-worker.js';
+ const worker = new SharedWorker(scriptURL, { type: 'module' });
+ return new Promise(resolve => worker.onerror = resolve);
+}, 'Worker construction for non-existent script should dispatch an ' +
+ 'ErrorEvent.');
+
+promise_test(() => {
+ const scriptURL = 'resources/static-import-non-existent-script-worker.js';
+ const worker = new SharedWorker(scriptURL, { type: 'module' });
+ return new Promise(resolve => worker.onerror = resolve);
+}, 'Static import for non-existent script should dispatch an ErrorEvent.');
+
+promise_test(async () => {
+ const scriptURL = './non-existent-worker.js';
+ const worker =
+ new SharedWorker('resources/dynamic-import-given-url-worker.js',
+ { type: 'module' });
+ worker.port.postMessage(scriptURL);
+ const msg_event = await new Promise((resolve, reject) => {
+ worker.port.onmessage = resolve;
+ worker.onerror = error => {
+ const msg = error instanceof ErrorEvent ? error.message
+ : 'unknown error';
+ reject(msg);
+ };
+ });
+ assert_equals(msg_event.data, 'TypeError');
+}, 'Dynamic import for non-existent script should throw an exception.');
+
+test(() => {
+ const scriptURL = 'http://invalid:123$';
+ assert_throws_dom('SyntaxError',
+ () => new SharedWorker(scriptURL, { type: 'module' }));
+}, 'SharedWorker construction for an invalid URL should throw an exception.');
+
+async_test((t) => {
+ const scriptURL = 'file:///static-import-worker.js';
+ const worker = new SharedWorker(scriptURL, { type: 'module' });
+ worker.onerror = t.step_func_done(function(e) {
+ assert_true(e instanceof Event);
+ });
+
+}, 'SharedWorker construction for a file URL should throw an exception.');
+
+</script>
diff --git a/testing/web-platform/tests/workers/modules/shared-worker-import-meta.html b/testing/web-platform/tests/workers/modules/shared-worker-import-meta.html
new file mode 100644
index 0000000000..e8e9b51f6a
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/shared-worker-import-meta.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<title>SharedWorker: import.meta</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+promise_test(() => {
+ const script_url = 'resources/import-meta-url-worker.js';
+ const worker = new SharedWorker(script_url, { type: 'module' });
+ return new Promise((resolve, reject) => {
+ worker.port.onmessage = resolve;
+ worker.onerror = (error) => reject(error && error.message);
+ })
+ .then(msg_event => assert_true(msg_event.data.endsWith(script_url)));
+}, 'Test import.meta.url on the top-level module script.');
+
+promise_test(() => {
+ const script_url = 'import-meta-url-export.js';
+ const worker = new SharedWorker(
+ 'resources/dynamic-import-given-url-worker.js',
+ { type: 'module' });
+ worker.port.postMessage('./' + script_url);
+ return new Promise((resolve, reject) => {
+ worker.port.onmessage = resolve;
+ worker.onerror = (error) => reject(error && error.message);
+ })
+ .then(msg_event => assert_true(msg_event.data.endsWith(script_url)));
+}, 'Test import.meta.url on the imported module script.');
+
+promise_test(() => {
+ const script_url = 'import-meta-url-export.js';
+ const worker = new SharedWorker(
+ 'resources/dynamic-import-given-url-worker.js',
+ { type: 'module' });
+ worker.port.postMessage('./' + script_url);
+
+ return new Promise((resolve, reject) => {
+ worker.port.onmessage = resolve;
+ worker.onerror = (error) => reject(error && error.message);
+ })
+ .then(msg_event => assert_true(msg_event.data.endsWith(script_url)))
+ .then(() => {
+ worker.port.postMessage('./' + script_url + '#1');
+ return new Promise(resolve => worker.port.onmessage = resolve);
+ })
+ .then(msg_event => assert_true(msg_event.data.endsWith(script_url + "#1")));
+}, 'Test import.meta.url on the imported module script with a fragment.');
+
+</script>
diff --git a/testing/web-platform/tests/workers/modules/shared-worker-import-referrer.html b/testing/web-platform/tests/workers/modules/shared-worker-import-referrer.html
new file mode 100644
index 0000000000..1096fd2ad8
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/shared-worker-import-referrer.html
@@ -0,0 +1,259 @@
+<!DOCTYPE html>
+<title>SharedWorker: Referrer</title>
+<meta name="timeout" content="long" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+// This Set is for checking a shared worker in each test is newly created.
+const existingWorkers = new Set();
+
+async function openWindow(url) {
+ const win = window.open(url, '_blank');
+ add_result_callback(() => win.close());
+ const msg_event = await new Promise(resolve => window.onmessage = resolve);
+ assert_equals(msg_event.data, 'LOADED');
+ return win;
+}
+
+// Removes URL parameters from the given URL string and returns it.
+function removeParams(url_string) {
+ if (!url_string)
+ return url_string;
+ let url = new URL(url_string);
+ for (var key of url.searchParams.keys())
+ url.searchParams.delete(key);
+ return url.href;
+}
+
+// Generates a referrer given a fetchType, referrer policy, and a request URL
+// (used to determine whether request is remote-origin or not). This function
+// is used to generate expected referrers.
+function generateExpectedReferrer(referrerURL, referrerPolicy, requestURL) {
+ let generatedReferrer = "";
+ if (referrerPolicy === 'no-referrer')
+ generatedReferrer = "";
+ else if (referrerPolicy === 'origin')
+ generatedReferrer = new URL('resources/' + referrerURL, location.href).origin + '/';
+ else if (referrerPolicy === 'same-origin')
+ generatedReferrer = requestURL.includes('remote') ? "" : new URL('resources/' + referrerURL, location.href).href;
+ else
+ generatedReferrer = new URL('resources/' + referrerURL, location.href).href;
+
+ return generatedReferrer;
+}
+
+// Runs a referrer policy test with the given settings. This opens a new window
+// that starts a shared worker.
+//
+// |settings| has options as follows:
+//
+// settings = {
+// scriptURL: 'resources/referrer-checker.sub.js',
+// windowReferrerPolicy: 'no-referrer',
+// workerReferrerPolicy: 'same-origin',
+// fetchType: 'top-level' or 'descendant-static' or 'descendant-dynamic'
+// };
+//
+// - |scriptURL| is used for starting a new worker.
+// - |windowReferrerPolicy| is to set the ReferrerPolicy HTTP header of the
+// window. This policy should be applied to top-level worker module script
+// loading and static imports.
+// - |workerReferrerPolicy| is to set the ReferrerPolicy HTTP header of the
+// worker. This policy should be applied to dynamic imports.
+// - |fetchType| indicates a script whose referrer will be tested.
+function import_referrer_test(settings, description) {
+ promise_test(async () => {
+ let windowURL = 'resources/new-shared-worker-window.html';
+ if (settings.windowReferrerPolicy) {
+ windowURL +=
+ `?pipe=header(Referrer-Policy, ${settings.windowReferrerPolicy})`;
+ }
+
+ let scriptURL = settings.scriptURL;
+ if (settings.workerReferrerPolicy) {
+ // 'sub' is necessary even if the |scriptURL| contains the '.sub'
+ // extension because the extension doesn't work with the 'pipe' parameter.
+ // See an issue on the WPT's repository:
+ // https://github.com/web-platform-tests/wpt/issues/9345
+ scriptURL +=
+ `?pipe=sub|header(Referrer-Policy, ${settings.workerReferrerPolicy})`;
+ }
+
+ const win = await openWindow(windowURL);
+ // Construct a unique name for SharedWorker.
+ const name = `${settings.scriptURL}_` +
+ `${settings.windowReferrerPolicy ? settings.windowReferrerPolicy
+ : settings.workerReferrerPolicy}` +
+ `_${settings.fetchType}`;
+ const workerProperties = { scriptURL, name };
+ // Check if this shared worker is newly created.
+ assert_false(existingWorkers.has(workerProperties));
+ existingWorkers.add(workerProperties);
+
+ win.postMessage(workerProperties, '*');
+ const msgEvent = await new Promise(resolve => window.onmessage = resolve);
+
+ // Generate the expected referrer, given:
+ // - The fetchType of the test
+ // - Referrer URL to be used
+ // - Relevant referrer policy
+ // - Request URL
+ let expectedReferrer;
+ if (settings.fetchType === 'top-level') {
+ // Top-level worker requests have their outgoing referrers set given their
+ // containing window's URL and referrer policy.
+ expectedReferrer = generateExpectedReferrer('new-shared-worker-window.html', settings.windowReferrerPolicy, settings.scriptURL);
+ } else if (settings.fetchType === 'descendant-static') {
+ // Static descendant script requests from a worker have their outgoing
+ // referrer set given their containing script's URL and containing
+ // window's referrer policy.
+
+ // In the below cases, the referrer URL and the request URLs are the same
+ // because the initial request (for the top-level worker script) should
+ // act as the referrer for future descendant requests.
+ expectedReferrer = generateExpectedReferrer(settings.scriptURL, settings.windowReferrerPolicy, settings.scriptURL);
+ } else if (settings.fetchType === 'descendant-dynamic') {
+ // Dynamic descendant script requests from a worker have their outgoing
+ // referrer set given their containing script's URL and referrer policy.
+ expectedReferrer = generateExpectedReferrer(settings.scriptURL, settings.workerReferrerPolicy, settings.scriptURL);
+ }
+
+ // Delete query parameters from the actual referrer to make it easy to match
+ // it with the expected referrer.
+ const actualReferrer = removeParams(msgEvent.data);
+
+ assert_equals(actualReferrer, expectedReferrer);
+ }, description);
+}
+
+// Tests for top-level worker module script loading.
+//
+// Top-level worker module scripts should inherit the containing window's
+// referrer policy when using the containing window's URL as the referrer.
+//
+// [Current document]
+// --(open)--> [Window] whose referrer policy is |windowReferrerPolicy|.
+// --(new SharedWorker)--> [SharedWorker] should respect [windowReferrerPolicy|
+// when using [Window]'s URL as the referrer.
+
+import_referrer_test(
+ { scriptURL: 'postmessage-referrer-checker.py',
+ windowReferrerPolicy: 'no-referrer',
+ fetchType: 'top-level' },
+ 'Same-origin top-level module script loading with "no-referrer" referrer ' +
+ 'policy');
+
+import_referrer_test(
+ { scriptURL: 'postmessage-referrer-checker.py',
+ windowReferrerPolicy: 'origin',
+ fetchType: 'top-level' },
+ 'Same-origin top-level module script loading with "origin" referrer ' +
+ 'policy');
+
+import_referrer_test(
+ { scriptURL: 'postmessage-referrer-checker.py',
+ windowReferrerPolicy: 'same-origin',
+ fetchType: 'top-level' },
+ 'Same-origin top-level module script loading with "same-origin" referrer ' +
+ 'policy');
+
+// Tests for static imports.
+//
+// Static imports should inherit the containing window's referrer policy when
+// using the containing module script's URL as the referrer.
+// Note: This is subject to change in the future; see
+// https://github.com/w3c/webappsec-referrer-policy/issues/111.
+//
+// [Current document]
+// --(open)--> [Window] whose referrer policy is |windowReferrerPolicy|.
+// --(new SharedWorker)--> [SharedWorker]
+// --(static import)--> [Script] should respect |windowReferrerPolicy| when
+// using [SharedWorker]'s URL as the referrer.
+
+import_referrer_test(
+ { scriptURL: 'static-import-same-origin-referrer-checker-worker.js',
+ windowReferrerPolicy: 'no-referrer',
+ fetchType: 'descendant-static' },
+ 'Same-origin static import with "no-referrer" referrer policy.');
+
+import_referrer_test(
+ { scriptURL: 'static-import-same-origin-referrer-checker-worker.js',
+ windowReferrerPolicy: 'origin',
+ fetchType: 'descendant-static' },
+ 'Same-origin static import with "origin" referrer policy.');
+
+import_referrer_test(
+ { scriptURL: 'static-import-same-origin-referrer-checker-worker.js',
+ windowReferrerPolicy: 'same-origin',
+ fetchType: 'descendant-static' },
+ 'Same-origin static import with "same-origin" referrer policy.');
+
+import_referrer_test(
+ { scriptURL: 'static-import-remote-origin-referrer-checker-worker.sub.js',
+ windowReferrerPolicy: 'no-referrer',
+ fetchType: 'descendant-static' },
+ 'Cross-origin static import with "no-referrer" referrer policy.');
+
+import_referrer_test(
+ { scriptURL: 'static-import-remote-origin-referrer-checker-worker.sub.js',
+ windowReferrerPolicy: 'origin',
+ fetchType: 'descendant-static' },
+ 'Cross-origin static import with "origin" referrer policy.');
+
+import_referrer_test(
+ { scriptURL: 'static-import-remote-origin-referrer-checker-worker.sub.js',
+ windowReferrerPolicy: 'same-origin',
+ fetchType: 'descendant-static' },
+ 'Cross-origin static import with "same-origin" referrer policy.');
+
+// Tests for dynamic imports.
+//
+// Dynamic imports should inherit the containing script's referrer policy if
+// set, and use the default referrer policy otherwise, when using the
+// containing script's URL as the referrer.
+//
+// [Current document]
+// --(open)--> [Window]
+// --(new SharedWorker)--> [SharedWorker] whose referrer policy is
+// |workerReferrerPolicy|.
+// --(dynamic import)--> [Script] should respect |workerReferrerPolicy| when
+// using [SharedWorker]'s URL as the referrer.
+
+import_referrer_test(
+ { scriptURL: 'dynamic-import-same-origin-referrer-checker-worker.js',
+ workerReferrerPolicy: 'no-referrer',
+ fetchType: 'descendant-dynamic' },
+ 'Same-origin dynamic import with "no-referrer" referrer policy.');
+
+import_referrer_test(
+ { scriptURL: 'dynamic-import-same-origin-referrer-checker-worker.js',
+ workerReferrerPolicy: 'origin',
+ fetchType: 'descendant-dynamic' },
+ 'Same-origin dynamic import with "origin" referrer policy.');
+
+import_referrer_test(
+ { scriptURL: 'dynamic-import-same-origin-referrer-checker-worker.js',
+ workerReferrerPolicy: 'same-origin',
+ fetchType: 'descendant-dynamic' },
+ 'Same-origin dynamic import with "same-origin" referrer policy.');
+
+import_referrer_test(
+ { scriptURL: 'dynamic-import-remote-origin-referrer-checker-worker.sub.js',
+ workerReferrerPolicy: 'no-referrer',
+ fetchType: 'descendant-dynamic' },
+ 'Cross-origin dynamic import with "no-referrer" referrer policy.');
+
+import_referrer_test(
+ { scriptURL: 'dynamic-import-remote-origin-referrer-checker-worker.sub.js',
+ workerReferrerPolicy: 'origin',
+ fetchType: 'descendant-dynamic' },
+ 'Cross-origin dynamic import with "origin" referrer policy.');
+
+import_referrer_test(
+ { scriptURL: 'dynamic-import-remote-origin-referrer-checker-worker.sub.js',
+ workerReferrerPolicy: 'same-origin',
+ fetchType: 'descendant-dynamic' },
+ 'Cross-origin dynamic import with "same-origin" referrer policy.');
+
+</script>
diff --git a/testing/web-platform/tests/workers/modules/shared-worker-import.window.js b/testing/web-platform/tests/workers/modules/shared-worker-import.window.js
new file mode 100644
index 0000000000..5be49ec125
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/shared-worker-import.window.js
@@ -0,0 +1,22 @@
+// META: script=/workers/modules/resources/import-test-cases.js
+
+// Starts a shared worker for |testCase.scriptURL| and waits until the list
+// of imported modules is sent from the worker. Passes if the list is equal to
+// |testCase.expectation|.
+function import_test(testCase) {
+ promise_test(async () => {
+ const worker = new SharedWorker(testCase.scriptURL, {type: 'module'});
+ worker.port.postMessage('Send message for tests from main script.');
+ const msgEvent = await new Promise((resolve, reject) => {
+ worker.port.onmessage = resolve;
+ worker.onerror = error => {
+ const msg = error instanceof ErrorEvent ? error.message
+ : 'unknown error';
+ reject(msg);
+ };
+ });
+ assert_array_equals(msgEvent.data, testCase.expectation);
+ }, testCase.description);
+}
+
+testCases.forEach(import_test);
diff --git a/testing/web-platform/tests/workers/modules/shared-worker-options-credentials.html b/testing/web-platform/tests/workers/modules/shared-worker-options-credentials.html
new file mode 100644
index 0000000000..221dd01a37
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/shared-worker-options-credentials.html
@@ -0,0 +1,309 @@
+<!DOCTYPE html>
+<title>SharedWorker: WorkerOptions 'credentials'</title>
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script>
+host_info = get_host_info();
+
+// Determines the expected cookie value to be reported by a shared worker
+// based on the given option. The worker reports an empty string as the actual
+// cookie value if the cookie wasn't sent to the server. Otherwise, it's the
+// value set by the headers file:
+// "shared-worker-options-credentials.html.headers"
+function DetermineExpectedCookieValue(options, config) {
+ // Valid WorkerOptions and test config checking.
+ if (config.origin !== 'same' && config.origin !== 'remote')
+ assert_unreached('Invalid config.origin was specified: ' + config.origin);
+ if (options.credentials && options.credentials !== 'omit' &&
+ options.credentials !== 'same-origin' &&
+ options.credentials !== 'include') {
+ assert_unreached('Invalid credentials option was specified: ' +
+ options.credentials);
+ }
+ if (options.type !== 'classic' && options.type !== 'module')
+ assert_unreached('Invalid type option was specified: ' + options.type);
+
+ if (options.type === 'classic')
+ return (config.origin === 'same') ? '1' : '';
+
+ if (options.credentials === 'omit')
+ return '';
+ else if (options.credentials === 'include')
+ return '1';
+ else
+ return (config.origin === 'same') ? '1' : '';
+}
+
+// Runs a credentials test with the given WorkerOptions.
+//
+// |options| is a WorkerOptions dict.
+// |config| has options as follows:
+//
+// config = {
+// fetchType: 'top-level' or 'descendant-static' or 'descendant-dynamic'
+// origin: 'remote' or 'same'
+// };
+//
+// - |config.fetchType| indicates the type of script to load for the test.
+// - |config.origin| indicates same-origin-ness of the script to load.
+function credentials_test(options, config, description) {
+ promise_test(async () => {
+ let workerURL, origin = config.origin;
+ if (config.fetchType === 'top-level') {
+ workerURL = 'resources/postmessage-credentials.py';
+ } else if (config.fetchType === 'descendant-static') {
+ workerURL =
+ `resources/static-import-${origin}-origin-credentials-checker-worker.${origin === 'same' ? '' : 'sub.'}js`;
+ } else if (config.fetchType === 'descendant-dynamic') {
+ workerURL =
+ `resources/dynamic-import-${origin}-origin-credentials-checker-worker.${origin === 'same' ? '' : 'sub.'}js`;
+ } else {
+ assert_unreached('Invalid config.fetchType: ' + config.fetchType);
+ }
+
+ // Name idetically for each test cases so that it connects to the shared
+ // worker with specified type and credentials.
+ options.name = `${options.type}_${options.credentials || 'default'}_${config.fetchType}_${config.origin}`;
+
+ const worker = new SharedWorker(workerURL, options);
+
+ // Wait until the worker sends the actual cookie value.
+ const msg_event = await new Promise(resolve => worker.port.onmessage = resolve);
+
+ const expectedCookieValue = DetermineExpectedCookieValue(options, config);
+ assert_equals(msg_event.data, expectedCookieValue);
+ }, description);
+}
+
+function init() {
+ // Same-origin cookie is set up in the .headers file in this directory.
+ promise_test(async () => {
+ return fetch(
+ `${host_info.HTTP_REMOTE_ORIGIN}/cookies/resources/set-cookie.py?name=COOKIE_NAME&path=/workers/modules/`,
+ {
+ mode: 'no-cors',
+ credentials: 'include'
+ });
+ }, 'Test initialization: setting up cross-origin cookie');
+}
+
+init();
+
+// Tests for module workers.
+
+credentials_test(
+ { type: 'module' },
+ { fetchType: 'top-level', origin: 'same' },
+ 'new SharedWorker() with type=module and default credentials option ' +
+ 'should behave as credentials=same-origin and send the credentials');
+
+credentials_test(
+ { credentials: 'omit', type: 'module' },
+ { fetchType: 'top-level', origin: 'same' },
+ 'new SharedWorker() with type=module and credentials=omit should not ' +
+ 'send the credentials');
+
+credentials_test(
+ { credentials: 'same-origin', type: 'module' },
+ { fetchType: 'top-level', origin: 'same' },
+ 'new SharedWorker() with type=module and credentials=same-origin should ' +
+ 'send the credentials');
+
+credentials_test(
+ { credentials: 'include', type: 'module' },
+ { fetchType: 'top-level', origin: 'same' },
+ 'new SharedWorker() with type=module and credentials=include should send ' +
+ 'the credentials');
+
+// Tests for module worker static imports.
+
+credentials_test(
+ { type: 'module' },
+ { fetchType: 'descendant-static', origin: 'same' },
+ 'new SharedWorker() with type=module and default credentials option ' +
+ 'should behave as credentials=same-origin and send the credentials for ' +
+ 'same-origin static imports');
+
+credentials_test(
+ { credentials: 'omit', type: 'module' },
+ { fetchType: 'descendant-static', origin: 'same' },
+ 'new SharedWorker() with type=module and credentials=omit should not ' +
+ 'send the credentials for same-origin static imports');
+
+credentials_test(
+ { credentials: 'same-origin', type: 'module' },
+ { fetchType: 'descendant-static', origin: 'same' },
+ 'new SharedWorker() with type=module and credentials=same-origin should ' +
+ 'send the credentials for same-origin static imports');
+
+credentials_test(
+ { credentials: 'include', type: 'module' },
+ { fetchType: 'descendant-static', origin: 'same' },
+ 'new SharedWorker() with type=module and credentials=include should send ' +
+ 'the credentials for same-origin static imports');
+
+credentials_test(
+ { type: 'module' },
+ { fetchType: 'descendant-static', origin: 'remote' },
+ 'new SharedWorker() with type=module and default credentials option ' +
+ 'should behave as credentials=same-origin and not send the credentials ' +
+ 'for cross-origin static imports');
+
+credentials_test(
+ { credentials: 'omit', type: 'module' },
+ { fetchType: 'descendant-static', origin: 'remote' },
+ 'new SharedWorker() with type=module and credentials=omit should not ' +
+ 'send the credentials for cross-origin static imports');
+
+credentials_test(
+ { credentials: 'same-origin', type: 'module' },
+ { fetchType: 'descendant-static', origin: 'remote' },
+ 'new SharedWorker() with type=module and credentials=same-origin should ' +
+ 'not send the credentials for cross-origin static imports');
+
+credentials_test(
+ { credentials: 'include', type: 'module' },
+ { fetchType: 'descendant-static', origin: 'remote' },
+ 'new SharedWorker() with type=module and credentials=include should send ' +
+ 'the credentials for cross-origin static imports');
+
+// Tests for module worker dynamic imports.
+
+credentials_test(
+ { type: 'module' },
+ { fetchType: 'descendant-dynamic', origin: 'same' },
+ 'new SharedWorker() with type=module and default credentials option ' +
+ 'should behave as credentials=same-origin and send the credentials for ' +
+ 'same-origin dynamic imports');
+
+credentials_test(
+ { credentials: 'omit', type: 'module' },
+ { fetchType: 'descendant-dynamic', origin: 'same' },
+ 'new SharedWorker() with type=module and credentials=omit should not ' +
+ 'send the credentials for same-origin dynamic imports');
+
+credentials_test(
+ { credentials: 'same-origin', type: 'module' },
+ { fetchType: 'descendant-dynamic', origin: 'same' },
+ 'new SharedWorker() with type=module and credentials=same-origin should ' +
+ 'send the credentials for same-origin dynamic imports');
+
+credentials_test(
+ { credentials: 'include', type: 'module' },
+ { fetchType: 'descendant-dynamic', origin: 'same' },
+ 'new SharedWorker() with type=module and credentials=include should send ' +
+ 'the credentials for same-origin dynamic imports');
+
+credentials_test(
+ { type: 'module'},
+ { fetchType: 'descendant-dynamic', origin: 'remote' },
+ 'new SharedWorker() with type=module and default credentials option ' +
+ 'should behave as credentials=same-origin and not send the credentials ' +
+ 'for cross-origin dynamic imports');
+
+credentials_test(
+ { credentials: 'omit', type: 'module' },
+ { fetchType: 'descendant-dynamic', origin: 'remote' },
+ 'new SharedWorker() with type=module and credentials=omit should not ' +
+ 'send the credentials for cross-origin dynamic imports');
+
+credentials_test(
+ { credentials: 'same-origin', type: 'module' },
+ { fetchType: 'descendant-dynamic', origin: 'remote' },
+ 'new SharedWorker() with type=module and credentials=same-origin should ' +
+ 'not send the credentials for cross-origin dynamic imports');
+
+credentials_test(
+ { credentials: 'include', type: 'module' },
+ { fetchType: 'descendant-dynamic', origin: 'remote' },
+ 'new SharedWorker() with type=module and credentials=include should send ' +
+ 'the credentials for cross-origin dynamic imports');
+
+// Tests for classic workers.
+// TODO(domfarolino): Maybe move classic worker tests up a directory?
+
+credentials_test(
+ { type: 'classic' },
+ { fetchType: 'top-level', origin: 'same' },
+ 'new SharedWorker() with type=classic should always send the credentials ' +
+ 'regardless of the credentials option (default).');
+
+credentials_test(
+ { credentials: 'omit', type: 'classic' },
+ { fetchType: 'top-level', origin: 'same' },
+ 'new SharedWorker() with type=classic should always send the credentials ' +
+ 'regardless of the credentials option (omit).');
+
+credentials_test(
+ { credentials: 'same-origin', type: 'classic' },
+ { fetchType: 'top-level', origin: 'same' },
+ 'new SharedWorker() with type=classic should always send the credentials ' +
+ 'regardless of the credentials option (same-origin).');
+
+credentials_test(
+ { credentials: 'include', type: 'classic' },
+ { fetchType: 'top-level', origin: 'same' },
+ 'new SharedWorker() with type=classic should always send the credentials ' +
+ 'regardless of the credentials option (include).');
+
+// Tests for classic worker dynamic imports.
+
+credentials_test(
+ { type: 'classic' },
+ { fetchType: 'descendant-dynamic', origin: 'same' },
+ 'new SharedWorker() with type=classic should always send the credentials ' +
+ 'for same-origin dynamic imports regardless of the credentials option ' +
+ '(default).');
+
+credentials_test(
+ { credentials: 'omit', type: 'classic' },
+ { fetchType: 'descendant-dynamic', origin: 'same' },
+ 'new SharedWorker() with type=classic should always send the credentials ' +
+ 'for same-origin dynamic imports regardless of the credentials option ' +
+ '(omit).');
+
+credentials_test(
+ { credentials: 'same-origin', type: 'classic' },
+ { fetchType: 'descendant-dynamic', origin: 'same' },
+ 'new SharedWorker() with type=classic should always send the credentials ' +
+ 'for same-origin dynamic imports regardless of the credentials option ' +
+ '(same-origin).');
+
+credentials_test(
+ { credentials: 'include', type: 'classic' },
+ { fetchType: 'descendant-dynamic', origin: 'same' },
+ 'new SharedWorker() with type=classic should always send the credentials ' +
+ 'for same-origin dynamic imports regardless of the credentials option ' +
+ '(include).');
+
+credentials_test(
+ { type: 'classic' },
+ { fetchType: 'descendant-dynamic', origin: 'remote' },
+ 'new SharedWorker() with type=classic should never send the credentials ' +
+ 'for cross-origin dynamic imports regardless of the credentials option ' +
+ '(default).');
+
+credentials_test(
+ { credentials: 'omit', type: 'classic' },
+ { fetchType: 'descendant-dynamic', origin: 'remote' },
+ 'new SharedWorker() with type=classic should never send the credentials ' +
+ 'for cross-origin dynamic imports regardless of the credentials option ' +
+ '(omit).');
+
+credentials_test(
+ { credentials: 'same-origin', type: 'classic' },
+ { fetchType: 'descendant-dynamic', origin: 'remote' },
+ 'new SharedWorker() with type=classic should never send the credentials ' +
+ 'for cross-origin dynamic imports regardless of the credentials option ' +
+ '(same-origin).');
+
+credentials_test(
+ { credentials: 'include', type: 'classic' },
+ { fetchType: 'descendant-dynamic', origin: 'remote' },
+ 'new SharedWorker() with type=classic should never send the credentials ' +
+ 'for cross-origin dynamic imports regardless of the credentials option ' +
+ '(include).');
+
+</script>
diff --git a/testing/web-platform/tests/workers/modules/shared-worker-options-credentials.html.headers b/testing/web-platform/tests/workers/modules/shared-worker-options-credentials.html.headers
new file mode 100644
index 0000000000..8da851ab73
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/shared-worker-options-credentials.html.headers
@@ -0,0 +1,2 @@
+Set-Cookie: COOKIE_NAME=1
+Access-Control-Allow-Credentials: true
diff --git a/testing/web-platform/tests/workers/modules/shared-worker-options-type.html b/testing/web-platform/tests/workers/modules/shared-worker-options-type.html
new file mode 100644
index 0000000000..f62eeeb76b
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/shared-worker-options-type.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<title>SharedWorker: WorkerOptions 'type'</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+promise_test(() => {
+ const worker = new SharedWorker('resources/post-message-on-load-worker.js',
+ 'default');
+ return new Promise(resolve => worker.port.onmessage = resolve)
+ .then(msg_event => assert_equals(msg_event.data, 'LOADED'));
+}, 'Test worker construction with the default worker type.');
+
+promise_test(() => {
+ const worker = new SharedWorker('resources/post-message-on-load-worker.js',
+ { name: 'classic', type: 'classic' });
+ return new Promise(resolve => worker.port.onmessage = resolve)
+ .then(msg_event => assert_equals(msg_event.data, 'LOADED'));
+}, 'Test worker construction with the "classic" worker type.');
+
+promise_test(() => {
+ const worker = new SharedWorker('resources/post-message-on-load-worker.js',
+ { name: 'module', type: 'module' });
+ return new Promise(resolve => worker.port.onmessage = resolve)
+ .then(msg_event => assert_equals(msg_event.data, 'LOADED'));
+}, 'Test worker construction with the "module" worker type.');
+
+test(() => {
+ assert_throws_js(
+ TypeError,
+ () => {
+ new SharedWorker('resources/post-message-on-load-worker.js',
+ { name: 'blank', type : '' });
+ },
+ 'Worker construction with an empty type should throw an exception');
+}, 'Test worker construction with an empty worker type.');
+
+test(() => {
+ assert_throws_js(
+ TypeError,
+ () => {
+ new SharedWorker('resources/post-message-on-load-worker.js',
+ { name: 'unknown', type : 'unknown' });
+ },
+ 'Worker construction with an unknown type should throw an exception');
+}, 'Test worker construction with an unknown worker type.');
+
+</script>
diff --git a/testing/web-platform/tests/workers/modules/shared-worker-parse-error-failure.html b/testing/web-platform/tests/workers/modules/shared-worker-parse-error-failure.html
new file mode 100644
index 0000000000..f197d81e36
--- /dev/null
+++ b/testing/web-platform/tests/workers/modules/shared-worker-parse-error-failure.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<title>SharedWorker: parse error failure</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../support/check-error-arguments.js"></script>
+<script>
+
+// Use a unique URL fragment to prevent potential interference from other tests
+// which might use the same SharedWorker URL.
+const uniqueFragment = '#shared-worker-parse-error-failure';
+
+// Check if module shared worker is supported.
+// In this test scope, we only use simple non-nested static import as a feature
+// of module shared worker, so we only check if static import is supported.
+//
+// This check is necessary to appropriately test parse error handling because
+// we need to distingusih the parse error invoked by unsupported "import" in
+// the top-level script from the parse error invoked by the statically imported
+// script which is the one we want to check in this test.
+promise_setup(async () => {
+ const scriptURL = 'resources/static-import-worker.js' + uniqueFragment;
+ const worker = new SharedWorker(scriptURL, { type: 'module' });
+ const supportsModuleWorkers = await new Promise((resolve, reject) => {
+ worker.port.onmessage = e => {
+ resolve(e.data.length == 1 && e.data[0] == 'export-on-load-script.js');
+ };
+ worker.onerror = () => resolve(false);
+ });
+ assert_implements(
+ supportsModuleWorkers,
+ "Static import must be supported on module shared worker to run this test."
+ );
+});
+
+promise_test(async () => {
+ const scriptURL = 'resources/syntax-error.js' + uniqueFragment;
+ const worker = new SharedWorker(scriptURL, { type: 'module' });
+ const args = await new Promise(resolve =>
+ worker.onerror = (...args) => resolve(args));
+ window.checkErrorArguments(args);
+}, 'Module shared worker construction for script with syntax error should ' +
+ 'dispatch an event named error.');
+
+promise_test(async () => {
+ const scriptURL = 'resources/static-import-syntax-error.js' + uniqueFragment;
+ const worker = new SharedWorker(scriptURL, { type: 'module' });
+ const args = await new Promise(resolve =>
+ worker.onerror = (...args) => resolve(args));
+ window.checkErrorArguments(args);
+}, 'Static import on module shared worker for script with syntax error ' +
+ 'should dispatch an event named error.');
+
+</script>
diff --git a/testing/web-platform/tests/workers/multi-globals/current/current.html b/testing/web-platform/tests/workers/multi-globals/current/current.html
new file mode 100644
index 0000000000..e6261f8388
--- /dev/null
+++ b/testing/web-platform/tests/workers/multi-globals/current/current.html
@@ -0,0 +1,3 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Current page</title>
diff --git a/testing/web-platform/tests/workers/multi-globals/current/worker.js b/testing/web-platform/tests/workers/multi-globals/current/worker.js
new file mode 100644
index 0000000000..44103842a4
--- /dev/null
+++ b/testing/web-platform/tests/workers/multi-globals/current/worker.js
@@ -0,0 +1 @@
+postMessage('current');
diff --git a/testing/web-platform/tests/workers/multi-globals/incumbent/incumbent.html b/testing/web-platform/tests/workers/multi-globals/incumbent/incumbent.html
new file mode 100644
index 0000000000..d8bd1ae2c0
--- /dev/null
+++ b/testing/web-platform/tests/workers/multi-globals/incumbent/incumbent.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Incumbent page</title>
+
+<iframe src="../current/current.html" id="c"></iframe>
+
+<script>
+ const current = document.querySelector("#c").contentWindow;
+
+ window.hello = () => {
+ const worker = new current.Worker('worker.js');
+ worker.onmessage = e => { parent.postMessage(e.data, '*'); }
+ };
+</script>
diff --git a/testing/web-platform/tests/workers/multi-globals/incumbent/worker.js b/testing/web-platform/tests/workers/multi-globals/incumbent/worker.js
new file mode 100644
index 0000000000..03f02a8690
--- /dev/null
+++ b/testing/web-platform/tests/workers/multi-globals/incumbent/worker.js
@@ -0,0 +1 @@
+postMessage('incumbent');
diff --git a/testing/web-platform/tests/workers/multi-globals/url-parsing.html b/testing/web-platform/tests/workers/multi-globals/url-parsing.html
new file mode 100644
index 0000000000..27bbc0cb50
--- /dev/null
+++ b/testing/web-platform/tests/workers/multi-globals/url-parsing.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Multiple globals for Worker constructor: parsing scriptURL</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<!-- This is the entry global -->
+
+<iframe src="incumbent/incumbent.html"></iframe>
+
+<script>
+async_test((t) => {
+ onload = t.step_func(() => {
+ frames[0].hello();
+ });
+ onmessage = t.step_func_done(e => {
+ assert_equals(e.data, 'current');
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/multi-globals/worker.js b/testing/web-platform/tests/workers/multi-globals/worker.js
new file mode 100644
index 0000000000..fcc521e313
--- /dev/null
+++ b/testing/web-platform/tests/workers/multi-globals/worker.js
@@ -0,0 +1 @@
+postMessage('entry');
diff --git a/testing/web-platform/tests/workers/name-property.html b/testing/web-platform/tests/workers/name-property.html
new file mode 100644
index 0000000000..ccc2a9de3a
--- /dev/null
+++ b/testing/web-platform/tests/workers/name-property.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test the name property of shared and dedicated workers via the name constructor option</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#concept-workerglobalscope-name">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-sharedworkerglobalscope-name">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-dedicatedworkerglobalscope-name">
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+"use strict";
+setup({explicit_done: true});
+
+(async function() {
+ const worker = new Worker("support/name.js", { name: "my name" });
+ await fetch_tests_from_worker(worker);
+
+ const worker2 = new Worker("support/name-as-accidental-global.js");
+ await fetch_tests_from_worker(worker2);
+
+ const sharedWorker = new SharedWorker("support/name.js", { name: "my name" });
+ await fetch_tests_from_worker(sharedWorker);
+
+ const sharedWorker2 = new SharedWorker("support/name-as-accidental-global.js");
+ await fetch_tests_from_worker(sharedWorker2);
+
+ done();
+})();
+</script>
diff --git a/testing/web-platform/tests/workers/nested_worker.worker.js b/testing/web-platform/tests/workers/nested_worker.worker.js
new file mode 100644
index 0000000000..005b3c2f30
--- /dev/null
+++ b/testing/web-platform/tests/workers/nested_worker.worker.js
@@ -0,0 +1,11 @@
+importScripts("/resources/testharness.js");
+
+async_test(function() {
+ var worker1 = new Worker("support/WorkerBasic.js");
+ worker1.postMessage("ping");
+ worker1.onmessage = this.step_func_done(function(evt) {
+ assert_equals(evt.data, "Pass");
+ worker1.terminate();
+ });
+}, "Nested worker");
+done();
diff --git a/testing/web-platform/tests/workers/nested_worker_close_from_parent_worker.html b/testing/web-platform/tests/workers/nested_worker_close_from_parent_worker.html
new file mode 100644
index 0000000000..57c98517cb
--- /dev/null
+++ b/testing/web-platform/tests/workers/nested_worker_close_from_parent_worker.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test terminating a nested workers by calling terminate() from its parent worker</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(function() {
+ const worker = new Worker("support/parent_of_nested_worker.js");
+ worker.onmessage = this.step_func_done(function(e) {
+ assert_equals(e.data, "Pass");
+ done();
+ });
+ worker.postMessage("close");
+});
+</script>
diff --git a/testing/web-platform/tests/workers/nested_worker_close_self.worker.js b/testing/web-platform/tests/workers/nested_worker_close_self.worker.js
new file mode 100644
index 0000000000..73c87f4055
--- /dev/null
+++ b/testing/web-platform/tests/workers/nested_worker_close_self.worker.js
@@ -0,0 +1,12 @@
+importScripts("/resources/testharness.js");
+
+async_test(function() {
+ if (!self.Worker)
+ done();
+ const worker = new Worker("support/WorkerClose.js");
+ worker.onmessage = this.step_func_done(function(e) {
+ assert_equals(e.data, "close");
+ done();
+ });
+ worker.postMessage("close");
+}, "Nested work that closes itself");
diff --git a/testing/web-platform/tests/workers/nested_worker_importScripts.worker.js b/testing/web-platform/tests/workers/nested_worker_importScripts.worker.js
new file mode 100644
index 0000000000..a671ee4e1e
--- /dev/null
+++ b/testing/web-platform/tests/workers/nested_worker_importScripts.worker.js
@@ -0,0 +1,11 @@
+importScripts("/resources/testharness.js");
+
+async_test(function() {
+ const worker = new Worker("support/ImportScripts.js");
+ worker.postMessage("ping");
+ worker.onmessage = this.step_func_done(function(evt) {
+ assert_equals(evt.data, "Pass");
+ worker.terminate();
+ });
+}, "Nested worker that calls importScripts()");
+done();
diff --git a/testing/web-platform/tests/workers/nested_worker_sync_xhr.worker.js b/testing/web-platform/tests/workers/nested_worker_sync_xhr.worker.js
new file mode 100644
index 0000000000..609ecc49e1
--- /dev/null
+++ b/testing/web-platform/tests/workers/nested_worker_sync_xhr.worker.js
@@ -0,0 +1,11 @@
+importScripts("/resources/testharness.js");
+
+async_test(function() {
+ const worker = new Worker("support/sync_xhr.js");
+ worker.postMessage("ping");
+ worker.onmessage = this.step_func_done(function(evt) {
+ assert_equals(evt.data, "Pass");
+ worker.terminate();
+ });
+}, "Nested worker that issues a sync XHR");
+done();
diff --git a/testing/web-platform/tests/workers/nested_worker_terminate_from_document.html b/testing/web-platform/tests/workers/nested_worker_terminate_from_document.html
new file mode 100644
index 0000000000..10849b3f6c
--- /dev/null
+++ b/testing/web-platform/tests/workers/nested_worker_terminate_from_document.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test terminating a chain of nested workers by calling terminate() from the owning document</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(function() {
+ const worker = new Worker("support/parent_of_nested_worker.js");
+ worker.onmessage = this.step_func_done(function(e) {
+ assert_equals(e.data, "Pass");
+ worker.terminate();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/non-automated/infinite-nested.html b/testing/web-platform/tests/workers/non-automated/infinite-nested.html
new file mode 100644
index 0000000000..3ff3edb353
--- /dev/null
+++ b/testing/web-platform/tests/workers/non-automated/infinite-nested.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>infinite nested workers</title>
+<p>There number below should be increasing (ideally never-ending).</p>
+<div>0</div>
+<script>
+var worker = new Worker('infinite-nested.js');
+var div = document.getElementsByTagName('div')[0];
+var i = 0;
+worker.onmessage = function(e) {
+ div.textContent = i++;
+}
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/non-automated/infinite-nested.js b/testing/web-platform/tests/workers/non-automated/infinite-nested.js
new file mode 100644
index 0000000000..137dd0a2e2
--- /dev/null
+++ b/testing/web-platform/tests/workers/non-automated/infinite-nested.js
@@ -0,0 +1,5 @@
+postMessage(1);
+var w = new Worker('infinite-nested.js');
+w.onmessage = function(e) {
+ postMessage(e.data);
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/non-automated/infinite-sibling-and-nested.html b/testing/web-platform/tests/workers/non-automated/infinite-sibling-and-nested.html
new file mode 100644
index 0000000000..463546cc96
--- /dev/null
+++ b/testing/web-platform/tests/workers/non-automated/infinite-sibling-and-nested.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>infinite sibling and nested workers</title>
+<p>The number below should be increasing (ideally never-ending).</p>
+<div>0</div>
+<script>
+var worker = new Worker('infinite-sibling-and-nested.js');
+var div = document.getElementsByTagName('div')[0];
+var i = 0;
+worker.onmessage = function(e) {
+ div.textContent = i + e.data;
+}
+</script>
diff --git a/testing/web-platform/tests/workers/non-automated/infinite-sibling-and-nested.js b/testing/web-platform/tests/workers/non-automated/infinite-sibling-and-nested.js
new file mode 100644
index 0000000000..cf7b794a41
--- /dev/null
+++ b/testing/web-platform/tests/workers/non-automated/infinite-sibling-and-nested.js
@@ -0,0 +1,8 @@
+function createWorker() {
+ var worker = new Worker('infinite-nested.js?' + Math.random());
+ worker.onmessage = function(e) {
+ postMessage(e.data);
+ createWorker();
+ }
+}
+createWorker(); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/non-automated/infinite-sibling.html b/testing/web-platform/tests/workers/non-automated/infinite-sibling.html
new file mode 100644
index 0000000000..edcb8d7072
--- /dev/null
+++ b/testing/web-platform/tests/workers/non-automated/infinite-sibling.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>infinite sibling workers</title>
+<p>The number below should be increasing (ideally never-ending).</p>
+<div>0</div>
+<script>
+var worker = new Worker('infinite-sibling.js');
+var div = document.getElementsByTagName('div')[0];
+var i = 0;
+worker.onmessage = function(e) {
+ div.textContent = i + e.data;
+}
+</script>
diff --git a/testing/web-platform/tests/workers/non-automated/infinite-sibling.js b/testing/web-platform/tests/workers/non-automated/infinite-sibling.js
new file mode 100644
index 0000000000..6424f70093
--- /dev/null
+++ b/testing/web-platform/tests/workers/non-automated/infinite-sibling.js
@@ -0,0 +1,8 @@
+function createWorker() {
+ var worker = new Worker('post-a-1.js?' + Math.random());
+ worker.onmessage = function(e) {
+ postMessage(e.data);
+ createWorker();
+ }
+}
+createWorker(); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/non-automated/navigator-onLine.html b/testing/web-platform/tests/workers/non-automated/navigator-onLine.html
new file mode 100644
index 0000000000..5f2746b546
--- /dev/null
+++ b/testing/web-platform/tests/workers/non-automated/navigator-onLine.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<title>navigator.onLine in dedicated worker</title>
+<pre>Log:
+</pre>
+<script>
+var pre = document.querySelector('pre');
+var worker, shared;
+try { worker = new Worker('navigator-onLine.js'); } catch(e) { pre.textContent += '\nnew Worker threw: ' + e.message; }
+try { shared = new SharedWorker('#', ''); } catch(e) { pre.textContent += '\nnew SharedWorker threw: ' + e.message; }
+if (worker) {
+ worker.onmessage = function(e) {
+ pre.textContent += '\ndedicated worker: ' + e.data;
+ }
+}
+if (shared) {
+ shared.port.onmessage = function(e) {
+ pre.textContent += '\nshared worker: ' + e.data;
+ }
+}
+function update() {
+ pre.textContent += '\n\n' + new Date() + '\n<script>: ' + navigator.onLine;
+ if (worker) worker.postMessage(1);
+ if (shared) shared.port.postMessage(1);
+}
+update();
+ononline = onoffline = update;
+</script>
+<p>As you go online and offline, the log should be filled with the correct status of navigator.onLine.</p>
+<p><button onclick="update()">Check navigator.onLine status</button></p> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/non-automated/navigator-onLine.js b/testing/web-platform/tests/workers/non-automated/navigator-onLine.js
new file mode 100644
index 0000000000..592b286bb3
--- /dev/null
+++ b/testing/web-platform/tests/workers/non-automated/navigator-onLine.js
@@ -0,0 +1,11 @@
+if ('onmessage' in self) { // dedicated worker
+ onmessage = function(e) {
+ postMessage(navigator.onLine);
+ }
+} else { // shared worker
+ onconnect = function(e) {
+ e.ports[0].onmessage = function(e) {
+ this.postMessage(navigator.onLine);
+ }
+ }
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/non-automated/post-a-1.js b/testing/web-platform/tests/workers/non-automated/post-a-1.js
new file mode 100644
index 0000000000..2318c2e267
--- /dev/null
+++ b/testing/web-platform/tests/workers/non-automated/post-a-1.js
@@ -0,0 +1 @@
+postMessage(1); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/opaque-origin.html b/testing/web-platform/tests/workers/opaque-origin.html
new file mode 100644
index 0000000000..83574b456f
--- /dev/null
+++ b/testing/web-platform/tests/workers/opaque-origin.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+// Sandboxed iframe forwards messages from its worker, this translates those
+// messages back to something fetch_tests_from_worker can parse.
+const channel = new MessageChannel();
+onmessage = e => {
+ channel.port2.postMessage(e.data);
+};
+fetch_tests_from_worker(channel.port1);
+channel.port1.start();
+</script>
+<iframe sandbox="allow-scripts" src="support/sandboxed-tests.html?pipe=sub"></iframe>
+</body>
diff --git a/testing/web-platform/tests/workers/postMessage_DataCloneErr.htm b/testing/web-platform/tests/workers/postMessage_DataCloneErr.htm
new file mode 100644
index 0000000000..24093ce4e3
--- /dev/null
+++ b/testing/web-platform/tests/workers/postMessage_DataCloneErr.htm
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title> postMessage() with WorkerNavigator </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var worker = new Worker("./support/WorkerDataCloneErr.js");
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data, "Pass");
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/postMessage_block.https.html b/testing/web-platform/tests/workers/postMessage_block.https.html
new file mode 100644
index 0000000000..c3e69f6193
--- /dev/null
+++ b/testing/web-platform/tests/workers/postMessage_block.https.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+const t = async_test('postMessage and block');
+
+const w = new Worker('support/postMessage_block_worker.js');
+
+w.onmessage = t.step_func_done(() => {
+ const a = new Int32Array(new SharedArrayBuffer(4));
+ w.postMessage(a);
+ while (Atomics.load(a, 0) === 0);
+ assert_equals(Atomics.load(a, 0), 1);
+});
+</script>
+</body>
diff --git a/testing/web-platform/tests/workers/postMessage_block.https.html.headers b/testing/web-platform/tests/workers/postMessage_block.https.html.headers
new file mode 100644
index 0000000000..63b60e490f
--- /dev/null
+++ b/testing/web-platform/tests/workers/postMessage_block.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/workers/postMessage_clone_port.htm b/testing/web-platform/tests/workers/postMessage_clone_port.htm
new file mode 100644
index 0000000000..b1d7b84e3c
--- /dev/null
+++ b/testing/web-platform/tests/workers/postMessage_clone_port.htm
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<title> postMessage(): clone a port </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var channelA = new MessageChannel();
+ var channelB = new MessageChannel();
+ var originalPort = channelB.port2;
+ channelA.port2.onmessage = t.step_func(function(e) {
+ assert_equals(e.data, "ports");
+ var clonedPort = e.ports[0];
+ assert_not_equals(clonedPort, originalPort, "new cloned port object should not equal to the original port!");
+ clonedPort.onmessage = t.step_func_done(function(e) {
+ assert_equals(e.data, "ping", "Data sent through remote port is received by the new cloned port");
+ });
+ });
+ channelA.port1.postMessage("ports", [channelB.port2]);
+ channelB.port1.postMessage("ping");
+});
+</script>
diff --git a/testing/web-platform/tests/workers/postMessage_clone_port_error.htm b/testing/web-platform/tests/workers/postMessage_clone_port_error.htm
new file mode 100644
index 0000000000..3558987476
--- /dev/null
+++ b/testing/web-platform/tests/workers/postMessage_clone_port_error.htm
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<title> postMessage(): cloning source port </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+test(function() {
+ var channel = new MessageChannel();
+ channel.port1.start();
+ assert_throws_dom("DataCloneError", function() {
+ channel.port1.postMessage("ports", [channel.port1]);
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/postMessage_event_properties.htm b/testing/web-platform/tests/workers/postMessage_event_properties.htm
new file mode 100644
index 0000000000..8122413de4
--- /dev/null
+++ b/testing/web-platform/tests/workers/postMessage_event_properties.htm
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title> postMessage(): MessageEvent properties </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var channel = new MessageChannel();
+ var targetPort = channel.port2;
+ targetPort.start();
+ targetPort.addEventListener("message", t.step_func_done(function (evt) {
+ assert_class_string(evt, "MessageEvent");
+ assert_equals(evt.type, "message");
+ assert_false(evt.bubbles, "bubbles should be false");
+ assert_false(evt.cancelable, "cancelable should be false");
+ assert_equals(evt.data, "ping", "data");
+ assert_equals(evt.origin, "", "origin");
+ assert_equals(evt.lastEventId, "", "lastEventId");
+ assert_equals(evt.source, null, "source");
+ assert_array_equals(evt.ports, [], "ports");
+ }), true);
+ channel.port1.postMessage("ping");
+});
+</script>
diff --git a/testing/web-platform/tests/workers/postMessage_ports_readonly_array.htm b/testing/web-platform/tests/workers/postMessage_ports_readonly_array.htm
new file mode 100644
index 0000000000..bd833ede93
--- /dev/null
+++ b/testing/web-platform/tests/workers/postMessage_ports_readonly_array.htm
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<title> postMessage(): read-only ports array </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+"use strict";
+async_test(function(t) {
+ var channel = new MessageChannel();
+ var targetPort = channel.port2;
+ targetPort.start();
+ targetPort.addEventListener("message", t.step_func_done(function(e) {
+ var channel3 = new MessageChannel();
+ assert_throws_js(TypeError, () => {
+ e.ports.push(channel3.port1);
+ }, "ports is a frozen object");
+ assert_equals(e.ports.length, 1, "ports is a read only array with length == 1.");
+ }), true);
+ var channel2 = new MessageChannel();
+ channel.port1.postMessage("ports", [channel2.port1]);
+});
+</script>
diff --git a/testing/web-platform/tests/workers/postMessage_target_source.htm b/testing/web-platform/tests/workers/postMessage_target_source.htm
new file mode 100644
index 0000000000..7d684916dd
--- /dev/null
+++ b/testing/web-platform/tests/workers/postMessage_target_source.htm
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<title> postMessage(): target port and source port </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var channel = new MessageChannel();
+ var source = channel.port1;
+ var target = channel.port2;
+ target.start();
+ target.addEventListener("message", t.step_func_done(function(e) {
+ assert_equals(e.target, target);
+ assert_not_equals(e.target, source);
+ }), true);
+ source.postMessage("ping");
+});
+</script>
diff --git a/testing/web-platform/tests/workers/same-origin-check.sub.html b/testing/web-platform/tests/workers/same-origin-check.sub.html
new file mode 100644
index 0000000000..7af021b8db
--- /dev/null
+++ b/testing/web-platform/tests/workers/same-origin-check.sub.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+const sameOrigin = 'http://{{host}}:{{ports[http][0]}}';
+const crossOrigin = 'http://{{host}}:{{ports[http][1]}}';
+const workerPath = '/workers/support/post-message-on-load-worker.js?pipe=header(Access-Control-Allow-Origin,*)';
+const redirectPath = '/service-workers/service-worker/resources/redirect.py?ACAOrigin=*&Redirect=';
+const tests = [
+ {
+ name: "cross-origin",
+ url: crossOrigin + workerPath
+ },
+ {
+ name: "cross-origin-to-same-origin-redirect",
+ url: crossOrigin + redirectPath +
+ encodeURIComponent(sameOrigin + workerPath)
+ },
+ {
+ name: "same-origin-to-cross-origin-redirect",
+ url: sameOrigin + redirectPath + encodeURIComponent(crossOrigin + workerPath)
+ },
+ {
+ name: "same-origin-to-cross-origin-to-same-origin-redirect",
+ url: sameOrigin + redirectPath +
+ encodeURIComponent(
+ crossOrigin + redirectPath +
+ encodeURIComponent(sameOrigin + workerPath))
+ },
+];
+
+for (const test of tests) {
+ for (const type of ['classic', 'module']) {
+ promise_test(t => new Promise((resolve, reject) => {
+ try {
+ const worker = new Worker(test.url, {type});
+ worker.onmessage = _ => reject('Worker loaded unexpectedly');
+ worker.onerror = resolve;
+ } catch (e) {
+ resolve();
+ }
+ }), 'Worker: ' + test.name + ' (' + type + ')');
+
+ promise_test(t => new Promise((resolve, reject) => {
+ try {
+ const worker = new SharedWorker(
+ test.url + '&label=' + type + test.name, {type});
+ worker.port.onmessage = _ => reject('Worker loaded unexpectedly');
+ worker.onerror = resolve;
+ } catch (e) {
+ resolve();
+ }
+ }), 'SharedWorker: ' + test.name + ' (' + type + ')');
+ }
+}
+</script>
diff --git a/testing/web-platform/tests/workers/same-site-cookies/first-party.all.tentative.https.window.js b/testing/web-platform/tests/workers/same-site-cookies/first-party.all.tentative.https.window.js
new file mode 100644
index 0000000000..d7e5f2ee42
--- /dev/null
+++ b/testing/web-platform/tests/workers/same-site-cookies/first-party.all.tentative.https.window.js
@@ -0,0 +1,19 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+
+'use strict';
+
+// Here's the set-up for this test:
+// Step 1 (window) Set up listener for "DidStart" message and start worker.
+// Step 2 (worker) Send "DidStart" message to window.
+// Step 3 (window) Receive "DidStart" message and cleanup.
+
+async_test(t => {
+ // Step 1
+ const worker = new SharedWorker("/workers/same-site-cookies/resources/worker.js", {sameSiteCookies: "all"});
+ worker.port.onmessage = t.step_func(e => {
+ // Step 3
+ assert_equals(e.data, "DidStart", "Worker should have started");
+ t.done();
+ });
+}, "Check SharedWorker sameSiteCookies option all for first-party");
diff --git a/testing/web-platform/tests/workers/same-site-cookies/first-party.default.tentative.https.window.js b/testing/web-platform/tests/workers/same-site-cookies/first-party.default.tentative.https.window.js
new file mode 100644
index 0000000000..b120014c1a
--- /dev/null
+++ b/testing/web-platform/tests/workers/same-site-cookies/first-party.default.tentative.https.window.js
@@ -0,0 +1,19 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+
+'use strict';
+
+// Here's the set-up for this test:
+// Step 1 (window) Set up listener for "DidStart" message and start worker.
+// Step 2 (worker) Send "DidStart" message to window.
+// Step 3 (window) Receive "DidStart" message and cleanup.
+
+async_test(t => {
+ // Step 1
+ const worker = new SharedWorker("/workers/same-site-cookies/resources/worker.js");
+ worker.port.onmessage = t.step_func(e => {
+ // Step 3
+ assert_equals(e.data, "DidStart", "Worker should have started");
+ t.done();
+ });
+}, "Check SharedWorker sameSiteCookies option default for first-party");
diff --git a/testing/web-platform/tests/workers/same-site-cookies/first-party.none.tentative.https.window.js b/testing/web-platform/tests/workers/same-site-cookies/first-party.none.tentative.https.window.js
new file mode 100644
index 0000000000..762d924eb9
--- /dev/null
+++ b/testing/web-platform/tests/workers/same-site-cookies/first-party.none.tentative.https.window.js
@@ -0,0 +1,19 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+
+'use strict';
+
+// Here's the set-up for this test:
+// Step 1 (window) Set up listener for "DidStart" message and start worker.
+// Step 2 (worker) Send "DidStart" message to window.
+// Step 3 (window) Receive "DidStart" message and cleanup.
+
+async_test(t => {
+ // Step 1
+ const worker = new SharedWorker("/workers/same-site-cookies/resources/worker.js", {sameSiteCookies: "none"});
+ worker.port.onmessage = t.step_func(e => {
+ // Step 3
+ assert_equals(e.data, "DidStart", "Worker should have started");
+ t.done();
+ });
+}, "Check SharedWorker sameSiteCookies option none for first-party");
diff --git a/testing/web-platform/tests/workers/same-site-cookies/resources/iframe-iframe.html b/testing/web-platform/tests/workers/same-site-cookies/resources/iframe-iframe.html
new file mode 100644
index 0000000000..0c5582176d
--- /dev/null
+++ b/testing/web-platform/tests/workers/same-site-cookies/resources/iframe-iframe.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<meta charset="utf-8">
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<body>
+<script>
+// Step 3 (workers/same-site-cookies/third-party.{})
+test_driver.set_test_context(window.top);
+const type = (new URLSearchParams(window.location.search)).get("type");
+let options = {};
+switch (type) {
+ case "default":
+ break;
+ case "all":
+ options.sameSiteCookies = "all";
+ break;
+ case "none":
+ options.sameSiteCookies = "none";
+ break;
+}
+// Step 5 (workers/same-site-cookies/third-party.{})
+try {
+ const worker = new SharedWorker("/workers/same-site-cookies/resources/worker.js", options);
+ worker.port.onmessage = (e) => {
+ window.top.postMessage(e.data, "*");
+ };
+} catch (_) {
+ window.top.postMessage("DidNotStart", "*");
+}
+</script>
+</body>
diff --git a/testing/web-platform/tests/workers/same-site-cookies/resources/iframe.sub.html b/testing/web-platform/tests/workers/same-site-cookies/resources/iframe.sub.html
new file mode 100644
index 0000000000..2531f3d620
--- /dev/null
+++ b/testing/web-platform/tests/workers/same-site-cookies/resources/iframe.sub.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<meta charset="utf-8">
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<body>
+<script>
+// Step 2 (workers/same-site-cookies/third-party.{})
+test_driver.set_test_context(window.top);
+const type = (new URLSearchParams(window.location.search)).get("type");
+let iframe = document.createElement("iframe");
+iframe.src = "https://{{hosts[][]}}:{{ports[https][0]}}/workers/same-site-cookies/resources/iframe-iframe.html?type=" + type;
+document.body.appendChild(iframe);
+</script>
+</body>
diff --git a/testing/web-platform/tests/workers/same-site-cookies/resources/worker.js b/testing/web-platform/tests/workers/same-site-cookies/resources/worker.js
new file mode 100644
index 0000000000..658f499e92
--- /dev/null
+++ b/testing/web-platform/tests/workers/same-site-cookies/resources/worker.js
@@ -0,0 +1,5 @@
+// Step 2/4 (workers/same-site-cookies/{})
+self.onconnect = (e) => {
+ e.ports[0].postMessage("DidStart");
+ self.close();
+}
diff --git a/testing/web-platform/tests/workers/same-site-cookies/third-party.all.tentative.sub.https.window.js b/testing/web-platform/tests/workers/same-site-cookies/third-party.all.tentative.sub.https.window.js
new file mode 100644
index 0000000000..51ad1d3b02
--- /dev/null
+++ b/testing/web-platform/tests/workers/same-site-cookies/third-party.all.tentative.sub.https.window.js
@@ -0,0 +1,24 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+
+'use strict';
+
+// Here's the set-up for this test:
+// Step 1 (top-frame) Set up listener for "DidNotStart" message and open cross-site iframe.
+// Step 2 (sub-frame) Open iframe same-site to top-frame.
+// Step 3 (sub-sub-frame) Set up listener for message and start worker.
+// Step 4 (worker) Skipped.
+// Step 5 (sub-sub-frame) Worker failed to start and window messages "DidNotStart".
+// Step 6 (top-frame) Receive "DidNotStart" message and cleanup.
+
+async_test(t => {
+ // Step 1
+ window.addEventListener("message", t.step_func(e => {
+ // Step 6
+ assert_equals(e.data, "DidNotStart", "Worker should not have started");
+ t.done();
+ }));
+ let iframe = document.createElement("iframe");
+ iframe.src = "https://{{hosts[alt][]}}:{{ports[https][0]}}/workers/same-site-cookies/resources/iframe.sub.html?type=all";
+ document.body.appendChild(iframe);
+}, "Check SharedWorker sameSiteCookies option all for third-party");
diff --git a/testing/web-platform/tests/workers/same-site-cookies/third-party.default.tentative.sub.https.window.js b/testing/web-platform/tests/workers/same-site-cookies/third-party.default.tentative.sub.https.window.js
new file mode 100644
index 0000000000..194df38390
--- /dev/null
+++ b/testing/web-platform/tests/workers/same-site-cookies/third-party.default.tentative.sub.https.window.js
@@ -0,0 +1,24 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+
+'use strict';
+
+// Here's the set-up for this test:
+// Step 1 (top-frame) Set up listener for "DidStart" message and open cross-site iframe.
+// Step 2 (sub-frame) Open iframe same-site to top-frame.
+// Step 3 (sub-sub-frame) Set up listener for message and start worker.
+// Step 4 (worker) Send "DidStart" message to iframe.
+// Step 5 (sub-sub-frame) Receive message and pass on to window.
+// Step 6 (top-frame) Receive "DidStart" message and cleanup.
+
+async_test(t => {
+ // Step 1
+ window.addEventListener("message", t.step_func(e => {
+ // Step 6
+ assert_equals(e.data, "DidStart", "Worker should have started");
+ t.done();
+ }));
+ let iframe = document.createElement("iframe");
+ iframe.src = "https://{{hosts[alt][]}}:{{ports[https][0]}}/workers/same-site-cookies/resources/iframe.sub.html?type=default";
+ document.body.appendChild(iframe);
+}, "Check SharedWorker sameSiteCookies option default for third-party");
diff --git a/testing/web-platform/tests/workers/same-site-cookies/third-party.none.tentative.sub.https.window.js b/testing/web-platform/tests/workers/same-site-cookies/third-party.none.tentative.sub.https.window.js
new file mode 100644
index 0000000000..b91b9d7ab2
--- /dev/null
+++ b/testing/web-platform/tests/workers/same-site-cookies/third-party.none.tentative.sub.https.window.js
@@ -0,0 +1,24 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+
+'use strict';
+
+// Here's the set-up for this test:
+// Step 1 (top-frame) Set up listener for "DidStart" message and open cross-site iframe.
+// Step 2 (sub-frame) Open iframe same-site to top-frame.
+// Step 3 (sub-sub-frame) Set up listener for message and start worker.
+// Step 4 (worker) Send "DidStart" message to iframe.
+// Step 5 (sub-sub-frame) Receive message and pass on to window.
+// Step 6 (top-frame) Receive "DidStart" message and cleanup.
+
+async_test(t => {
+ // Step 1
+ window.addEventListener("message", t.step_func(e => {
+ // Step 6
+ assert_equals(e.data, "DidStart", "Worker should have started");
+ t.done();
+ }));
+ let iframe = document.createElement("iframe");
+ iframe.src = "https://{{hosts[alt][]}}:{{ports[https][0]}}/workers/same-site-cookies/resources/iframe.sub.html?type=none";
+ document.body.appendChild(iframe);
+}, "Check SharedWorker sameSiteCookies option none for third-party");
diff --git a/testing/web-platform/tests/workers/semantics/encodings/001.html b/testing/web-platform/tests/workers/semantics/encodings/001.html
new file mode 100644
index 0000000000..05ee5e006b
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/encodings/001.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>encoding, dedicated worker</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var worker = new Worker('001.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, '\u00e5');
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/encodings/001.js b/testing/web-platform/tests/workers/semantics/encodings/001.js
new file mode 100644
index 0000000000..03bc557c33
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/encodings/001.js
@@ -0,0 +1 @@
+postMessage('Ã¥'); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/encodings/001.js.headers b/testing/web-platform/tests/workers/semantics/encodings/001.js.headers
new file mode 100644
index 0000000000..5614aaa7f0
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/encodings/001.js.headers
@@ -0,0 +1 @@
+Content-Type: text/javascript; charset=windows-1252
diff --git a/testing/web-platform/tests/workers/semantics/encodings/002.html b/testing/web-platform/tests/workers/semantics/encodings/002.html
new file mode 100644
index 0000000000..fecbffc18d
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/encodings/002.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>encoding, shared worker</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var worker = new SharedWorker('002.js', '');
+ worker.port.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, '\u00e5');
+ this.done();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/semantics/encodings/002.js b/testing/web-platform/tests/workers/semantics/encodings/002.js
new file mode 100644
index 0000000000..9dde7bbda9
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/encodings/002.js
@@ -0,0 +1,3 @@
+onconnect = function(e) {
+ e.ports[0].postMessage('Ã¥');
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/encodings/002.js.headers b/testing/web-platform/tests/workers/semantics/encodings/002.js.headers
new file mode 100644
index 0000000000..5614aaa7f0
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/encodings/002.js.headers
@@ -0,0 +1 @@
+Content-Type: text/javascript; charset=windows-1252
diff --git a/testing/web-platform/tests/workers/semantics/encodings/003-1.py b/testing/web-platform/tests/workers/semantics/encodings/003-1.py
new file mode 100644
index 0000000000..4f5df2bb10
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/encodings/003-1.py
@@ -0,0 +1,4 @@
+ # -*- coding: utf-8 -*-
+
+def main(request, response):
+ return u"PASS" if request.GET.first(b'x').decode('utf-8') == u'Ã¥' else u"FAIL"
diff --git a/testing/web-platform/tests/workers/semantics/encodings/003.html b/testing/web-platform/tests/workers/semantics/encodings/003.html
new file mode 100644
index 0000000000..095320e4d1
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/encodings/003.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>URL encoding, dedicated worker</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var worker = new Worker('003.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_true(e.data);
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/encodings/003.js b/testing/web-platform/tests/workers/semantics/encodings/003.js
new file mode 100644
index 0000000000..35bda8bba8
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/encodings/003.js
@@ -0,0 +1,5 @@
+var xhr = new XMLHttpRequest();
+xhr.open('GET', '003-1.py?x=Ã¥', false);
+xhr.send();
+var passed = xhr.responseText == 'PASS';
+postMessage(passed); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/encodings/004.html b/testing/web-platform/tests/workers/semantics/encodings/004.html
new file mode 100644
index 0000000000..cd556b8190
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/encodings/004.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>URL encoding, shared worker</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var worker = new SharedWorker('004.js');
+ worker.port.onmessage = this.step_func(function(e) {
+ assert_true(e.data);
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/encodings/004.js b/testing/web-platform/tests/workers/semantics/encodings/004.js
new file mode 100644
index 0000000000..5146929a73
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/encodings/004.js
@@ -0,0 +1,7 @@
+onconnect = function(e) {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', '003-1.py?x=Ã¥', false);
+ xhr.send();
+ var passed = xhr.responseText == 'PASS';
+ e.ports[0].postMessage(passed);
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/encodings/004.worker.js b/testing/web-platform/tests/workers/semantics/encodings/004.worker.js
new file mode 100644
index 0000000000..28489a572b
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/encodings/004.worker.js
@@ -0,0 +1,5 @@
+importScripts("/resources/testharness.js");
+test(function() {
+ assert_equals("ÿ", "\ufffd");
+}, "Decoding invalid utf-8");
+done();
diff --git a/testing/web-platform/tests/workers/semantics/interface-objects/001.worker.js b/testing/web-platform/tests/workers/semantics/interface-objects/001.worker.js
new file mode 100644
index 0000000000..873e8701bb
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/interface-objects/001.worker.js
@@ -0,0 +1,81 @@
+importScripts("/resources/testharness.js");
+var expected = [
+ // https://html.spec.whatwg.org/
+ "WorkerGlobalScope",
+ "DedicatedWorkerGlobalScope",
+ "Worker",
+ "MessagePort",
+ "MessageEvent",
+ "WorkerNavigator",
+ "MessageChannel",
+ "WorkerLocation",
+ "ImageData",
+ "ImageBitmap",
+ "CanvasGradient",
+ "CanvasPattern",
+ "TextMetrics",
+ "Path2D",
+ "PromiseRejectionEvent",
+ "EventSource",
+ "BroadcastChannel",
+ // https://websockets.spec.whatwg.org/
+ "WebSocket",
+ "CloseEvent",
+ // https://tc39.github.io/ecma262/
+ "ArrayBuffer",
+ "Int8Array",
+ "Uint8Array",
+ "Uint8ClampedArray",
+ "Int16Array",
+ "Uint16Array",
+ "Int32Array",
+ "Uint32Array",
+ "Float32Array",
+ "Float64Array",
+ "DataView",
+ // https://xhr.spec.whatwg.org/
+ "XMLHttpRequestEventTarget",
+ "XMLHttpRequestUpload",
+ "XMLHttpRequest",
+ "ProgressEvent",
+ "FormData",
+ // https://url.spec.whatwg.org/
+ "URL",
+ "URLSearchParams",
+ // https://w3c.github.io/FileAPI/
+ "File",
+ "Blob",
+ "FileList",
+ "FileReader",
+ "FileReaderSync",
+ // https://dom.spec.whatwg.org/
+ "EventTarget",
+ "ErrorEvent",
+ "Event",
+ "CustomEvent",
+ // https://webidl.spec.whatwg.org/
+ "DOMException",
+ // https://streams.spec.whatwg.org/
+ "ReadableStream",
+ "WritableStream",
+ "ByteLengthQueuingStrategy",
+ "CountQueuingStrategy",
+ // http://w3c.github.io/IndexedDB/
+ "IDBRequest",
+ "IDBOpenDBRequest",
+ "IDBVersionChangeEvent",
+ "IDBFactory",
+ "IDBDatabase",
+ "IDBObjectStore",
+ "IDBIndex",
+ "IDBKeyRange",
+ "IDBCursor",
+ "IDBCursorWithValue",
+ "IDBTransaction",
+];
+for (var i = 0; i < expected.length; ++i) {
+ test(function () {
+ assert_own_property(self, expected[i]);
+ }, "The " + expected[i] + " interface object should be exposed.");
+}
+done();
diff --git a/testing/web-platform/tests/workers/semantics/interface-objects/002.worker.js b/testing/web-platform/tests/workers/semantics/interface-objects/002.worker.js
new file mode 100644
index 0000000000..9c8dc6746e
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/interface-objects/002.worker.js
@@ -0,0 +1,45 @@
+importScripts("/resources/testharness.js");
+var unexpected = [
+ // https://html.spec.whatwg.org/
+ "SharedWorker",
+ "CanvasPath",
+ "SharedWorkerGlobalScope",
+ "AbstractView",
+ "AbstractWorker",
+ "ApplicationCache",
+ "Location",
+ "Navigator",
+ "Audio",
+ "HTMLCanvasElement",
+ "Path",
+ "CanvasProxy",
+ "CanvasRenderingContext2D",
+ "DrawingStyle",
+ "BeforeUnloadEvent",
+ "PopStateEvent",
+ "HashChangeEvent",
+ "PageTransitionEvent",
+ // https://dom.spec.whatwg.org/
+ "DOMImplementation",
+ // http://w3c.github.io/IndexedDB/
+ "IDBEnvironment",
+ // https://www.w3.org/TR/2010/NOTE-webdatabase-20101118/
+ "Database",
+ // https://w3c.github.io/uievents/
+ "UIEvent",
+ "FocusEvent",
+ "MouseEvent",
+ "WheelEvent",
+ "InputEvent",
+ "KeyboardEvent",
+ "CompositionEvent",
+ // https://w3c.github.io/webvtt/
+ "VTTCue",
+ "VTTRegion",
+];
+for (var i = 0; i < unexpected.length; ++i) {
+ test(function () {
+ assert_false(unexpected[i] in self);
+ }, "The " + unexpected[i] + " interface object should not be exposed.");
+}
+done();
diff --git a/testing/web-platform/tests/workers/semantics/interface-objects/003.any.js b/testing/web-platform/tests/workers/semantics/interface-objects/003.any.js
new file mode 100644
index 0000000000..974756c508
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/interface-objects/003.any.js
@@ -0,0 +1,81 @@
+// META: global=sharedworker
+
+var expected = [
+ // https://html.spec.whatwg.org/
+ "WorkerGlobalScope",
+ "SharedWorkerGlobalScope",
+ "Worker",
+ "MessagePort",
+ "MessageEvent",
+ "WorkerNavigator",
+ "MessageChannel",
+ "WorkerLocation",
+ "ImageData",
+ "ImageBitmap",
+ "CanvasGradient",
+ "CanvasPattern",
+ "Path2D",
+ "PromiseRejectionEvent",
+ "EventSource",
+ "BroadcastChannel",
+ // https://websockets.spec.whatwg.org/
+ "WebSocket",
+ "CloseEvent",
+ // https://tc39.github.io/ecma262/
+ "ArrayBuffer",
+ "Int8Array",
+ "Uint8Array",
+ "Uint8ClampedArray",
+ "Int16Array",
+ "Uint16Array",
+ "Int32Array",
+ "Uint32Array",
+ "Float32Array",
+ "Float64Array",
+ "DataView",
+ // https://xhr.spec.whatwg.org/
+ "XMLHttpRequestEventTarget",
+ "XMLHttpRequestUpload",
+ "XMLHttpRequest",
+ "ProgressEvent",
+ "FormData",
+ // https://url.spec.whatwg.org/
+ "URL",
+ "URLSearchParams",
+ // https://w3c.github.io/FileAPI/
+ "File",
+ "Blob",
+ "FileList",
+ "FileReader",
+ "FileReaderSync",
+ // https://dom.spec.whatwg.org/
+ "EventTarget",
+ "ErrorEvent",
+ "Event",
+ "CustomEvent",
+ // https://webidl.spec.whatwg.org/
+ "DOMException",
+ // https://streams.spec.whatwg.org/
+ "ReadableStream",
+ "WritableStream",
+ "ByteLengthQueuingStrategy",
+ "CountQueuingStrategy",
+ // http://w3c.github.io/IndexedDB/
+ "IDBRequest",
+ "IDBOpenDBRequest",
+ "IDBVersionChangeEvent",
+ "IDBFactory",
+ "IDBDatabase",
+ "IDBObjectStore",
+ "IDBIndex",
+ "IDBKeyRange",
+ "IDBCursor",
+ "IDBCursorWithValue",
+ "IDBTransaction",
+];
+
+for (var i = 0; i < expected.length; ++i) {
+ test(function() {
+ assert_true(expected[i] in self);
+ }, "The " + expected[i] + " interface object should be exposed");
+}
diff --git a/testing/web-platform/tests/workers/semantics/interface-objects/004.any.js b/testing/web-platform/tests/workers/semantics/interface-objects/004.any.js
new file mode 100644
index 0000000000..1b0b93b5df
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/interface-objects/004.any.js
@@ -0,0 +1,41 @@
+// META: global=sharedworker
+
+var unexpected = [
+ // https://html.spec.whatwg.org/
+ "ApplicationCache",
+ "SharedWorker",
+ "CanvasPath",
+ "DedicatedWorkerGlobalScope",
+ "AbstractView",
+ "AbstractWorker",
+ "Location",
+ "Navigator",
+ "DOMImplementation",
+ "Audio",
+ "HTMLCanvasElement",
+ "Path",
+ "CanvasProxy",
+ "CanvasRenderingContext2D",
+ "DrawingStyle",
+ "PopStateEvent",
+ "HashChangeEvent",
+ "PageTransitionEvent",
+ // http://w3c.github.io/IndexedDB/
+ "IDBEnvironment",
+ // https://www.w3.org/TR/2010/NOTE-webdatabase-20101118/
+ "Database",
+ // https://w3c.github.io/uievents/
+ "UIEvent",
+ "FocusEvent",
+ "MouseEvent",
+ "WheelEvent",
+ "InputEvent",
+ "KeyboardEvent",
+ "CompositionEvent",
+];
+
+for (var i = 0; i < unexpected.length; ++i) {
+ test(function() {
+ assert_false(unexpected[i] in self);
+ }, "The " + unexpected[i] + " interface object should not be exposed");
+}
diff --git a/testing/web-platform/tests/workers/semantics/multiple-workers/001.html b/testing/web-platform/tests/workers/semantics/multiple-workers/001.html
new file mode 100644
index 0000000000..f9e2bbeaba
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/multiple-workers/001.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<title>dedicated and shared worker in same page</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var worker = new Worker('001.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, 'dedicated');
+ this.done();
+ });
+ worker.postMessage('dedicated');
+}, 'dedicated');
+async_test(function() {
+ var shared = new SharedWorker('001.js', '');
+ shared.port.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, 'shared');
+ this.done();
+ });
+ shared.port.postMessage('shared');
+}, 'shared');
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/multiple-workers/001.js b/testing/web-platform/tests/workers/semantics/multiple-workers/001.js
new file mode 100644
index 0000000000..6d51169dea
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/multiple-workers/001.js
@@ -0,0 +1,11 @@
+if ('onmessage' in self) { // dedicated worker
+ onmessage = function(e) {
+ postMessage(e.data);
+ }
+} else { // shared worker
+ onconnect = function(e) {
+ e.ports[0].onmessage = function(e) {
+ this.postMessage(e.data);
+ }
+ }
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/multiple-workers/002.html b/testing/web-platform/tests/workers/semantics/multiple-workers/002.html
new file mode 100644
index 0000000000..aa01e361d8
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/multiple-workers/002.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<title>creating 3 sibling dedicated workers</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var w1 = new Worker('002.js');
+ var w2 = new Worker('002.js');
+ var w3 = new Worker('002.js');
+ var got = [false, false, false];
+ var check_done = t.step_func(function() {
+ if (got.every(function(x) {return x})) {
+ t.done();
+ }
+ });
+ w1.onmessage = t.step_func(function(e) {got[0] = true; check_done()});
+ w2.onmessage = t.step_func(function(e) {got[1] = true; check_done()});
+ w3.onmessage = t.step_func(function(e) {got[2] = true; check_done()});
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/multiple-workers/002.js b/testing/web-platform/tests/workers/semantics/multiple-workers/002.js
new file mode 100644
index 0000000000..2318c2e267
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/multiple-workers/002.js
@@ -0,0 +1 @@
+postMessage(1); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/multiple-workers/003.html b/testing/web-platform/tests/workers/semantics/multiple-workers/003.html
new file mode 100644
index 0000000000..f6e03c75f7
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/multiple-workers/003.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<title>creating 3 nested dedicated workers</title>
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var w1 = new Worker('003.js#1');
+ w1.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, '123');
+ this.done();
+ });
+ w1.onerror = this.unreached_func("error");
+});
+</script>
diff --git a/testing/web-platform/tests/workers/semantics/multiple-workers/003.js b/testing/web-platform/tests/workers/semantics/multiple-workers/003.js
new file mode 100644
index 0000000000..14a5a614b3
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/multiple-workers/003.js
@@ -0,0 +1,13 @@
+if (location.hash == '#1') {
+ var w2 = new Worker('003.js#2');
+ w2.onmessage = function(e) {
+ postMessage('1'+e.data);
+ }
+} else if (location.hash == '#2') {
+ var w3 = new Worker('003.js#3');
+ w3.onmessage = function(e) {
+ postMessage('2'+e.data);
+ }
+} else {
+ postMessage('3');
+}
diff --git a/testing/web-platform/tests/workers/semantics/multiple-workers/004-1.html b/testing/web-platform/tests/workers/semantics/multiple-workers/004-1.html
new file mode 100644
index 0000000000..eac038c5be
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/multiple-workers/004-1.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<title></title>
+<script>
+window.onload = function() {
+ var w=new SharedWorker('004-2.js', 'x');
+};
+</script>
diff --git a/testing/web-platform/tests/workers/semantics/multiple-workers/004-2.js b/testing/web-platform/tests/workers/semantics/multiple-workers/004-2.js
new file mode 100644
index 0000000000..e59cd6927e
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/multiple-workers/004-2.js
@@ -0,0 +1,6 @@
+var port;
+onconnect = function(e) {
+ if (!port)
+ port = e.ports[0];
+ port.postMessage(1);
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/multiple-workers/004.html b/testing/web-platform/tests/workers/semantics/multiple-workers/004.html
new file mode 100644
index 0000000000..552cc8a633
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/multiple-workers/004.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<title>shared worker with multiple documents</title>
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+setup({ single_test: true });
+
+var i = 0;
+var load_count = 0;
+
+var w1 = new SharedWorker('004-2.js', 'x');
+w1.port.onmessage = function(e) {
+ i++;
+ check_result();
+};
+
+
+function iframe_loaded() {
+ load_count++;
+ check_result();
+}
+
+function check_result() {
+ //timeout to allow for extra, unexpected, messages to arrive
+ if (i == 3 && load_count == 2) {
+ setTimeout(function() {
+ assert_equals(load_count, 2);
+ assert_equals(i, 3);
+ done();
+ }, 500);
+ }
+}
+</script>
+<iframe src=004-1.html onload="iframe_loaded()"></iframe>
+<iframe src=004-1.html onload="iframe_loaded()"></iframe>
diff --git a/testing/web-platform/tests/workers/semantics/multiple-workers/008-1.html b/testing/web-platform/tests/workers/semantics/multiple-workers/008-1.html
new file mode 100644
index 0000000000..d19d7fa336
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/multiple-workers/008-1.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<title>008-1</title>
+<script>
+var w1 = new SharedWorker('008.js');
+w1.port.onmessage = function(e) {
+ e.ports[0].postMessage(2);
+}
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/multiple-workers/008.html b/testing/web-platform/tests/workers/semantics/multiple-workers/008.html
new file mode 100644
index 0000000000..ee38d80866
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/multiple-workers/008.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>messagechannel in shared worker</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<iframe src=008-1.html></iframe>
+<script>
+var t = async_test();
+onload = t.step_func(function() {
+ var w1 = new SharedWorker('008.js');
+ w1.port.onmessage = this.step_func(function(e) {
+ e.ports[0].onmessage = this.step_func(function(e) {
+ assert_equals(e.data, 2);
+ this.done();
+ });
+ });
+ w1.onerror = this.unreached_func("error");
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/multiple-workers/008.js b/testing/web-platform/tests/workers/semantics/multiple-workers/008.js
new file mode 100644
index 0000000000..92593ebb86
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/multiple-workers/008.js
@@ -0,0 +1,6 @@
+var channel = new MessageChannel();
+var i = 0;
+onconnect = function(e) {
+ i++;
+ e.ports[0].postMessage(1, [channel['port' + i]]);
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/multiple-workers/exposure.any.js b/testing/web-platform/tests/workers/semantics/multiple-workers/exposure.any.js
new file mode 100644
index 0000000000..7e226a7333
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/multiple-workers/exposure.any.js
@@ -0,0 +1,11 @@
+// META: global=window,worker
+
+test(() => {
+ const assert = "ServiceWorkerGlobalScope" in globalThis ? assert_equals : assert_not_equals;
+ assert(globalThis.Worker, undefined);
+}, "Worker exposure");
+
+test(() => {
+ const assert = globalThis.GLOBAL.isWindow() ? assert_not_equals : assert_equals;
+ assert(globalThis.SharedWorker, undefined);
+}, "SharedWorker exposure");
diff --git a/testing/web-platform/tests/workers/semantics/navigation/001-1.html b/testing/web-platform/tests/workers/semantics/navigation/001-1.html
new file mode 100644
index 0000000000..c259c2c839
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/navigation/001-1.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>001-1</title>
+<script>
+onload = function() {
+ var worker = new Worker('001-1.js');
+ worker.onmessage = function(e) {
+ var started = !!parent.date;
+ parent.date = e.data;
+ if (!started) {
+ parent.start_test()
+ }
+ }
+}
+</script>
+<a href='data:text/html,<title>foo</title><script>onload=function(){window.parent.postMessage({title: window.document.title}, "*")}</script>'>link</a> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/navigation/001-1.js b/testing/web-platform/tests/workers/semantics/navigation/001-1.js
new file mode 100644
index 0000000000..f62c365e32
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/navigation/001-1.js
@@ -0,0 +1 @@
+setInterval(function() { postMessage(new Date()) }, 10) \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/navigation/001.html b/testing/web-platform/tests/workers/semantics/navigation/001.html
new file mode 100644
index 0000000000..f31c2590e5
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/navigation/001.html
@@ -0,0 +1,39 @@
+<!--
+
+/*
+-->
+<!doctype html>
+<title>navigating</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+setup({ single_test: true });
+var date;
+var newDate;
+</script>
+<iframe></iframe>
+<script>
+var iframe = document.querySelector('iframe');
+onload = function() {
+ iframe.src = "001-1.html?" + Math.random();
+};
+var start_test = function() {
+ window[0].document.links[0].click();
+};
+var after_load = function(event) {
+ history.back();
+ newDate = new Date();
+ setTimeout(function() {
+ assert_greater_than(Number(date), Number(newDate));
+ assert_equals(window[0].document.title, '001-1');
+ window.removeEventListener("message", after_load);
+ done();
+ }, 2000);
+};
+window.addEventListener("message", after_load);
+</script>
+<!--
+*/
+//-->
+
diff --git a/testing/web-platform/tests/workers/semantics/navigation/002.html b/testing/web-platform/tests/workers/semantics/navigation/002.html
new file mode 100644
index 0000000000..8ea98ef2d4
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/navigation/002.html
@@ -0,0 +1,38 @@
+<!--
+
+/*
+-->
+<!doctype html>
+<title>navigating 2</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+var date;
+var newDate;
+</script>
+<iframe></iframe>
+<script>
+var t = async_test();
+var iframe = document.querySelector('iframe');
+onload = t.step_func(function() {
+ iframe.src = "001-1.html?" + Math.random();
+});
+var start_test = t.step_func(function() {
+ window[0].document.links[0].click();
+});
+var after_load = t.step_func(function(event) {
+ newDate = new Date();
+ setTimeout(this.step_func(function() {
+ assert_less_than(Number(date), Number(newDate));
+ assert_equals(event.data.title, 'foo');
+ window.removeEventListener("message", after_load);
+ this.done();
+ }), 500);
+});
+window.addEventListener("message", after_load);
+</script>
+<!--
+*/
+//-->
+
diff --git a/testing/web-platform/tests/workers/semantics/reporting-errors/001.html b/testing/web-platform/tests/workers/semantics/reporting-errors/001.html
new file mode 100644
index 0000000000..d8b17289fe
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/reporting-errors/001.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<title>shared worker, not handled</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+setup({allow_uncaught_exception:true});
+async_test(function() {
+ window.onerror = this.step_func(function(a) {
+ assert_unreached('window.onerror invoked: ' + a);
+ });
+ var worker = new SharedWorker('001.js', '');
+ worker.port.onmessage = this.step_func_done(function(e) {
+ assert_equals(e.data, '');
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/semantics/reporting-errors/001.js b/testing/web-platform/tests/workers/semantics/reporting-errors/001.js
new file mode 100644
index 0000000000..5736666cc3
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/reporting-errors/001.js
@@ -0,0 +1,28 @@
+var port;
+var timeout;
+onerror = function(a,b,c,d,e) {
+ // will return undefined, thus the error is "not handled"
+ // so error should be reported to the user, but this test doesn't check
+ // that.
+ // just make sure that this method is invoked with five arguments
+ clearTimeout(timeout);
+ var log = '';
+ if (arguments.length != 5)
+ log += 'got ' + arguments.length + ' arguments, expected 5. ';
+ if (typeof a != 'string')
+ log += 'first argument wasn\'t a string. ';
+ if (b != location.href)
+ log += 'second argument was ' + b + ', expected ' + location.href + '. ';
+ if (typeof c != 'number')
+ log += 'third argument wasn\'t a number. ';
+ if (typeof d != 'number')
+ log += 'fourth argument wasn\'t a number. ';
+ if (e != 42)
+ log += 'fifth argument wasn\'t the thrown exception. ';
+ port.postMessage(log);
+}
+onconnect = function (e) {
+ port = e.ports[0];
+ timeout = setTimeout(function() { port.postMessage('self.onerror was not invoked'); }, 250);
+ throw 42; // will "report the error"
+}
diff --git a/testing/web-platform/tests/workers/semantics/reporting-errors/002.html b/testing/web-platform/tests/workers/semantics/reporting-errors/002.html
new file mode 100644
index 0000000000..4b322a5f07
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/reporting-errors/002.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<title>shared worker, addEventListener</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+setup({allow_uncaught_exception:true});
+async_test(function() {
+ window.onerror = this.step_func(function(a) {
+ assert_unreached('window.onerror invoked: ' + a);
+ });
+ var worker = new SharedWorker('002.js', '');
+ worker.port.onmessage = this.step_func_done(function(e) {
+ assert_equals(e.data, '');
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/semantics/reporting-errors/002.js b/testing/web-platform/tests/workers/semantics/reporting-errors/002.js
new file mode 100644
index 0000000000..ff96922634
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/reporting-errors/002.js
@@ -0,0 +1,34 @@
+var port;
+var timeout;
+addEventListener('error', function(e) {
+ // event is not canceled, thus the error is "not handled"
+ // so error should be reported to the user, but this test doesn't check
+ // that.
+ // just make sure that this event has the right properties
+ clearTimeout(timeout);
+ var log = '';
+ if (!self.ErrorEvent || Object.getPrototypeOf(e) != ErrorEvent.prototype)
+ log += 'event should be an ErrorEvent. ';
+ if (e.bubbles)
+ log += 'event should not bubble. ';
+ if (!e.cancelable)
+ log += 'event should be cancelable. ';
+ if (!e.isTrusted)
+ log += 'event should be trusted. ';
+ if (typeof e.message != 'string')
+ log += 'message wasn\'t a string. ';
+ if (e.filename != location.href)
+ log += 'filename was ' + e.filename + ', expected ' + location.href + '. ';
+ if (typeof e.lineno != 'number')
+ log += 'lineno wasn\'t a number. ';
+ if (typeof e.colno != 'number')
+ log += 'colno argument wasn\'t a number. ';
+ if (e.error != 42)
+ log += 'fifth argument wasn\'t the thrown exception. ';
+ port.postMessage(log);
+}, false);
+onconnect = function (e) {
+ port = e.ports[0];
+ timeout = setTimeout(function() { port.postMessage('No error event fired'); }, 250);
+ throw 42; // will "report the error"
+}
diff --git a/testing/web-platform/tests/workers/semantics/reporting-errors/003.html b/testing/web-platform/tests/workers/semantics/reporting-errors/003.html
new file mode 100644
index 0000000000..8ea59b8106
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/reporting-errors/003.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<title>shared worker, no error event on worker or port</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+setup({allow_uncaught_exception:true});
+async_test(function() {
+ window.onerror = this.step_func(function(a) {
+ assert_unreached('window.onerror invoked: ' + a);
+ });
+ var worker = new SharedWorker('003.js', '');
+ worker.addEventListener('error', this.step_func(function(e) {
+ assert_unreached('error on worker');
+ }), false);
+ worker.port.addEventListener('error', this.step_func(function(e) {
+ assert_unreached('error on port');
+ }), false);
+ worker.port.onmessage = this.step_func_done(function(e) {
+ assert_equals(e.data, '');
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/semantics/reporting-errors/003.js b/testing/web-platform/tests/workers/semantics/reporting-errors/003.js
new file mode 100644
index 0000000000..8a3390bb24
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/reporting-errors/003.js
@@ -0,0 +1,8 @@
+onconnect = function (e) {
+ setTimeout(function() { e.ports[0].postMessage(''); }, 250);
+ y(); // will "report the error"
+ // onerror is null so it'll be "not handled", and the error should be
+ // reported to the user, although we don't test that here
+ // make sure we don't fire an error event on the message port or the
+ // SharedWorker object
+}
diff --git a/testing/web-platform/tests/workers/semantics/reporting-errors/004-1.html b/testing/web-platform/tests/workers/semantics/reporting-errors/004-1.html
new file mode 100644
index 0000000000..326e1399ec
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/reporting-errors/004-1.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<script>
+parent.t.step(function() {
+ window.onerror = this.step_func(function(a) {
+ assert_unreached('(inner) window.onerror invoked: ' + a);
+ });
+ var worker = new SharedWorker('004.js', '');
+ worker.addEventListener('error', this.step_func(function(e) {
+ parent.assert_unreached('(inner) error on worker');
+ }), false);
+ worker.port.addEventListener('error', this.step_func(function(e) {
+ parent.assert_unreached('(inner) error on port');
+ }), false);
+ worker.port.onmessage = this.step_func_done(function(e) {
+ parent.assert_equals(e.data, 2);
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/semantics/reporting-errors/004.html b/testing/web-platform/tests/workers/semantics/reporting-errors/004.html
new file mode 100644
index 0000000000..8516e52c6f
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/reporting-errors/004.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<title>shared worker in two documents and window.onerror</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+setup({allow_uncaught_exception:true});
+var t = async_test(function() {
+ window.onerror = this.step_func(function(a) {
+ assert_unreached('(outer) window.onerror invoked: ' + a);
+ });
+ var worker = new SharedWorker('004.js', '');
+ worker.addEventListener('error', this.step_func(function(e) {
+ assert_unreached('(outer) error on worker');
+ }), false);
+ worker.port.addEventListener('error', this.step_func(function(e) {
+ assert_unreached('(outer) error on port');
+ }), false);
+ worker.port.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, 1);
+ var iframe = document.createElement('iframe');
+ iframe.src = '004-1.html';
+ document.body.appendChild(iframe);
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/workers/semantics/reporting-errors/004.js b/testing/web-platform/tests/workers/semantics/reporting-errors/004.js
new file mode 100644
index 0000000000..a68d2ab01d
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/reporting-errors/004.js
@@ -0,0 +1,6 @@
+var i = 0;
+onconnect = function (e) {
+ i++;
+ setTimeout(function() { e.ports[0].postMessage(i); }, 250);
+ y(); // will "report the error"
+}
diff --git a/testing/web-platform/tests/workers/semantics/run-a-worker/001.html b/testing/web-platform/tests/workers/semantics/run-a-worker/001.html
new file mode 100644
index 0000000000..71e48c2771
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/run-a-worker/001.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>worker global scope, dedicated worker</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var worker = new Worker('001.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_true(e.data);
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/run-a-worker/001.js b/testing/web-platform/tests/workers/semantics/run-a-worker/001.js
new file mode 100644
index 0000000000..33ed47f1b4
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/run-a-worker/001.js
@@ -0,0 +1 @@
+postMessage(this === self); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/run-a-worker/002.html b/testing/web-platform/tests/workers/semantics/run-a-worker/002.html
new file mode 100644
index 0000000000..9487d886a6
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/run-a-worker/002.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>worker global scope, shared worker</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var worker = new SharedWorker('002.js');
+ worker.port.onmessage = this.step_func(function(e) {
+ assert_true(e.data);
+ this.done();
+ });
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/run-a-worker/002.js b/testing/web-platform/tests/workers/semantics/run-a-worker/002.js
new file mode 100644
index 0000000000..627272aaef
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/run-a-worker/002.js
@@ -0,0 +1,4 @@
+var passed = this === self;
+onconnect = function(e) {
+ e.ports[0].postMessage(passed);
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/run-a-worker/003.html b/testing/web-platform/tests/workers/semantics/run-a-worker/003.html
new file mode 100644
index 0000000000..e96c176f20
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/run-a-worker/003.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>handling for 404 response</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ const worker = new Worker('404_worker');
+ worker.onerror = e => t.done();
+}, 'worker');
+
+async_test(t => {
+ const shared = new SharedWorker('404_shared');
+ shared.onerror = e => t.done();
+}, 'shared');
+</script>
diff --git a/testing/web-platform/tests/workers/semantics/structured-clone/dedicated.html b/testing/web-platform/tests/workers/semantics/structured-clone/dedicated.html
new file mode 100644
index 0000000000..16b6be56f1
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/structured-clone/dedicated.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<title>structured clone to dedicated worker</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=/common/sab.js></script>
+<script src=/html/webappapis/structured-clone/structured-clone-battery-of-tests.js></script>
+<script src=/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js></script>
+<script src=/html/webappapis/structured-clone/structured-clone-battery-of-tests-harness.js></script>
+<div id=log></div>
+<script>
+ runStructuredCloneBatteryOfTests({
+ setup() {
+ const blob = new Blob([`
+ onmessage = ev => postMessage(ev.data, ev.data.transfer);
+ `], {type: 'text/javascript'});
+ this.blobURL = URL.createObjectURL(blob);
+ this.worker = new Worker(this.blobURL);
+ },
+ structuredClone(data, transfer) {
+ return new Promise(resolve => {
+ this.worker.addEventListener('message', function f(ev) {
+ this.worker.removeEventListener('message', f);
+ resolve(ev.data.data);
+ }.bind(this));
+ this.worker.postMessage({data, transfer}, transfer);
+ });
+ },
+ teardown() {
+ this.worker.terminate();
+ URL.revokeObjectURL(this.blobURL);
+ }
+ });
+</script>
diff --git a/testing/web-platform/tests/workers/semantics/structured-clone/shared.html b/testing/web-platform/tests/workers/semantics/structured-clone/shared.html
new file mode 100644
index 0000000000..eb85499fe2
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/structured-clone/shared.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<title>structured clone to shared worker</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=/common/sab.js></script>
+<script src=/html/webappapis/structured-clone/structured-clone-battery-of-tests.js></script>
+<script src=/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js></script>
+<script src=/html/webappapis/structured-clone/structured-clone-battery-of-tests-harness.js></script>
+<div id=log></div>
+<script>
+ runStructuredCloneBatteryOfTests({
+ setup() {
+ const blob = new Blob([`
+ onconnect = ev => {
+ const port = ev.ports[0];
+ port.onmessage = ev => port.postMessage(ev.data, ev.data.transfer);
+ };
+ `], {type: 'text/javascript'});
+ this.blobURL = URL.createObjectURL(blob);
+ this.worker = new SharedWorker(this.blobURL);
+ this.port = this.worker.port;
+ },
+ structuredClone(data, transfer) {
+ return new Promise(resolve => {
+ this.port.addEventListener('message', function f(ev) {
+ this.port.removeEventListener('message', f);
+ resolve(ev.data.data);
+ }.bind(this));
+ this.port.start();
+ this.port.postMessage({data, transfer}, transfer);
+ });
+ },
+ teardown() {
+ URL.revokeObjectURL(this.blobURL);
+ }
+ });
+</script>
diff --git a/testing/web-platform/tests/workers/semantics/xhr/001-1.xml b/testing/web-platform/tests/workers/semantics/xhr/001-1.xml
new file mode 100644
index 0000000000..5d735bdf61
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/xhr/001-1.xml
@@ -0,0 +1 @@
+<x>foo</x> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/xhr/001.html b/testing/web-platform/tests/workers/semantics/xhr/001.html
new file mode 100644
index 0000000000..da59f5ac2d
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/xhr/001.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<title>async XMLHttpRequest in dedicated worker</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+var t = async_test();
+function runtest() {
+ var worker = new Worker('001.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, '');
+ this.done();
+ });
+}
+</script>
+<iframe src=001-1.xml onload="t.step(runtest);"></iframe> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/xhr/001.js b/testing/web-platform/tests/workers/semantics/xhr/001.js
new file mode 100644
index 0000000000..1cbe98ba47
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/xhr/001.js
@@ -0,0 +1,13 @@
+var xhr = new XMLHttpRequest();
+var log = '';
+xhr.onreadystatechange = function(e) {
+ if (this.readyState == 4) {
+ if (this.responseXML != null)
+ log += 'responseXML was not null. ';
+ if (this.responseText != '<x>foo</x>')
+ log += 'responseText was ' + this.responseText + ', expected <x>foo</x>. ';
+ postMessage(log);
+ }
+}
+xhr.open('GET', '001-1.xml', true);
+xhr.send(); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/xhr/002.html b/testing/web-platform/tests/workers/semantics/xhr/002.html
new file mode 100644
index 0000000000..60c0e161cc
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/xhr/002.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<title>sync XMLHttpRequest in dedicated worker</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+var t = async_test();
+function runtest() {
+ var worker = new Worker('002.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, '');
+ this.done();
+ });
+}
+</script>
+<iframe src=001-1.xml onload="t.step(runtest);"></iframe> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/xhr/002.js b/testing/web-platform/tests/workers/semantics/xhr/002.js
new file mode 100644
index 0000000000..68d7e91d45
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/xhr/002.js
@@ -0,0 +1,9 @@
+var xhr = new XMLHttpRequest();
+var log = '';
+xhr.open('GET', '001-1.xml', false);
+xhr.send();
+if (xhr.responseXML != null)
+ log += 'responseXML was not null. ';
+if (xhr.responseText != '<x>foo</x>')
+ log += 'responseText was ' + this.responseText + ', expected <x>foo</x>. ';
+postMessage(log); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/xhr/003.html b/testing/web-platform/tests/workers/semantics/xhr/003.html
new file mode 100644
index 0000000000..e3ce36b82c
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/xhr/003.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<title>async XMLHttpRequest in shared worker</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+var t = async_test();
+function runtest() {
+ var worker = new SharedWorker('003.js', '');
+ worker.port.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, '');
+ this.done();
+ });
+}
+</script>
+<iframe src=001-1.xml onload="t.step(runtest);"></iframe>
diff --git a/testing/web-platform/tests/workers/semantics/xhr/003.js b/testing/web-platform/tests/workers/semantics/xhr/003.js
new file mode 100644
index 0000000000..1a9c5a7ee8
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/xhr/003.js
@@ -0,0 +1,17 @@
+onconnect = function(e) {
+ var xhr = new XMLHttpRequest();
+ var log = '';
+ var port = e.ports[0];
+ var postMessage = port.postMessage;
+ xhr.onreadystatechange = function(e) {
+ if (this.readyState == 4) {
+ if (this.responseXML != null)
+ log += 'responseXML was not null. ';
+ if (this.responseText && this.responseText != '<x>foo</x>')
+ log += 'responseText was ' + this.responseText + ', expected <x>foo</x>. ';
+ postMessage.call(port, log);
+ }
+ }
+ xhr.open('GET', '001-1.xml', true);
+ xhr.send();
+}
diff --git a/testing/web-platform/tests/workers/semantics/xhr/004.html b/testing/web-platform/tests/workers/semantics/xhr/004.html
new file mode 100644
index 0000000000..d11e3dbc1b
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/xhr/004.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<title>sync XMLHttpRequest in shared worker</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+var t = async_test();
+function runtest() {
+ var worker = new SharedWorker('004.js', '');
+ worker.port.onmessage = this.step_func(function(e) {
+ assert_equals(e.data, '');
+ this.done();
+ });
+}
+</script>
+<iframe src=001-1.xml onload="t.step(runtest);"></iframe>
diff --git a/testing/web-platform/tests/workers/semantics/xhr/004.js b/testing/web-platform/tests/workers/semantics/xhr/004.js
new file mode 100644
index 0000000000..1741c8d36a
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/xhr/004.js
@@ -0,0 +1,11 @@
+onconnect = function(e) {
+ var xhr = new XMLHttpRequest();
+ var log = '';
+ xhr.open('GET', '001-1.xml', false);
+ xhr.send();
+ if (xhr.responseXML != null)
+ log += 'responseXML was not null. ';
+ if (xhr.responseText != '<x>foo</x>')
+ log += 'responseText was ' + xhr.responseText + ', expected <x>foo</x>. ';
+ e.ports[0].postMessage(log);
+}
diff --git a/testing/web-platform/tests/workers/semantics/xhr/005.html b/testing/web-platform/tests/workers/semantics/xhr/005.html
new file mode 100644
index 0000000000..84abdb0c42
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/xhr/005.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<title>base url, dedicated worker</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+var t = async_test();
+var i = 0;
+function runtest() {
+ i++;
+ if (i != 2)
+ return;
+ var worker = new Worker('support/005-1.js');
+ worker.onmessage = this.step_func(function(e) {
+ assert_true(e.data);
+ this.done();
+ });
+}
+</script>
+<iframe src=001-1.xml onload="t.step(runtest);"></iframe>
+<iframe src=support/001-1.xml onload="t.step(runtest);"></iframe>
diff --git a/testing/web-platform/tests/workers/semantics/xhr/006.html b/testing/web-platform/tests/workers/semantics/xhr/006.html
new file mode 100644
index 0000000000..7411b4baef
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/xhr/006.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<title>base url, shared worker</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+var t = async_test();
+var i = 0;
+function runtest() {
+ i++;
+ if (i != 2)
+ return;
+ var worker = new SharedWorker('support/006-1.js','');
+ worker.port.onmessage = this.step_func(function(e) {
+ assert_true(e.data);
+ this.done();
+ });
+}
+</script>
+<iframe src=001-1.xml onload="t.step(runtest);"></iframe>
+<iframe src=support/001-1.xml onload="t.step(runtest);"></iframe>
diff --git a/testing/web-platform/tests/workers/semantics/xhr/support/001-1.xml b/testing/web-platform/tests/workers/semantics/xhr/support/001-1.xml
new file mode 100644
index 0000000000..ecea58a935
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/xhr/support/001-1.xml
@@ -0,0 +1 @@
+<x>bar</x> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/xhr/support/005-1.js b/testing/web-platform/tests/workers/semantics/xhr/support/005-1.js
new file mode 100644
index 0000000000..45f6519a21
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/xhr/support/005-1.js
@@ -0,0 +1,5 @@
+var xhr = new XMLHttpRequest();
+xhr.open('GET', '001-1.xml', false);
+xhr.send();
+var passed = xhr.responseText == '<x>bar</x>';
+postMessage(passed); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/semantics/xhr/support/006-1.js b/testing/web-platform/tests/workers/semantics/xhr/support/006-1.js
new file mode 100644
index 0000000000..d446781eb7
--- /dev/null
+++ b/testing/web-platform/tests/workers/semantics/xhr/support/006-1.js
@@ -0,0 +1,7 @@
+onconnect = function(e) {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', '001-1.xml', false);
+ xhr.send();
+ var passed = xhr.responseText == '<x>bar</x>';
+ e.ports[0].postMessage(passed);
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/shared-worker-from-blob-url.window.js b/testing/web-platform/tests/workers/shared-worker-from-blob-url.window.js
new file mode 100644
index 0000000000..98e34cc3a6
--- /dev/null
+++ b/testing/web-platform/tests/workers/shared-worker-from-blob-url.window.js
@@ -0,0 +1,53 @@
+function message_from_port(port) {
+ return new Promise(resolve => {
+ port.onmessage = e => resolve(e.data);
+ });
+}
+
+promise_test(async t => {
+ const run_result = 'worker_OK_';
+ const blob_contents =
+ 'self.counter = 0; self.onconnect = e => {++self.counter;' +
+ 'e.source.postMessage("' + run_result + '" + self.counter); };';
+ const blob = new Blob([blob_contents]);
+ const url = URL.createObjectURL(blob);
+
+ const worker1 = new SharedWorker(url);
+ const reply1 = await message_from_port(worker1.port);
+ assert_equals(reply1, run_result + '1');
+ const worker2 = new SharedWorker(url);
+ const reply2 = await message_from_port(worker2.port);
+ assert_equals(reply2, run_result + '2');
+}, 'Creating a shared worker from a blob URL works.');
+
+promise_test(async t => {
+ const run_result = 'worker_OK';
+ const blob_contents =
+ 'self.onconnect = e => { e.source.postMessage("' + run_result + '"); };';
+ const blob = new Blob([blob_contents]);
+ const url = URL.createObjectURL(blob);
+
+ const worker = new SharedWorker(url);
+ URL.revokeObjectURL(url);
+
+ const reply = await message_from_port(worker.port);
+ assert_equals(reply, run_result);
+}, 'Creating a shared worker from a blob URL works immediately before revoking.');
+
+promise_test(async t => {
+ const run_result = 'worker_OK_';
+ const blob_contents =
+ 'self.counter = 0; self.onconnect = e => {++self.counter;' +
+ 'e.source.postMessage("' + run_result + '" + self.counter); };';
+ const blob = new Blob([blob_contents]);
+ const url = URL.createObjectURL(blob);
+
+ const worker1 = new SharedWorker(url);
+ URL.revokeObjectURL(url);
+
+ const reply1 = await message_from_port(worker1.port);
+ assert_equals(reply1, run_result + '1');
+ const worker2 = new SharedWorker(url);
+ const reply2 = await message_from_port(worker2.port);
+ assert_equals(reply2, run_result + '2');
+}, 'Connecting to a shared worker on a revoked blob URL works.');
diff --git a/testing/web-platform/tests/workers/shared-worker-in-data-url-context.window.js b/testing/web-platform/tests/workers/shared-worker-in-data-url-context.window.js
new file mode 100644
index 0000000000..b768c815d0
--- /dev/null
+++ b/testing/web-platform/tests/workers/shared-worker-in-data-url-context.window.js
@@ -0,0 +1,65 @@
+// META: title=data URL shared worker in data URL context
+// META: script=/service-workers/service-worker/resources/test-helpers.sub.js
+const mimeType = 'application/javascript';
+
+// Tests creating a data URL shared worker in a data URL iframe.
+promise_test(async t => {
+ const nestedWorkerScriptURL =
+ new URL('/workers/support/post-message-on-load-worker.js', location.href);
+
+ // This code will be executed in a data URL iframe. The iframe tries to create
+ // a shared worker from |nestedWorkerScriptURL|, but that should result in a
+ // failure. This is because the data URL iframe has an opaque origin, and
+ // script fetch is handled as a cross-origin request.
+ const frameCode = `
+ <script>
+ try {
+ const worker = new SharedWorker('${nestedWorkerScriptURL}');
+ worker.port.onmessage = e => {
+ window.parent.postMessage(
+ 'SharedWorker construction unexpectedly succeeded', '*');
+ };
+ worker.onerror = e => window.parent.postMessage('PASS', '*');
+ } catch (e) {
+ // Cross-origin request should asynchronously fail during worker script
+ // fetch because its request mode is 'same-origin'.
+ window.parent.postMessage(
+ 'SharedWorker construction unexpectedly synchronously failed', '*');
+ }
+ </script>
+ `;
+
+ const p = new Promise(r => window.onmessage = e => r(e.data));
+ const frame = await with_iframe(`data:text/html;base64,${btoa(frameCode)}`);
+ const result = await p;
+ assert_equals(result, 'PASS');
+}, 'Create a shared worker in a data url frame');
+
+// Tests creating a data URL shared worker in a data URL iframe.
+promise_test(async t => {
+ const workerCode = `onconnect = e => e.ports[0].postMessage("PASS");`;
+
+ // This code will be executed in a data URL iframe. The iframe tries to create
+ // a data URL shared worker. Fetching a data URL from the data URL shared
+ // worker is allowed, so the worker construction should succeed. The worker
+ // posts the result to the parent frame.
+ const frameCode = `
+ <script>
+ try {
+ const worker = new SharedWorker('data:${mimeType},${workerCode};');
+ worker.port.onmessage = e => window.parent.postMessage(e.data, '*');
+ worker.onerror = e => {
+ window.parent.postMessage('FAIL: ' + e.message, '*');
+ };
+ } catch (e) {
+ window.parent.postMessage(
+ 'SharedWorker construction unexpectedly synchronously failed', '*');
+ }
+ </script>
+ `;
+
+ const p = new Promise(r => window.onmessage = e => r(e.data));
+ const frame = await with_iframe(`data:text/html;base64,${btoa(frameCode)}`);
+ const result = await p;
+ assert_equals(result, 'PASS');
+}, 'Create a data url shared worker in a data url frame');
diff --git a/testing/web-platform/tests/workers/shared-worker-name-via-options.html b/testing/web-platform/tests/workers/shared-worker-name-via-options.html
new file mode 100644
index 0000000000..1914d66db7
--- /dev/null
+++ b/testing/web-platform/tests/workers/shared-worker-name-via-options.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test the name property of shared workers mixing constructor options and constructor strings</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#concept-workerglobalscope-name">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-sharedworker">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-sharedworkerglobalscope-name">
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+"use strict";
+setup({ single_test: true });
+
+const name = "my name";
+
+const worker1 = new SharedWorker("support/shared-name.js", { name });
+worker1.port.onmessage = receiveMessage;
+
+const worker2 = new SharedWorker("support/shared-name.js", { name });
+worker2.port.onmessage = receiveMessage;
+
+const worker3 = new SharedWorker("support/shared-name.js", name);
+worker3.port.onmessage = receiveMessage;
+
+let nextCounterExpected = 1;
+function receiveMessage(e) {
+ const { counter, name: receivedName } = e.data;
+
+ assert_equals(receivedName, name);
+ assert_equals(counter, nextCounterExpected);
+
+ ++nextCounterExpected;
+ if (nextCounterExpected === 4) {
+ done();
+ }
+}
+</script>
diff --git a/testing/web-platform/tests/workers/shared-worker-options-mismatch.html b/testing/web-platform/tests/workers/shared-worker-options-mismatch.html
new file mode 100644
index 0000000000..604f69a436
--- /dev/null
+++ b/testing/web-platform/tests/workers/shared-worker-options-mismatch.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<title>SharedWorker: type or credentials mismatch failure</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+const mismatch_test = (testName, firstOptions, secondOptions) => {
+ promise_test(async () => {
+ firstOptions.name = testName;
+ secondOptions.name = testName;
+ const scriptURL = 'support/empty-worker.js';
+ const firstWorker = new SharedWorker(scriptURL, firstOptions);
+ const secondWorker = new SharedWorker(scriptURL, secondOptions);
+ return new Promise(resolve => secondWorker.onerror = resolve);
+ }, 'Connecting to shared worker with different options should be blocked: '
+ + testName);
+};
+
+// Tests different type.
+mismatch_test('default to module', {}, { type: 'module' });
+mismatch_test('module to default', { type: 'module' }, {});
+mismatch_test('classic to module', { type: 'classic' }, { type: 'module' });
+mismatch_test('module to classic', { type: 'module' }, { type: 'classic' });
+
+// Tests different credentials in classic and module.
+['classic', 'module'].forEach(type => {
+ mismatch_test('default to omit in ' + type,
+ { type },
+ { type, credentials: 'omit' });
+ mismatch_test('default to include in ' + type,
+ { type },
+ { type, credentials: 'include' });
+ mismatch_test('omit to default in ' + type,
+ { type, credentials: 'omit' },
+ { type });
+ mismatch_test('omit to same-origin in ' + type,
+ { type, credentials: 'omit' },
+ { type, credentials: 'same-origin' });
+ mismatch_test('omit to include in ' + type,
+ { type, credentials: 'omit' },
+ { type, credentials: 'include' });
+ mismatch_test('same-origin to omit in ' + type,
+ { type, credentials: 'same-origin'},
+ { type, credentials: 'omit' });
+ mismatch_test('same-origin to include in ' + type,
+ { type, credentials: 'same-origin'},
+ { type, credentials: 'include' });
+ mismatch_test('include to default in ' + type,
+ { type, credentials: 'include' },
+ { type });
+ mismatch_test('include to omit in ' + type,
+ { type, credentials: 'include' },
+ { type, credentials: 'omit' });
+ mismatch_test('include to same-origin in ' + type,
+ { type, credentials: 'include' },
+ { type, credentials: 'same-origin' });
+});
+
+</script>
diff --git a/testing/web-platform/tests/workers/shared-worker-parse-error-failure.html b/testing/web-platform/tests/workers/shared-worker-parse-error-failure.html
new file mode 100644
index 0000000000..3f1b4c5d85
--- /dev/null
+++ b/testing/web-platform/tests/workers/shared-worker-parse-error-failure.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<title>SharedWorker: parse error failure</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/check-error-arguments.js"></script>
+<script>
+
+promise_test(async () => {
+ const scriptURL = 'modules/resources/syntax-error.js';
+ const worker = new SharedWorker(scriptURL, { type: 'classic' });
+ const args = await new Promise(resolve =>
+ worker.onerror = (...args) => resolve(args));
+ window.checkErrorArguments(args);
+}, 'Classic shared worker construction for script with syntax error should ' +
+ 'dispatch an event named error.');
+
+promise_test(async () => {
+ const scriptURL = 'modules/resources/static-import-worker.js';
+ const worker = new SharedWorker(scriptURL, { type: 'classic' });
+ const args = await new Promise(resolve =>
+ worker.onerror = (...args) => resolve(args));
+ window.checkErrorArguments(args);
+}, 'Static import on classic shared worker should dispatch an event named ' +
+ 'error.');
+
+</script>
diff --git a/testing/web-platform/tests/workers/shared-worker-partitioned-cookies.tentative.https.html b/testing/web-platform/tests/workers/shared-worker-partitioned-cookies.tentative.https.html
new file mode 100644
index 0000000000..f17a964497
--- /dev/null
+++ b/testing/web-platform/tests/workers/shared-worker-partitioned-cookies.tentative.https.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8"/>
+<meta name="timeout" content="long">
+<title>SharedWorker: Partitioned Cookies</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/test-helpers.sub.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="support/shared-worker-partitioned-cookies-helper.js"></script>
+</head>
+
+<body>
+<script>
+
+promise_test(async () => {
+ // Set a Partitioned cookie.
+ document.cookie =
+ '__Host-partitioned=123; Secure; Path=/; SameSite=None; Partitioned;';
+ assert_true(document.cookie.includes('__Host-partitioned=123'));
+
+ // Set an unpartitioned cookie.
+ document.cookie = 'unpartitioned=456; Secure; Path=/; SameSite=None;';
+ assert_true(document.cookie.includes('unpartitioned=456'));
+
+ const worker = new SharedWorker('support/shared-worker-echo-cookies.js');
+ const next_message = worker_message_generator(worker);
+
+ worker.port.postMessage({type: 'test_message'});
+ const msg1 = await next_message();
+ assert_true(msg1.ok, 'Message passing');
+
+ worker.port.postMessage({type: 'echo_cookies_http'});
+ const msg2 = await next_message();
+ assert_true(msg2.ok, 'Get cookies');
+ assert_true(
+ msg2.cookies.includes('__Host-partitioned'),
+ 'Can access partitioned cookie via HTTP');
+ assert_true(
+ msg2.cookies.includes('unpartitioned'),
+ 'Can access unpartitioned cookie via HTTP');
+
+ worker.port.postMessage({type: 'echo_cookies_import'});
+ const msg3 = await next_message();
+ assert_true(msg3.ok, 'Get cookies');
+ assert_true(msg3.cookies.includes(
+ '__Host-partitioned'),
+ 'Can access partitioned cookie via importScripts');
+ assert_true(
+ msg3.cookies.includes('unpartitioned'),
+ 'Can access unpartitioned cookie via importScripts');
+
+ const popup = window.open(
+ new URL(
+ `./support/shared-worker-partitioned-cookies-3p-window.html?origin=${
+ encodeURIComponent(self.location.origin)}`,
+ get_host_info().HTTPS_NOTSAMESITE_ORIGIN + self.location.pathname));
+ await fetch_tests_from_window(popup);
+});
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/workers/shared-worker-partitioned.tentative.html b/testing/web-platform/tests/workers/shared-worker-partitioned.tentative.html
new file mode 100644
index 0000000000..0be8479fa9
--- /dev/null
+++ b/testing/web-platform/tests/workers/shared-worker-partitioned.tentative.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test partitioning of shared workers</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+
+<body>
+<script>
+async function onload() {
+ const worker = new SharedWorker("support/shared-name.js");
+
+ let e = await new Promise((r) => {worker.port.onmessage = r});
+ assert_equals(e.data.counter, 1);
+
+ const third_party_url = new URL(
+ 'support/window-sw-shared-name.html',
+ get_host_info().HTTP_NOTSAMESITE_ORIGIN + self.location.pathname);
+
+ third_party_window = window.open(third_party_url);
+
+ e = await new Promise((r) => {window.onmessage = r});
+ assert_equals(e.data.counter, 1);
+
+ third_party_window.close();
+}
+
+promise_test(onload);
+</script>
+</body> \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/support/ErrorEvent-error.js b/testing/web-platform/tests/workers/support/ErrorEvent-error.js
new file mode 100644
index 0000000000..930b54c0d5
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/ErrorEvent-error.js
@@ -0,0 +1,9 @@
+onerror = function(message, location, line, col, error) {
+ postMessage({ source: "onerror", value: error });
+}
+
+addEventListener("error", function(e) {
+ postMessage({ source: "event listener", value: e.error });
+});
+
+throw "hello";
diff --git a/testing/web-platform/tests/workers/support/ErrorEvent.js b/testing/web-platform/tests/workers/support/ErrorEvent.js
new file mode 100644
index 0000000000..22ea6d4fb5
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/ErrorEvent.js
@@ -0,0 +1,10 @@
+onmessage = function(evt)
+{
+ throw(new Error(evt.data));
+}
+
+onerror = function(message, location, line, col)
+{
+ postMessage( {"message": message, "filename": location, "lineno": line, "colno": col} );
+ return false; // "not handled" so the error propagates up to the Worker object
+}
diff --git a/testing/web-platform/tests/workers/support/ImportScripts.js b/testing/web-platform/tests/workers/support/ImportScripts.js
new file mode 100644
index 0000000000..7f2a2bcb55
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/ImportScripts.js
@@ -0,0 +1,9 @@
+try
+{
+ importScripts("WorkerBasic.js");
+}
+catch(ex)
+{
+ result = "Fail";
+ postMessage(result);
+}
diff --git a/testing/web-platform/tests/workers/support/ImportScriptsNetworkErr.js b/testing/web-platform/tests/workers/support/ImportScriptsNetworkErr.js
new file mode 100644
index 0000000000..8179c8b100
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/ImportScriptsNetworkErr.js
@@ -0,0 +1,15 @@
+var result = "Fail";
+
+try
+{
+ importScripts("NonExistentFile.js");
+}
+catch(ex)
+{
+ if (ex.code != null && ex.code == ex.NETWORK_ERR)
+ {
+ result = "Pass";
+ }
+}
+
+postMessage(result); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/support/ImportScriptsNosniffErr.js b/testing/web-platform/tests/workers/support/ImportScriptsNosniffErr.js
new file mode 100644
index 0000000000..22dc9c1ba5
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/ImportScriptsNosniffErr.js
@@ -0,0 +1,9 @@
+importScripts('/resources/testharness.js');
+
+test(t => {
+ assert_throws_dom('NetworkError', () => {
+ importScripts("nosiniff-error-worker.py");
+ });
+}, "importScripts throws on 'nosniff' violation");
+
+done();
diff --git a/testing/web-platform/tests/workers/support/SharedWorker-common.js b/testing/web-platform/tests/workers/support/SharedWorker-common.js
new file mode 100644
index 0000000000..1c1dac3971
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/SharedWorker-common.js
@@ -0,0 +1,32 @@
+function generateError()
+{
+ // Generate an exception by accessing an undefined variable.
+ foo.bar = 0;
+}
+
+onconnect = function(event) {
+ event.ports[0].onmessage = function(evt) { handleMessage(evt, event.ports[0]); };
+};
+
+function handleMessage(event, port) {
+ self.port = port;
+ if (event.data == "ping")
+ port.postMessage("PASS: Received ping message");
+ else if (event.data == "close")
+ close();
+ else if (event.data == "done")
+ port.postMessage("DONE");
+ else if (event.data == "throw")
+ generateError();
+ else if (event.data == "testingNameAttribute")
+ port.postMessage(self.name);
+ else if (/eval.+/.test(event.data)) {
+ try {
+ port.postMessage(event.data.substr(5) + ": " + eval(event.data.substr(5)));
+ } catch (ex) {
+ port.postMessage(event.data.substr(5) + ": " + ex);
+ }
+ }
+ else
+ port.postMessage("FAILURE: Received unknown message: " + event.data);
+}
diff --git a/testing/web-platform/tests/workers/support/SharedWorker-create-common.js b/testing/web-platform/tests/workers/support/SharedWorker-create-common.js
new file mode 100644
index 0000000000..1d06174f12
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/SharedWorker-create-common.js
@@ -0,0 +1,8 @@
+// Make a SharedWorker that has the same external interface as a DedicatedWorker, to use in shared test code.
+function createWorker()
+{
+ var worker = new SharedWorker('support/SharedWorker-common.js', 'name');
+ worker.port.onmessage = function(evt) { worker.onmessage(evt); };
+ worker.postMessage = function(msg, port) { worker.port.postMessage(msg, port); };
+ return worker;
+}
diff --git a/testing/web-platform/tests/workers/support/SharedWorker-script-error.js b/testing/web-platform/tests/workers/support/SharedWorker-script-error.js
new file mode 100644
index 0000000000..0e78949d97
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/SharedWorker-script-error.js
@@ -0,0 +1,22 @@
+onconnect = function(event) {
+ event.ports[0].onmessage = function(evt) { handleMessage(evt, event.ports[0]); };
+};
+
+function handleMessage(event, port) {
+ if (event.data == "unhandledError") {
+ // Generate an unhandled error.
+ onerror = null;
+ setTimeout(function() {
+ port.postMessage("SUCCESS: unhandled error generated");
+ }, 100);
+ generateError(); // Undefined function call
+ } else if (event.data == "handledError") {
+ onerror = function() {
+ port.postMessage("SUCCESS: error handled via onerror");
+ return true;
+ };
+ generateError(); // Undefined function call
+ } else {
+ port.postMessage("FAIL: Got unexpected message: " + event.data);
+ }
+};
diff --git a/testing/web-platform/tests/workers/support/Timer.js b/testing/web-platform/tests/workers/support/Timer.js
new file mode 100644
index 0000000000..a86a224dbb
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/Timer.js
@@ -0,0 +1,50 @@
+var count = 0;
+var id;
+
+onmessage = function(evt)
+{
+ try
+ {
+ switch(evt.data)
+ {
+ case "TimeoutHandler":
+ count = 0;
+ id = setTimeout("TimeoutHandler()", 10);
+ postMessage('hello');
+ break;
+ case "IntervalHandler":
+ count = 0;
+ id = setInterval("IntervalHandler()", 10);
+ postMessage('hello');
+ break;
+ }
+ }
+ catch(ex)
+ {
+ postMessage("Fail");
+ }
+}
+
+function TimeoutHandler()
+{
+ count++;
+ postMessage("worker");
+
+ id = setTimeout("TimeoutHandler()", 10);
+
+ if (count >= 2)
+ {
+ clearTimeout(id);
+ }
+}
+
+function IntervalHandler()
+{
+ count++;
+ postMessage("worker");
+
+ if (count >= 2)
+ {
+ clearInterval(id);
+ }
+}
diff --git a/testing/web-platform/tests/workers/support/Worker-common.js b/testing/web-platform/tests/workers/support/Worker-common.js
new file mode 100644
index 0000000000..55188fe913
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/Worker-common.js
@@ -0,0 +1,16 @@
+onmessage = function(evt)
+{
+ if (evt.data == "ping")
+ postMessage("pong");
+ else if (evt.data == "freeze")
+ while (1) {}
+ else if (evt.data == "close")
+ close();
+ else if (/eval.+/.test(evt.data)) {
+ try {
+ postMessage(evt.data.substr(5) + ": " + eval(evt.data.substr(5)));
+ } catch (ex) {
+ postMessage(evt.data.substr(5) + ": " + ex);
+ }
+ }
+}
diff --git a/testing/web-platform/tests/workers/support/Worker-create-common.js b/testing/web-platform/tests/workers/support/Worker-create-common.js
new file mode 100644
index 0000000000..f0b8efe46b
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/Worker-create-common.js
@@ -0,0 +1,4 @@
+function createWorker()
+{
+ return new Worker('support/Worker-common.js');
+}
diff --git a/testing/web-platform/tests/workers/support/Worker-messageport.js b/testing/web-platform/tests/workers/support/Worker-messageport.js
new file mode 100644
index 0000000000..1e01b0a52b
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/Worker-messageport.js
@@ -0,0 +1,40 @@
+onmessage = function(evt) {
+ if (evt.data == "port") {
+ if (evt.ports) {
+ postMessage("PASS: Received message port");
+ evt.ports[0].onmessage = pingBack;
+ evt.ports[0].start();
+ } else {
+ postMessage("FAIL: Did not receive expected MessagePort");
+ }
+ } else if (evt.data == "noport") {
+ if (!evt.ports || evt.ports.length) {
+ postMessage("FAIL: Received message port or null ports array");
+ } else {
+ postMessage("PASS: evt.ports = [] as expected");
+ }
+ } else if (evt.data == "spam") {
+ for (var i = 0 ; i < 1000 ; i++) {
+ evt.ports[0].postMessage(i);
+ }
+ postMessage("spamDone");
+ } else if (evt.data == "getport") {
+ var channel = new MessageChannel();
+ postMessage("port", [channel.port1]);
+ channel.port2.onmessage = pingBack;
+ channel.port2.start();
+ } else {
+ postMessage("Unknown message:" + evt.data);
+ }
+
+}
+
+function pingBack(evt) {
+ // Make sure we got the expected data and send a return message over
+ // the port.
+ if (evt.data == "ping") {
+ evt.target.postMessage("pong");
+ } else {
+ postMessage("FAIL: unknown message: " + evt.data);
+ }
+}
diff --git a/testing/web-platform/tests/workers/support/Worker-run-forever-during-dynamic-import.js b/testing/web-platform/tests/workers/support/Worker-run-forever-during-dynamic-import.js
new file mode 100644
index 0000000000..62840bd5b4
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/Worker-run-forever-during-dynamic-import.js
@@ -0,0 +1,3 @@
+import('./Worker-run-forever.js')
+ .then(r => postMessage('resolved: ' + r))
+ .catch(e => postMessage('rejected: ' + e));
diff --git a/testing/web-platform/tests/workers/support/Worker-run-forever-during-importScripts.js b/testing/web-platform/tests/workers/support/Worker-run-forever-during-importScripts.js
new file mode 100644
index 0000000000..6a3083f382
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/Worker-run-forever-during-importScripts.js
@@ -0,0 +1,4 @@
+importScripts('Worker-run-forever.js');
+
+// This is not expected to run.
+postMessage('after importScripts()');
diff --git a/testing/web-platform/tests/workers/support/Worker-run-forever-during-nested-importScripts.js b/testing/web-platform/tests/workers/support/Worker-run-forever-during-nested-importScripts.js
new file mode 100644
index 0000000000..aae86a0b05
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/Worker-run-forever-during-nested-importScripts.js
@@ -0,0 +1 @@
+importScripts('Worker-run-forever-during-importScripts.js');
diff --git a/testing/web-platform/tests/workers/support/Worker-run-forever-during-top-level-await.js b/testing/web-platform/tests/workers/support/Worker-run-forever-during-top-level-await.js
new file mode 100644
index 0000000000..a1c8b32b61
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/Worker-run-forever-during-top-level-await.js
@@ -0,0 +1,4 @@
+await 1;
+postMessage('start');
+onerror = () => postMessage('onerror');
+while(1);
diff --git a/testing/web-platform/tests/workers/support/Worker-run-forever.js b/testing/web-platform/tests/workers/support/Worker-run-forever.js
new file mode 100644
index 0000000000..2d822d407f
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/Worker-run-forever.js
@@ -0,0 +1,3 @@
+postMessage('start');
+onerror = () => postMessage('onerror');
+while(1);
diff --git a/testing/web-platform/tests/workers/support/Worker-structure-message.js b/testing/web-platform/tests/workers/support/Worker-structure-message.js
new file mode 100644
index 0000000000..81cd98243b
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/Worker-structure-message.js
@@ -0,0 +1,15 @@
+self.onmessage = function(evt) {
+ if (evt.data.operation == 'find-edges' &&
+ ArrayBuffer.prototype.isPrototypeOf(evt.data.input) &&
+ evt.data.input.byteLength == 20 &&
+ evt.data.threshold == 0.6) {
+ self.postMessage("PASS: Worker receives correct structure message.");
+ self.postMessage({
+ operation: evt.data.operation,
+ input: evt.data.input,
+ threshold: evt.data.threshold
+ });
+ }
+ else
+ self.postMessage("FAIL: Worker receives error structure message.");
+}
diff --git a/testing/web-platform/tests/workers/support/Worker-termination-with-port-messages.js b/testing/web-platform/tests/workers/support/Worker-termination-with-port-messages.js
new file mode 100644
index 0000000000..a827db357e
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/Worker-termination-with-port-messages.js
@@ -0,0 +1,10 @@
+function echo(evt)
+{
+ evt.target.postMessage(evt.data);
+}
+
+onmessage = function(evt)
+{
+ evt.ports[0].onmessage = echo;
+ evt.ports[0].start();
+}
diff --git a/testing/web-platform/tests/workers/support/Worker-thread-multi-port.js b/testing/web-platform/tests/workers/support/Worker-thread-multi-port.js
new file mode 100644
index 0000000000..2ce7cae596
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/Worker-thread-multi-port.js
@@ -0,0 +1,43 @@
+onmessage = function(event) {
+ if (event.data == "noport") {
+ if (event.ports && !event.ports.length)
+ testPassed("event.ports is non-null and zero length when no port sent");
+ else
+ testFailed("event.ports is null or non-zero length when no port sent");
+ } else if (event.data == "zero ports") {
+ if (event.ports && !event.ports.length)
+ testPassed("event.ports is non-null and zero length when empty array sent");
+ else
+ testFailed("event.ports is null or non-zero length when empty array sent");
+ } else if (event.data == "two ports") {
+ if (!event.ports) {
+ testFailed("event.ports should be non-null when ports sent");
+ return;
+ }
+ if (event.ports.length == 2)
+ testPassed("event.ports contains two ports when two ports sent");
+ else
+ testFailed("event.ports contained " + event.ports.length + " when two ports sent");
+ } else if (event.data == "failed ports") {
+ if (event.ports.length == 2)
+ testPassed("event.ports contains two ports when two ports re-sent after error");
+ else
+ testFailed("event.ports contained " + event.ports.length + " when two ports re-sent after error");
+ } else if (event.data == "noargs") {
+ try {
+ postMessage();
+ testFailed("postMessage() did not throw");
+ } catch (e) {
+ testPassed("postMessage() threw exception: " + e);
+ }
+ } else
+ testFailed("Received unexpected message: " + event.data);
+};
+
+function testPassed(msg) {
+ postMessage("PASS"+msg);
+}
+
+function testFailed(msg) {
+ postMessage("FAIL"+msg);
+}
diff --git a/testing/web-platform/tests/workers/support/Worker-timeout-cancel-order.js b/testing/web-platform/tests/workers/support/Worker-timeout-cancel-order.js
new file mode 100644
index 0000000000..afc66cf6a0
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/Worker-timeout-cancel-order.js
@@ -0,0 +1,7 @@
+// The test will create 2 timeouts and cancel the first one. If only the second
+// timeout executes then the test passes.
+self.addEventListener('message', function(e) {
+ var t1 = setTimeout(function () { postMessage(1); }, 5);
+ setTimeout(function () { postMessage(2); }, 10);
+ clearTimeout(t1);
+}, false);
diff --git a/testing/web-platform/tests/workers/support/Worker-timeout-decreasing-order.js b/testing/web-platform/tests/workers/support/Worker-timeout-decreasing-order.js
new file mode 100644
index 0000000000..b93dd5dc77
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/Worker-timeout-decreasing-order.js
@@ -0,0 +1,7 @@
+// The test will create 3 timeouts with their intervals decreasing.
+// If the timeouts execute in order then the test is PASS.
+self.addEventListener('message', function(e) {
+ setTimeout(function () { postMessage(3); }, 15);
+ setTimeout(function () { postMessage(2); }, 10);
+ setTimeout(function () { postMessage(1); }, 5);
+}, false);
diff --git a/testing/web-platform/tests/workers/support/Worker-timeout-increasing-order.js b/testing/web-platform/tests/workers/support/Worker-timeout-increasing-order.js
new file mode 100644
index 0000000000..42f81daa29
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/Worker-timeout-increasing-order.js
@@ -0,0 +1,7 @@
+// The test will create 3 timeouts with their intervals increasing.
+// If the timeouts execute in order then the test is PASS.
+self.addEventListener('message', function(e) {
+ setTimeout(function () { postMessage(1); }, 5);
+ setTimeout(function () { postMessage(2); }, 10);
+ setTimeout(function () { postMessage(3); }, 15);
+}, false);
diff --git a/testing/web-platform/tests/workers/support/WorkerBasic.js b/testing/web-platform/tests/workers/support/WorkerBasic.js
new file mode 100644
index 0000000000..6bb6d32b14
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/WorkerBasic.js
@@ -0,0 +1,7 @@
+var result = "Fail";
+
+onmessage = function(evt)
+{
+ result = "Pass";
+ postMessage(result);
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/support/WorkerClose.js b/testing/web-platform/tests/workers/support/WorkerClose.js
new file mode 100644
index 0000000000..81f99993d8
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/WorkerClose.js
@@ -0,0 +1,5 @@
+onmessage = function(evt)
+{
+ postMessage(evt.data);
+ self.close();
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/support/WorkerDataCloneErr.js b/testing/web-platform/tests/workers/support/WorkerDataCloneErr.js
new file mode 100644
index 0000000000..b7e8b0ae16
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/WorkerDataCloneErr.js
@@ -0,0 +1,15 @@
+var result = "Fail";
+
+try
+{
+ postMessage(navigator);
+}
+catch(ex)
+{
+ if(ex.code != null && ex.code == ex.DATA_CLONE_ERR)
+ {
+ result = "Pass";
+ }
+}
+
+postMessage(result); \ No newline at end of file
diff --git a/testing/web-platform/tests/workers/support/WorkerFetchURL.js b/testing/web-platform/tests/workers/support/WorkerFetchURL.js
new file mode 100644
index 0000000000..4ad700bcce
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/WorkerFetchURL.js
@@ -0,0 +1,8 @@
+onconnect = e => {
+ let port = e.ports[0];
+ port.onmessage = (e) => {
+ fetch(e.data)
+ .then(response => response.text())
+ .then(text => port.postMessage('Worker reply:' + text));
+ };
+}
diff --git a/testing/web-platform/tests/workers/support/WorkerGlobalScope-close.js b/testing/web-platform/tests/workers/support/WorkerGlobalScope-close.js
new file mode 100644
index 0000000000..e2b1c0a2fd
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/WorkerGlobalScope-close.js
@@ -0,0 +1,43 @@
+// Check to see if the worker handles pending events. Messages after close() will not be sent to the parent page, so we use exceptions instead to report failures after close().
+onmessage = function(evt)
+{
+ if (evt.data == "closeWithPendingEvents") {
+ // Set a timer to generate an event - minimum timeout is 1ms.
+ setTimeout(function() {
+ postMessage("pending event processed");
+ throw "should not be executed";
+ }, 1);
+ var start = new Date().getTime();
+ // Loop for 10 ms so the timer is ready to fire
+ while (new Date().getTime() - start < 100)
+ ;
+ // Now close - timer should not fire
+ close();
+ } else if (evt.data == "typeofClose") {
+ postMessage("typeof close: " + (typeof close));
+ } else if (evt.data == "close") {
+ close();
+ postMessage("Should be delivered");
+ } else if (evt.data == "ping") {
+ postMessage("pong");
+ } else if (evt.data == "throw") {
+ throw "should never be executed";
+ } else if (evt.data == "closeWithError") {
+ close();
+ nonExistentFunction(); // Undefined function - throws exception
+ } else if (evt.data == "close_post_loop") {
+ close();
+ postMessage("closed");
+ while(true) {} // Should loop forever.
+ } else if (evt.data == "take_port") {
+ messagePort = evt.ports[0];
+ messagePort.onmessage = function(event) {
+ close();
+ postMessage("echo_" + event.data);
+ }
+ } else if (evt.data == "start_port") {
+ messagePort.start();
+ } else {
+ postMessage("FAIL: Unknown message type: " + evt.data);
+ }
+}
diff --git a/testing/web-platform/tests/workers/support/WorkerLocation-origin.html b/testing/web-platform/tests/workers/support/WorkerLocation-origin.html
new file mode 100644
index 0000000000..3d948030a7
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/WorkerLocation-origin.html
@@ -0,0 +1,6 @@
+<script>
+const w = new Worker("./WorkerLocation.js");
+w.onmessage = e => {
+ parent.postMessage(e.data, "*");
+}
+</script>
diff --git a/testing/web-platform/tests/workers/support/WorkerLocation.js b/testing/web-platform/tests/workers/support/WorkerLocation.js
new file mode 100644
index 0000000000..901e21542a
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/WorkerLocation.js
@@ -0,0 +1,13 @@
+var obj = new Object();
+obj.location = location.toString();
+obj.href = location.href;
+obj.origin = location.origin;
+obj.protocol = location.protocol;
+obj.host = location.host;
+obj.hostname = location.hostname;
+obj.port = location.port;
+obj.pathname = location.pathname;
+obj.search = location.search;
+obj.hash = location.hash;
+
+postMessage(obj);
diff --git a/testing/web-platform/tests/workers/support/WorkerNavigator.js b/testing/web-platform/tests/workers/support/WorkerNavigator.js
new file mode 100644
index 0000000000..76834e16c7
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/WorkerNavigator.js
@@ -0,0 +1,27 @@
+(async () => {
+ const obj = new Object();
+ obj.appName = navigator.appName;
+ obj.appVersion = navigator.appVersion;
+ obj.platform = navigator.platform;
+ obj.userAgent = navigator.userAgent;
+ obj.onLine = navigator.onLine;
+ if (navigator.userAgentData) {
+ obj.brands = navigator.userAgentData.brands;
+ obj.mobile = navigator.userAgentData.mobile;
+ obj.platform = navigator.userAgentData.platform;
+ const highEntropyValues = await navigator.userAgentData.getHighEntropyValues([
+ "architecture", "bitness", "fullVersionList", "model",
+ "platformVersion", "uaFullVersion", "wow64", "formFactor",
+ ]);
+ obj.architecture = highEntropyValues.architecture;
+ obj.bitness = highEntropyValues.bitness;
+ obj.fullVersionList = highEntropyValues.fullVersionList;
+ obj.model = highEntropyValues.model;
+ obj.platformVersion = highEntropyValues.platformVersion;
+ obj.uaFullVersion = highEntropyValues.uaFullVersion;
+ obj.wow64 = highEntropyValues.wow64;
+ obj.formFactor = highEntropyValues.formFactor;
+ obj.NavigatorUADataExposed = (typeof self.NavigatorUAData != "undefined");
+ }
+ postMessage(obj);
+})();
diff --git a/testing/web-platform/tests/workers/support/WorkerSendingPerformanceNow.js b/testing/web-platform/tests/workers/support/WorkerSendingPerformanceNow.js
new file mode 100644
index 0000000000..ac12190efe
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/WorkerSendingPerformanceNow.js
@@ -0,0 +1,22 @@
+function calcResponse() {
+ const response = [
+ typeof(workerStart),
+ typeof(performance),
+ typeof(performance.now),
+ performance.now()
+ ];
+ return response;
+}
+
+self.onmessage = function(event) {
+ postMessage(calcResponse());
+ self.close();
+}
+
+self.addEventListener("connect", function(event) {
+ const port = event.ports[0];
+ port.onmessage = function(event) {
+ port.postMessage(calcResponse());
+ port.close();
+ };
+});
diff --git a/testing/web-platform/tests/workers/support/WorkerTerminate.js b/testing/web-platform/tests/workers/support/WorkerTerminate.js
new file mode 100644
index 0000000000..7c99e7ec56
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/WorkerTerminate.js
@@ -0,0 +1,10 @@
+onmessage = function(evt)
+{
+ for (var i=0; true; i++)
+ {
+ if (i%1000 == 0)
+ {
+ postMessage(i);
+ }
+ }
+}
diff --git a/testing/web-platform/tests/workers/support/WorkerText.txt b/testing/web-platform/tests/workers/support/WorkerText.txt
new file mode 100644
index 0000000000..e4eeb5391d
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/WorkerText.txt
@@ -0,0 +1,2 @@
+var result = "Pass";
+postMessage(result);
diff --git a/testing/web-platform/tests/workers/support/abrupt-completion.js b/testing/web-platform/tests/workers/support/abrupt-completion.js
new file mode 100644
index 0000000000..f0884cc1d2
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/abrupt-completion.js
@@ -0,0 +1,21 @@
+const isSharedWorker =
+ "SharedWorkerGlobalScope" in self && self instanceof SharedWorkerGlobalScope;
+
+function setMessageHandler(response) {
+ onmessage = e => {
+ e.ports[0].postMessage(response);
+ };
+
+ if (isSharedWorker) {
+ onconnect = e => {
+ e.ports[0].onmessage = onmessage;
+ };
+ }
+}
+
+setMessageHandler("handler-before-throw");
+
+throw new Error("uncaught-exception");
+
+// This should never be called because of the uncaught exception above.
+setMessageHandler("handler-after-throw");
diff --git a/testing/web-platform/tests/workers/support/check-error-arguments.js b/testing/web-platform/tests/workers/support/check-error-arguments.js
new file mode 100644
index 0000000000..64441f9225
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/check-error-arguments.js
@@ -0,0 +1,4 @@
+window.checkErrorArguments = args => {
+ assert_equals(args.length, 1);
+ assert_equals(args[0].constructor, Event);
+};
diff --git a/testing/web-platform/tests/workers/support/empty-worker.js b/testing/web-platform/tests/workers/support/empty-worker.js
new file mode 100644
index 0000000000..49ceb2648a
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/empty-worker.js
@@ -0,0 +1 @@
+// Do nothing.
diff --git a/testing/web-platform/tests/workers/support/iframe-sw-shared-name.html b/testing/web-platform/tests/workers/support/iframe-sw-shared-name.html
new file mode 100644
index 0000000000..c1c7a536e1
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/iframe-sw-shared-name.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title>Iframe for cross-origin Shared Worker</title>
+<script src="/common/get-host-info.sub.js"></script>
+
+<body>
+<script>
+
+const worker_url = new URL(
+ 'shared-name.js',
+ get_host_info().ORIGIN + self.location.pathname);
+
+let worker = new SharedWorker(worker_url);
+worker.port.onmessage = e => {
+ parent.postMessage(e.data, '*');
+}
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/workers/support/iframe_sw_dataUrl.html b/testing/web-platform/tests/workers/support/iframe_sw_dataUrl.html
new file mode 100644
index 0000000000..0fb0ec2280
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/iframe_sw_dataUrl.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title>Iframe for Shared Worker: Data URL cross-origin checks</title>
+<body>
+<script>
+
+let worker = new SharedWorker('data:text/javascript,let conns=0; onconnect = e => { e.ports[0].postMessage(++conns); }');
+worker.port.onmessage = e => {
+ parent.postMessage(e.data, '*');
+}
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/workers/support/importScripts-1.js b/testing/web-platform/tests/workers/support/importScripts-1.js
new file mode 100644
index 0000000000..8869a4fbca
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/importScripts-1.js
@@ -0,0 +1 @@
+importScripts("importScripts-2.js");
diff --git a/testing/web-platform/tests/workers/support/importScripts-2.js b/testing/web-platform/tests/workers/support/importScripts-2.js
new file mode 100644
index 0000000000..7f3f1116e7
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/importScripts-2.js
@@ -0,0 +1 @@
+importScripts("importScripts-3.js");
diff --git a/testing/web-platform/tests/workers/support/importScripts-3.js b/testing/web-platform/tests/workers/support/importScripts-3.js
new file mode 100644
index 0000000000..2d103a0411
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/importScripts-3.js
@@ -0,0 +1 @@
+importScripts("invalidScript.js");
diff --git a/testing/web-platform/tests/workers/support/imported_script.py b/testing/web-platform/tests/workers/support/imported_script.py
new file mode 100644
index 0000000000..2f9c6a81d9
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/imported_script.py
@@ -0,0 +1,2 @@
+def main(request, response):
+ return [(b'Content-Type', request.GET[b'mime'])], u""
diff --git a/testing/web-platform/tests/workers/support/invalidScript.js b/testing/web-platform/tests/workers/support/invalidScript.js
new file mode 100644
index 0000000000..8655d4d1f1
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/invalidScript.js
@@ -0,0 +1 @@
+SELECT * FROM TABLE; // an invalid script.
diff --git a/testing/web-platform/tests/workers/support/name-as-accidental-global.js b/testing/web-platform/tests/workers/support/name-as-accidental-global.js
new file mode 100644
index 0000000000..f2c39ea715
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/name-as-accidental-global.js
@@ -0,0 +1,9 @@
+"use strict";
+importScripts("/resources/testharness.js");
+
+var name = "something else";
+
+// This just makes the test name not "Untitled"
+test(() => { }, `Declaring name as an accidental global must not cause a harness error for ${self.constructor.name}`);
+
+done();
diff --git a/testing/web-platform/tests/workers/support/name.js b/testing/web-platform/tests/workers/support/name.js
new file mode 100644
index 0000000000..970578e425
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/name.js
@@ -0,0 +1,18 @@
+"use strict";
+importScripts("/resources/testharness.js");
+
+test(() => {
+ assert_true(self.hasOwnProperty("name"), "property exists on the global");
+ assert_equals(self.name, "my name");
+}, `name property value for ${self.constructor.name}`);
+
+test(() => {
+ self.name = "something new";
+ const propDesc = Object.getOwnPropertyDescriptor(self, "name");
+ assert_equals(propDesc.value, "something new", "value");
+ assert_true(propDesc.configurable, "configurable");
+ assert_true(propDesc.writable, "writable");
+ assert_true(propDesc.enumerable, "enumerable");
+}, `name property is replaceable for ${self.constructor.name}`);
+
+done();
diff --git a/testing/web-platform/tests/workers/support/nosiniff-error-worker.py b/testing/web-platform/tests/workers/support/nosiniff-error-worker.py
new file mode 100644
index 0000000000..e4367ba6e1
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/nosiniff-error-worker.py
@@ -0,0 +1,3 @@
+def main(request, response):
+ return [(b'Content-Type', b'text/html'),
+ (b'X-Content-Type-Options', b'nosniff')], u""
diff --git a/testing/web-platform/tests/workers/support/parent_of_nested_worker.js b/testing/web-platform/tests/workers/support/parent_of_nested_worker.js
new file mode 100644
index 0000000000..1f14334290
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/parent_of_nested_worker.js
@@ -0,0 +1,14 @@
+try {
+ var worker = new Worker("WorkerBasic.js");
+ worker.onmessage = function(e) {
+ if (e.data == "Pass") {
+ postMessage("Pass");
+ } else if (e.data == "close") {
+ close();
+ postMessage("Pass");
+ }
+ };
+ worker.postMessage("start");
+} catch (e) {
+ postMessage("Fail: " + e);
+}
diff --git a/testing/web-platform/tests/workers/support/post-message-on-load-worker.js b/testing/web-platform/tests/workers/support/post-message-on-load-worker.js
new file mode 100644
index 0000000000..e1c547ab6a
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/post-message-on-load-worker.js
@@ -0,0 +1,10 @@
+if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ postMessage('LOADED');
+} else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ self.onconnect = e => {
+ e.ports[0].postMessage('LOADED');
+ };
+}
diff --git a/testing/web-platform/tests/workers/support/postMessage_block_worker.js b/testing/web-platform/tests/workers/support/postMessage_block_worker.js
new file mode 100644
index 0000000000..0c7bcaccca
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/postMessage_block_worker.js
@@ -0,0 +1,2 @@
+onmessage = e => Atomics.store(e.data, 0, 1);
+postMessage('ready');
diff --git a/testing/web-platform/tests/workers/support/postMessage_block_worker.js.headers b/testing/web-platform/tests/workers/support/postMessage_block_worker.js.headers
new file mode 100644
index 0000000000..6604450991
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/postMessage_block_worker.js.headers
@@ -0,0 +1 @@
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/workers/support/sandboxed-tests.html b/testing/web-platform/tests/workers/support/sandboxed-tests.html
new file mode 100644
index 0000000000..811c925f56
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/sandboxed-tests.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<script>
+const channel = new BroadcastChannel('echochannel');
+channel.onmessage = e => channel.postMessage(e.data);
+</script>
+<div id='workersrc' style='display:none'>
+importScripts("http://{{host}}:{{ports[http][0]}}/resources/testharness.js");
+onmessage = e => {
+ const external_blob = e.data.blob;
+ const external_blob_url = e.data.url;
+
+ test(t => {
+ assert_equals('null', self.location.origin);
+ }, 'Worker has an opaque origin.');
+
+ async_test(t => {
+ const r = new FileReader();
+ r.onloadend = t.step_func_done(e => assert_equals(r.result, 'from worker'));
+ r.readAsText(new Blob(['from worker']));
+ }, 'Worker can read its own blobs.');
+
+ async_test(t => {
+ const r = new FileReader();
+ r.onloadend = t.step_func_done(e => assert_equals(r.result, 'from page'));
+ r.readAsText(external_blob);
+ }, 'Worker can read its owners blobs.');
+
+ async_test(t => {
+ const request = new XMLHttpRequest();
+ request.open('GET', external_blob_url);
+ request.onreadystatechange = t.step_func(() => {
+ if (request.readyState == 4) {
+ assert_equals(request.responseText, 'from page');
+ t.done();
+ }
+ });
+ request.send();
+ }, 'Worker can XHR fetch a blob.');
+
+ promise_test(t =>
+ fetch(external_blob_url).then(r => r.text()).then(text => assert_equals(text, 'from page'))
+ , 'Worker can fetch a blob.');
+
+ async_test(t => {
+ const channel = new BroadcastChannel('echochannel');
+ channel.onmessage = t.step_func_done(e => assert_equals('ping', e.data));
+ channel.postMessage('ping');
+ }, 'Worker can access BroadcastChannel');
+ done();
+};
+</div>
+<script>
+// Create a worker with a blob URL to get a same opaque origin worker.
+const b = new Blob([document.getElementById('workersrc').textContent]);
+const url = URL.createObjectURL(b);
+const worker = new Worker(url);
+// Pass back any messages from the worker to our parent to collect test results.
+worker.onmessage = e => {
+ parent.postMessage(e.data, '*');
+};
+
+// Send test data to the worker.
+const b2 = new Blob(['from page']);
+const url2 = URL.createObjectURL(b2);
+worker.postMessage({url: url2, blob: b2});
+</script>
diff --git a/testing/web-platform/tests/workers/support/shared-name.js b/testing/web-platform/tests/workers/support/shared-name.js
new file mode 100644
index 0000000000..f004482719
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/shared-name.js
@@ -0,0 +1,8 @@
+"use strict";
+
+self.counter = 0;
+
+self.onconnect = e => {
+ ++self.counter;
+ e.source.postMessage({ counter: self.counter, name: self.name });
+};
diff --git a/testing/web-platform/tests/workers/support/shared-worker-echo-cookies.js b/testing/web-platform/tests/workers/support/shared-worker-echo-cookies.js
new file mode 100644
index 0000000000..34dcbc9d26
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/shared-worker-echo-cookies.js
@@ -0,0 +1,40 @@
+let port;
+
+self.onconnect = e => {
+ port = e.ports[0];
+ port.addEventListener('message', onMessage);
+ port.start();
+};
+
+async function onMessage(e) {
+ switch (e.data.type) {
+ case 'test_message':
+ port.postMessage({ok: true});
+ return;
+ case 'echo_cookies_http':
+ return onEchoCookiesHttp(e);
+ case 'echo_cookies_import':
+ return onEchoCookiesImport();
+ default:
+ throw new Error('Unexpected message type ' + e.data.type);
+ }
+}
+
+async function onEchoCookiesHttp(e) {
+ try {
+ const resp = await fetch(
+ `${self.origin}/cookies/resources/list.py`, {credentials: 'include'});
+ const cookies = await resp.json();
+ port.postMessage({ok: true, cookies: Object.keys(cookies)});
+ } catch (err) {
+ port.postMessage({ok: false});
+ }
+}
+
+// Sets `self._cookies` variable, array of the names of cookies available to
+// the request.
+importScripts(`${self.origin}/cookies/resources/list-cookies-for-script.py`);
+
+function onEchoCookiesImport() {
+ port.postMessage({ok: true, cookies: self._cookies});
+}
diff --git a/testing/web-platform/tests/workers/support/shared-worker-partitioned-cookies-3p-frame.html b/testing/web-platform/tests/workers/support/shared-worker-partitioned-cookies-3p-frame.html
new file mode 100644
index 0000000000..45c01c8937
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/shared-worker-partitioned-cookies-3p-frame.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8"/>
+<meta name="timeout" content="long">
+<title>Service Worker: Partitioned Cookies 3P Iframe</title>
+<script src="/resources/testharness.js"></script>
+<script src="shared-worker-partitioned-cookies-helper.js"></script>
+</head>
+
+<body>
+<script>
+
+promise_test(async () => {
+ const worker = new SharedWorker('./shared-worker-echo-cookies.js');
+ const next_message = worker_message_generator(worker);
+
+ worker.port.postMessage({type: 'test_message'});
+ const msg1 = await next_message();
+ assert_true(msg1.ok, 'Message passing');
+
+ worker.port.postMessage({type: 'echo_cookies_http'});
+ const msg2 = await next_message();
+ assert_true(msg2.ok, 'Get cookies');
+ assert_false(
+ msg2.cookies.includes('__Host-partitioned'),
+ 'Cannot access partitioned cookie via HTTP');
+ assert_true(
+ msg2.cookies.includes('unpartitioned'),
+ 'Can access unpartitioned cookie via HTTP');
+
+ worker.port.postMessage({type: 'echo_cookies_import'});
+ const msg3 = await next_message();
+ assert_true(msg3.ok, 'Get cookies');
+ assert_false(
+ msg3.cookies.includes('__Host-partitioned'),
+ 'Cannot access partitioned cookie via importScripts');
+ assert_true(
+ msg3.cookies.includes('unpartitioned'),
+ 'Can access unpartitioned cookie via importScripts');
+});
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/workers/support/shared-worker-partitioned-cookies-3p-window.html b/testing/web-platform/tests/workers/support/shared-worker-partitioned-cookies-3p-window.html
new file mode 100644
index 0000000000..e37e0a2cc6
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/shared-worker-partitioned-cookies-3p-window.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8"/>
+<meta name="timeout" content="long">
+<title>SharedWorker: Partitioned Cookies 3P Window</title>
+<script src="/resources/testharness.js"></script>
+</head>
+
+<body>
+<script>
+
+promise_test(async t => {
+ assert_true(
+ location.search.includes('origin='), 'First party origin passed');
+ const first_party_origin =
+ new URLSearchParams(window.location.search).get('origin');
+ const iframe = document.createElement('iframe');
+ iframe.src = new URL(
+ './shared-worker-partitioned-cookies-3p-frame.html',
+ first_party_origin + location.pathname).href;
+ document.body.appendChild(iframe);
+ await fetch_tests_from_window(iframe.contentWindow);
+});
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/workers/support/shared-worker-partitioned-cookies-helper.js b/testing/web-platform/tests/workers/support/shared-worker-partitioned-cookies-helper.js
new file mode 100644
index 0000000000..e54d3848ae
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/shared-worker-partitioned-cookies-helper.js
@@ -0,0 +1,28 @@
+// Return a generator containing the worker's message.
+//
+// Usage:
+// const worker = new SharedWorker(...);
+// const nextMessage = worker_message_generator(worker);
+// const msg_1 = await nextMessage();
+// const msg_2 = await nextMessage();
+// const msg_3 = await nextMessage();
+function worker_message_generator(shared_worker) {
+ const buffer = [];
+ let resolve = null;
+
+ shared_worker.port.onmessage = message => {
+ buffer.push(message.data);
+ if (resolve) {
+ resolve();
+ }
+ }
+ shared_worker.port.start();
+
+ return async function() {
+ if (buffer.length != 0) {
+ return buffer.shift();
+ }
+ await new Promise(r => resolve = r);
+ return buffer.shift();
+ }
+}
diff --git a/testing/web-platform/tests/workers/support/sync_xhr.js b/testing/web-platform/tests/workers/support/sync_xhr.js
new file mode 100644
index 0000000000..5de7476537
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/sync_xhr.js
@@ -0,0 +1,13 @@
+try
+{
+ const request = new XMLHttpRequest();
+ request.open("GET", "sync_xhr_target.xml", false);
+ request.send();
+ result = request.responseText == "<foo>sometext</foo>\n" ? "Pass" : "Fail";
+ postMessage(result);
+}
+catch(ex)
+{
+ result = "Fail";
+ postMessage(result);
+}
diff --git a/testing/web-platform/tests/workers/support/sync_xhr_target.xml b/testing/web-platform/tests/workers/support/sync_xhr_target.xml
new file mode 100644
index 0000000000..d31a8c5eb4
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/sync_xhr_target.xml
@@ -0,0 +1 @@
+<foo>sometext</foo>
diff --git a/testing/web-platform/tests/workers/support/throw-on-message-Worker.js b/testing/web-platform/tests/workers/support/throw-on-message-Worker.js
new file mode 100644
index 0000000000..3648f1f478
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/throw-on-message-Worker.js
@@ -0,0 +1,11 @@
+self.onerror = function(evt) {
+ postMessage('error');
+ return true;
+}
+
+self.onmessage = function(evt) {
+ if (evt.data === "first")
+ throw Error();
+ else
+ postMessage(evt.data);
+}
diff --git a/testing/web-platform/tests/workers/support/window-sw-shared-name.html b/testing/web-platform/tests/workers/support/window-sw-shared-name.html
new file mode 100644
index 0000000000..4a0704f9e4
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/window-sw-shared-name.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<title>Window for cross-origin iframe with Shared Worker</title>
+<script src="/common/get-host-info.sub.js"></script>
+
+<body>
+<script>
+
+const iframe_url = new URL(
+ 'iframe-sw-shared-name.html',
+ get_host_info().ORIGIN + self.location.pathname);
+
+
+window.onmessage = (e) => {window.opener.postMessage(e.data, '*')};
+
+var frame = document.createElement('iframe');
+frame.src = iframe_url;
+frame.style.position = 'absolute';
+document.body.appendChild(frame);
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/workers/support/worker-request-animation-frame.js b/testing/web-platform/tests/workers/support/worker-request-animation-frame.js
new file mode 100644
index 0000000000..b73781244e
--- /dev/null
+++ b/testing/web-platform/tests/workers/support/worker-request-animation-frame.js
@@ -0,0 +1,6 @@
+self.onmessage = function(event) {
+ requestAnimationFrame(time => {
+ postMessage(time);
+ self.close();
+ });
+}
diff --git a/testing/web-platform/tests/workers/worker-performance.worker.js b/testing/web-platform/tests/workers/worker-performance.worker.js
new file mode 100644
index 0000000000..c913b2e737
--- /dev/null
+++ b/testing/web-platform/tests/workers/worker-performance.worker.js
@@ -0,0 +1,129 @@
+"use strict";
+
+// Tests that most of the functionality of the window.performance object is available in web workers.
+
+importScripts("/resources/testharness.js");
+
+function verifyEntry (entry, name, type, duration, assertName) {
+ assert_equals(entry.name, name, assertName + " has the right name");
+ assert_equals(entry.entryType, type, assertName + " has the right type");
+ assert_equals(entry.duration, duration, assertName + "has the right duration");
+}
+
+var start;
+test(function testPerformanceNow () {
+ start = performance.now();
+}, "Can use performance.now in workers");
+
+test(function testPerformanceMark () {
+ while (performance.now() == start) { }
+ performance.mark("mark1");
+ // Stall the minimum amount of time to ensure the marks are separate
+ var now = performance.now();
+ while (performance.now() == now) { }
+ performance.mark("mark2");
+}, "Can use performance.mark in workers");
+
+test(function testPerformanceMeasure () {
+ performance.measure("measure1", "mark1", "mark2");
+}, "Can use performance.measure in workers");
+
+test(function testPerformanceGetEntriesByName () {
+ var mark1s = performance.getEntriesByName("mark1");
+ assert_equals(mark1s.length, 1, "getEntriesByName gave correct number of entries");
+ verifyEntry(mark1s[0], "mark1", "mark", 0, "Entry got by name");
+}, "Can use performance.getEntriesByName in workers");
+
+var marks;
+var measures;
+test(function testPerformanceGetEntriesByType () {
+ marks = performance.getEntriesByType("mark");
+ assert_equals(marks.length, 2, "getEntriesByType gave correct number of entries");
+ verifyEntry(marks[0], "mark1", "mark", 0, "First mark entry");
+ verifyEntry(marks[1], "mark2", "mark", 0, "Second mark entry");
+ measures = performance.getEntriesByType("measure");
+ assert_equals(measures.length, 1, "getEntriesByType(\"measure\") gave correct number of entries");
+ verifyEntry(measures[0], "measure1", "measure", marks[1].startTime - marks[0].startTime, "Measure entry");
+}, "Can use performance.getEntriesByType in workers");
+
+test(function testPerformanceEntryOrder () {
+ assert_greater_than(marks[0].startTime, start, "First mark startTime is after a time before it");
+ assert_greater_than(marks[1].startTime, marks[0].startTime, "Second mark startTime is after first mark startTime");
+ assert_equals(measures[0].startTime, marks[0].startTime, "measure's startTime is the first mark's startTime");
+}, "Performance marks and measures seem to be working correctly in workers");
+
+test(function testPerformanceClearing () {
+ performance.clearMarks();
+ assert_equals(performance.getEntriesByType("mark").length, 0, "clearMarks cleared the marks");
+ performance.clearMeasures();
+ assert_equals(performance.getEntriesByType("measure").length, 0, "clearMeasures cleared the measures");
+}, "Can use clearMarks and clearMeasures in workers");
+
+test(function testPerformanceResourceTiming () { // Resource timing
+ var start = performance.now();
+ var xhr = new XMLHttpRequest();
+ // Do a synchronous request and add a little artificial delay
+ xhr.open("GET", "/resources/testharness.js?pipe=trickle(d0.25)", false);
+ xhr.send();
+ // The browser might or might not have added a resource performance entry for the importScripts() above; we're only interested in xmlhttprequest entries
+ var entries = performance.getEntriesByType("resource").filter(entry => entry.initiatorType == "xmlhttprequest");
+ assert_equals(entries.length, 1, "getEntriesByType(\"resource\") returns one entry with initiatorType of xmlhttprequest");
+ assert_true(!!entries[0].name.match(/\/resources\/testharness.js/), "Resource entry has loaded url as its name");
+ assert_equals(entries[0].entryType, "resource", "Resource entry has correct entryType");
+ assert_equals(entries[0].initiatorType, "xmlhttprequest", "Resource entry has correct initiatorType");
+ var currentTimestamp = start;
+ var currentTimestampName = "a time before it";
+ [
+ "startTime", "fetchStart", "requestStart", "responseStart", "responseEnd"
+ ].forEach((name) => {
+ var timestamp = entries[0][name];
+ // We want to skip over values that are 0 because of TAO securty rescritions
+ // Or else this test will fail. This can happen for "requestStart", "responseStart".
+ if (timestamp != 0) {
+ assert_greater_than_equal(timestamp, currentTimestamp, "Resource entry " + name + " is after " + currentTimestampName);
+ currentTimestamp = timestamp;
+ currentTimestampName = name;
+ }
+ });
+ assert_greater_than(entries[0].responseEnd, entries[0].startTime, "The resource request should have taken at least some time");
+ // We requested a delay of 250ms, but it could be a little bit less, and could be significantly more.
+ assert_greater_than(entries[0].responseEnd - entries[0].responseStart, 230, "Resource timing numbers reflect reality somewhat");
+}, "Resource timing seems to work in workers");
+
+test(function testPerformanceClearResourceTimings () {
+ performance.clearResourceTimings();
+ assert_equals(performance.getEntriesByType("resource").length, 0, "clearResourceTimings cleared the resource timings");
+}, "performance.clearResourceTimings in workers");
+
+test(function testPerformanceSetResourceTimingBufferSize () {
+ performance.setResourceTimingBufferSize(0);
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", "/resources/testharness.js", false); // synchronous request
+ xhr.send();
+ assert_equals(performance.getEntriesByType("resource").length, 0, "setResourceTimingBufferSize(0) prevents resource entries from being added");
+}, "performance.setResourceTimingBufferSize in workers");
+
+test(function testPerformanceHasNoTiming () {
+ assert_equals(typeof(performance.timing), "undefined", "performance.timing is undefined");
+}, "performance.timing is not available in workers");
+
+test(function testPerformanceHasNoNavigation () {
+ assert_equals(typeof(performance.navigation), "undefined", "performance.navigation is undefined");
+}, "performance.navigation is not available in workers");
+
+test(function testPerformanceHasToJSON () {
+ assert_equals(typeof(performance.toJSON), "function", "performance.toJSON is a function");
+}, "performance.toJSON is available in workers");
+
+test(function testPerformanceNoNavigationEntries () {
+ assert_equals(performance.getEntriesByType("navigation").length, 0, "getEntriesByType(\"navigation\") returns nothing");
+ assert_equals(performance.getEntriesByName("document", "navigation").length, 0, "getEntriesByName(\"document\", \"navigation\") returns nothing");
+ assert_equals(performance.getEntriesByName("document").length, 0, "getEntriesByName(\"document\") returns nothing");
+ var hasNavigation = performance.getEntries().some((e,i,a) => {
+ return e.entryType == "navigation";
+ });
+ assert_false(hasNavigation, "getEntries should return no navigation entries.");
+
+}, "There are no navigation type performance entries in workers");
+
+done();
diff --git a/testing/web-platform/tests/workers/worker-request-animation-frame.html b/testing/web-platform/tests/workers/worker-request-animation-frame.html
new file mode 100644
index 0000000000..2d65bc2c46
--- /dev/null
+++ b/testing/web-platform/tests/workers/worker-request-animation-frame.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>raf time in dedicated workers</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<script>
+ async function waitForMessage(worker) {
+ return new Promise(resolve => {
+ worker.onmessage = event => resolve(event);
+ });
+ }
+
+ promise_test(t => {
+ const worker = new Worker('support/worker-request-animation-frame.js');
+ const message = waitForMessage(worker);
+ worker.postMessage('');
+ message.then((event) => {
+ const raf_time = event.data;
+ assert_true(performance.now() >= raf_time,
+ 'raf time cannot exceed time of page load');
+ });
+ return message;
+ }, 'requestAnimationTime reports frame time relative to worker load');
+</script>