Bug 1120505 - Add Blink service-worker tests to local wpt tests, rs=Ms2ger
authorJames Graham <james@hoppipolla.co.uk>
Thu, 25 Jun 2015 16:10:50 -0700
changeset 250330 a03152790896f9304cf6b79e48de91cc0388cc64
parent 250329 b0cbb6e2284bcdc8482b8ec6f5994393664a78f8
child 250331 11373e6e556f02838d8e037c13d4b4c4b3597f9b
push id61510
push userjames@hoppipolla.co.uk
push dateFri, 26 Jun 2015 16:25:02 +0000
treeherdermozilla-inbound@a03152790896 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMs2ger
bugs1120505
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1120505 - Add Blink service-worker tests to local wpt tests, rs=Ms2ger
testing/web-platform/mozilla/meta/MANIFEST.json
testing/web-platform/mozilla/meta/service-workers/service-worker/ServiceWorkerGlobalScope/registration-attribute.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/ServiceWorkerGlobalScope/unregister.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/ServiceWorkerGlobalScope/update.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/claim-using-registration.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/clients-matchall-client-types.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/clients-matchall-include-uncontrolled.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/controller-on-reload.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/extendable-event-async-waituntil.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/extendable-event-waituntil.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-canvas-tainting.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-cors-xhr.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-csp.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-event-async-respond-with.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-event-network-error.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-event-respond-with-stops-propagation.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-event.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-frame-resource.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-mixed-content-to-inscope.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-mixed-content-to-outscope.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-request-css-base-url.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-request-fallback.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-request-html-imports.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-request-no-freshness-headers.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-request-resources.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-request-xhr.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-response-xhr.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/getregistration.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/getregistrations.sub.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/install-event-type.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/invalid-blobtype.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/invalid-header.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/multiple-register.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/onactivate-script-error.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/oninstall-script-error.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/performance-timeline.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/postmessage-msgport-to-client.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/postmessage-to-client.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/referer.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/register-same-scope-different-script-url.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/register-wait-forever-in-install-worker.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/registration-iframe.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/registration-service-worker-attributes.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/registration.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/request-end-to-end.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/resource-timing.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/resources/fetch-request-resources-iframe.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/resources/fetch-request-xhr-iframe.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/resources/fetch-response-xhr-iframe.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/resources/invalid-blobtype-iframe.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/resources/invalid-header-iframe.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/service-worker-csp-connect.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/service-worker-csp-default.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/service-worker-csp-script.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/serviceworkerobject-scripturl.sub.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/shared-worker-controlled.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/stashed-ports.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/synced-state.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/uncontrolled-page.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/unregister-controller.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/unregister-then-register-new-script.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/unregister-then-register.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/update.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/waiting.https.html.ini
testing/web-platform/mozilla/tests/service-workers/service-worker/ServiceWorkerGlobalScope/close.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/ServiceWorkerGlobalScope/registration-attribute.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/ServiceWorkerGlobalScope/resources/close-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/ServiceWorkerGlobalScope/resources/registration-attribute-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/ServiceWorkerGlobalScope/resources/unregister-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/ServiceWorkerGlobalScope/unregister.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/ServiceWorkerGlobalScope/update.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/activation-after-registration.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/active.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/appcache-ordering-main.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/claim-not-using-registration.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/claim-using-registration.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/clients-matchall-client-types.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/clients-matchall-include-uncontrolled.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/clients-matchall.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/controller-on-load.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/controller-on-reload.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/extendable-event-async-waituntil.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/extendable-event-waituntil.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-canvas-tainting.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-cors-xhr.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-csp.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-event-after-navigation-within-page.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-event-async-respond-with.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-event-network-error.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-event-respond-with-stops-propagation.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-event.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-frame-resource.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-mixed-content-to-inscope.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-mixed-content-to-outscope.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-request-css-base-url.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-request-fallback.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-request-html-imports.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-request-no-freshness-headers.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-request-resources.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-request-xhr.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-response-xhr.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/getregistration.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/getregistrations.sub.html
testing/web-platform/mozilla/tests/service-workers/service-worker/indexeddb.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/install-event-type.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/installing.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/interfaces.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/invalid-blobtype.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/invalid-header.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/multiple-register.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/onactivate-script-error.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/oninstall-script-error.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/performance-timeline.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/postmessage-msgport-to-client.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/postmessage-to-client.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/postmessage.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/ready.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/referer.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/register-default-scope.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/register-same-scope-different-script-url.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/register-wait-forever-in-install-worker.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/registration-end-to-end.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/registration-events.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/registration-iframe.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/registration-service-worker-attributes.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/registration.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/rejections.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/request-end-to-end.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resource-timing.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/appcache-ordering.install.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/appcache-ordering.is-appcached.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/appcache-ordering.is-appcached.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/appcache-ordering.manifest
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/blank.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/claim-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/clients-matchall-client-types-iframe.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/clients-matchall-client-types-shared-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/clients-matchall-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/dummy-shared-worker-interceptor.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/empty-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/empty.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/end-to-end-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/events-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/extendable-event-async-waituntil.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/extendable-event-waituntil.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fail-on-fetch-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-access-control-login.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-canvas-tainting-iframe.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-cors-xhr-iframe.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-csp-iframe.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-event-after-navigation-within-page-iframe.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-event-async-respond-with-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-event-network-error-controllee-iframe.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-event-network-error-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-event-respond-with-stops-propagation-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-event-test-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-mixed-content-iframe-inscope-to-inscope.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-mixed-content-iframe-inscope-to-outscope.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-mixed-content-iframe.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-request-css-base-url-iframe.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-request-css-base-url-style.css
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-request-css-base-url-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-request-fallback-iframe.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-request-fallback-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-request-html-imports-iframe.sub.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-request-html-imports-worker.sub.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-request-no-freshness-headers-iframe.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-request-no-freshness-headers-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-request-resources-iframe.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-request-resources-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-request-xhr-iframe.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-request-xhr-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-response-xhr-iframe.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-response-xhr-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-rewrite-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/frame-for-getregistrations.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/get-host-info.sub.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/indexeddb-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/install-event-type-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/interfaces-worker.sub.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/interfaces.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/invalid-blobtype-iframe.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/invalid-blobtype-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/invalid-header-iframe.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/invalid-header-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/onactivate-throw-error-from-nested-event-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/onactivate-throw-error-then-cancel-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/onactivate-throw-error-then-prevent-default-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/onactivate-throw-error-with-empty-onerror-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/onactivate-throw-error-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/oninstall-throw-error-from-nested-event-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/oninstall-throw-error-then-cancel-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/oninstall-throw-error-then-prevent-default-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/oninstall-throw-error-with-empty-onerror-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/oninstall-throw-error-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/other.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/override_assert_object_equals.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/postmessage-msgport-to-client-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/postmessage-to-client-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/postmessage-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/referer-iframe.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/registration-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/reject-install-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/request-end-to-end-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/resource-timing-iframe.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/resource-timing-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/shared-worker-controlled.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/shared-worker-import.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/simple-intercept-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/simple.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/simple.txt
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/skip-waiting-installed-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/skip-waiting-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/stashed-ports-basics.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock-iframe.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock.data
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/test-helpers.sub.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/testharness-helpers.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/unregister-controller-page.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/wait-forever-in-install-worker.js
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/worker-testharness.js
testing/web-platform/mozilla/tests/service-workers/service-worker/service-worker-csp-connect.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/service-worker-csp-default.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/service-worker-csp-script.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/serviceworkerobject-scripturl.sub.html
testing/web-platform/mozilla/tests/service-workers/service-worker/shared-worker-controlled.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/skip-waiting-installed.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/skip-waiting-using-registration.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/skip-waiting-without-client.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/skip-waiting-without-using-registration.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/skip-waiting.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/stashed-ports.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/state.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/synced-state.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/uncontrolled-page.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/unregister-controller.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/unregister-then-register-new-script.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/unregister-then-register.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/unregister.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/update.https.html
testing/web-platform/mozilla/tests/service-workers/service-worker/waiting.https.html
--- a/testing/web-platform/mozilla/meta/MANIFEST.json
+++ b/testing/web-platform/mozilla/meta/MANIFEST.json
@@ -3,16 +3,547 @@
     "manual": [],
     "reftest": [],
     "stub": [],
     "testharness": [],
     "wdspec": []
   },
   "local_changes": {
     "deleted": [],
-    "items": {},
+    "items": {
+      "testharness": {
+        "service-workers/service-worker/ServiceWorkerGlobalScope/close.https.html": [
+          {
+            "path": "service-workers/service-worker/ServiceWorkerGlobalScope/close.https.html",
+            "url": "/_mozilla/service-workers/service-worker/ServiceWorkerGlobalScope/close.https.html"
+          }
+        ],
+        "service-workers/service-worker/ServiceWorkerGlobalScope/registration-attribute.https.html": [
+          {
+            "path": "service-workers/service-worker/ServiceWorkerGlobalScope/registration-attribute.https.html",
+            "url": "/_mozilla/service-workers/service-worker/ServiceWorkerGlobalScope/registration-attribute.https.html"
+          }
+        ],
+        "service-workers/service-worker/ServiceWorkerGlobalScope/unregister.https.html": [
+          {
+            "path": "service-workers/service-worker/ServiceWorkerGlobalScope/unregister.https.html",
+            "url": "/_mozilla/service-workers/service-worker/ServiceWorkerGlobalScope/unregister.https.html"
+          }
+        ],
+        "service-workers/service-worker/ServiceWorkerGlobalScope/update.https.html": [
+          {
+            "path": "service-workers/service-worker/ServiceWorkerGlobalScope/update.https.html",
+            "url": "/_mozilla/service-workers/service-worker/ServiceWorkerGlobalScope/update.https.html"
+          }
+        ],
+        "service-workers/service-worker/activation-after-registration.https.html": [
+          {
+            "path": "service-workers/service-worker/activation-after-registration.https.html",
+            "url": "/_mozilla/service-workers/service-worker/activation-after-registration.https.html"
+          }
+        ],
+        "service-workers/service-worker/active.https.html": [
+          {
+            "path": "service-workers/service-worker/active.https.html",
+            "url": "/_mozilla/service-workers/service-worker/active.https.html"
+          }
+        ],
+        "service-workers/service-worker/appcache-ordering-main.https.html": [
+          {
+            "path": "service-workers/service-worker/appcache-ordering-main.https.html",
+            "url": "/_mozilla/service-workers/service-worker/appcache-ordering-main.https.html"
+          }
+        ],
+        "service-workers/service-worker/claim-not-using-registration.https.html": [
+          {
+            "path": "service-workers/service-worker/claim-not-using-registration.https.html",
+            "url": "/_mozilla/service-workers/service-worker/claim-not-using-registration.https.html"
+          }
+        ],
+        "service-workers/service-worker/claim-using-registration.https.html": [
+          {
+            "path": "service-workers/service-worker/claim-using-registration.https.html",
+            "url": "/_mozilla/service-workers/service-worker/claim-using-registration.https.html"
+          }
+        ],
+        "service-workers/service-worker/clients-matchall-client-types.https.html": [
+          {
+            "path": "service-workers/service-worker/clients-matchall-client-types.https.html",
+            "url": "/_mozilla/service-workers/service-worker/clients-matchall-client-types.https.html"
+          }
+        ],
+        "service-workers/service-worker/clients-matchall-include-uncontrolled.https.html": [
+          {
+            "path": "service-workers/service-worker/clients-matchall-include-uncontrolled.https.html",
+            "url": "/_mozilla/service-workers/service-worker/clients-matchall-include-uncontrolled.https.html"
+          }
+        ],
+        "service-workers/service-worker/clients-matchall.https.html": [
+          {
+            "path": "service-workers/service-worker/clients-matchall.https.html",
+            "url": "/_mozilla/service-workers/service-worker/clients-matchall.https.html"
+          }
+        ],
+        "service-workers/service-worker/controller-on-load.https.html": [
+          {
+            "path": "service-workers/service-worker/controller-on-load.https.html",
+            "url": "/_mozilla/service-workers/service-worker/controller-on-load.https.html"
+          }
+        ],
+        "service-workers/service-worker/controller-on-reload.https.html": [
+          {
+            "path": "service-workers/service-worker/controller-on-reload.https.html",
+            "url": "/_mozilla/service-workers/service-worker/controller-on-reload.https.html"
+          }
+        ],
+        "service-workers/service-worker/extendable-event-async-waituntil.https.html": [
+          {
+            "path": "service-workers/service-worker/extendable-event-async-waituntil.https.html",
+            "url": "/_mozilla/service-workers/service-worker/extendable-event-async-waituntil.https.html"
+          }
+        ],
+        "service-workers/service-worker/extendable-event-waituntil.https.html": [
+          {
+            "path": "service-workers/service-worker/extendable-event-waituntil.https.html",
+            "url": "/_mozilla/service-workers/service-worker/extendable-event-waituntil.https.html"
+          }
+        ],
+        "service-workers/service-worker/fetch-canvas-tainting.https.html": [
+          {
+            "path": "service-workers/service-worker/fetch-canvas-tainting.https.html",
+            "url": "/_mozilla/service-workers/service-worker/fetch-canvas-tainting.https.html"
+          }
+        ],
+        "service-workers/service-worker/fetch-cors-xhr.https.html": [
+          {
+            "path": "service-workers/service-worker/fetch-cors-xhr.https.html",
+            "url": "/_mozilla/service-workers/service-worker/fetch-cors-xhr.https.html"
+          }
+        ],
+        "service-workers/service-worker/fetch-csp.https.html": [
+          {
+            "path": "service-workers/service-worker/fetch-csp.https.html",
+            "url": "/_mozilla/service-workers/service-worker/fetch-csp.https.html"
+          }
+        ],
+        "service-workers/service-worker/fetch-event-after-navigation-within-page.https.html": [
+          {
+            "path": "service-workers/service-worker/fetch-event-after-navigation-within-page.https.html",
+            "url": "/_mozilla/service-workers/service-worker/fetch-event-after-navigation-within-page.https.html"
+          }
+        ],
+        "service-workers/service-worker/fetch-event-async-respond-with.https.html": [
+          {
+            "path": "service-workers/service-worker/fetch-event-async-respond-with.https.html",
+            "url": "/_mozilla/service-workers/service-worker/fetch-event-async-respond-with.https.html"
+          }
+        ],
+        "service-workers/service-worker/fetch-event-network-error.https.html": [
+          {
+            "path": "service-workers/service-worker/fetch-event-network-error.https.html",
+            "url": "/_mozilla/service-workers/service-worker/fetch-event-network-error.https.html"
+          }
+        ],
+        "service-workers/service-worker/fetch-event-respond-with-stops-propagation.https.html": [
+          {
+            "path": "service-workers/service-worker/fetch-event-respond-with-stops-propagation.https.html",
+            "url": "/_mozilla/service-workers/service-worker/fetch-event-respond-with-stops-propagation.https.html"
+          }
+        ],
+        "service-workers/service-worker/fetch-event.https.html": [
+          {
+            "path": "service-workers/service-worker/fetch-event.https.html",
+            "url": "/_mozilla/service-workers/service-worker/fetch-event.https.html"
+          }
+        ],
+        "service-workers/service-worker/fetch-frame-resource.https.html": [
+          {
+            "path": "service-workers/service-worker/fetch-frame-resource.https.html",
+            "url": "/_mozilla/service-workers/service-worker/fetch-frame-resource.https.html"
+          }
+        ],
+        "service-workers/service-worker/fetch-mixed-content-to-inscope.https.html": [
+          {
+            "path": "service-workers/service-worker/fetch-mixed-content-to-inscope.https.html",
+            "url": "/_mozilla/service-workers/service-worker/fetch-mixed-content-to-inscope.https.html"
+          }
+        ],
+        "service-workers/service-worker/fetch-mixed-content-to-outscope.https.html": [
+          {
+            "path": "service-workers/service-worker/fetch-mixed-content-to-outscope.https.html",
+            "url": "/_mozilla/service-workers/service-worker/fetch-mixed-content-to-outscope.https.html"
+          }
+        ],
+        "service-workers/service-worker/fetch-request-css-base-url.https.html": [
+          {
+            "path": "service-workers/service-worker/fetch-request-css-base-url.https.html",
+            "url": "/_mozilla/service-workers/service-worker/fetch-request-css-base-url.https.html"
+          }
+        ],
+        "service-workers/service-worker/fetch-request-fallback.https.html": [
+          {
+            "path": "service-workers/service-worker/fetch-request-fallback.https.html",
+            "url": "/_mozilla/service-workers/service-worker/fetch-request-fallback.https.html"
+          }
+        ],
+        "service-workers/service-worker/fetch-request-html-imports.https.html": [
+          {
+            "path": "service-workers/service-worker/fetch-request-html-imports.https.html",
+            "url": "/_mozilla/service-workers/service-worker/fetch-request-html-imports.https.html"
+          }
+        ],
+        "service-workers/service-worker/fetch-request-no-freshness-headers.https.html": [
+          {
+            "path": "service-workers/service-worker/fetch-request-no-freshness-headers.https.html",
+            "url": "/_mozilla/service-workers/service-worker/fetch-request-no-freshness-headers.https.html"
+          }
+        ],
+        "service-workers/service-worker/fetch-request-resources.https.html": [
+          {
+            "path": "service-workers/service-worker/fetch-request-resources.https.html",
+            "url": "/_mozilla/service-workers/service-worker/fetch-request-resources.https.html"
+          }
+        ],
+        "service-workers/service-worker/fetch-request-xhr.https.html": [
+          {
+            "path": "service-workers/service-worker/fetch-request-xhr.https.html",
+            "url": "/_mozilla/service-workers/service-worker/fetch-request-xhr.https.html"
+          }
+        ],
+        "service-workers/service-worker/fetch-response-xhr.https.html": [
+          {
+            "path": "service-workers/service-worker/fetch-response-xhr.https.html",
+            "url": "/_mozilla/service-workers/service-worker/fetch-response-xhr.https.html"
+          }
+        ],
+        "service-workers/service-worker/getregistration.https.html": [
+          {
+            "path": "service-workers/service-worker/getregistration.https.html",
+            "url": "/_mozilla/service-workers/service-worker/getregistration.https.html"
+          }
+        ],
+        "service-workers/service-worker/getregistrations.sub.html": [
+          {
+            "path": "service-workers/service-worker/getregistrations.sub.html",
+            "url": "/_mozilla/service-workers/service-worker/getregistrations.sub.html"
+          }
+        ],
+        "service-workers/service-worker/indexeddb.https.html": [
+          {
+            "path": "service-workers/service-worker/indexeddb.https.html",
+            "url": "/_mozilla/service-workers/service-worker/indexeddb.https.html"
+          }
+        ],
+        "service-workers/service-worker/install-event-type.https.html": [
+          {
+            "path": "service-workers/service-worker/install-event-type.https.html",
+            "url": "/_mozilla/service-workers/service-worker/install-event-type.https.html"
+          }
+        ],
+        "service-workers/service-worker/installing.https.html": [
+          {
+            "path": "service-workers/service-worker/installing.https.html",
+            "url": "/_mozilla/service-workers/service-worker/installing.https.html"
+          }
+        ],
+        "service-workers/service-worker/interfaces.https.html": [
+          {
+            "path": "service-workers/service-worker/interfaces.https.html",
+            "url": "/_mozilla/service-workers/service-worker/interfaces.https.html"
+          }
+        ],
+        "service-workers/service-worker/invalid-blobtype.https.html": [
+          {
+            "path": "service-workers/service-worker/invalid-blobtype.https.html",
+            "url": "/_mozilla/service-workers/service-worker/invalid-blobtype.https.html"
+          }
+        ],
+        "service-workers/service-worker/invalid-header.https.html": [
+          {
+            "path": "service-workers/service-worker/invalid-header.https.html",
+            "url": "/_mozilla/service-workers/service-worker/invalid-header.https.html"
+          }
+        ],
+        "service-workers/service-worker/multiple-register.https.html": [
+          {
+            "path": "service-workers/service-worker/multiple-register.https.html",
+            "url": "/_mozilla/service-workers/service-worker/multiple-register.https.html"
+          }
+        ],
+        "service-workers/service-worker/onactivate-script-error.https.html": [
+          {
+            "path": "service-workers/service-worker/onactivate-script-error.https.html",
+            "url": "/_mozilla/service-workers/service-worker/onactivate-script-error.https.html"
+          }
+        ],
+        "service-workers/service-worker/oninstall-script-error.https.html": [
+          {
+            "path": "service-workers/service-worker/oninstall-script-error.https.html",
+            "url": "/_mozilla/service-workers/service-worker/oninstall-script-error.https.html"
+          }
+        ],
+        "service-workers/service-worker/performance-timeline.https.html": [
+          {
+            "path": "service-workers/service-worker/performance-timeline.https.html",
+            "url": "/_mozilla/service-workers/service-worker/performance-timeline.https.html"
+          }
+        ],
+        "service-workers/service-worker/postmessage-msgport-to-client.https.html": [
+          {
+            "path": "service-workers/service-worker/postmessage-msgport-to-client.https.html",
+            "url": "/_mozilla/service-workers/service-worker/postmessage-msgport-to-client.https.html"
+          }
+        ],
+        "service-workers/service-worker/postmessage-to-client.https.html": [
+          {
+            "path": "service-workers/service-worker/postmessage-to-client.https.html",
+            "url": "/_mozilla/service-workers/service-worker/postmessage-to-client.https.html"
+          }
+        ],
+        "service-workers/service-worker/postmessage.https.html": [
+          {
+            "path": "service-workers/service-worker/postmessage.https.html",
+            "url": "/_mozilla/service-workers/service-worker/postmessage.https.html"
+          }
+        ],
+        "service-workers/service-worker/ready.https.html": [
+          {
+            "path": "service-workers/service-worker/ready.https.html",
+            "url": "/_mozilla/service-workers/service-worker/ready.https.html"
+          }
+        ],
+        "service-workers/service-worker/referer.https.html": [
+          {
+            "path": "service-workers/service-worker/referer.https.html",
+            "url": "/_mozilla/service-workers/service-worker/referer.https.html"
+          }
+        ],
+        "service-workers/service-worker/register-default-scope.https.html": [
+          {
+            "path": "service-workers/service-worker/register-default-scope.https.html",
+            "url": "/_mozilla/service-workers/service-worker/register-default-scope.https.html"
+          }
+        ],
+        "service-workers/service-worker/register-same-scope-different-script-url.https.html": [
+          {
+            "path": "service-workers/service-worker/register-same-scope-different-script-url.https.html",
+            "url": "/_mozilla/service-workers/service-worker/register-same-scope-different-script-url.https.html"
+          }
+        ],
+        "service-workers/service-worker/register-wait-forever-in-install-worker.https.html": [
+          {
+            "path": "service-workers/service-worker/register-wait-forever-in-install-worker.https.html",
+            "url": "/_mozilla/service-workers/service-worker/register-wait-forever-in-install-worker.https.html"
+          }
+        ],
+        "service-workers/service-worker/registration-end-to-end.https.html": [
+          {
+            "path": "service-workers/service-worker/registration-end-to-end.https.html",
+            "url": "/_mozilla/service-workers/service-worker/registration-end-to-end.https.html"
+          }
+        ],
+        "service-workers/service-worker/registration-events.https.html": [
+          {
+            "path": "service-workers/service-worker/registration-events.https.html",
+            "url": "/_mozilla/service-workers/service-worker/registration-events.https.html"
+          }
+        ],
+        "service-workers/service-worker/registration-iframe.https.html": [
+          {
+            "path": "service-workers/service-worker/registration-iframe.https.html",
+            "url": "/_mozilla/service-workers/service-worker/registration-iframe.https.html"
+          }
+        ],
+        "service-workers/service-worker/registration-service-worker-attributes.https.html": [
+          {
+            "path": "service-workers/service-worker/registration-service-worker-attributes.https.html",
+            "url": "/_mozilla/service-workers/service-worker/registration-service-worker-attributes.https.html"
+          }
+        ],
+        "service-workers/service-worker/registration.https.html": [
+          {
+            "path": "service-workers/service-worker/registration.https.html",
+            "url": "/_mozilla/service-workers/service-worker/registration.https.html"
+          }
+        ],
+        "service-workers/service-worker/rejections.https.html": [
+          {
+            "path": "service-workers/service-worker/rejections.https.html",
+            "url": "/_mozilla/service-workers/service-worker/rejections.https.html"
+          }
+        ],
+        "service-workers/service-worker/request-end-to-end.https.html": [
+          {
+            "path": "service-workers/service-worker/request-end-to-end.https.html",
+            "url": "/_mozilla/service-workers/service-worker/request-end-to-end.https.html"
+          }
+        ],
+        "service-workers/service-worker/resource-timing.https.html": [
+          {
+            "path": "service-workers/service-worker/resource-timing.https.html",
+            "url": "/_mozilla/service-workers/service-worker/resource-timing.https.html"
+          }
+        ],
+        "service-workers/service-worker/resources/fetch-request-resources-iframe.https.html": [
+          {
+            "path": "service-workers/service-worker/resources/fetch-request-resources-iframe.https.html",
+            "url": "/_mozilla/service-workers/service-worker/resources/fetch-request-resources-iframe.https.html"
+          }
+        ],
+        "service-workers/service-worker/resources/fetch-request-xhr-iframe.https.html": [
+          {
+            "path": "service-workers/service-worker/resources/fetch-request-xhr-iframe.https.html",
+            "url": "/_mozilla/service-workers/service-worker/resources/fetch-request-xhr-iframe.https.html"
+          }
+        ],
+        "service-workers/service-worker/resources/fetch-response-xhr-iframe.https.html": [
+          {
+            "path": "service-workers/service-worker/resources/fetch-response-xhr-iframe.https.html",
+            "url": "/_mozilla/service-workers/service-worker/resources/fetch-response-xhr-iframe.https.html"
+          }
+        ],
+        "service-workers/service-worker/resources/invalid-blobtype-iframe.https.html": [
+          {
+            "path": "service-workers/service-worker/resources/invalid-blobtype-iframe.https.html",
+            "url": "/_mozilla/service-workers/service-worker/resources/invalid-blobtype-iframe.https.html"
+          }
+        ],
+        "service-workers/service-worker/resources/invalid-header-iframe.https.html": [
+          {
+            "path": "service-workers/service-worker/resources/invalid-header-iframe.https.html",
+            "url": "/_mozilla/service-workers/service-worker/resources/invalid-header-iframe.https.html"
+          }
+        ],
+        "service-workers/service-worker/service-worker-csp-connect.https.html": [
+          {
+            "path": "service-workers/service-worker/service-worker-csp-connect.https.html",
+            "url": "/_mozilla/service-workers/service-worker/service-worker-csp-connect.https.html"
+          }
+        ],
+        "service-workers/service-worker/service-worker-csp-default.https.html": [
+          {
+            "path": "service-workers/service-worker/service-worker-csp-default.https.html",
+            "url": "/_mozilla/service-workers/service-worker/service-worker-csp-default.https.html"
+          }
+        ],
+        "service-workers/service-worker/service-worker-csp-script.https.html": [
+          {
+            "path": "service-workers/service-worker/service-worker-csp-script.https.html",
+            "url": "/_mozilla/service-workers/service-worker/service-worker-csp-script.https.html"
+          }
+        ],
+        "service-workers/service-worker/serviceworkerobject-scripturl.sub.html": [
+          {
+            "path": "service-workers/service-worker/serviceworkerobject-scripturl.sub.html",
+            "url": "/_mozilla/service-workers/service-worker/serviceworkerobject-scripturl.sub.html"
+          }
+        ],
+        "service-workers/service-worker/shared-worker-controlled.https.html": [
+          {
+            "path": "service-workers/service-worker/shared-worker-controlled.https.html",
+            "url": "/_mozilla/service-workers/service-worker/shared-worker-controlled.https.html"
+          }
+        ],
+        "service-workers/service-worker/skip-waiting-installed.https.html": [
+          {
+            "path": "service-workers/service-worker/skip-waiting-installed.https.html",
+            "url": "/_mozilla/service-workers/service-worker/skip-waiting-installed.https.html"
+          }
+        ],
+        "service-workers/service-worker/skip-waiting-using-registration.https.html": [
+          {
+            "path": "service-workers/service-worker/skip-waiting-using-registration.https.html",
+            "url": "/_mozilla/service-workers/service-worker/skip-waiting-using-registration.https.html"
+          }
+        ],
+        "service-workers/service-worker/skip-waiting-without-client.https.html": [
+          {
+            "path": "service-workers/service-worker/skip-waiting-without-client.https.html",
+            "url": "/_mozilla/service-workers/service-worker/skip-waiting-without-client.https.html"
+          }
+        ],
+        "service-workers/service-worker/skip-waiting-without-using-registration.https.html": [
+          {
+            "path": "service-workers/service-worker/skip-waiting-without-using-registration.https.html",
+            "url": "/_mozilla/service-workers/service-worker/skip-waiting-without-using-registration.https.html"
+          }
+        ],
+        "service-workers/service-worker/skip-waiting.https.html": [
+          {
+            "path": "service-workers/service-worker/skip-waiting.https.html",
+            "url": "/_mozilla/service-workers/service-worker/skip-waiting.https.html"
+          }
+        ],
+        "service-workers/service-worker/stashed-ports.https.html": [
+          {
+            "path": "service-workers/service-worker/stashed-ports.https.html",
+            "url": "/_mozilla/service-workers/service-worker/stashed-ports.https.html"
+          }
+        ],
+        "service-workers/service-worker/state.https.html": [
+          {
+            "path": "service-workers/service-worker/state.https.html",
+            "url": "/_mozilla/service-workers/service-worker/state.https.html"
+          }
+        ],
+        "service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html": [
+          {
+            "path": "service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html",
+            "url": "/_mozilla/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html"
+          }
+        ],
+        "service-workers/service-worker/synced-state.https.html": [
+          {
+            "path": "service-workers/service-worker/synced-state.https.html",
+            "url": "/_mozilla/service-workers/service-worker/synced-state.https.html"
+          }
+        ],
+        "service-workers/service-worker/uncontrolled-page.https.html": [
+          {
+            "path": "service-workers/service-worker/uncontrolled-page.https.html",
+            "url": "/_mozilla/service-workers/service-worker/uncontrolled-page.https.html"
+          }
+        ],
+        "service-workers/service-worker/unregister-controller.https.html": [
+          {
+            "path": "service-workers/service-worker/unregister-controller.https.html",
+            "url": "/_mozilla/service-workers/service-worker/unregister-controller.https.html"
+          }
+        ],
+        "service-workers/service-worker/unregister-then-register-new-script.https.html": [
+          {
+            "path": "service-workers/service-worker/unregister-then-register-new-script.https.html",
+            "url": "/_mozilla/service-workers/service-worker/unregister-then-register-new-script.https.html"
+          }
+        ],
+        "service-workers/service-worker/unregister-then-register.https.html": [
+          {
+            "path": "service-workers/service-worker/unregister-then-register.https.html",
+            "url": "/_mozilla/service-workers/service-worker/unregister-then-register.https.html"
+          }
+        ],
+        "service-workers/service-worker/unregister.https.html": [
+          {
+            "path": "service-workers/service-worker/unregister.https.html",
+            "url": "/_mozilla/service-workers/service-worker/unregister.https.html"
+          }
+        ],
+        "service-workers/service-worker/update.https.html": [
+          {
+            "path": "service-workers/service-worker/update.https.html",
+            "url": "/_mozilla/service-workers/service-worker/update.https.html"
+          }
+        ],
+        "service-workers/service-worker/waiting.https.html": [
+          {
+            "path": "service-workers/service-worker/waiting.https.html",
+            "url": "/_mozilla/service-workers/service-worker/waiting.https.html"
+          }
+        ]
+      }
+    },
     "reftest_nodes": {}
   },
   "reftest_nodes": {},
   "rev": null,
   "url_base": "/_mozilla/",
   "version": 2
 }
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/ServiceWorkerGlobalScope/registration-attribute.https.html.ini
@@ -0,0 +1,6 @@
+[registration-attribute.https.html]
+  type: testharness
+  expected: ERROR
+  [Verify registration attribute on ServiceWorkerGlobalScope]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/ServiceWorkerGlobalScope/unregister.https.html.ini
@@ -0,0 +1,6 @@
+[unregister.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [Unregister controlling service worker]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/ServiceWorkerGlobalScope/update.https.html.ini
@@ -0,0 +1,5 @@
+[update.https.html]
+  type: testharness
+  [Update a registration on ServiceWorkerGlobalScope]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/claim-using-registration.https.html.ini
@@ -0,0 +1,6 @@
+[claim-using-registration.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [Test worker claims client which is using another registration]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/clients-matchall-client-types.https.html.ini
@@ -0,0 +1,6 @@
+[clients-matchall-client-types.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [Verify matchAll() with various client types]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/clients-matchall-include-uncontrolled.https.html.ini
@@ -0,0 +1,6 @@
+[clients-matchall-include-uncontrolled.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [Verify matchAll() respect includeUncontrolled]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/controller-on-reload.https.html.ini
@@ -0,0 +1,5 @@
+[controller-on-reload.https.html]
+  type: testharness
+  [controller is set upon reload after registration]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/extendable-event-async-waituntil.https.html.ini
@@ -0,0 +1,5 @@
+[extendable-event-async-waituntil.https.html]
+  type: testharness
+  [Calling waitUntil asynchronously throws an exception]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/extendable-event-waituntil.https.html.ini
@@ -0,0 +1,9 @@
+[extendable-event-waituntil.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [Test ExtendableEvent waitUntil reject precedence.]
+    expected: TIMEOUT
+
+  [Test activate event waitUntil rejected.]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-canvas-tainting.https.html.ini
@@ -0,0 +1,6 @@
+[fetch-canvas-tainting.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [Verify canvas tainting of fetched image in a Service Worker]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-cors-xhr.https.html.ini
@@ -0,0 +1,6 @@
+[fetch-cors-xhr.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [Verify CORS XHR of fetch() in a Service Worker]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-csp.https.html.ini
@@ -0,0 +1,6 @@
+[fetch-csp.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [Verify CSP control of fetch() in a Service Worker]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-event-async-respond-with.https.html.ini
@@ -0,0 +1,7 @@
+[fetch-event-async-respond-with.https.html]
+  type: testharness
+  expected:
+    if not debug and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): CRASH
+    if not debug and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): CRASH
+    if not debug and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): CRASH
+    TIMEOUT
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-event-network-error.https.html.ini
@@ -0,0 +1,5 @@
+[fetch-event-network-error.https.html]
+  type: testharness
+  [Rejecting the fetch event or using preventDefault() causes a network error]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-event-respond-with-stops-propagation.https.html.ini
@@ -0,0 +1,7 @@
+[fetch-event-respond-with-stops-propagation.https.html]
+  type: testharness
+  expected:
+    if not debug and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): CRASH
+    if not debug and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): CRASH
+    if not debug and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): CRASH
+    TIMEOUT
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-event.https.html.ini
@@ -0,0 +1,5 @@
+[fetch-event.https.html]
+  type: testharness
+  [Service Worker responds to fetch event with POST form]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-frame-resource.https.html.ini
@@ -0,0 +1,9 @@
+[fetch-frame-resource.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [Basic type response could be loaded in the iframe.]
+    expected: TIMEOUT
+
+  [Basic type response could be loaded in the new window.]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-mixed-content-to-inscope.https.html.ini
@@ -0,0 +1,6 @@
+[fetch-mixed-content-to-inscope.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [Verify Mixed content of fetch() in a Service Worker]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-mixed-content-to-outscope.https.html.ini
@@ -0,0 +1,6 @@
+[fetch-mixed-content-to-outscope.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [Verify Mixed content of fetch() in a Service Worker]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-request-css-base-url.https.html.ini
@@ -0,0 +1,6 @@
+[fetch-request-css-base-url.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [CSS's base URL must be the request URL even when fetched from other URL.]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-request-fallback.https.html.ini
@@ -0,0 +1,6 @@
+[fetch-request-fallback.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [Verify the fallback behavior of FetchEvent]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-request-html-imports.https.html.ini
@@ -0,0 +1,5 @@
+[fetch-request-html-imports.https.html]
+  type: testharness
+  [Verify the FetchEvent for HTMLImports]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-request-no-freshness-headers.https.html.ini
@@ -0,0 +1,3 @@
+[fetch-request-no-freshness-headers.https.html]
+  type: testharness
+  expected: ERROR
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-request-resources.https.html.ini
@@ -0,0 +1,5 @@
+[fetch-request-resources.https.html]
+  type: testharness
+  [Verify FetchEvent for resources.]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-request-xhr.https.html.ini
@@ -0,0 +1,6 @@
+[fetch-request-xhr.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [Verify the body of FetchEvent using XMLHttpRequest]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-response-xhr.https.html.ini
@@ -0,0 +1,6 @@
+[fetch-response-xhr.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [Verify the response of FetchEvent using XMLHttpRequest]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/getregistration.https.html.ini
@@ -0,0 +1,8 @@
+[getregistration.https.html]
+  type: testharness
+  [Register then getRegistration]
+    expected: FAIL
+
+  [Register then getRegistration with a URL having a fragment]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/getregistrations.sub.html.ini
@@ -0,0 +1,3 @@
+[getregistrations.sub.html]
+  type: testharness
+  expected: ERROR
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/install-event-type.https.html.ini
@@ -0,0 +1,6 @@
+[install-event-type.https.html]
+  type: testharness
+  expected: ERROR
+  [install event type]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/invalid-blobtype.https.html.ini
@@ -0,0 +1,6 @@
+[invalid-blobtype.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [Verify the response of FetchEvent using XMLHttpRequest]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/invalid-header.https.html.ini
@@ -0,0 +1,6 @@
+[invalid-header.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [Verify the response of FetchEvent using XMLHttpRequest]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/multiple-register.https.html.ini
@@ -0,0 +1,12 @@
+[multiple-register.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [Subsequent registrations resolve to the same registration object]
+    expected: FAIL
+
+  [Subsequent registrations from a different iframe resolve to the different registration object but they refer to the same registration and workers]
+    expected: TIMEOUT
+
+  [Concurrent registrations resolve to the same registration object]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/onactivate-script-error.https.html.ini
@@ -0,0 +1,18 @@
+[onactivate-script-error.https.html]
+  type: testharness
+  expected: ERROR
+  [activate handler throws an error]
+    expected: FAIL
+
+  [activate handler throws an error, error handler does not cancel]
+    expected: FAIL
+
+  [activate handler dispatches an event that throws an error]
+    expected: FAIL
+
+  [activate handler throws an error that is cancelled]
+    expected: FAIL
+
+  [activate handler throws an error and prevents default]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/oninstall-script-error.https.html.ini
@@ -0,0 +1,9 @@
+[oninstall-script-error.https.html]
+  type: testharness
+  expected: ERROR
+  [install handler throws an error that is cancelled]
+    expected: FAIL
+
+  [install handler throws an error and prevents default]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/performance-timeline.https.html.ini
@@ -0,0 +1,5 @@
+[performance-timeline.https.html]
+  type: testharness
+  [Test Performance Timeline API in Service Worker]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/postmessage-msgport-to-client.https.html.ini
@@ -0,0 +1,7 @@
+[postmessage-msgport-to-client.https.html]
+  type: testharness
+  expected:
+    if not debug and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): CRASH
+    if not debug and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): CRASH
+    if not debug and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): CRASH
+    TIMEOUT
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/postmessage-to-client.https.html.ini
@@ -0,0 +1,6 @@
+[postmessage-to-client.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [postMessage from ServiceWorker to Client]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/referer.https.html.ini
@@ -0,0 +1,6 @@
+[referer.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [Verify the referer]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/register-same-scope-different-script-url.https.html.ini
@@ -0,0 +1,9 @@
+[register-same-scope-different-script-url.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [Register then register new script URL]
+    expected: TIMEOUT
+
+  [Register same-scope new script url effect on controller]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/register-wait-forever-in-install-worker.https.html.ini
@@ -0,0 +1,6 @@
+[register-wait-forever-in-install-worker.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [register worker that calls waitUntil with a promise that never resolves in oninstall]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/registration-iframe.https.html.ini
@@ -0,0 +1,11 @@
+[registration-iframe.https.html]
+  type: testharness
+  [Subframe's container's register method should use calling frame's document's url as a base url for parsing its script url and scope url - normal case]
+    expected: FAIL
+
+  [Subframe's container's register method should use calling frame's document's url as a base url for parsing its script url and scope url - error case]
+    expected: FAIL
+
+  [A scope url should start with the given script url]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/registration-service-worker-attributes.https.html.ini
@@ -0,0 +1,5 @@
+[registration-service-worker-attributes.https.html]
+  type: testharness
+  [installing/waiting/active after registration]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/registration.https.html.ini
@@ -0,0 +1,53 @@
+[registration.https.html]
+  type: testharness
+  [Registering non-existent script]
+    expected: FAIL
+
+  [Registering invalid chunked encoding script]
+    expected: FAIL
+
+  [Registering invalid chunked encoding script with flush]
+    expected: FAIL
+
+  [Registering script with no MIME type]
+    expected: FAIL
+
+  [Registering script with bad MIME type]
+    expected: FAIL
+
+  [Registering redirected script]
+    expected: FAIL
+
+  [Registering script including parse error]
+    expected: FAIL
+
+  [Registering script including undefined error]
+    expected: FAIL
+
+  [Registering script including uncaught exception]
+    expected: FAIL
+
+  [Registering script including caught exception]
+    expected: FAIL
+
+  [Registering script importing malformed script]
+    expected: FAIL
+
+  [Registering script importing non-existent script]
+    expected: FAIL
+
+  [Script URL including URL-encoded slash]
+    expected: FAIL
+
+  [Scope including URL-encoded slash]
+    expected: FAIL
+
+  [Script URL including URL-encoded backslash]
+    expected: FAIL
+
+  [Scope including URL-encoded backslash]
+    expected: FAIL
+
+  [Script URL including parent-reference]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/request-end-to-end.https.html.ini
@@ -0,0 +1,6 @@
+[request-end-to-end.https.html]
+  type: testharness
+  expected: ERROR
+  [Request: end-to-end]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/resource-timing.https.html.ini
@@ -0,0 +1,8 @@
+[resource-timing.https.html]
+  type: testharness
+  [Controlled resource loads]
+    expected: FAIL
+
+  [Non-controlled resource loads]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/resources/fetch-request-resources-iframe.https.html.ini
@@ -0,0 +1,3 @@
+[fetch-request-resources-iframe.https.html]
+  type: testharness
+  expected: TIMEOUT
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/resources/fetch-request-xhr-iframe.https.html.ini
@@ -0,0 +1,3 @@
+[fetch-request-xhr-iframe.https.html]
+  type: testharness
+  expected: TIMEOUT
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/resources/fetch-response-xhr-iframe.https.html.ini
@@ -0,0 +1,3 @@
+[fetch-response-xhr-iframe.https.html]
+  type: testharness
+  expected: TIMEOUT
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/resources/invalid-blobtype-iframe.https.html.ini
@@ -0,0 +1,3 @@
+[invalid-blobtype-iframe.https.html]
+  type: testharness
+  expected: TIMEOUT
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/resources/invalid-header-iframe.https.html.ini
@@ -0,0 +1,3 @@
+[invalid-header-iframe.https.html]
+  type: testharness
+  expected: TIMEOUT
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/service-worker-csp-connect.https.html.ini
@@ -0,0 +1,5 @@
+[service-worker-csp-connect.https.html]
+  type: testharness
+  [CSP test for connect-src in ServiceWorkerGlobalScope]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/service-worker-csp-default.https.html.ini
@@ -0,0 +1,5 @@
+[service-worker-csp-default.https.html]
+  type: testharness
+  [CSP test for default-src in ServiceWorkerGlobalScope]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/service-worker-csp-script.https.html.ini
@@ -0,0 +1,5 @@
+[service-worker-csp-script.https.html]
+  type: testharness
+  [CSP test for script-src in ServiceWorkerGlobalScope]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/serviceworkerobject-scripturl.sub.html.ini
@@ -0,0 +1,11 @@
+[serviceworkerobject-scripturl.sub.html]
+  type: testharness
+  [Verify the scriptURL property: relative]
+    expected: FAIL
+
+  [Verify the scriptURL property: with-fragment]
+    expected: FAIL
+
+  [Verify the scriptURL property: absolute]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/shared-worker-controlled.https.html.ini
@@ -0,0 +1,12 @@
+[shared-worker-controlled.https.html]
+  type: testharness
+  expected: ERROR
+  [Verify subresource loads in SharedWorker are controlled by a Service Worker]
+    expected: FAIL
+
+  [Verify SharedWorker construction is controlled by a Service Worker]
+    expected: TIMEOUT
+
+  [Verify importScripts from SharedWorker is controlled by a Service Worker]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/stashed-ports.https.html.ini
@@ -0,0 +1,11 @@
+[stashed-ports.https.html]
+  type: testharness
+  [Name set when adding port is set correctly.]
+    expected: FAIL
+
+  [Messages posted into stashed port arrive on other side.]
+    expected: FAIL
+
+  [Messages sent to stashed port arrive as global events.]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html.ini
@@ -0,0 +1,5 @@
+[sync-xhr-doesnt-deadlock.https.html]
+  type: testharness
+  [Verify SyncXHR does not deadlock]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/synced-state.https.html.ini
@@ -0,0 +1,6 @@
+[synced-state.https.html]
+  type: testharness
+  expected: ERROR
+  [worker objects for the same entity have the same state]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/uncontrolled-page.https.html.ini
@@ -0,0 +1,5 @@
+[uncontrolled-page.https.html]
+  type: testharness
+  [Fetch events should not go through uncontrolled page.]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/unregister-controller.https.html.ini
@@ -0,0 +1,6 @@
+[unregister-controller.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [Unregister prevents new controllee even if registration is still in use]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/unregister-then-register-new-script.https.html.ini
@@ -0,0 +1,12 @@
+[unregister-then-register-new-script.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [Registering a new script URL while an unregistered registration is in use]
+    expected: TIMEOUT
+
+  [Registering a new script URL that 404s does not resurrect an unregistered registration]
+    expected: TIMEOUT
+
+  [Registering a new script URL that fails to install does not resurrect an unregistered registration]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/unregister-then-register.https.html.ini
@@ -0,0 +1,12 @@
+[unregister-then-register.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [Unregister then register resolves to the original value if the registration is in use.]
+    expected: TIMEOUT
+
+  [Unregister then register does not affect existing controllee]
+    expected: TIMEOUT
+
+  [Unregister then register resurrects the registration]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/update.https.html.ini
@@ -0,0 +1,5 @@
+[update.https.html]
+  type: testharness
+  [Update a registration]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/waiting.https.html.ini
@@ -0,0 +1,6 @@
+[waiting.https.html]
+  type: testharness
+  expected: TIMEOUT
+  [waiting is set]
+    expected: TIMEOUT
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/ServiceWorkerGlobalScope/close.https.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<title>ServiceWorkerGlobalScope: close operation</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/test-helpers.sub.js"></script>
+<script>
+
+service_worker_test(
+  'resources/close-worker.js', 'ServiceWorkerGlobalScope: close operation');
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/ServiceWorkerGlobalScope/registration-attribute.https.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<title>ServiceWorkerGlobalScope: registration</title>
+<script src='/resources/testharness.js'></script>
+<script src='/resources/testharnessreport.js'></script>
+<script src='../resources/test-helpers.sub.js'></script>
+<script>
+
+promise_test(function(t) {
+    var script = 'resources/registration-attribute-worker.js';
+    var scope = 'resources/scope/registration-attribute';
+
+    return service_worker_unregister_and_register(t, script, scope)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() { return with_iframe(scope); })
+      .then(function(frame) {
+          var expected_events_seen = [
+            'updatefound',
+            'install',
+            'statechange(installed)',
+            'statechange(activating)',
+            'activate',
+            'statechange(activated)',
+            'fetch',
+          ];
+
+          assert_equals(
+              frame.contentDocument.body.textContent,
+              expected_events_seen.toString(),
+              'Service Worker should respond to fetch');
+          frame.remove();
+          return service_worker_unregister_and_done(t, scope);
+        });
+  }, 'Verify registration attribute on ServiceWorkerGlobalScope');
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/ServiceWorkerGlobalScope/resources/close-worker.js
@@ -0,0 +1,8 @@
+importScripts('../../resources/interfaces.js');
+importScripts('../../resources/worker-testharness.js');
+
+test(function() {
+  assert_throws({name: 'InvalidAccessError'}, function() {
+    self.close();
+  });
+}, 'ServiceWorkerGlobalScope close operation');
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/ServiceWorkerGlobalScope/resources/registration-attribute-worker.js
@@ -0,0 +1,132 @@
+importScripts('../../resources/test-helpers.sub.js');
+importScripts('../../resources/worker-testharness.js');
+
+var events_seen = [];
+
+assert_equals(
+  self.registration.scope,
+  normalizeURL('scope/registration-attribute'),
+  'On worker script evaluation, registration attribute should be set');
+assert_equals(
+  self.registration.installing,
+  null,
+  'On worker script evaluation, installing worker should be null');
+assert_equals(
+  self.registration.waiting,
+  null,
+  'On worker script evaluation, waiting worker should be null');
+assert_equals(
+  self.registration.active,
+  null,
+  'On worker script evaluation, active worker should be null');
+
+self.registration.addEventListener('updatefound', function() {
+    events_seen.push('updatefound');
+
+    assert_equals(
+      self.registration.scope,
+      normalizeURL('scope/registration-attribute'),
+      'On updatefound event, registration attribute should be set');
+    assert_equals(
+      self.registration.installing.scriptURL,
+      normalizeURL('registration-attribute-worker.js'),
+      'On updatefound event, installing worker should be set');
+    assert_equals(
+      self.registration.waiting,
+      null,
+      'On updatefound event, waiting worker should be null');
+    assert_equals(
+      self.registration.active,
+      null,
+      'On updatefound event, active worker should be null');
+
+    assert_equals(
+      self.registration.installing.state,
+      'installing',
+      'On updatefound event, worker should be in the installing state');
+
+    var worker = self.registration.installing;
+    self.registration.installing.addEventListener('statechange', function() {
+        events_seen.push('statechange(' + worker.state + ')');
+      });
+  });
+
+self.addEventListener('install', function(e) {
+    events_seen.push('install');
+
+    assert_equals(
+      self.registration.scope,
+      normalizeURL('scope/registration-attribute'),
+      'On install event, registration attribute should be set');
+    assert_equals(
+      self.registration.installing.scriptURL,
+      normalizeURL('registration-attribute-worker.js'),
+      'On install event, installing worker should be set');
+    assert_equals(
+      self.registration.waiting,
+      null,
+      'On install event, waiting worker should be null');
+    assert_equals(
+      self.registration.active,
+      null,
+      'On install event, active worker should be null');
+
+    assert_equals(
+      self.registration.installing.state,
+      'installing',
+      'On install event, worker should be in the installing state');
+  });
+
+self.addEventListener('activate', function(e) {
+    events_seen.push('activate');
+
+    assert_equals(
+      self.registration.scope,
+      normalizeURL('scope/registration-attribute'),
+      'On activate event, registration attribute should be set');
+    assert_equals(
+      self.registration.installing,
+      null,
+      'On activate event, installing worker should be null');
+    assert_equals(
+      self.registration.waiting,
+      null,
+      'On activate event, waiting worker should be null');
+    assert_equals(
+      self.registration.active.scriptURL,
+      normalizeURL('registration-attribute-worker.js'),
+      'On activate event, active worker should be set');
+
+    assert_equals(
+      self.registration.active.state,
+      'activating',
+      'On activate event, worker should be in the activating state');
+  });
+
+self.addEventListener('fetch', function(e) {
+    events_seen.push('fetch');
+
+    assert_equals(
+      self.registration.scope,
+      normalizeURL('scope/registration-attribute'),
+      'On fetch event, registration attribute should be set');
+    assert_equals(
+      self.registration.installing,
+      null,
+      'On fetch event, installing worker should be null');
+    assert_equals(
+      self.registration.waiting,
+      null,
+      'On fetch event, waiting worker should be null');
+    assert_equals(
+      self.registration.active.scriptURL,
+      normalizeURL('registration-attribute-worker.js'),
+      'On fetch event, active worker should be set');
+
+    assert_equals(
+      self.registration.active.state,
+      'activated',
+      'On fetch event, worker should be in the activated state');
+
+    e.respondWith(new Response(events_seen));
+  });
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/ServiceWorkerGlobalScope/resources/unregister-worker.js
@@ -0,0 +1,23 @@
+function matchQuery(query) {
+  return self.location.href.indexOf(query) != -1;
+}
+
+if (matchQuery('?evaluation'))
+  self.registration.unregister();
+
+self.addEventListener('install', function(e) {
+    if (matchQuery('?install'))
+      self.registration.unregister();
+  });
+
+self.addEventListener('activate', function(e) {
+    if (matchQuery('?activate'))
+      self.registration.unregister();
+  });
+
+self.addEventListener('message', function(e) {
+    self.registration.unregister()
+      .then(function(result) {
+          e.data.port.postMessage({result: result});
+        });
+  });
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/ServiceWorkerGlobalScope/unregister.https.html
@@ -0,0 +1,127 @@
+<!DOCTYPE html>
+<title>ServiceWorkerGlobalScope: unregister</title>
+<script src='/resources/testharness.js'></script>
+<script src='/resources/testharnessreport.js'></script>
+<script src='../resources/test-helpers.sub.js'></script>
+<script>
+
+promise_test(function(t) {
+    var script = 'resources/unregister-worker.js?evaluation';
+    var scope = 'resources/scope/unregister-on-script-evaluation';
+
+    return service_worker_unregister_and_register(t, script, scope)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'redundant');
+        })
+      .then(function() {
+          return navigator.serviceWorker.getRegistration(scope);
+        })
+      .then(function(result) {
+          assert_equals(
+            result,
+            undefined,
+            'After unregister(), the registration should not found');
+          return service_worker_unregister_and_done(t, scope);
+        });
+  }, 'Unregister on script evaluation');
+
+promise_test(function(t) {
+    var script = 'resources/unregister-worker.js?install';
+    var scope = 'resources/scope/unregister-on-install-event';
+
+    return service_worker_unregister_and_register(t, script, scope)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'redundant');
+        })
+      .then(function() {
+          return navigator.serviceWorker.getRegistration(scope);
+        })
+      .then(function(result) {
+          assert_equals(
+            result,
+            undefined,
+            'After unregister(), the registration should not found');
+          return service_worker_unregister_and_done(t, scope);
+        });
+  }, 'Unregister on installing event');
+
+promise_test(function(t) {
+    var script = 'resources/unregister-worker.js?activate';
+    var scope = 'resources/scope/unregister-on-activate-event';
+
+    return service_worker_unregister_and_register(t, script, scope)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'redundant');
+        })
+      .then(function() {
+          return navigator.serviceWorker.getRegistration(scope);
+        })
+      .then(function(result) {
+          assert_equals(
+            result,
+            undefined,
+            'After unregister(), the registration should not found');
+          return service_worker_unregister_and_done(t, scope);
+        });
+  }, 'Unregister on activate event');
+
+promise_test(function(t) {
+    var script = 'resources/unregister-worker.js';
+    var scope = 'resources/unregister-controlling-worker';
+
+    var controller;
+    var frame;
+
+    return service_worker_unregister_and_register(t, script, scope)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() { return with_iframe(scope); })
+      .then(function(f) {
+          frame = f;
+          controller = frame.contentWindow.navigator.serviceWorker.controller;
+
+          assert_equals(
+            controller.scriptURL,
+            normalizeURL(script),
+            'Service worker should control a new document')
+
+          // Wait for the completion of unregister() on the worker.
+          var channel = new MessageChannel();
+          var promise = new Promise(function(resolve) {
+              channel.port1.onmessage = t.step_func(function(e) {
+                  assert_true(e.data.result,
+                              'unregister() should successfully finish');
+                  resolve();
+                });
+            });
+          controller.postMessage({port: channel.port2}, [channel.port2]);
+          return promise;
+        })
+      .then(function() {
+          return navigator.serviceWorker.getRegistration(scope);
+        })
+      .then(function(result) {
+          assert_equals(
+            result,
+            undefined,
+            'After unregister(), the registration should not found');
+          assert_equals(
+            frame.contentWindow.navigator.serviceWorker.controller,
+            controller,
+            'After unregister(), the worker should still control the document');
+          return with_iframe(scope);
+        })
+      .then(function(new_frame) {
+          assert_equals(
+            new_frame.contentWindow.navigator.serviceWorker.controller,
+            null,
+            'After unregister(), the worker should not control a new document');
+
+          frame.remove();
+          new_frame.remove();
+          return service_worker_unregister_and_done(t, scope);
+        })
+  }, 'Unregister controlling service worker');
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/ServiceWorkerGlobalScope/update.https.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<title>ServiceWorkerGlobalScope: update</title>
+<script src='/resources/testharness.js'></script>
+<script src='/resources/testharnessreport.js'></script>
+<script src='../resources/test-helpers.sub.js'></script>
+<script>
+
+promise_test(function(t) {
+    var script = 'resources/update-worker.py';
+    var scope = 'resources/scope/update';
+    var registration;
+    var frame1;
+
+    return service_worker_unregister_and_register(t, script, scope)
+      .then(function(r) {
+          registration = r;
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() { return with_iframe(scope); })
+      .then(function(f) {
+          frame1 = f;
+          registration.active.postMessage('update');
+          return wait_for_update(t, registration);
+        })
+      .then(function() { return with_iframe(scope); })
+      .then(function(frame2) {
+          var expected_events_seen = [
+            'updatefound',  // by register().
+            'activate',
+            'fetch',
+            'message',
+            'updatefound',  // by update() in the message handler.
+            'fetch',
+          ];
+          assert_equals(
+              frame2.contentDocument.body.textContent,
+              expected_events_seen.toString(),
+              'events seen by the worker');
+          frame1.remove();
+          frame2.remove();
+          return service_worker_unregister_and_done(t, scope);
+        });
+  }, 'Update a registration on ServiceWorkerGlobalScope');
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/activation-after-registration.https.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<title>Service Worker: Activation occurs after registration</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<body>
+<script>
+var t = async_test('activation occurs after registration');
+t.step(function() {
+    var scope = 'resources/blank.html';
+    var registration;
+
+    service_worker_unregister_and_register(
+        t, 'resources/empty-worker.js', scope)
+      .then(function(r) {
+          registration = r;
+          assert_equals(
+              r.installing.state,
+              'installing',
+              'worker should be in the "installing" state upon registration');
+          return wait_for_state(t, r.installing, 'activated');
+        })
+      .then(function() {
+          service_worker_unregister_and_done(t, scope);
+        })
+      .catch(unreached_rejection(t));
+});
+</script>
+</body>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/active.https.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<title>ServiceWorker: navigator.serviceWorker.active</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<body>
+<script>
+// "active" is set
+async_test(function(t) {
+    var step = t.step_func.bind(t);
+    var url = 'resources/empty-worker.js';
+    var scope = 'resources/blank.html';
+    var frame;
+    var registration;
+
+    service_worker_unregister(t, scope)
+      .then(step(function() { return with_iframe(scope); }))
+      .then(step(function(f) {
+          frame = f;
+          return navigator.serviceWorker.register(url, {scope: scope});
+        }))
+      .then(step(function(r) {
+          registration = r;
+          return wait_for_state(t, r.installing, 'activating');
+        }))
+      .then(step(function() {
+          var container = frame.contentWindow.navigator.serviceWorker;
+          assert_equals(
+            container.controller,
+            null,
+            'On activating state a document should not have a controller');
+          assert_equals(
+            registration.active.scriptURL,
+            normalizeURL(url),
+            'On activating state a document should have an active worker ');
+          assert_equals(
+            registration.waiting,
+            null,
+            'On activating state a document should not have a waiting worker');
+          assert_equals(
+            registration.installing,
+            null,
+            'On activating state a document should not have an installing ' +
+                'worker');
+
+          // FIXME: Add a test for a frame created after installation.
+          // Should the existing frame ("frame") block activation?
+        }))
+      .then(step(function() {
+          frame.remove();
+          return service_worker_unregister_and_done(t, scope);
+        }))
+      .catch(unreached_rejection(t));
+  }, 'active is set');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/appcache-ordering-main.https.html
@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<body>
+<script>
+
+var INSTALL_APPCACHE_URL = "resources/appcache-ordering.install.html";
+var IS_APPCACHED_URL = "resources/appcache-ordering.is-appcached.html";
+var SERVICE_WORKER_SCOPE = "resources/appcache-ordering";
+var SERVICE_WORKER_SCRIPT = "resources/empty-worker.js";
+
+var resolve_install_appcache = undefined;
+var reject_install_appcache = undefined;
+
+// Called by the INSTALL_APPCACHE_URL child frame.
+function notify_appcache_installed(success) {
+  if (success)
+    resolve_install_appcache();
+  else
+    reject_install_appcache();
+}
+
+function install_appcache() {
+  return new Promise(function(resolve, reject) {
+      var frame = document.createElement('iframe');
+      frame.src = INSTALL_APPCACHE_URL;
+      document.body.appendChild(frame);      
+      resolve_install_appcache = function() {
+          document.body.removeChild(frame);
+          resolve();
+        };
+      reject_install_appcache = function() {
+          document.body.removeChild(frame);
+          reject();
+        };
+  });
+}
+
+var resolve_is_appcached = undefined;
+
+// Called by the IS_APPCACHED_URL child frame.
+function notify_is_appcached(is) {
+  resolve_is_appcached(is);
+}
+
+function is_appcached() {
+  return new Promise(function(resolve) {
+      var frame = document.createElement('iframe');
+      frame.src = IS_APPCACHED_URL;
+      document.body.appendChild(frame);
+      resolve_is_appcached = function(is) {
+          document.body.removeChild(frame);
+          resolve(is);
+        };
+  });
+}
+
+async_test(function(t) {
+    service_worker_unregister(t, SERVICE_WORKER_SCOPE)
+      .then(function() {
+          return install_appcache();
+        })
+      .then(function() {
+          return is_appcached();
+        })
+      .then(function(result) {
+          assert_true(result, 'appcache should initially be utilized');
+          return service_worker_unregister_and_register(
+              t, SERVICE_WORKER_SCRIPT, SERVICE_WORKER_SCOPE);
+        })
+      .then(function(r) {  
+          return wait_for_state(t, r.installing, 'activated');
+        })
+      .then(function() {  
+          return is_appcached();
+        })
+      .then(function(result) {
+          assert_false(result, 'but serviceworkers should take priority');
+          service_worker_unregister_and_done(t, SERVICE_WORKER_SCOPE);
+        })
+      .catch(unreached_rejection(t));
+  }, 'serviceworkers take priority over appcaches');
+
+</script>
+</body>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/claim-not-using-registration.https.html
@@ -0,0 +1,123 @@
+<!DOCTYPE html>
+<title>Service Worker: claim client not using registration</title>
+<script src="/resources/testharness.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<body>
+<script>
+
+promise_test(function(t) {
+    var init_scope = 'resources/blank.html?not-using-init';
+    var claim_scope = 'resources/blank.html?not-using';
+    var init_worker_url = 'resources/empty.js';
+    var claim_worker_url = 'resources/claim-worker.js';
+    var claim_worker, claim_registration, frame1, frame2;
+    return service_worker_unregister_and_register(
+        t, init_worker_url, init_scope)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() {
+          return Promise.all(
+              [with_iframe(init_scope), with_iframe(claim_scope)]);
+        })
+      .then(function(frames) {
+          frame1 = frames[0];
+          frame2 = frames[1];
+          assert_equals(
+              frame1.contentWindow.navigator.serviceWorker.controller.scriptURL,
+              normalizeURL(init_worker_url),
+              'Frame1 controller should not be null');
+          assert_equals(
+              frame2.contentWindow.navigator.serviceWorker.controller, null,
+              'Frame2 controller should be null');
+          return navigator.serviceWorker.register(claim_worker_url,
+                                                  {scope: claim_scope});
+        })
+      .then(function(registration) {
+          claim_worker = registration.installing;
+          claim_registration = registration;
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() {
+          var saw_controllerchanged = new Promise(function(resolve) {
+              frame2.contentWindow.navigator.serviceWorker.oncontrollerchange =
+                  function() { resolve(); }
+            });
+          var channel = new MessageChannel();
+          var saw_message = new Promise(function(resolve) {
+              channel.port1.onmessage = t.step_func(function(e) {
+                  assert_equals(e.data, 'PASS',
+                                'Worker call to claim() should fulfill.');
+                  resolve();
+                });
+            });
+          claim_worker.postMessage({port: channel.port2}, [channel.port2]);
+          return Promise.all([saw_controllerchanged, saw_message]);
+        })
+      .then(function() {
+          assert_equals(
+              frame1.contentWindow.navigator.serviceWorker.controller.scriptURL,
+              normalizeURL(init_worker_url),
+              'Frame1 should not be influenced');
+          assert_equals(
+              frame2.contentWindow.navigator.serviceWorker.controller.scriptURL,
+              normalizeURL(claim_worker_url),
+              'Frame2 should be controlled by the new registration');
+          frame1.remove();
+          frame2.remove();
+          return claim_registration.unregister();
+        })
+      .then(function() {
+          return service_worker_unregister_and_done(t, init_scope);
+        });
+  }, 'Test claim client which is not using registration');
+
+promise_test(function(t) {
+    var scope = 'resources/blank.html?longer-matched';
+    var claim_scope = 'resources/blank.html?longer';
+    var claim_worker_url = 'resources/claim-worker.js';
+    var installing_worker_url = 'resources/empty-worker.js';
+    var frame, claim_worker;
+    return with_iframe(scope)
+      .then(function(f) {
+          frame = f;
+          return navigator.serviceWorker.register(
+              claim_worker_url, {scope: claim_scope});
+        })
+      .then(function(registration) {
+          claim_worker = registration.installing;
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() {
+          return navigator.serviceWorker.register(
+              installing_worker_url, {scope: scope});
+        })
+      .then(function() {
+          var channel = new MessageChannel();
+          var saw_message = new Promise(function(resolve) {
+              channel.port1.onmessage = t.step_func(function(e) {
+                  assert_equals(e.data, 'PASS',
+                                'Worker call to claim() should fulfill.');
+                  resolve();
+                });
+            });
+          claim_worker.postMessage({port: channel.port2}, [channel.port2]);
+          return saw_message;
+        })
+      .then(function() {
+          assert_equals(
+              frame.contentWindow.navigator.serviceWorker.controller, null,
+              'Frame should not be claimed when a longer-matched ' +
+              'registration exists');
+          frame.remove();
+          return service_worker_unregister(t, claim_scope);
+        })
+      .then(function() {
+          return service_worker_unregister_and_done(t, scope);
+        });
+  }, 'Test claim client when there\'s a longer-matched registration not ' +
+     'already used by the page');
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/claim-using-registration.https.html
@@ -0,0 +1,100 @@
+<!DOCTYPE html>
+<title>Service Worker: claim client using registration</title>
+<script src="/resources/testharness.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+
+promise_test(function(t) {
+    var scope = 'resources/';
+    var frame_url = 'resources/blank.html?using-different-registration';
+    var url1 = 'resources/empty.js';
+    var url2 = 'resources/claim-worker.js';
+    var worker, sw_registration, frame;
+    return service_worker_unregister_and_register(t, url1, scope)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() {
+          return with_iframe(frame_url);
+        })
+      .then(function(f) {
+          frame = f;
+          return navigator.serviceWorker.register(url2, {scope: frame_url});
+        })
+      .then(function(registration) {
+          worker = registration.installing;
+          sw_registration = registration;
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() {
+          var saw_controllerchanged = new Promise(function(resolve) {
+              frame.contentWindow.navigator.serviceWorker.oncontrollerchange =
+                  function() { resolve(); }
+            });
+          var channel = new MessageChannel();
+          var saw_message = new Promise(function(resolve) {
+              channel.port1.onmessage = t.step_func(function(e) {
+                  assert_equals(e.data, 'PASS',
+                                'Worker call to claim() should fulfill.');
+                  resolve();
+                });
+            });
+          worker.postMessage({port: channel.port2}, [channel.port2]);
+          return Promise.all([saw_controllerchanged, saw_message]);
+        })
+      .then(function() {
+          assert_equals(
+              frame.contentWindow.navigator.serviceWorker.controller.scriptURL,
+              normalizeURL(url2),
+              'Frame1 controller scriptURL should be changed to url2');
+          frame.remove();
+          return sw_registration.unregister();
+        })
+      .then(function() {
+          return service_worker_unregister_and_done(t, scope);
+        });
+  }, 'Test worker claims client which is using another registration');
+
+promise_test(function(t) {
+    var scope = 'resources/blank.html?using-same-registration';
+    var url1 = 'resources/empty.js';
+    var url2 = 'resources/claim-worker.js';
+    var frame, worker;
+    return service_worker_unregister_and_register(t, url1, scope)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() {
+          return with_iframe(scope);
+        })
+      .then(function(f) {
+          frame = f;
+          return navigator.serviceWorker.register(url2, {scope: scope});
+        })
+      .then(function(registration) {
+          worker = registration.installing;
+          return wait_for_state(t, registration.installing, 'installed');
+        })
+      .then(function() {
+          var channel = new MessageChannel();
+          var saw_message = new Promise(function(resolve) {
+              channel.port1.onmessage = t.step_func(function(e) {
+                  assert_equals(e.data, 'FAIL: exception: InvalidStateError',
+                                'Worker call to claim() should reject with ' +
+                                'InvalidStateError');
+                  resolve();
+                });
+            });
+          worker.postMessage({port: channel.port2}, [channel.port2]);
+          return saw_message;
+        })
+      .then(function() {
+          frame.remove();
+          return service_worker_unregister_and_done(t, scope);
+        });
+  }, 'Test for the waiting worker claims a client which is using the the ' +
+     'same registration');
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/clients-matchall-client-types.https.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<title>Service Worker: Clients.matchAll with various clientTypes</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+var scope = 'resources/clients-matchall-client-types';
+var iframe_url = scope + '-iframe.html';
+var shared_worker_url = scope + '-shared-worker.js';
+
+/* visibilityState, focused, url, frameType */
+var expected_without_type = [
+    ['visible', true, new URL(iframe_url, location).href, 'nested']
+];
+var expected_with_window = [
+    ['visible', true, new URL(iframe_url, location).href, 'nested']
+];
+var expected_with_shared_worker = [
+    [,,new URL(shared_worker_url, location).href, 'none']
+];
+var expected_with_all = [
+    ['visible', true, new URL(iframe_url, location).href, 'nested'],
+    [,,new URL(shared_worker_url, location).href, 'none']
+];
+
+function test_matchall(frame, expected, query_options) {
+  // Make sure the frame gets focus.
+  frame.focus();
+  expected.sort(function(a, b) { return a[2] > b[2] ? 1 : -1; });
+  return new Promise(function(resolve, reject) {
+    var channel = new MessageChannel();
+    channel.port1.onmessage = function(e) {
+      assert_equals(e.data.length, expected.length);
+      for (var i = 0; i < e.data.length; i++)
+        assert_array_equals(e.data[i], expected[i]);
+      resolve();
+    };
+    frame.contentWindow.navigator.serviceWorker.controller.postMessage(
+        {port:channel.port2, options:query_options},
+        [channel.port2]);
+  });
+}
+
+promise_test(function(t) {
+    var frame;
+    return service_worker_unregister_and_register(
+        t, 'resources/clients-matchall-worker.js', scope)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() { return with_iframe(iframe_url); })
+      .then(function(f) {
+          frame = f;
+          return new Promise(function(resolve, reject) {
+              var w = new SharedWorker(shared_worker_url);
+              w.port.onmessage = resolve;
+            });
+        })
+      .then(function() {
+          return test_matchall(frame, expected_without_type, {});
+        })
+      .then(function() {
+          return test_matchall(frame, expected_with_window, {type:'window'});
+        })
+      .then(function() {
+          return test_matchall(frame, expected_with_shared_worker,
+                               {type:'sharedworker'});
+        })
+      .then(function() {
+          return test_matchall(frame, expected_with_all, {type:'all'});
+        })
+      .then(function() {
+          frame.remove();
+          return service_worker_unregister_and_done(t, scope);
+        });
+  }, 'Verify matchAll() with various client types');
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/clients-matchall-include-uncontrolled.https.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<title>Service Worker: Clients.matchAll with includeUncontrolled</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+var base_url = 'resources/blank.html'; // This is out-of-scope.
+var scope = base_url + '?clients-matchAll-includeUncontrolled';
+
+// Creates 3 iframes, 2 for in-scope and 1 for out-of-scope.
+// The frame opened for scope + '#2' is returned via a promise.
+// FIXME: remove iframes when the test finishes.
+function create_iframes(scope) {
+  return with_iframe(base_url)
+    .then(function(frame0) {
+        return with_iframe(scope + '#1');
+      })
+    .then(function(frame1) {
+        return with_iframe(scope + '#2');
+      });
+}
+
+var expected_without_include_uncontrolled = [
+    /* visibilityState, focused, url, frameType */
+    ['visible', false, new URL(scope + '#1', location).toString(), 'nested'],
+    ['visible', true, new URL(scope + '#2', location).toString(), 'nested']
+];
+
+var expected_with_include_uncontrolled = [
+    /* visibilityState, focused, url, frameType */
+    ['visible', false, new URL(scope + '#1', location).toString(), 'nested'],
+    ['visible', true, new URL(scope + '#2', location).toString(), 'nested'],
+    ['visible', false, new URL(base_url, location).toString(), 'nested'],
+    ['visible', true, location.href, 'top-level']
+];
+
+function test_matchall(frame, expected, query_options) {
+  // Make sure we have focus for '#2' frame and its parent window.
+  frame.focus();
+  frame.contentWindow.focus();
+  expected.sort(function(a, b) { return a[2] > b[2] ? 1 : -1; });
+  return new Promise(function(resolve, reject) {
+    var channel = new MessageChannel();
+    channel.port1.onmessage = function(e) {
+      assert_equals(e.data.length, expected.length);
+      for (var i = 0; i < e.data.length; i++)
+        assert_array_equals(e.data[i], expected[i]);
+      resolve(frame);
+    };
+    frame.contentWindow.navigator.serviceWorker.controller.postMessage(
+        {port:channel.port2, options:query_options},
+        [channel.port2]);
+  });
+}
+
+// Run clients.matchAll without and with includeUncontrolled=true.
+// (We want to run the two tests sequentially in the same async_test
+// so that we can use the same set of iframes without intefering each other.
+async_test(function(t) {
+    service_worker_unregister_and_register(
+        t, 'resources/clients-matchall-worker.js', scope)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() { return create_iframes(scope); })
+      .then(function(frame) {
+          return test_matchall(frame, expected_without_include_uncontrolled);
+        })
+      .then(function(frame) {
+          return test_matchall(frame, expected_with_include_uncontrolled,
+                               {includeUncontrolled:true});
+        })
+      .then(function() {
+          service_worker_unregister_and_done(t, scope);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Verify matchAll() respect includeUncontrolled');
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/clients-matchall.https.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<title>Service Worker: Clients.matchAll</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+var scope = 'resources/blank.html?clients-matchAll';
+var t = async_test('Test Clients.matchAll()');
+t.step(function() {
+    service_worker_unregister_and_register(
+        t, 'resources/clients-matchall-worker.js', scope)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() { return with_iframe(scope + '#1'); })
+      .then(function(frame1) {
+          frame1.focus();
+          return with_iframe(scope + '#2');
+        })
+      .then(function(frame2) {
+          var channel = new MessageChannel();
+          channel.port1.onmessage = t.step_func(onMessage);
+          frame2.contentWindow.navigator.serviceWorker.controller.postMessage(
+              {port:channel.port2}, [channel.port2]);
+        })
+      .catch(unreached_rejection(t));
+  });
+
+var expected = [
+    /* visibilityState, focused, url, frameType */
+    ['visible', true, new URL(scope + '#1', location).toString(), 'nested'],
+    ['visible', false, new URL(scope + '#2', location).toString(), 'nested']
+];
+
+function onMessage(e) {
+  assert_equals(e.data.length, 2);
+  assert_array_equals(e.data[0], expected[0]);
+  assert_array_equals(e.data[1], expected[1]);
+  service_worker_unregister_and_done(t, scope);
+}
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/controller-on-load.https.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>Service Worker: Controller on load</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<body>
+<script>
+var t = async_test('controller is set for a controlled document');
+t.step(function() {
+    var url = 'resources/empty-worker.js';
+    var scope = 'resources/blank.html';
+    service_worker_unregister_and_register(t, url, scope)
+      .then(t.step_func(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        }))
+      .then(t.step_func(function() {
+          return with_iframe(scope)
+        }))
+      .then(t.step_func(function(frame) {
+          var w = frame.contentWindow;
+          var controller = w.navigator.serviceWorker.controller;
+          assert_true(controller instanceof w.ServiceWorker,
+                      'controller should be a ServiceWorker object');
+          assert_equals(controller.scriptURL, normalizeURL(url));
+          service_worker_unregister_and_done(t, scope);
+        }))
+      .catch(unreached_rejection(t));
+  });
+</script>
+</body>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/controller-on-reload.https.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<title>Service Worker: Controller on reload</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<body>
+<script>
+promise_test(function(t) {
+    var scope = 'resources/blank.html';
+    var frame;
+    return service_worker_unregister(t, scope)
+      .then(function() {
+          return with_iframe(scope);
+        })
+      .then(function(f) {
+          frame = f;
+          return frame.contentWindow.navigator.serviceWorker.register(
+              'resources/empty-worker.js', {scope: scope});
+        })
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() {
+          var w = frame.contentWindow;
+          assert_equals(w.navigator.serviceWorker.controller, null,
+                        'controller should be null until the document is ' +
+                        'reloaded');
+          return new Promise(function(resolve) {
+              frame.onload = function() { resolve(); }
+              w.location.reload();
+            });
+        })
+      .then(function() {
+          var w = frame.contentWindow;
+          assert_true(
+              w.navigator.serviceWorker.controller instanceof w.ServiceWorker,
+              'controller should be a ServiceWorker object upon reload');
+          frame.remove();
+          service_worker_unregister_and_done(t, scope);
+        });
+  }, 'controller is set upon reload after registration');
+</script>
+</body>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/extendable-event-async-waituntil.https.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+promise_test(function(t) {
+    var script = 'resources/extendable-event-async-waituntil.js';
+    var scope = 'resources/async-waituntil';
+    var worker;
+
+    return service_worker_unregister_and_register(t, script, scope)
+      .then(function(registration) {
+          worker = registration.installing; 
+          return wait_for_state(t, worker, 'activated');
+        })
+      .then(function() {
+          var channel = new MessageChannel();
+          var saw_message = new Promise(function(resolve) {
+              channel.port1.onmessage = function(e) { resolve(e.data); }
+            });
+          worker.postMessage({port: channel.port2}, [channel.port2]);
+          return saw_message;
+        })
+      .then(function(message) {
+          assert_equals(message, 'PASS');
+          return service_worker_unregister_and_done(t, scope);
+        })
+  }, 'Calling waitUntil asynchronously throws an exception');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/extendable-event-waituntil.https.html
@@ -0,0 +1,125 @@
+<!DOCTYPE html>
+<title>ExtendableEvent: waitUntil</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+function runTest(test, scope, onRegister) {
+  var script = 'resources/extendable-event-waituntil.js?' + scope;
+  service_worker_unregister_and_register(test, script, scope)
+    .then(function(registration) {
+        onRegister(registration.installing);
+      });
+}
+
+// Sends a SYN to the worker and asynchronously listens for an ACK; sets
+// |obj.synced| to true once ack'd.
+function syncWorker(test, worker, obj) {
+  var channel = new MessageChannel();
+  channel.port1.onmessage = test.step_func(function(e) {
+      var message = e.data;
+      assert_equals(message, 'SYNC',
+                    'Should receive sync message from worker.');
+      obj.synced = true;
+      channel.port1.postMessage('ACK');
+    });
+  worker.postMessage({port: channel.port2}, [channel.port2]);
+}
+
+async_test(function(t) {
+    // Passing scope as the test switch for worker script.
+    var scope = 'resources/install-fulfilled';
+    var onRegister = function(worker) {
+        var obj = {};
+        wait_for_state(t, worker, 'installed')
+          .then(function() {
+              assert_true(
+                obj.synced,
+                'state should be "installed" after the waitUntil promise ' +
+                    'for "oninstall" is fulfilled.');
+              service_worker_unregister_and_done(t, scope);
+            })
+          .catch(unreached_rejection(t));
+        syncWorker(t, worker, obj);
+      };
+    runTest(t, scope, onRegister);
+  }, 'Test install event waitUntil fulfilled');
+
+async_test(function(t) {
+    var scope = 'resources/install-multiple-fulfilled';
+    var onRegister = function(worker) {
+        var obj1 = {};
+        var obj2 = {};
+        wait_for_state(t, worker, 'installed')
+          .then(function() {
+              assert_true(
+                obj1.synced && obj2.synced,
+                'state should be "installed" after all waitUntil promises ' +
+                    'for "oninstall" are fulfilled.');
+              service_worker_unregister_and_done(t, scope);
+            })
+          .catch(unreached_rejection(t));
+        syncWorker(t, worker, obj1);
+        syncWorker(t, worker, obj2);
+      };
+    runTest(t, scope, onRegister);
+  }, 'Test ExtendableEvent multiple waitUntil fulfilled.');
+
+async_test(function(t) {
+    var scope = 'resources/install-reject-precedence';
+    var onRegister = function(worker) {
+        wait_for_state(t, worker, 'redundant')
+          .then(function() {
+              service_worker_unregister_and_done(t, scope);
+            })
+          .catch(unreached_rejection(t));
+      };
+    runTest(t, scope, onRegister);
+  }, 'Test ExtendableEvent waitUntil reject precedence.');
+
+async_test(function(t) {
+    var scope = 'resources/activate-fulfilled';
+    var onRegister = function(worker) {
+        var obj = {};
+        wait_for_state(t, worker, 'activating')
+          .then(function() {
+              syncWorker(t, worker, obj);
+              return wait_for_state(t, worker, 'activated');
+            })
+          .then(function() {
+              assert_true(
+                obj.synced,
+                'state should be "activated" after the waitUntil promise ' +
+                    'for "onactivate" is fulfilled.');
+              service_worker_unregister_and_done(t, scope);
+            })
+          .catch(unreached_rejection(t));
+      };
+    runTest(t, scope, onRegister);
+  }, 'Test activate event waitUntil fulfilled');
+
+async_test(function(t) {
+    var scope = 'resources/install-rejected';
+    var onRegister = function(worker) {
+        wait_for_state(t, worker, 'redundant')
+          .then(function() {
+              service_worker_unregister_and_done(t, scope);
+            })
+          .catch(unreached_rejection(t));
+      };
+    runTest(t, scope, onRegister);
+  }, 'Test install event waitUntil rejected');
+
+async_test(function(t) {
+    var scope = 'resources/activate-rejected';
+    var onRegister = function(worker) {
+        wait_for_state(t, worker, 'activated')
+          .then(function() {
+              service_worker_unregister_and_done(t, scope);
+            })
+          .catch(unreached_rejection(t));
+      };
+    runTest(t, scope, onRegister);
+  }, 'Test activate event waitUntil rejected.');
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-canvas-tainting.https.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<title>Service Worker: canvas tainting of the fetched image</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js?pipe=sub"></script>
+<body>
+<script>
+async_test(function(t) {
+    var SCOPE = 'resources/fetch-canvas-tainting-iframe.html';
+    var SCRIPT = 'resources/fetch-rewrite-worker.js';
+    var host_info = get_host_info();
+
+    login(t)
+      .then(function() {
+          return service_worker_unregister_and_register(t, SCRIPT, SCOPE);
+        })
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() { return with_iframe(SCOPE); })
+      .then(function(frame) {
+          return new Promise(function(resolve, reject) {
+              var channel = new MessageChannel();
+              channel.port1.onmessage = t.step_func(function(e) {
+                  assert_equals(e.data.results, 'finish');
+                  frame.remove();
+                  service_worker_unregister_and_done(t, SCOPE);
+                });
+              frame.contentWindow.postMessage({},
+                                              host_info['HTTP_ORIGIN'],
+                                              [channel.port2]);
+            });
+        })
+      .catch(unreached_rejection(t));
+  }, 'Verify canvas tainting of fetched image in a Service Worker');
+</script>
+</body>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-cors-xhr.https.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<title>Service Worker: CORS XHR of fetch()</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js?pipe=sub"></script>
+<body>
+<script>
+async_test(function(t) {
+    var SCOPE = 'resources/fetch-cors-xhr-iframe.html';
+    var SCRIPT = 'resources/fetch-rewrite-worker.js';
+    var host_info = get_host_info();
+
+    login(t)
+      .then(function() {
+          return service_worker_unregister_and_register(t, SCRIPT, SCOPE);
+        })
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() { return with_iframe(SCOPE); })
+      .then(function(frame) {
+          return new Promise(function(resolve, reject) {
+              var channel = new MessageChannel();
+              channel.port1.onmessage = t.step_func(function(e) {
+                  assert_equals(e.data.results, 'finish');
+                  frame.remove();
+                  service_worker_unregister_and_done(t, SCOPE);
+                });
+              frame.contentWindow.postMessage({},
+                                              host_info['HTTP_ORIGIN'],
+                                              [channel.port2]);
+            });
+        })
+      .catch(unreached_rejection(t));
+  }, 'Verify CORS XHR of fetch() in a Service Worker');
+</script>
+</body>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-csp.https.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<title>Service Worker: CSP control of fetch()</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js?pipe=sub"></script>
+<script>
+async_test(function(t) {
+    var SCOPE = 'resources/fetch-csp-iframe.html';
+    var SCRIPT = 'resources/fetch-rewrite-worker.js';
+    var host_info = get_host_info();
+    service_worker_unregister_and_register(t, SCRIPT, SCOPE)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() { return with_iframe(SCOPE); })
+      .then(function(frame) {
+          return new Promise(function(resolve, reject) {
+              var channel = new MessageChannel();
+              channel.port1.onmessage = t.step_func(function(e) {
+                  assert_equals(e.data.results, 'finish');
+                  service_worker_unregister_and_done(t, SCOPE);
+                });
+              frame.contentWindow.postMessage({},
+                                              host_info['HTTP_ORIGIN'],
+                                              [channel.port2]);
+            });
+        })
+      .catch(unreached_rejection(t));
+  }, 'Verify CSP control of fetch() in a Service Worker');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-event-after-navigation-within-page.https.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<title>ServiceWorker: navigator.serviceWorker.waiting</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<body>
+<script>
+
+promise_test(function(t) {
+    var scope =
+        'resources/fetch-event-after-navigation-within-page-iframe.html' +
+        '?hashchange';
+    var worker = 'resources/simple-intercept-worker.js';
+    var frame;
+
+    return service_worker_unregister_and_register(t, worker, scope)
+      .then(function(reg) {
+          return wait_for_state(t, reg.installing, 'activated');
+        })
+      .then(function() { return with_iframe(scope); })
+      .then(function(f) {
+          frame = f;
+          return frame.contentWindow.fetch_url('simple.txt');
+        })
+      .then(function(response) {
+          assert_equals(response, 'intercepted by service worker');
+          frame.contentWindow.location.hash = 'foo';
+          return frame.contentWindow.fetch_url('simple.txt');
+        })
+      .then(function(response) {
+          assert_equals(response, 'intercepted by service worker');
+          frame.remove();
+          return service_worker_unregister_and_done(t, scope);
+        })
+  }, 'Service Worker should respond to fetch event after the hash changes');
+
+promise_test(function(t) {
+    var scope =
+        'resources/fetch-event-after-navigation-within-page-iframe.html' +
+        '?pushState';
+    var worker = 'resources/simple-intercept-worker.js';
+    var frame;
+
+    return service_worker_unregister_and_register(t, worker, scope)
+      .then(function(reg) {
+          return wait_for_state(t, reg.installing, 'activated');
+        })
+      .then(function() { return with_iframe(scope); })
+      .then(function(f) {
+          frame = f;
+          return frame.contentWindow.fetch_url('simple.txt');
+        })
+      .then(function(response) {
+          assert_equals(response, 'intercepted by service worker');
+          frame.contentWindow.history.pushState('', '', 'bar');
+          return frame.contentWindow.fetch_url('simple.txt');
+        })
+      .then(function(response) {
+          assert_equals(response, 'intercepted by service worker');
+          frame.remove();
+          return service_worker_unregister_and_done(t, scope);
+        })
+  }, 'Service Worker should respond to fetch event after the pushState');
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-event-async-respond-with.https.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+promise_test(function(t) {
+    var script = 'resources/fetch-event-async-respond-with-worker.js';
+    var scope = 'resources/simple.html';
+
+    return service_worker_unregister_and_register(t, script, scope)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() {
+          return with_iframe(scope);
+        })
+      .then(function(frame) {
+          var channel = new MessageChannel();
+          var saw_message = new Promise(function(resolve) {
+              channel.port1.onmessage = function(e) { resolve(e.data); }
+            });
+          var worker = frame.contentWindow.navigator.serviceWorker.controller;
+
+          frame.remove();
+          worker.postMessage({port: channel.port2}, [channel.port2]);
+          return saw_message;
+        })
+      .then(function(message) {
+          assert_equals(message, 'PASS');
+          return service_worker_unregister_and_done(t, scope);
+        })
+  }, 'Calling respondWith asynchronously throws an exception');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-event-network-error.https.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<title>Service Worker: Fetch event network error</title>
+<script src="/resources/testharness.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+var resolve_test_done;
+
+var test_done_promise = new Promise(function(resolve) {
+    resolve_test_done = resolve;
+  });
+
+// Called by the child frame.
+function notify_test_done(result) {
+  resolve_test_done(result);
+}
+
+promise_test(function(t) {
+    var scope = 'resources/fetch-event-network-error-controllee-iframe.html';
+    var script = 'resources/fetch-event-network-error-worker.js';
+    var frame;
+
+    return service_worker_unregister_and_register(t, script, scope)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() {
+          return with_iframe(scope);
+        })
+      .then(function(f) {
+          frame = f;
+          return test_done_promise;
+        })
+      .then(function(result) {
+          frame.remove();
+          assert_equals(result, 'PASS');
+          return service_worker_unregister_and_done(t, scope);
+        });
+  }, 'Rejecting the fetch event or using preventDefault() causes a network ' +
+     'error');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-event-respond-with-stops-propagation.https.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+promise_test(function(t) {
+    var script =
+        'resources/fetch-event-respond-with-stops-propagation-worker.js';
+    var scope = 'resources/simple.html';
+
+    return service_worker_unregister_and_register(t, script, scope)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() {
+          return with_iframe(scope);
+        })
+      .then(function(frame) {
+          var channel = new MessageChannel();
+          var saw_message = new Promise(function(resolve) {
+              channel.port1.onmessage = function(e) { resolve(e.data); }
+            });
+          var worker = frame.contentWindow.navigator.serviceWorker.controller;
+
+          frame.remove();
+          worker.postMessage({port: channel.port2}, [channel.port2]);
+          return saw_message;
+        })
+      .then(function(message) {
+          assert_equals(message, 'PASS');
+          return service_worker_unregister_and_done(t, scope);
+        })
+  }, 'respondWith() invokes stopImmediatePropagation()');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-event.https.html
@@ -0,0 +1,221 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<body>
+<script>
+var worker = 'resources/fetch-event-test-worker.js';
+
+async_test(function(t) {
+    var scope = 'resources/simple.html?string';
+    service_worker_unregister_and_register(t, worker, scope)
+      .then(function(reg) {
+          return wait_for_state(t, reg.installing, 'activated');
+        })
+      .then(function() { return with_iframe(scope); })
+      .then(function(frame) {
+          assert_equals(
+            frame.contentDocument.body.textContent,
+            'Test string',
+            'Service Worker should respond to fetch with a test string');
+          assert_equals(
+            frame.contentDocument.contentType,
+            'text/plain',
+            'The content type of the response created with a string should be text/plain');
+          assert_equals(
+            frame.contentDocument.characterSet,
+            'UTF-8',
+            'The character set of the response created with a string should be UTF-8');
+          frame.remove();
+          return service_worker_unregister_and_done(t, scope);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Service Worker responds to fetch event with string');
+
+async_test(function(t) {
+    var scope = 'resources/simple.html?blob';
+    service_worker_unregister_and_register(t, worker, scope)
+      .then(function(reg) {
+          return wait_for_state(t, reg.installing, 'activated');
+        })
+      .then(function() { return with_iframe(scope); })
+      .then(function(frame) {
+          assert_equals(
+            frame.contentDocument.body.textContent,
+            'Test blob',
+            'Service Worker should respond to fetch with a test string');
+          frame.remove();
+          return service_worker_unregister_and_done(t, scope);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Service Worker responds to fetch event with blob body');
+
+async_test(function(t) {
+    var scope = 'resources/simple.html?referrer';
+    service_worker_unregister_and_register(t, worker, scope)
+      .then(function(reg) {
+          return wait_for_state(t, reg.installing, 'activated');
+        })
+      .then(function() { return with_iframe(scope); })
+      .then(function(frame) {
+          assert_equals(
+            frame.contentDocument.body.textContent,
+            'Referrer: ' + document.location.href,
+            'Service Worker should respond to fetch with the referrer URL');
+          frame.remove();
+          return service_worker_unregister_and_done(t, scope);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Service Worker responds to fetch event with the referrer URL');
+
+async_test(function(t) {
+    var scope = 'resources/simple.html?ignore';
+    service_worker_unregister_and_register(t, worker, scope)
+      .then(function(reg) {
+          return wait_for_state(t, reg.installing, 'activated');
+        })
+      .then(function() { return with_iframe(scope); })
+      .then(function(frame) {
+          assert_equals(frame.contentDocument.body.textContent,
+                        'Here\'s a simple html file.\n',
+                        'Response should come from fallback to native fetch');
+          frame.remove();
+          return service_worker_unregister_and_done(t, scope);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Service Worker does not respond to fetch event');
+
+async_test(function(t) {
+    var scope = 'resources/simple.html?null';
+    service_worker_unregister_and_register(t, worker, scope)
+      .then(function(reg) {
+          return wait_for_state(t, reg.installing, 'activated');
+        })
+      .then(function() { return with_iframe(scope); })
+      .then(function(frame) {
+          assert_equals(frame.contentDocument.body.textContent,
+                        '',
+                        'Response should be the empty string');
+          frame.remove();
+          return service_worker_unregister_and_done(t, scope);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Service Worker responds to fetch event with null response body');
+
+async_test(function(t) {
+    var scope = 'resources/simple.html?fetch';
+    service_worker_unregister_and_register(t, worker, scope)
+      .then(function(reg) {
+          return wait_for_state(t, reg.installing, 'activated');
+        })
+      .then(function() { return with_iframe(scope); })
+      .then(function(frame) {
+          assert_equals(frame.contentDocument.body.textContent,
+                        'Here\'s an other html file.\n',
+                        'Response should come from fetched other file');
+          frame.remove();
+          return service_worker_unregister_and_done(t, scope);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Service Worker fetches other file in fetch event');
+
+async_test(function(t) {
+    var scope = 'resources/simple.html?form-post';
+    var frame_name = 'xhr-post-frame';
+    service_worker_unregister_and_register(t, worker, scope)
+      .then(function(reg) {
+          return wait_for_state(t, reg.installing, 'activated');
+        })
+      .then(function(sw) {
+         return new Promise(function(resolve) {
+            var frame = document.createElement('iframe');
+            frame.name = frame_name;
+            document.body.appendChild(frame);
+            var form = document.createElement('form');
+            form.target = frame_name;
+            form.action = scope;
+            form.method = 'post';
+            var input1 = document.createElement('input');
+            input1.type = 'text';
+            input1.value = 'testValue1';
+            input1.name = 'testName1'
+            form.appendChild(input1);
+            var input2 = document.createElement('input');
+            input2.type = 'text';
+            input2.value = 'testValue2';
+            input2.name = 'testName2'
+            form.appendChild(input2);
+            document.body.appendChild(form);
+            frame.onload = function() {
+              document.body.removeChild(form);
+              resolve(frame);
+            };
+            form.submit();
+          });
+        })
+      .then(function(frame) {
+          assert_equals(frame.contentDocument.body.textContent,
+                        'POST:testName1=testValue1&testName2=testValue2');
+          document.body.removeChild(frame);
+          return service_worker_unregister_and_done(t, scope);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Service Worker responds to fetch event with POST form');
+
+async_test(function(t) {
+    var scope = 'resources/simple.html?multiple-respond-with';
+    service_worker_unregister_and_register(t, worker, scope)
+      .then(function(reg) {
+          return wait_for_state(t, reg.installing, 'activated');
+        })
+      .then(function() { return with_iframe(scope); })
+      .then(function(frame) {
+          assert_equals(
+            frame.contentDocument.body.textContent,
+            '(0)',
+            'Response should be the argument of the first respondWith() call.');
+          frame.remove();
+          return with_iframe(scope);
+        })
+      .then(function(frame) {
+          assert_equals(
+            frame.contentDocument.body.textContent,
+            '(0)(1)[InvalidStateError](2)[InvalidStateError](0)',
+            'Multiple calls of respondWith must throw InvalidStateErrors.');
+          frame.remove();
+          return service_worker_unregister_and_done(t, scope);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Multiple calls of respondWith must throw InvalidStateErrors');
+
+async_test(function(t) {
+    var scope = 'resources/simple.html?used-check';
+    service_worker_unregister_and_register(t, worker, scope)
+      .then(function(reg) {
+          return wait_for_state(t, reg.installing, 'activated');
+        })
+      .then(function() { return with_iframe(scope); })
+      .then(function(frame) {
+          assert_equals(frame.contentDocument.body.textContent,
+                        'Here\'s an other html file.\n',
+                        'Response should come from fetched other file');
+          frame.remove();
+          return with_iframe(scope);
+        })
+      .then(function(frame) {
+          // When we access to the scope in the second time, the content of the
+          // response is generated inside the ServiceWorker. The body contains
+          // the value of bodyUsed of the first response which is already
+          // consumed by FetchEvent.respondWith method.
+          assert_equals(
+            frame.contentDocument.body.textContent,
+            'bodyUsed: true',
+            'event.respondWith must set the used flag.');
+          frame.remove();
+          return service_worker_unregister_and_done(t, scope);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Service Worker event.respondWith must set the used flag');
+
+</script>
+</body>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-frame-resource.https.html
@@ -0,0 +1,174 @@
+<!DOCTYPE html>
+<title>Service Worker: Fetch for the frame loading.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<body>
+<script>
+var worker = 'resources/fetch-rewrite-worker.js';
+var path = base_path() + 'resources/fetch-access-control.py';
+var host_info = get_host_info();
+
+if (window.testRunner) {
+  testRunner.setCanOpenWindows();
+}
+
+async_test(function(t) {
+    var scope = 'resources/fetch-frame-resource/frame-basic';
+    service_worker_unregister_and_register(t, worker, scope)
+      .then(function(reg) {
+          return wait_for_state(t, reg.installing, 'activated');
+        })
+      .then(function() {
+          return with_iframe(
+            scope + '?url=' +
+            encodeURIComponent(host_info['HTTP_ORIGIN'] + path));
+        })
+      .then(function(frame) {
+          assert_not_equals(
+            frame.contentDocument.body.textContent,
+            '',
+            'Basic type response could be loaded in the iframe.');
+          frame.remove();
+          return service_worker_unregister_and_done(t, scope);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Basic type response could be loaded in the iframe.');
+
+async_test(function(t) {
+    var scope = 'resources/fetch-frame-resource/frame-cors';
+    service_worker_unregister_and_register(t, worker, scope)
+      .then(function(reg) {
+          return wait_for_state(t, reg.installing, 'activated');
+        })
+      .then(function() {
+          var frame = document.createElement('iframe');
+          frame.src =
+            scope + '?mode=cors&url=' +
+            encodeURIComponent(host_info['HTTP_REMOTE_ORIGIN'] + path +
+                               '?ACAOrigin=' + host_info['HTTP_ORIGIN']);
+          document.body.appendChild(frame);
+          // We can't catch the network error on iframe. So we use the timer.
+          return new Promise(function(resolve) {
+              setTimeout(function() { resolve(frame); }, 1000);
+            });
+        })
+      .then(function(frame) {
+          assert_equals(
+            frame.contentDocument.body.textContent,
+            '',
+            'CORS type response could not be loaded in the iframe.');
+          frame.remove();
+          return service_worker_unregister_and_done(t, scope);
+        })
+      .catch(unreached_rejection(t));
+  }, 'CORS type response could not be loaded in the iframe.');
+
+async_test(function(t) {
+    var scope = 'resources/fetch-frame-resource/frame-opaque';
+    service_worker_unregister_and_register(t, worker, scope)
+      .then(function(reg) {
+          return wait_for_state(t, reg.installing, 'activated');
+        })
+      .then(function() {
+          var frame = document.createElement('iframe');
+          frame.src =
+            scope + '?mode=no-cors&url=' +
+            encodeURIComponent(host_info['HTTP_REMOTE_ORIGIN'] + path);
+          document.body.appendChild(frame);
+          // We can't catch the network error on iframe. So we use the timer.
+          return new Promise(function(resolve) {
+              setTimeout(function() { resolve(frame); }, 1000);
+            });
+        })
+      .then(function(frame) {
+          assert_equals(
+            frame.contentDocument.body.textContent,
+            '',
+            'Opaque type response could not be loaded in the iframe.');
+          frame.remove();
+          return service_worker_unregister_and_done(t, scope);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Opaque type response could not be loaded in the iframe.');
+
+async_test(function(t) {
+    var scope = 'resources/fetch-frame-resource/window-basic';
+    service_worker_unregister_and_register(t, worker, scope)
+      .then(function(reg) {
+          return wait_for_state(t, reg.installing, 'activated');
+        })
+      .then(function() {
+          return new Promise(function(resolve) {
+              var win = window.open(
+                scope + '?url=' +
+                encodeURIComponent(host_info['HTTP_ORIGIN'] + path));
+              win.onload = function() { resolve(win); };
+            });
+        })
+      .then(function(win) {
+          assert_not_equals(
+            win.document.body.textContent,
+            '',
+            'Basic type response could be loaded in the new window.');
+          win.close();
+          return service_worker_unregister_and_done(t, scope);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Basic type response could be loaded in the new window.');
+
+async_test(function(t) {
+    var scope = 'resources/fetch-frame-resource/window-cors';
+    service_worker_unregister_and_register(t, worker, scope)
+      .then(function(reg) {
+          return wait_for_state(t, reg.installing, 'activated');
+        })
+      .then(function() {
+          var win = window.open(
+            scope + '?mode=cors&url=' +
+            encodeURIComponent(host_info['HTTP_REMOTE_ORIGIN'] + path +
+                               '?ACAOrigin=' + host_info['HTTP_ORIGIN']));
+          // We can't catch the network error on window. So we use the timer.
+          return new Promise(function(resolve) {
+              setTimeout(function() { resolve(win); }, 1000);
+            });
+        })
+      .then(function(win) {
+          assert_equals(
+            win.document.body.textContent,
+            '',
+            'CORS type response could not be loaded in the new window.');
+          win.close();
+          return service_worker_unregister_and_done(t, scope);
+        })
+      .catch(unreached_rejection(t));
+  }, 'CORS type response could not be loaded in the new window.');
+
+async_test(function(t) {
+    var scope = 'resources/fetch-frame-resource/window-opaque';
+    service_worker_unregister_and_register(t, worker, scope)
+      .then(function(reg) {
+          return wait_for_state(t, reg.installing, 'activated');
+        })
+      .then(function() {
+          var win = window.open(
+            scope + '?mode=no-cors&url=' +
+            encodeURIComponent(host_info['HTTP_REMOTE_ORIGIN'] + path));
+          // We can't catch the network error on window. So we use the timer.
+          return new Promise(function(resolve) {
+              setTimeout(function() { resolve(win); }, 1000);
+            });
+        })
+      .then(function(win) {
+          assert_equals(
+            win.document.body.textContent,
+            '',
+            'Opaque type response could not be loaded in the new window.');
+          win.close();
+          return service_worker_unregister_and_done(t, scope);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Opaque type response could not be loaded in the new window.');
+</script>
+</body>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-mixed-content-to-inscope.https.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<title>Service Worker: Mixed content of fetch()</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js?pipe=sub"></script>
+<body></body>
+<script>
+if (window.testRunner) {
+  // In Chromium we need to change the setting to disallow displaying insecure
+  // contents.
+  testRunner.overridePreference('WebKitAllowDisplayingInsecureContent', false);
+}
+
+async_test(function(t) {
+    var host_info = get_host_info();
+    window.addEventListener('message', t.step_func(on_message), false);
+    with_iframe(
+      host_info['HTTPS_ORIGIN'] + base_path() +
+      'resources/fetch-mixed-content-iframe.html?target=inscope');
+    function on_message(e) {
+      assert_equals(e.data.results, 'finish');
+      t.done();
+    }
+  }, 'Verify Mixed content of fetch() in a Service Worker');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-mixed-content-to-outscope.https.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<title>Service Worker: Mixed content of fetch()</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js?pipe=sub"></script>
+<body></body>
+<script>
+if (window.testRunner) {
+  // In Chromium we need to change the setting to disallow displaying insecure
+  // contents.
+  testRunner.overridePreference('WebKitAllowDisplayingInsecureContent', false);
+}
+
+async_test(function(t) {
+    var host_info = get_host_info();
+    window.addEventListener('message', t.step_func(on_message), false);
+    with_iframe(
+      host_info['HTTPS_ORIGIN'] + base_path() +
+      'resources/fetch-mixed-content-iframe.html?target=outscope');
+    function on_message(e) {
+      assert_equals(e.data.results, 'finish');
+      t.done();
+    }
+  }, 'Verify Mixed content of fetch() in a Service Worker');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-request-css-base-url.https.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<title>Service Worker: CSS's base URL must be the request URL even when fetched from other URL</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js?pipe=sub"></script>
+<script>
+async_test(function(t) {
+    var SCOPE = 'resources/fetch-request-css-base-url-iframe.html';
+    var SCRIPT = 'resources/fetch-request-css-base-url-worker.js';
+    var worker;
+    var frame;
+
+    return service_worker_unregister_and_register(t, SCRIPT, SCOPE)
+      .then(function(registration) {
+          worker = registration.installing;
+          return wait_for_state(t, worker, 'activated');
+        })
+      .then(function() {
+          return new Promise(function(resolve) {
+              var channel = new MessageChannel();
+              channel.port1.onmessage = t.step_func(function(msg) {
+                if (msg.data.ready) {
+                  resolve();
+                  return;
+                }
+                var result = msg.data;
+                var base = get_host_info()['HTTP_ORIGIN'] + base_path();
+                assert_equals(
+                  result.url,
+                  base + 'resources/dummy.png',
+                  'The base URL while loading the images referred from CSS ' +
+                  'must be the request URL of CSS.');
+                assert_equals(
+                  result.referrer,
+                  base + 'resources/fetch-request-css-base-url-style.css',
+                  'While loading the image defined in CSS the referrer must ' +
+                  'be the request URL of CSS.');
+                frame.remove();
+                service_worker_unregister_and_done(t, SCOPE);
+              });
+              worker.postMessage(
+                {port: channel.port2}, [channel.port2]);
+            });
+        })
+      .then(function() { return with_iframe(SCOPE); })
+      .then(function(f) {
+          frame = f;
+        })
+      .catch(unreached_rejection(t));
+  }, 'CSS\'s base URL must be the request URL even when fetched from other URL.');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-request-fallback.https.html
@@ -0,0 +1,112 @@
+<!DOCTYPE html>
+<title>Service Worker: the fallback behavior of FetchEvent</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js?pipe=sub"></script>
+<script>
+var expected_urls = [];
+
+function xhr_fail_test(frame, url) {
+  expected_urls.push(url);
+  return new Promise(function(resolve, reject) {
+      frame.contentWindow.xhr(url)
+        .then(function(){
+            reject(msg + ' should fail.');
+          })
+        .catch(function(){
+            resolve();
+          });
+    });
+}
+
+function xhr_succeed_test(frame, url) {
+  expected_urls.push(url);
+  return new Promise(function(resolve, reject) {
+      frame.contentWindow.xhr(url)
+        .then(function(){
+            resolve();
+          })
+        .catch(function(){
+            reject(msg + ' should succeed.');
+          });
+    });
+}
+
+async_test(function(t) {
+    var SCOPE = 'resources/fetch-request-fallback-iframe.html';
+    var SCRIPT = 'resources/fetch-request-fallback-worker.js';
+    var host_info = get_host_info();
+    var BASE_URL = host_info['HTTP_ORIGIN'] +
+                   '/service-worker/resources/fetch-access-control.py?';
+    var OTHER_BASE_URL = host_info['HTTP_REMOTE_ORIGIN'] +
+                         '/service-worker/resources/fetch-access-control.py?';
+    var REDIRECT_URL = host_info['HTTP_ORIGIN'] +
+                       '/service-worker/resources/redirect.py?Redirect=';
+    var frame;
+    var worker;
+    service_worker_unregister_and_register(t, SCRIPT, SCOPE)
+      .then(function(registration) {
+          worker = registration.installing;
+          return wait_for_state(t, worker, 'activated');
+        })
+      .then(function() { return with_iframe(SCOPE); })
+      .then(function(f) {
+          frame = f;
+          return xhr_succeed_test(frame, BASE_URL);
+        })
+      .then(function(f) {
+          return xhr_fail_test(frame, OTHER_BASE_URL);
+        })
+      .then(function(f) {
+          return xhr_succeed_test(frame, OTHER_BASE_URL + 'ACAOrigin=*');
+        })
+      .then(function(f) {
+          return xhr_succeed_test(frame,
+                                  REDIRECT_URL + encodeURIComponent(BASE_URL));
+        })
+      .then(function() {
+          return xhr_fail_test(
+              frame,
+              REDIRECT_URL + encodeURIComponent(OTHER_BASE_URL));
+        })
+      .then(function() {
+          return xhr_succeed_test(
+              frame,
+              REDIRECT_URL +
+              encodeURIComponent(OTHER_BASE_URL + 'ACAOrigin=*'));
+        })
+      .then(function() {
+          return new Promise(function(resolve) {
+              var channel = new MessageChannel();
+              channel.port1.onmessage = t.step_func(function(msg) {
+                  frame.remove();
+                  resolve(msg);
+                });
+              worker.postMessage({port: channel.port2}, [channel.port2]);
+            });
+        })
+      .then(function(msg) {
+          var requests = msg.data.requests;
+          assert_equals(requests.length, expected_urls.length + 1,
+                        'The count of the requests which are passed to the ' +
+                        'ServiceWorker must be correct.');
+          assert_equals(requests[0].url, new URL(SCOPE, location).toString(),
+                        'The first request to the SW must be the request for ' +
+                        'the page.');
+          assert_equals(requests[0].mode, 'no-cors',
+                        'The mode of the first request to the SW must be ' +
+                        'no-cors.');
+          for (var i = 0; i < expected_urls.length; ++i) {
+            assert_equals(requests[i + 1].url, expected_urls[i],
+                          'The URL of the request which was passed from XHR ' +
+                          'to the ServiceWorker must be correct.');
+            assert_equals(requests[i + 1].mode, 'cors',
+                          'The mode of the request which was passed from XHR ' +
+                          'to the ServiceWorker must be cors.');
+          }
+          service_worker_unregister_and_done(t, SCOPE);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Verify the fallback behavior of FetchEvent');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-request-html-imports.https.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<title>Service Worker: FetchEvent for HTMLImports</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js?pipe=sub"></script>
+<script>
+async_test(function(t) {
+    var SCOPE = 'resources/fetch-request-html-imports-iframe.sub.html';
+    var SCRIPT = 'resources/fetch-request-html-imports-worker.sub.js';
+    var host_info = get_host_info();
+    service_worker_unregister_and_register(t, SCRIPT, SCOPE)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() { return with_iframe(SCOPE); })
+      .then(function(frame) {
+          var same = frame.contentWindow.document.getElementById("same").import;
+          var same_same = same.getElementById("same-same").import;
+          var same_other = same.getElementById("same-other").import;
+          var other =
+              frame.contentWindow.document.getElementById("other").import;
+          var other_same = other.getElementById("other-same").import;
+          var other_other = other.getElementById("other-other").import;
+
+          assert_equals(
+              same.body.innerText,
+              'mode=cors credentials=include',
+              'The request mode and credentials for same origin HTMLImport ' +
+              'must be set correctly.');
+          assert_equals(
+              same_same.body.innerText,
+              'mode=cors credentials=include',
+              'The request mode and credentials for same origin HTMLImport ' +
+              'from same origin HTMLImports must be set correctly.');
+          assert_equals(
+              same_other.body.innerText,
+              'mode=cors credentials=omit',
+              'The request mode and credentials for other origin HTMLImport ' +
+              'from same origin HTMLImports must be set correctly.');
+          assert_equals(
+              other.body.innerText,
+              'mode=cors credentials=omit',
+              'The request mode and credentials for other origin HTMLImport ' +
+              'must be set correctly.');
+          assert_equals(
+              other_same.body.innerText,
+              'mode=cors credentials=include',
+              'The request mode and credentials for same origin HTMLImport ' +
+              'from other origin HTMLImports must be set correctly.');
+          assert_equals(
+              other_other.body.innerText,
+              'mode=cors credentials=omit',
+              'The request mode and credentials for other origin HTMLImport ' +
+              'from other origin HTMLImport must be set correctly.');
+
+          service_worker_unregister_and_done(t, SCOPE);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Verify the FetchEvent for HTMLImports');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-request-no-freshness-headers.https.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<title>Service Worker: the headers of FetchEvent shouldn't contain freshness headers</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js?pipe=sub"></script>
+<script>
+async_test(function(t) {
+    var SCOPE = 'resources/fetch-request-no-freshness-headers-iframe.html';
+    var SCRIPT = 'resources/fetch-request-no-freshness-headers-worker.js';
+    var worker;
+    service_worker_unregister_and_register(t, SCRIPT, SCOPE)
+      .then(function(registration) {
+          worker = registration.installing;
+          return wait_for_state(t, worker, 'activated');
+        })
+      .then(function() { return with_iframe(SCOPE); })
+      .then(function(frame) {
+          return new Promise(function(resolve) {
+              frame.onload = function() {
+                  resolve(frame);
+                };
+              frame.contentWindow.location.reload();
+            });
+        })
+      .then(function(frame) {
+          return new Promise(function(resolve) {
+              var channel = new MessageChannel();
+              channel.port1.onmessage = t.step_func(function(msg) {
+                  frame.remove();
+                  resolve(msg);
+                });
+              worker.postMessage(
+                {port: channel.port2}, [channel.port2]);
+            });
+        })
+      .then(function(msg) {
+          var freshness_headers = {
+            'if-none-match': true,
+            'if-modified-since': true
+          };
+          msg.data.requests.forEach(t.step_func(function(request) {
+              request.headers.forEach(t.step_func(function(header) {
+                  assert_false(
+                      !!freshness_headers[header[0]],
+                      header[0] + ' header must not be set in the ' +
+                      'FetchEvent\'s request. (url = ' + request.url + ')');
+                }));
+            }))
+          service_worker_unregister_and_done(t, SCOPE);
+        })
+      .catch(unreached_rejection(t));
+  }, 'The headers of FetchEvent shouldn\'t contain freshness headers.');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-request-resources.https.html
@@ -0,0 +1,204 @@
+<!DOCTYPE html>
+<title>Service Worker: FetchEvent for resources</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js?pipe=sub"></script>
+<script>
+var url_count = 0;
+var expected_results = {};
+
+function image_test(frame, url, cross_origin, expected_context,
+                    expexted_mode, expected_credentials) {
+  var actual_url = url + (++url_count);
+  expected_results[actual_url] = {
+      cross_origin: cross_origin,
+      context: expected_context,
+      mode: expexted_mode,
+      credentials: expected_credentials,
+      message: 'Image load (url:' +
+               actual_url + ' cross_origin:' + cross_origin + ')'
+    };
+  return frame.contentWindow.load_image(actual_url, cross_origin);
+}
+
+function script_test(frame, url, cross_origin, expected_context,
+                     expexted_mode, expected_credentials) {
+  var actual_url = url + (++url_count);
+  expected_results[actual_url] = {
+      cross_origin: cross_origin,
+      context: expected_context,
+      mode: expexted_mode,
+      credentials: expected_credentials,
+      message: 'Script load (url:' +
+               actual_url + ' cross_origin:' + cross_origin + ')'
+    };
+  return frame.contentWindow.load_script(actual_url, cross_origin);
+}
+
+function css_test(frame, url, cross_origin, expected_context,
+                  expexted_mode, expected_credentials) {
+  var actual_url = url + (++url_count);
+  expected_results[actual_url] = {
+      cross_origin: cross_origin,
+      context: expected_context,
+      mode: expexted_mode,
+      credentials: expected_credentials,
+      message: 'CSS load (url:' +
+               actual_url + ' cross_origin:' + cross_origin + ')'
+    };
+  return frame.contentWindow.load_css(actual_url, cross_origin);
+}
+
+function font_face_test(frame, url, expected_context, expexted_mode,
+                        expected_credentials) {
+  var actual_url = url + (++url_count);
+  expected_results[actual_url] = {
+      url: actual_url,
+      context: expected_context,
+      mode: expexted_mode,
+      credentials: expected_credentials,
+      message: 'FontFace load (url:' + actual_url + ')'
+    };
+  return frame.contentWindow.load_font(actual_url);
+}
+
+function css_image_test(frame, url, type, expected_context,
+                        expexted_mode, expected_credentials) {
+  var actual_url = url + (++url_count);
+  expected_results[actual_url] = {
+      url: actual_url,
+      context: expected_context,
+      mode: expexted_mode,
+      credentials: expected_credentials,
+      message: 'CSSImage load (url:' + actual_url + ' type:' + type + ')'
+    };
+  return frame.contentWindow.load_css_image(actual_url, type);
+}
+
+function css_image_set_test(frame, url, type, expected_context,
+                            expexted_mode, expected_credentials) {
+  var actual_url = url + (++url_count);
+  expected_results[actual_url] = {
+      url: actual_url,
+      context: expected_context,
+      mode: expexted_mode,
+      credentials: expected_credentials,
+      message: 'CSSImageSet load (url:' + actual_url + ' type:' + type + ')'
+    };
+  return frame.contentWindow.load_css_image_set(actual_url, type);
+}
+
+async_test(function(t) {
+    var SCOPE = 'resources/fetch-request-resources-iframe.https.html';
+    var SCRIPT = 'resources/fetch-request-resources-worker.js';
+    var host_info = get_host_info();
+    var LOCAL_URL =
+      host_info['HTTP_ORIGIN'] + base_path() + 'resources/dummy?test';
+    var REMOTE_URL =
+      host_info['HTTP_REMOTE_ORIGIN'] + base_path() + 'resources/dummy?test';
+    var worker;
+    var frame;
+    service_worker_unregister_and_register(t, SCRIPT, SCOPE)
+      .then(function(registration) {
+          worker = registration.installing;
+          return wait_for_state(t, worker, 'activated');
+        })
+      .then(function() {
+          return new Promise(function(resolve) {
+              var channel = new MessageChannel();
+              channel.port1.onmessage = t.step_func(function(msg) {
+                if (msg.data.ready) {
+                  resolve();
+                  return;
+                }
+                var result = msg.data;
+                var expected = expected_results[result.url];
+                if (!expected) {
+                  return;
+                }
+                assert_equals(
+                    result.context, expected.context,
+                    'context of ' + expected.message +  ' must be ' +
+                    expected.context + '.');
+                assert_equals(
+                    result.context_clone, expected.context,
+                    'context of clone() of' + expected.message +
+                    ' must be ' + expected.context + '.');
+                assert_equals(
+                    result.context_new, '',
+                    'context of new Request() must be the empty string');
+                assert_equals(
+                    result.mode, expected.mode,
+                    'mode of ' + expected.message +  ' must be ' +
+                    expected.mode + '.');
+                assert_equals(
+                    result.credentials, expected.credentials,
+                    'credentials of ' + expected.message +  ' must be ' +
+                    expected.credentials + '.');
+                --url_count;
+                delete expected_results[result.url];
+                if (url_count == 0) {
+                  frame.remove();
+                  service_worker_unregister_and_done(t, SCOPE);
+                }
+              });
+              worker.postMessage(
+                {port: channel.port2}, [channel.port2]);
+            });
+        })
+      .then(function() { return with_iframe(SCOPE); })
+      .then(function(f) {
+        frame = f;
+        image_test(f, LOCAL_URL, '', 'image', 'no-cors', 'same-origin');
+        image_test(f, LOCAL_URL, 'anonymous', 'image', 'cors', 'omit');
+        image_test(f, LOCAL_URL, 'use-credentials', 'image', 'cors',
+                   'include');
+        image_test(f, REMOTE_URL, '', 'image', 'no-cors', 'same-origin');
+        image_test(f, REMOTE_URL, 'anonymous', 'image', 'cors', 'omit');
+        image_test(f, REMOTE_URL, 'use-credentials', 'image', 'cors',
+                   'include');
+
+        script_test(f, LOCAL_URL, '', 'script', 'no-cors', 'same-origin');
+        script_test(f, LOCAL_URL, 'anonymous', 'script', 'cors', 'omit');
+        script_test(f, LOCAL_URL, 'use-credentials', 'script', 'cors',
+                    'include');
+        script_test(f, REMOTE_URL, '', 'script', 'no-cors', 'same-origin');
+        script_test(f, REMOTE_URL, 'anonymous', 'script', 'cors', 'omit');
+        script_test(f, REMOTE_URL, 'use-credentials', 'script', 'cors',
+                    'include');
+
+        css_test(f, LOCAL_URL, '', 'style', 'no-cors', 'same-origin');
+        css_test(f, LOCAL_URL, 'anonymous', 'style', 'cors', 'omit');
+        css_test(f, LOCAL_URL, 'use-credentials', 'style', 'cors',
+                 'include');
+        css_test(f, REMOTE_URL, '', 'style', 'no-cors', 'same-origin');
+        css_test(f, REMOTE_URL, 'anonymous', 'style', 'cors', 'omit');
+        css_test(f, REMOTE_URL, 'use-credentials', 'style', 'cors',
+                 'include');
+
+        font_face_test(f, LOCAL_URL, 'font', 'no-cors', 'same-origin');
+        font_face_test(f, REMOTE_URL, 'font', 'cors', 'omit');
+
+        css_image_test(f, LOCAL_URL, 'backgroundImage', 'image',
+                       'no-cors', 'same-origin');
+        css_image_test(f, REMOTE_URL, 'backgroundImage', 'image',
+                       'no-cors', 'same-origin');
+        css_image_test(f, LOCAL_URL, 'shapeOutside', 'image', 'cors',
+                       'omit');
+        css_image_test(f, REMOTE_URL, 'shapeOutside', 'image', 'cors',
+                       'omit');
+
+        css_image_set_test(f, LOCAL_URL, 'backgroundImage', 'image',
+                           'no-cors', 'same-origin');
+        css_image_set_test(f, REMOTE_URL, 'backgroundImage', 'image',
+                           'no-cors', 'same-origin');
+        css_image_set_test(f, LOCAL_URL, 'shapeOutside', 'image', 'cors',
+                           'omit');
+        css_image_set_test(f, REMOTE_URL, 'shapeOutside', 'image', 'cors',
+                           'omit');
+
+      })
+      .catch(unreached_rejection(t));
+  }, 'Verify FetchEvent for resources.');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-request-xhr.https.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>Service Worker: the body of FetchEvent using XMLHttpRequest</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js?pipe=sub"></script>
+<script>
+async_test(function(t) {
+    var SCOPE = 'resources/fetch-request-xhr-iframe.https.html';
+    var SCRIPT = 'resources/fetch-request-xhr-worker.js';
+    var host_info = get_host_info();
+    service_worker_unregister_and_register(t, SCRIPT, SCOPE)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() { return with_iframe(SCOPE); })
+      .then(function(frame) {
+          var channel = new MessageChannel();
+          channel.port1.onmessage = t.step_func(function(e) {
+              assert_equals(e.data.results, 'finish');
+              frame.remove();
+              service_worker_unregister_and_done(t, SCOPE);
+            });
+          frame.contentWindow.postMessage({},
+                                          host_info['HTTP_ORIGIN'],
+                                          [channel.port2]);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Verify the body of FetchEvent using XMLHttpRequest');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-response-xhr.https.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>Service Worker: the response of FetchEvent using XMLHttpRequest</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js?pipe=sub"></script>
+<script>
+async_test(function(t) {
+    var SCOPE = 'resources/fetch-response-xhr-iframe.https.html';
+    var SCRIPT = 'resources/fetch-response-xhr-worker.js';
+    var host_info = get_host_info();
+    service_worker_unregister_and_register(t, SCRIPT, SCOPE)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() { return with_iframe(SCOPE); })
+      .then(function(frame) {
+          var channel = new MessageChannel();
+          channel.port1.onmessage = t.step_func(function(e) {
+              assert_equals(e.data.results, 'finish');
+              frame.remove();
+              service_worker_unregister_and_done(t, SCOPE);
+            });
+          frame.contentWindow.postMessage({},
+                                          host_info['HTTP_ORIGIN'],
+                                          [channel.port2]);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Verify the response of FetchEvent using XMLHttpRequest');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/getregistration.https.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+async_test(function(t) {
+    var documentURL = 'no-such-worker';
+    navigator.serviceWorker.getRegistration(documentURL)
+      .then(function(value) {
+          assert_equals(value, undefined,
+                        'getRegistration should resolve with undefined');
+          t.done();
+        })
+      .catch(unreached_rejection(t));
+  }, 'getRegistration');
+
+async_test(function(t) {
+    var scope = 'resources/scope/getregistration/normal';
+    var registration;
+    service_worker_unregister_and_register(t, 'resources/empty-worker.js',
+                                           scope)
+      .then(function(r) {
+          registration = r;
+          return navigator.serviceWorker.getRegistration(scope);
+        })
+      .then(function(value) {
+          assert_equals(value, registration,
+                        'getRegistration should resolve with registration');
+          service_worker_unregister_and_done(t, scope);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Register then getRegistration');
+
+async_test(function(t) {
+    var scope = 'resources/scope/getregistration/url-with-fragment';
+    var documentURL = scope + '#ref';
+    var registration;
+    service_worker_unregister_and_register(t, 'resources/empty-worker.js',
+                                           scope)
+      .then(function(r) {
+          registration = r;
+          return navigator.serviceWorker.getRegistration(documentURL);
+        })
+      .then(function(value) {
+          assert_equals(value, registration,
+                        'getRegistration should resolve with registration');
+          service_worker_unregister_and_done(t, scope);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Register then getRegistration with a URL having a fragment');
+
+async_test(function(t) {
+    var documentURL = 'http://example.com/';
+    navigator.serviceWorker.getRegistration(documentURL)
+      .then(function() {
+          assert_unreached(
+              'getRegistration with an out of origin URL should fail');
+      }, function(reason) {
+          assert_equals(
+              reason.name, 'SecurityError',
+              'getRegistration with an out of origin URL should fail');
+          t.done();
+      })
+      .catch(unreached_rejection(t));
+  }, 'getRegistration with a cross origin URL');
+
+async_test(function(t) {
+    var scope = 'resources/scope/getregistration/register-unregister';
+    service_worker_unregister_and_register(t, 'resources/empty-worker.js',
+                                           scope)
+      .then(function(registration) {
+          return registration.unregister();
+        })
+      .then(function() {
+          return navigator.serviceWorker.getRegistration(scope);
+        })
+      .then(function(value) {
+          assert_equals(value, undefined,
+                        'getRegistration should resolve with undefined');
+          t.done();
+        })
+      .catch(unreached_rejection(t));
+  }, 'Register then Unregister then getRegistration');
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/getregistrations.sub.html
@@ -0,0 +1,144 @@
+<!DOCTYPE html>
+<title>Service Worker: getRegistrations()</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script src="resources/get-host-info.sub.js"></script>
+<script src="../fetch/resources/fetch-test-helpers.sub.js"></script>
+<script>
+// Purge the existing registrations for the origin.
+// getRegistrations() is used in order to avoid adding additional complexity
+// e.g. adding an internal function.
+sequential_promise_test(function(t) {
+    return navigator.serviceWorker.getRegistrations()
+      .then(function(registrations) {
+          return registrations.reduce(function(sequence, registration) {
+              return sequence.then(function() {
+                  return registration.unregister();
+                });
+            }, Promise.resolve());
+        });
+  }, 'Purge the existing registrations.');
+
+sequential_promise_test(function(t) {
+    return navigator.serviceWorker.getRegistrations()
+      .then(function(value) {
+          assert_array_equals(
+            value,
+            [],
+            'getRegistrations should resolve with an empty array.');
+        });
+  }, 'getRegistrations');
+
+sequential_promise_test(function(t) {
+    var scope = 'resources/scope/getregistrations/normal';
+    var script = 'resources/empty-worker.js';
+    var registrations = [];
+    return service_worker_unregister_and_register(t, script, scope)
+      .then(function(r) {
+          registrations.push(r);
+          return navigator.serviceWorker.getRegistrations();
+        })
+      .then(function(value) {
+          assert_array_equals(
+            value,
+            registrations,
+            'getRegistrations should resolve with array of registrations.');
+          return service_worker_unregister(t, scope);
+        });
+  }, 'Register then getRegistrations');
+
+sequential_promise_test(function(t) {
+    var scope1 = 'resources/scope/getregistrations/scope1';
+    var scope2 = 'resources/scope/getregistrations/scope2';
+    var script = 'resources/empty-worker.js';
+    var registrations = [];
+    return service_worker_unregister_and_register(t, script, scope1)
+      .then(function(r) {
+          registrations.push(r);
+          return service_worker_unregister_and_register(t, script, scope2);
+        })
+      .then(function(r) {
+          registrations.push(r);
+          return navigator.serviceWorker.getRegistrations();
+        })
+      .then(function(value) {
+          assert_array_equals(
+            value,
+            registrations,
+            'getRegistrations should resolve with array of registrations.');
+          return service_worker_unregister(t, scope1);
+        })
+      .then(function() {
+          return service_worker_unregister(t, scope2);
+        });
+  }, 'Register multiple times then getRegistrations');
+
+sequential_promise_test(function(t) {
+    var scope = 'resources/scope/getregistrations/register-unregister';
+    var script = 'resources/empty-worker.js';
+    return service_worker_unregister_and_register(t, script, scope)
+      .then(function(registration) {
+          return registration.unregister();
+        })
+      .then(function() {
+          return navigator.serviceWorker.getRegistrations();
+        })
+      .then(function(value) {
+          assert_array_equals(
+            value,
+            [],
+            'getRegistrations should resolve with an empty array.');
+        });
+  }, 'Register then Unregister then getRegistrations');
+
+sequential_promise_test(function(t) {
+    // Top-level window's origin is http://{{domains[www]}}:{{ports[http][0]}}
+    // Set frame's origin to http://{{host}}:{{ports[http][0]}}
+    var host_info = get_host_info();
+    var frame_url = host_info['HTTP_REMOTE_ORIGIN'] +
+                    '/service-worker/resources/frame-for-getregistrations.sub.html';
+    var scope = 'resources/scope-for-getregistrations';
+    var script = 'resources/empty-worker.js';
+    var frame;
+    var registrations = [];
+
+    return with_iframe(frame_url)
+      .then(function(f) {
+          // frame registered its registration scoped
+          // http://{{host}}:{{ports[http][0]}}/service-worker/resources/scope-for-getregistrations
+          frame = f;
+          // Top-level window registers its registration scoped
+          // http://{{domains[www]}}:{{ports[http][0]}}/service-worker/resources/scope-for-getregistrations
+          return service_worker_unregister_and_register(t, script, scope);
+        })
+      .then(function(r) {
+          registrations.push(r);
+          return navigator.serviceWorker.getRegistrations();
+        })
+      .then(function(value) {
+          assert_array_equals(
+            value,
+            registrations,
+            'getRegistrations should only return same origin registrations.');
+
+          var channel = new MessageChannel();
+          var resolve;
+          var p = new Promise(function(r) { resolve = r; });
+
+          channel.port1.onmessage = function(e) {
+            if (e.data == 'unregistered')
+              resolve();
+          };
+          frame.contentWindow.postMessage('unregister', '*', [channel.port2]);
+          return p;
+        })
+      .then(function() {
+          frame.remove();
+          return service_worker_unregister(t, scope);
+        });
+  }, 'getRegistrations promise resolves only with same origin registrations.');
+
+sequential_promise_test_done();
+done();
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/indexeddb.https.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<title>Service Worker: Indexed DB</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+async_test(function(t) {
+    var scope = 'resources/blank.html';
+    service_worker_unregister_and_register(
+      t, 'resources/indexeddb-worker.js', scope)
+    .then(function(registration) {
+        var sw = registration.installing;
+        var messageChannel = new MessageChannel();
+        messageChannel.port1.onmessage = t.step_func(onMessage);
+        sw.postMessage({port: messageChannel.port2}, [messageChannel.port2]);
+      })
+    .catch(unreached_rejection(t));
+    
+    function onMessage() {
+      var openRequest = indexedDB.open('db');
+      openRequest.onsuccess = t.step_func(function() {
+          var db = openRequest.result;
+          var tx = db.transaction('store');
+          var store = tx.objectStore('store');
+          var getRequest = store.get('key');
+          getRequest.onsuccess = t.step_func(function() {
+              assert_equals(
+                getRequest.result, 'value',
+                'The get() result should match what the worker put().');
+              service_worker_unregister_and_done(t, scope);
+            });
+        });
+    }
+  }, 'Verify Indexed DB operation in a Service Worker');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/install-event-type.https.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+function wait_for_install_event(worker) {
+  return new Promise(function(resolve) {
+      worker.addEventListener('statechange', function(event) {
+          if (worker.state == 'installed')
+            resolve(true);
+          else if (worker.state == 'redundant')
+            resolve(false);
+        });
+    });
+}
+
+promise_test(function(t) {
+      var script = 'resources/install-event-type-worker.js';
+      var scope = 'resources/install-event-type';
+      return service_worker_unregister_and_register(t, script, scope)
+        .then(function(registration) {
+            return wait_for_install_event(registration.installing);
+          })
+        .then(function(did_install) {
+           assert_true(did_install, 'The worker was installed');
+          })
+    }, 'install event type');
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/installing.https.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<title>ServiceWorker: navigator.serviceWorker.installing</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<body>
+<script>
+// "installing" is set
+async_test(function(t) {
+    var step = t.step_func.bind(t);
+    var url = 'resources/empty-worker.js';
+    var scope = 'resources/blank.html';
+    var frame;
+
+    service_worker_unregister(t, scope)
+    .then(step(function() { return with_iframe(scope); }))
+    .then(step(function(f) {
+        frame = f;
+        return navigator.serviceWorker.register(url, {scope: scope});
+    }))
+    .then(step(function(registration) {
+        var container = frame.contentWindow.navigator.serviceWorker;
+        assert_equals(container.controller, null);
+        assert_equals(registration.active, null);
+        assert_equals(registration.waiting, null);
+        assert_equals(registration.installing.scriptURL, normalizeURL(url));
+
+        // FIXME: Add a test for a frame created after installation.
+        // Should the existing frame ("frame") block activation?
+    }))
+    .then(step(function() {
+        frame.remove();
+        return service_worker_unregister_and_done(t, scope);
+    }))
+    .catch(unreached_rejection(t));
+}, 'installing is set');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/interfaces.https.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<title>Service Worker: Interfaces</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/interfaces.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+
+test(function() {
+    var EVENT_HANDLER = 'object';
+    verify_interface(
+      'ServiceWorkerContainer', navigator.serviceWorker,
+      {
+        register: 'function',
+        getRegistration: 'function',
+        oncontrollerchange: EVENT_HANDLER
+      });
+  }, 'Interfaces and attributes of ServiceWorkerContainer');
+
+async_test(function(t) {
+    var EVENT_HANDLER = 'object';
+    var scope = 'resources/scope/interfaces-and-attributes';
+
+    service_worker_unregister_and_register(
+        t, 'resources/empty-worker.js', scope)
+      .then(function(registration) {
+          verify_interface(
+            'ServiceWorkerRegistration', registration,
+            {
+              installing: 'object',
+              waiting: 'object',
+              active: 'object',
+              scope: 'string',
+              unregister: 'function',
+              onupdatefound: EVENT_HANDLER
+            });
+          verify_interface(
+            'ServiceWorker', registration.installing,
+            {
+              scriptURL: 'string',
+              state: 'string',
+              onstatechange: EVENT_HANDLER
+            });
+          return registration.unregister();
+        })
+      .then(function() {
+          t.done();
+        })
+      .catch(unreached_rejection(t));
+  }, 'Interfaces and attributes of ServiceWorker');
+
+service_worker_test(
+  'resources/interfaces-worker.sub.js',
+  'Interfaces and attributes in ServiceWorkerGlobalScope');
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/invalid-blobtype.https.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>Service Worker: respondWith with header value containing a null byte</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js?pipe=sub"></script>
+<script>
+async_test(function(t) {
+    var SCOPE = 'resources/invalid-blobtype-iframe.https.html';
+    var SCRIPT = 'resources/invalid-blobtype-worker.js';
+    var host_info = get_host_info();
+    service_worker_unregister_and_register(t, SCRIPT, SCOPE)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() { return with_iframe(SCOPE); })
+      .then(function(frame) {
+          var channel = new MessageChannel();
+          channel.port1.onmessage = t.step_func(function(e) {
+              assert_equals(e.data.results, 'finish');
+              frame.remove();
+              service_worker_unregister_and_done(t, SCOPE);
+            });
+          frame.contentWindow.postMessage({},
+                                          host_info['HTTP_ORIGIN'],
+                                          [channel.port2]);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Verify the response of FetchEvent using XMLHttpRequest');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/invalid-header.https.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>Service Worker: respondWith with header value containing a null byte</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js?pipe=sub"></script>
+<script>
+async_test(function(t) {
+    var SCOPE = 'resources/invalid-header-iframe.https.html';
+    var SCRIPT = 'resources/invalid-header-worker.js';
+    var host_info = get_host_info();
+    service_worker_unregister_and_register(t, SCRIPT, SCOPE)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() { return with_iframe(SCOPE); })
+      .then(function(frame) {
+          var channel = new MessageChannel();
+          channel.port1.onmessage = t.step_func(function(e) {
+              assert_equals(e.data.results, 'finish');
+              frame.remove();
+              service_worker_unregister_and_done(t, SCOPE);
+            });
+          frame.contentWindow.postMessage({},
+                                          host_info['HTTP_ORIGIN'],
+                                          [channel.port2]);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Verify the response of FetchEvent using XMLHttpRequest');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/multiple-register.https.html
@@ -0,0 +1,114 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+var worker_url = 'resources/empty-worker.js';
+
+async_test(function(t) {
+  var scope = 'resources/scope/subsequent-register-from-same-window';
+  var registration;
+
+  service_worker_unregister_and_register(t, worker_url, scope)
+    .then(function(r) {
+        registration = r;
+        return wait_for_state(t, r.installing, 'activated');
+      })
+    .then(function() {
+        return navigator.serviceWorker.register(worker_url, { scope: scope });
+      })
+    .then(function(new_registration) {
+        assert_equals(new_registration, registration,
+                      'register should resolve to the same registration');
+        assert_equals(new_registration.active, registration.active,
+                      'register should resolve to the same worker');
+        assert_equals(new_registration.active.state, 'activated',
+                      'the worker should be in state "activated"');
+        return registration.unregister();
+      })
+    .then(function() { t.done(); })
+    .catch(unreached_rejection(t));
+}, 'Subsequent registrations resolve to the same registration object');
+
+async_test(function(t) {
+  var scope = 'resources/scope/subsequent-register-from-different-iframe';
+  var frame;
+  var registration;
+
+  service_worker_unregister_and_register(t, worker_url, scope)
+    .then(function(r) {
+        registration = r;
+        return wait_for_state(t, r.installing, 'activated');
+      })
+    .then(function() { return with_iframe('out-of-scope'); })
+    .then(function(f) {
+        frame = f;
+        return frame.contentWindow.navigator.serviceWorker.register(
+            worker_url, { scope: scope });
+      })
+    .then(function(new_registration) {
+        assert_not_equals(
+          registration, new_registration,
+          'register should resolve to the different registration');
+        assert_equals(
+          registration.scope, new_registration.scope,
+          'registrations should have the same scope');
+
+        assert_equals(
+          registration.installing, null,
+          'installing worker should be null');
+        assert_equals(
+          new_registration.installing, null,
+          'installing worker should be null');
+        assert_equals(
+          registration.waiting, null,
+          'waiting worker should be null')
+        assert_equals(
+          new_registration.waiting, null,
+          'waiting worker should be null')
+
+        assert_not_equals(
+          registration.active, new_registration.active,
+          'registration should have the different active worker');
+        assert_equals(
+          registration.active.scriptURL,
+          new_registration.active.scriptURL,
+          'active workers should have the same script URL');
+        assert_equals(
+          registration.active.state,
+          new_registration.active.state,
+          'active workers should be in the same state');
+
+        frame.remove();
+        return registration.unregister();
+      })
+    .then(function() { t.done(); })
+    .catch(unreached_rejection(t));
+}, 'Subsequent registrations from a different iframe resolve to the ' +
+       'different registration object but they refer to the same ' +
+       'registration and workers');
+
+async_test(function(t) {
+  var scope = 'resources/scope/concurrent-register';
+
+  service_worker_unregister(t, scope)
+    .then(function() {
+        var promises = [];
+        for (var i = 0; i < 10; ++i) {
+          promises.push(navigator.serviceWorker.register(worker_url,
+                                                         { scope: scope }));
+        }
+        return Promise.all(promises);
+      })
+    .then(function(registrations) {
+        registrations.forEach(function(registration) {
+            assert_equals(registration, registrations[0],
+                          'register should resolve to the same registration');
+          });
+        return registrations[0].unregister();
+      })
+    .then(function() { t.done(); })
+    .catch(unreached_rejection(t));
+}, 'Concurrent registrations resolve to the same registration object');
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/onactivate-script-error.https.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+function wait_for_install(worker) {
+  return new Promise(function(resolve, reject) {
+      worker.addEventListener('statechange', function(event) {
+          if (worker.state == 'installed')
+            resolve();
+          else if (worker.state == 'redundant')
+            reject();
+        });
+    });
+}
+
+function wait_for_activate(worker) {
+  return new Promise(function(resolve, reject) {
+      worker.addEventListener('statechange', function(event) {
+          if (worker.state == 'activated')
+            resolve();
+          else if (worker.state == 'redundant')
+            reject();
+        });
+    });
+}
+
+function make_test(name, script) {
+  promise_test(function(t) {
+      var scope = script;
+      var registration;
+      return service_worker_unregister_and_register(t, script, scope)
+        .then(function(r) {
+            registration = r;
+            return wait_for_install(registration.installing);
+          })
+        .then(function() {
+            // Activate should succeed regardless of script errors.
+            return wait_for_activate(registration.waiting);
+          });
+    }, name);
+}
+
+[
+  {
+    name: 'activate handler throws an error',
+    script: 'resources/onactivate-throw-error-worker.js',
+  },
+  {
+    name: 'activate handler throws an error, error handler does not cancel',
+    script: 'resources/onactivate-throw-error-with-empty-onerror-worker.js',
+  },
+  {
+    name: 'activate handler dispatches an event that throws an error',
+    script: 'resources/onactivate-throw-error-from-nested-event-worker.js',
+  },
+  {
+    name: 'activate handler throws an error that is cancelled',
+    script: 'resources/onactivate-throw-error-then-cancel-worker.js',
+  },
+  {
+    name: 'activate handler throws an error and prevents default',
+    script: 'resources/onactivate-throw-error-then-prevent-default-worker.js',
+  }
+].forEach(function(test_case) {
+    make_test(test_case.name, test_case.script);
+  });
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/oninstall-script-error.https.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+function wait_for_install_event(worker) {
+  return new Promise(function(resolve) {
+      worker.addEventListener('statechange', function(event) {
+          if (worker.state == 'installed')
+            resolve(true);
+          else if (worker.state == 'redundant')
+            resolve(false);
+        });
+    });
+}
+
+function make_test(name, script, expect_install) {
+  promise_test(function(t) {
+      var scope = script;
+      return service_worker_unregister_and_register(t, script, scope)
+        .then(function(registration) {
+            return wait_for_install_event(registration.installing);
+          })
+        .then(function(did_install) {
+            assert_equals(did_install, expect_install,
+                          'The worker was installed');
+          })
+    }, name);
+}
+
+[
+  {
+    name: 'install handler throws an error',
+    script: 'resources/oninstall-throw-error-worker.js',
+    expect_install: false
+  },
+  {
+    name: 'install handler throws an error, error handler does not cancel',
+    script: 'resources/oninstall-throw-error-with-empty-onerror-worker.js',
+    expect_install: false
+  },
+  {
+    name: 'install handler dispatches an event that throws an error',
+    script: 'resources/oninstall-throw-error-from-nested-event-worker.js',
+    expect_install: true
+  },
+  {
+    name: 'install handler throws an error that is cancelled',
+    script: 'resources/oninstall-throw-error-then-cancel-worker.js',
+    expect_install: true
+  },
+  {
+    name: 'install handler throws an error and prevents default',
+    script: 'resources/oninstall-throw-error-then-prevent-default-worker.js',
+    expect_install: true
+  }
+].forEach(function(test_case) {
+    make_test(test_case.name, test_case.script, test_case.expect_install);
+  });
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/performance-timeline.https.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+
+service_worker_test(
+    '../workers/resources/performance-timeline-worker.js',
+    'Test Performance Timeline API in Service Worker');
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/postmessage-msgport-to-client.https.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<title>Service Worker: postMessage to Client</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+var t = async_test('postMessage MessagePorts from ServiceWorker to Client');
+t.step(function() {
+    var scope = 'resources/blank.html'
+    service_worker_unregister_and_register(
+        t, 'resources/postmessage-msgport-to-client-worker.js', scope)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() { return with_iframe(scope); })
+      .then(function(frame) {
+          var w = frame.contentWindow;
+          w.onmessage = t.step_func(onMessage);
+          w.navigator.serviceWorker.controller.postMessage('ping');
+        })
+      .catch(unreached_rejection(t));
+
+    var result = [];
+    var expected = [
+        'Acking value: 1',
+        'Acking value: 2',
+    ];
+
+    function onMessage(e) {
+      var message = e.data;
+      if ('port' in message) {
+        var port = message.port;
+        port.postMessage({value: 1});
+        port.postMessage({value: 2});
+        port.postMessage({done: true});
+      } else if ('ack' in message) {
+        result.push(message.ack);
+      } else if ('done' in message) {
+        assert_array_equals(
+            result, expected,
+            'Worker should post back expected values via MessagePort.');
+        service_worker_unregister_and_done(t, scope);
+      } else {
+        assert_unreached('Got unexpected message from ServiceWorker');
+      }
+    }
+  });
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/postmessage-to-client.https.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<title>Service Worker: postMessage to Client</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+var t = async_test('postMessage from ServiceWorker to Client');
+t.step(function() {
+    var scope = 'resources/blank.html'
+    service_worker_unregister_and_register(
+        t, 'resources/postmessage-to-client-worker.js', scope)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() { return with_iframe(scope); })
+      .then(function(frame) {
+          var w = frame.contentWindow;
+          w.onmessage = t.step_func(onMessage);
+          w.navigator.serviceWorker.controller.postMessage('ping');
+        })
+      .catch(unreached_rejection(t));
+
+    var result = [];
+    var expected = ['Sending message via clients'];
+
+    function onMessage(e) {
+      var message = e.data;
+      if (message === 'quit') {
+        assert_array_equals(result, expected,
+                            'Worker should post back expected messages.');
+        service_worker_unregister_and_done(t, scope);
+      } else {
+        result.push(message);
+      }
+    }
+  });
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/postmessage.https.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<title>Service Worker: postMessage</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+async_test(function(t) {
+    var scope = 'resources/blank.html';
+    var registration;
+    var worker;
+    service_worker_unregister_and_register(
+        t, 'resources/postmessage-worker.js', scope)
+      .then(function(r) {
+          registration = r;
+          worker = registration.installing;
+          var messageChannel = new MessageChannel();
+          messageChannel.port1.onmessage = t.step_func(onMessage);
+          worker.postMessage({port: messageChannel.port2},
+                              [messageChannel.port2]);
+          worker.postMessage({value: 1});
+          worker.postMessage({value: 2});
+          worker.postMessage({done: true});
+        })
+      .catch(unreached_rejection(t));
+
+    var result = [];
+    var expected = [
+      'Acking value: 1',
+      'Acking value: 2',
+    ];
+
+    function onMessage(e) {
+      var message = e.data;
+      if (message === 'quit') {
+        assert_array_equals(result, expected,
+                            'Worker should post back expected values.');
+        postMessageToRedundantWorker();
+      } else {
+        result.push(message);
+      }
+    };
+
+    function postMessageToRedundantWorker() {
+      registration.unregister(scope)
+        .then(function() {
+            return wait_for_state(t, worker, 'redundant');
+          })
+        .then(function() {
+            assert_equals(worker.state, 'redundant');
+            assert_throws(
+              {name:'InvalidStateError'},
+              function() { worker.postMessage(''); },
+              'Calling postMessage on a redundant ServiceWorker should ' +
+                  'throw InvalidStateError.');
+            t.done();
+          })
+        .catch(unreached_rejection(t));
+    }
+  }, 'postMessage to a ServiceWorker (and back via MessagePort)');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/ready.https.html
@@ -0,0 +1,172 @@
+<!DOCTYPE html>
+<title>Service Worker: navigator.serviceWorker.ready</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<body>
+<script>
+test(function() {
+    var promise = navigator.serviceWorker.ready;
+    assert_equals(promise, navigator.serviceWorker.ready,
+                  'repeated access to ready without intervening ' +
+                  'registrations should return the same Promise object');
+  }, 'ready returns the same Promise object');
+
+async_test(function(t) {
+    with_iframe('resources/blank.html?uncontrolled')
+      .then(t.step_func(function(frame) {
+          var promise = frame.contentWindow.navigator.serviceWorker.ready;
+          assert_equals(Object.getPrototypeOf(promise),
+                        frame.contentWindow.Promise.prototype,
+                        'the Promise should be in the context of the ' +
+                        'related document');
+          frame.remove();
+          t.done();
+        }));
+  }, 'ready returns a Promise object in the context of the related document');
+
+async_test(function(t) {
+    var url = 'resources/empty-worker.js';
+    var scope = 'resources/blank.html?ready-controlled';
+    var expected_url = normalizeURL(url);
+    var frame;
+
+    service_worker_unregister_and_register(t, url, scope)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() { return with_iframe(scope); })
+      .then(function(f) {
+          frame = f;
+          return frame.contentWindow.navigator.serviceWorker.ready;
+        })
+      .then(function(registration) {
+          assert_equals(registration.installing, null,
+                        'installing should be null');
+          assert_equals(registration.waiting, null,
+                        'waiting should be null');
+          assert_equals(registration.active.scriptURL, expected_url,
+                        'active after ready should not be null');
+          assert_equals(
+              frame.contentWindow.navigator.serviceWorker.controller.scriptURL,
+              expected_url,
+              'controlled document should have a controller');
+
+          frame.remove();
+          service_worker_unregister_and_done(t, scope);
+        })
+      .catch(unreached_rejection(t));
+  }, 'ready on a controlled document');
+
+async_test(function(t) {
+    var url = 'resources/empty-worker.js';
+    var scope = 'resources/blank.html?ready-potential-controlled';
+    var expected_url = normalizeURL(url);
+    var frame;
+
+    with_iframe(scope)
+      .then(function(f) {
+          frame = f;
+          return navigator.serviceWorker.register(url, {scope:scope});
+        })
+      .then(function() {
+          return frame.contentWindow.navigator.serviceWorker.ready;
+        })
+      .then(function(registration) {
+          assert_equals(registration.installing, null,
+                        'installing should be null');
+          assert_equals(registration.waiting, null,
+                        'waiting should be null.')
+          assert_equals(registration.active.scriptURL, expected_url,
+                        'active after ready should not be null');
+          assert_equals(frame.contentWindow.navigator.serviceWorker.controller,
+                        null,
+                        'uncontrolled document should not have a controller');
+
+          frame.remove();
+          service_worker_unregister_and_done(t, scope);
+        })
+      .catch(unreached_rejection(t));
+  }, 'ready on a potential controlled document');
+
+async_test(function(t) {
+    var url = 'resources/empty-worker.js';
+    var matched_scope = 'resources/blank.html?ready-after-match';
+    var longer_matched_scope = 'resources/blank.html?ready-after-match-longer';
+    var frame, registration;
+
+    Promise.all([service_worker_unregister(t, matched_scope),
+                 service_worker_unregister(t, longer_matched_scope)])
+      .then(function() {
+          return with_iframe(longer_matched_scope);
+        })
+      .then(function(f) {
+          frame = f;
+          return navigator.serviceWorker.register(url, {scope: matched_scope});
+        })
+      .then(function(r) {
+          registration = r;
+          return wait_for_state(t, r.installing, 'activated');
+        })
+      .then(function() {
+          return navigator.serviceWorker.register(
+              url, {scope: longer_matched_scope});
+        })
+      .then(function() {
+          return frame.contentWindow.navigator.serviceWorker.ready;
+        })
+      .then(function(r) {
+          assert_equals(r.scope, normalizeURL(longer_matched_scope),
+                        'longer matched registration should be returned');
+          assert_equals(frame.contentWindow.navigator.serviceWorker.controller,
+                        null, 'controller should be null');
+          return registration.unregister();
+        })
+      .then(function() {
+          frame.remove();
+          return service_worker_unregister_and_done(t, longer_matched_scope);
+        })
+      .catch(unreached_rejection(t));
+  }, 'ready after a longer matched registration registered');
+
+async_test(function(t) {
+    var url = 'resources/empty-worker.js';
+    var matched_scope = 'resources/blank.html?ready-after-resolve';
+    var longer_matched_scope =
+        'resources/blank.html?ready-after-resolve-longer';
+    var frame, registration;
+
+    service_worker_unregister_and_register(t, url, matched_scope)
+      .then(function(r) {
+          registration = r;
+          return wait_for_state(t, r.installing, 'activated');
+        })
+      .then(function() {
+          return with_iframe(longer_matched_scope);
+        })
+      .then(function(f) {
+          frame = f;
+          return f.contentWindow.navigator.serviceWorker.ready;
+        })
+      .then(function(r) {
+          assert_equals(r.scope, normalizeURL(matched_scope),
+                        'matched registration should be returned');
+          return navigator.serviceWorker.register(
+              url, {scope: longer_matched_scope});
+        })
+      .then(function() {
+          return frame.contentWindow.navigator.serviceWorker.ready;
+        })
+      .then(function(r) {
+          assert_equals(r.scope, normalizeURL(matched_scope),
+                        'ready should only be resolved once');
+          return registration.unregister();
+        })
+      .then(function() {
+          frame.remove();
+          return service_worker_unregister_and_done(t, longer_matched_scope);
+        })
+      .catch(unreached_rejection(t));
+  }, 'access ready after it has been resolved');
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/referer.https.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>Service Worker: check referer of fetch()</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js?pipe=sub"></script>
+<script>
+async_test(function(t) {
+    var SCOPE = 'resources/referer-iframe.html';
+    var SCRIPT = 'resources/fetch-rewrite-worker.js';
+    var host_info = get_host_info();
+    service_worker_unregister_and_register(t, SCRIPT, SCOPE)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() { return with_iframe(SCOPE); })
+      .then(function(frame) {
+          var channel = new MessageChannel();
+          channel.port1.onmessage = t.step_func(function(e) {
+              assert_equals(e.data.results, 'finish');
+              frame.remove();
+              service_worker_unregister_and_done(t, SCOPE);
+            });
+          frame.contentWindow.postMessage({},
+                                          host_info['HTTP_ORIGIN'],
+                                          [channel.port2]);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Verify the referer');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/register-default-scope.https.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<title>register() and scope</title>
+<script src="/resources/testharness.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+
+promise_test(function(t) {
+    var script = 'resources/empty-worker.js';
+    var script_url = new URL(script, location.href);
+    var expected_scope = new URL('./', script_url).href;
+    return service_worker_unregister(t, expected_scope)
+      .then(function() {
+        return navigator.serviceWorker.register('resources/empty-worker.js');
+      }).then(function(registration) {
+        assert_equals(registration.scope, expected_scope,
+                      'The default scope should be URL("./", script_url)');
+        return registration.unregister();
+      }).then(function() {
+        t.done();
+      });
+  }, 'default scope');
+
+promise_test(function(t) {
+    // This script must be different than the 'default scope' test, or else
+    // the scopes will collide.
+    var script = 'resources/empty.js';
+    var script_url = new URL(script, location.href);
+    var expected_scope = new URL('./', script_url).href;
+    return service_worker_unregister(t, expected_scope)
+      .then(function() {
+        return navigator.serviceWorker.register('resources/empty.js',
+                                                { scope: undefined });
+      }).then(function(registration) {
+        assert_equals(registration.scope, expected_scope,
+                      'The default scope should be URL("./", script_url)');
+        return registration.unregister();
+      }).then(function() {
+        t.done();
+      });
+  }, 'undefined scope');
+
+promise_test(function(t) {
+    var script = 'resources/simple-fetch-worker.js';
+    var script_url = new URL(script, location.href);
+    var expected_scope = new URL('./', script_url).href;
+    return service_worker_unregister(t, expected_scope)
+      .then(function() {
+        return navigator.serviceWorker.register('resources/empty.js',
+                                                { scope: null });
+      })
+      .then(
+        function(registration) {
+          assert_unreached('register should fail');
+          service_worker_unregister_and_done(t, registration.scope);
+        },
+        function(error) {
+          assert_equals(error.name, 'SecurityError',
+                        'passing a null scope should be interpreted as ' +
+                        'scope="null" which violates the path restriction');
+          t.done();
+        });
+  }, 'null scope');
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/register-same-scope-different-script-url.https.html
@@ -0,0 +1,233 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+var script1 = normalizeURL('resources/empty-worker.js');
+var script2 = normalizeURL('resources/empty-worker.js?new');
+
+async_test(function(t) {
+    var scope = 'resources/scope/register-new-script-concurrently';
+    var register_promise1;
+    var register_promise2;
+
+    service_worker_unregister(t, scope)
+      .then(function() {
+          register_promise1 = navigator.serviceWorker.register(script1,
+                                                               {scope: scope});
+          register_promise2 = navigator.serviceWorker.register(script2,
+                                                               {scope: scope});
+          return register_promise1;
+        })
+      .then(function(registration) {
+          assert_equals(registration.installing.scriptURL, script1,
+                        'on first register, first script should be installing');
+          assert_equals(registration.waiting, null,
+                        'on first register, waiting should be null');
+          assert_equals(registration.active, null,
+                        'on first register, active should be null');
+          return register_promise2;
+        })
+      .then(function(registration) {
+          assert_equals(
+              registration.installing.scriptURL, script2,
+              'on second register, second script should be installing');
+          // Spec allows racing: the first register may have finished
+          // or the second one could have terminated the installing worker.
+          assert_true(registration.waiting == null ||
+                      registration.waiting.scriptURL == script1,
+                      'on second register, .waiting should be null or the ' +
+                      'first script');
+          assert_true(registration.active == null ||
+                      (registration.waiting == null &&
+                       registration.active.scriptURL == script1),
+                      'on second register, .active should be null or the ' +
+                      'first script');
+          return registration.unregister();
+        })
+      .then(function() {
+          t.done();
+        })
+      .catch(unreached_rejection(t));
+  }, 'Register different scripts concurrently');
+
+async_test(function(t) {
+    var scope = 'resources/scope/register-then-register-new-script';
+    var registration;
+
+    service_worker_unregister_and_register(t, script1, scope)
+      .then(function(r) {
+          registration = r;
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() {
+          assert_equals(registration.installing, null,
+                        'on activated, installing should be null');
+          assert_equals(registration.waiting, null,
+                        'on activated, waiting should be null');
+          assert_equals(registration.active.scriptURL, script1,
+                        'on activated, the first script should be active');
+          return navigator.serviceWorker.register(script2, {scope:scope});
+        })
+      .then(function(r) {
+          registration = r;
+          assert_equals(registration.installing.scriptURL, script2,
+                        'on second register, the second script should be ' +
+                        'installing');
+          assert_equals(registration.waiting, null,
+                        'on second register, waiting should be null');
+          assert_equals(registration.active.scriptURL, script1,
+                        'on second register, the first script should be ' +
+                        'active');
+          return wait_for_state(t, registration.installing, 'installed');
+        })
+      .then(function() {
+          assert_equals(registration.installing, null,
+                        'on installed, installing should be null');
+          assert_equals(registration.waiting.scriptURL, script2,
+                        'on installed, the second script should be waiting');
+          assert_equals(registration.active.scriptURL, script1,
+                        'on installed, the first script should be active');
+          return registration.unregister();
+        })
+      .then(function() {
+          t.done();
+        })
+      .catch(unreached_rejection(t));
+  }, 'Register then register new script URL');
+
+async_test(function(t) {
+    var scope = 'resources/scope/register-then-register-new-script-404';
+    var registration;
+
+    service_worker_unregister_and_register(t, script1, scope)
+      .then(function(r) {
+          registration = r;
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() {
+          assert_equals(registration.installing, null,
+                        'on activated, installing should be null');
+          assert_equals(registration.waiting, null,
+                        'on activated, waiting should be null');
+          assert_equals(registration.active.scriptURL, script1,
+                        'on activated, the first script should be active');
+          return navigator.serviceWorker.register('this-will-404.js',
+                                                  {scope:scope});
+        })
+      .then(
+        function() { assert_unreached('register should reject'); },
+        function(error) {
+          assert_equals(registration.installing, null,
+                        'on rejected, installing should be null');
+          assert_equals(registration.waiting, null,
+                        'on rejected, waiting should be null');
+          assert_equals(registration.active.scriptURL, script1,
+                        'on rejected, the first script should be active');
+          return registration.unregister();
+        })
+      .then(function() {
+          t.done();
+        })
+      .catch(unreached_rejection(t));
+  }, 'Register then register new script URL that 404s');
+
+async_test(function(t) {
+    var scope = 'resources/scope/register-then-register-new-script-reject-install';
+    var reject_script = normalizeURL('resources/reject-install-worker.js');
+    var registration;
+
+    service_worker_unregister_and_register(t, script1, scope)
+      .then(function(r) {
+          registration = r;
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() {
+          assert_equals(registration.installing, null,
+                        'on activated, installing should be null');
+          assert_equals(registration.waiting, null,
+                        'on activated, waiting should be null');
+          assert_equals(registration.active.scriptURL, script1,
+                        'on activated, the first script should be active');
+          return navigator.serviceWorker.register(reject_script, {scope:scope});
+        })
+      .then(function(r) {
+          registration = r;
+          assert_equals(registration.installing.scriptURL, reject_script,
+                        'on update, the second script should be installing');
+          assert_equals(registration.waiting, null,
+                        'on update, waiting should be null');
+          assert_equals(registration.active.scriptURL, script1,
+                        'on update, the first script should be active');
+          return wait_for_state(t, registration.installing, 'redundant');
+        })
+      .then(function() {
+          assert_equals(registration.installing, null,
+                        'on redundant, installing should be null');
+          assert_equals(registration.waiting, null,
+                        'on redundant, waiting should be null');
+          assert_equals(registration.active.scriptURL, script1,
+                        'on redundant, the first script should be active');
+          return registration.unregister();
+        })
+      .then(function() {
+          t.done();
+        })
+      .catch(unreached_rejection(t));
+  }, 'Register then register new script that does not install');
+
+async_test(function(t) {
+    var scope = 'resources/scope/register-new-script-controller';
+    var iframe;
+    var registration;
+
+    service_worker_unregister_and_register(t, script1, scope)
+      .then(function(r) {
+          registration = r;
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() {
+          return with_iframe(scope);
+        })
+      .then(function(frame) {
+          iframe = frame;
+          return navigator.serviceWorker.register(script2, { scope: scope })
+        })
+      .then(function(r) {
+          registration = r;
+          return wait_for_state(t, registration.installing, 'installed');
+        })
+      .then(function() {
+          var sw_container = iframe.contentWindow.navigator.serviceWorker;
+          assert_equals(sw_container.controller.scriptURL, script1,
+                        'the old version should control the old doc');
+          return with_iframe(scope);
+        })
+      .then(function(frame) {
+          var sw_container = frame.contentWindow.navigator.serviceWorker;
+          assert_equals(sw_container.controller.scriptURL, script1,
+                        'the old version should control a new doc');
+          var onactivated_promise = wait_for_state(t,
+                                                   registration.waiting,
+                                                   'activated');
+          frame.remove();
+          iframe.remove();
+          return onactivated_promise;
+        })
+      .then(function() {
+          return with_iframe(scope);
+        })
+      .then(function(frame) {
+          var sw_container = frame.contentWindow.navigator.serviceWorker;
+          assert_equals(sw_container.controller.scriptURL, script2,
+                        'the new version should control a new doc');
+          frame.remove();
+          return registration.unregister();
+        })
+      .then(function() {
+          t.done();
+        })
+      .catch(unreached_rejection(t));
+  }, 'Register same-scope new script url effect on controller');
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/register-wait-forever-in-install-worker.https.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>Service Worker: Register wait-forever-in-install-worker</title>
+<script src="/resources/testharness.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+
+promise_test(function(t) {
+    var bad_script = 'resources/wait-forever-in-install-worker.js';
+    var good_script = 'resources/empty-worker.js';
+    var scope = 'resources/wait-forever-in-install-worker';
+    return navigator.serviceWorker.register(bad_script, {scope: scope})
+      .then(function(registration) {
+          assert_equals(registration.installing.scriptURL,
+                        normalizeURL(bad_script));
+          return navigator.serviceWorker.register(good_script, {scope: scope});
+        })
+      .then(function(registration) {
+          assert_equals(registration.installing.scriptURL,
+                        normalizeURL(good_script));
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() {
+          return service_worker_unregister_and_done(t, scope);
+        })
+  }, 'register worker that calls waitUntil with a promise that never ' +
+     'resolves in oninstall');
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/registration-end-to-end.https.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<title>Service Worker: registration end-to-end</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+var t = async_test('Registration: end-to-end');
+t.step(function() {
+
+    var scope = 'resources/in-scope/';
+    var serviceWorkerStates = [];
+    var lastServiceWorkerState = '';
+    var receivedMessageFromPort = '';
+    var currentChangeCount = 0;
+
+    assert_true(navigator.serviceWorker instanceof ServiceWorkerContainer);
+    assert_equals(typeof navigator.serviceWorker.register, 'function');
+    assert_equals(typeof navigator.serviceWorker.getRegistration, 'function');
+
+    navigator.serviceWorker.oncurrentchange = function() {
+        ++currentChangeCount;
+    };
+
+    service_worker_unregister_and_register(
+        t, 'resources/end-to-end-worker.js', scope)
+      .then(onRegister)
+      .catch(unreached_rejection(t));
+
+    function sendMessagePort(worker, from) {
+        var messageChannel = new MessageChannel();
+        worker.postMessage({from:from, port:messageChannel.port2}, [messageChannel.port2]);
+        return messageChannel.port1;
+    }
+
+    function onRegister(registration) {
+        var sw = registration.installing;
+        serviceWorkerStates.push(sw.state);
+        lastServiceWorkerState = sw.state;
+
+        var sawMessage = new Promise(t.step_func(function(resolve) {
+            sendMessagePort(sw, 'registering doc').onmessage = t.step_func(function (e) {
+                receivedMessageFromPort = e.data;
+                resolve();
+            });
+        }));
+
+        var sawActive = new Promise(t.step_func(function(resolve) {
+            sw.onstatechange = t.step_func(function() {
+                serviceWorkerStates.push(sw.state);
+
+                switch (sw.state) {
+                case 'installed':
+                    assert_equals(lastServiceWorkerState, 'installing');
+                    break;
+                case 'activating':
+                    assert_equals(lastServiceWorkerState, 'installed');
+                    break;
+                case 'activated':
+                    assert_equals(lastServiceWorkerState, 'activating');
+                    break;
+                default:
+                    // We won't see 'redundant' because onstatechange is
+                    // overwritten before calling unregister.
+                    assert_unreached('Unexpected state: ' + sw.state);
+                }
+
+                lastServiceWorkerState = sw.state;
+                if (sw.state === 'activated')
+                    resolve();
+            });
+        }));
+
+        Promise.all([sawMessage, sawActive]).then(t.step_func(function() {
+            assert_array_equals(serviceWorkerStates,
+                                ['installing', 'installed', 'activating', 'activated'],
+                                'Service worker should pass through all states');
+
+            assert_equals(currentChangeCount, 0,
+                          'Should not see current changes since document is out of scope');
+
+            assert_equals(receivedMessageFromPort, 'Ack for: registering doc');
+
+            var sawRedundant = new Promise(t.step_func(function(resolve) {
+                sw.onstatechange = t.step_func(function() {
+                    assert_equals(sw.state, 'redundant');
+                    resolve();
+                });
+            }));
+            registration.unregister();
+            sawRedundant.then(t.step_func(function() {
+                t.done();
+            }));
+        }));
+    }
+});
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/registration-events.https.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<title>Service Worker: registration events</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+var t = async_test('Registration: events');
+t.step(function() {
+    var scope = 'resources/in-scope/';
+    service_worker_unregister_and_register(
+        t, 'resources/events-worker.js', scope)
+      .then(t.step_func(function(registration) {
+          onRegister(registration.installing);
+        }))
+      .catch(unreached_rejection(t));
+
+    function sendMessagePort(worker, from) {
+        var messageChannel = new MessageChannel();
+        worker.postMessage({from:from, port:messageChannel.port2}, [messageChannel.port2]);
+        return messageChannel.port1;
+    }
+
+    function onRegister(sw) {
+        sw.onstatechange = t.step_func(function() {
+            if (sw.state !== 'activated')
+                return;
+
+            sendMessagePort(sw, 'registering doc').onmessage = t.step_func(function (e) {
+                assert_array_equals(e.data.events,
+                                    ['install', 'activate'],
+                                   'Worker should see install then activate events');
+                service_worker_unregister_and_done(t, scope);
+            });
+        });
+    }
+});
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/registration-iframe.https.html
@@ -0,0 +1,108 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Service Worker: Registration for iframe</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+// Set script url and scope url relative to the calling frame's document's url.
+// Assert the implementation parses the urls against the calling frame's
+// document's url.
+async_test(function(t) {
+  var url = 'resources/blank.html';
+  var scope = 'resources/registration-for-iframe-from-calling-frame';
+  var parsed_scope = normalizeURL(scope);
+  var script = 'resources/empty-worker.js';
+  var parsed_script = normalizeURL(script);
+  var frame;
+  var registration;
+
+  service_worker_unregister(t, scope)
+    .then(function() { return with_iframe(url); })
+    .then(function(f) {
+        frame = f;
+        return frame.contentWindow.navigator.serviceWorker.register(
+            script,
+            { scope: scope });
+      })
+    .then(function(r) {
+        registration = r;
+        return wait_for_state(t, r.installing, 'activated');
+      })
+    .then(function() {
+        assert_equals(
+          registration.scope, parsed_scope,
+          'registration\'s scope must be the scope parsed against calling ' +
+          'document\'s url');
+        assert_equals(
+          registration.active.scriptURL, parsed_script,
+          'worker\'s script must be the url parsed against calling ' +
+          'document\'s url');
+        frame.remove();
+        return service_worker_unregister_and_done(t, scope);
+      })
+    .catch(unreached_rejection(t));
+  }, 'Subframe\'s container\'s register method should use calling frame\'s ' +
+     'document\'s url as a base url for parsing its script url and scope url ' +
+     '- normal case');
+
+// Set script url and scope url relative to the iframe's document's url.
+// Assert the implementation throws a NetworkError exception.
+async_test(function(t) {
+  var url = 'resources/blank.html';
+  var scope = 'registration-for-iframe-from-calling-frame';
+  var script = 'empty-worker.js';
+  var frame;
+  var registration;
+
+  service_worker_unregister(t, scope)
+    .then(function() { return with_iframe(url); })
+    .then(function(f) {
+        frame = f;
+        return frame.contentWindow.navigator.serviceWorker.register(
+            script,
+            { scope: scope });
+      })
+    .then(
+      function() {
+        assert_unreached('register() should reject');
+      },
+      function(e) {
+        assert_equals(e.name, 'NetworkError');
+        frame.remove();
+        return service_worker_unregister_and_done(t, scope);
+      })
+    .catch(unreached_rejection(t));
+  }, 'Subframe\'s container\'s register method should use calling frame\'s ' +
+     'document\'s url as a base url for parsing its script url and scope url ' +
+     '- error case');
+
+// Set the scope url to a non-subdirectory of the script url.
+// Assert the implementation throws a SecurityError exception.
+async_test(function(t) {
+  var url = 'resources/blank.html';
+  var scope = 'registration-for-iframe-from-calling-frame';
+  var script = 'resources/empty-worker.js';
+  var frame;
+  var registration;
+
+  service_worker_unregister(t, scope)
+    .then(function() { return with_iframe(url); })
+    .then(function(f) {
+        frame = f;
+        return frame.contentWindow.navigator.serviceWorker.register(
+            script,
+            { scope: scope });
+      })
+    .then(
+      function() {
+        assert_unreached('register() should reject');
+      },
+      function(e) {
+        assert_equals(e.name, 'SecurityError');
+        frame.remove();
+        return service_worker_unregister_and_done(t, scope);
+      })
+    .catch(unreached_rejection(t));
+  }, 'A scope url should start with the given script url');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/registration-service-worker-attributes.https.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+async_test(function(t) {
+    var scope = 'resources/scope/installing-waiting-active-after-registration';
+    var worker_url = 'resources/empty-worker.js';
+    var expected_url = normalizeURL(worker_url);
+
+    service_worker_unregister_and_register(t, worker_url, scope)
+      .then(function(r) {
+          registration = r;
+          assert_equals(registration.installing.scriptURL, expected_url,
+                        'installing before updatefound');
+          assert_equals(registration.waiting, null,
+                        'waiting before updatefound');
+          assert_equals(registration.active, null,
+                        'active before updatefound');
+          return wait_for_update(t, registration);
+        })
+      .then(function(worker) {
+          assert_equals(registration.installing.scriptURL, expected_url,
+                        'installing after updatefound');
+          assert_equals(registration.waiting, null,
+                        'waiting after updatefound');
+          assert_equals(registration.active, null,
+                        'active after updatefound');
+          return wait_for_state(t, registration.installing, 'installed');
+        })
+      .then(function() {
+          assert_equals(registration.installing, null,
+                        'installing after installed');
+          assert_equals(registration.waiting.scriptURL, expected_url,
+                        'waiting after installed');
+          assert_equals(registration.active, null,
+                        'active after installed');
+          return wait_for_state(t, registration.waiting, 'activated');
+        })
+      .then(function() {
+          assert_equals(registration.installing, null,
+                        'installing after activated');
+          assert_equals(registration.waiting, null,
+                        'waiting after activated');
+          assert_equals(registration.active.scriptURL, expected_url,
+                        'active after activated');
+          return Promise.all([
+              wait_for_state(t, registration.active, 'redundant'),
+              registration.unregister()
+            ]);
+        })
+      .then(function() {
+          assert_equals(registration.installing, null,
+                        'installing after redundant');
+          assert_equals(registration.waiting, null,
+                        'waiting after redundant');
+          assert_equals(registration.active.scriptURL, expected_url,
+                        'active after redundant');
+          t.done();
+        })
+      .catch(unreached_rejection(t));
+  }, 'installing/waiting/active after registration');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/registration.https.html
@@ -0,0 +1,368 @@
+<!DOCTYPE html>
+<title>Service Worker: Registration</title>
+<script src="/resources/testharness.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+
+promise_test(function(t) {
+    var script = 'resources/registration-worker.js';
+    var scope = 'resources/registration/normal';
+    return navigator.serviceWorker.register(script, {scope: scope})
+      .then(function(registration) {
+          assert_true(registration instanceof ServiceWorkerRegistration,
+                      'Successfully registered.');
+          service_worker_unregister_and_done(t, scope);
+        })
+  }, 'Registering normal scope');
+
+promise_test(function(t) {
+    var script = 'resources/registration-worker.js';
+    var scope = 'resources/registration/scope-with-fragment#ref';
+    return navigator.serviceWorker.register(script, {scope: scope})
+      .then(function(registration) {
+          assert_true(
+            registration instanceof ServiceWorkerRegistration,
+            'Successfully registered.');
+          assert_equals(
+            registration.scope,
+            normalizeURL('resources/registration/scope-with-fragment'),
+            'A fragment should be removed from scope')
+          service_worker_unregister_and_done(t, scope);
+        })
+  }, 'Registering scope with fragment');
+
+promise_test(function(t) {
+    var script = 'resources/registration-worker.js';
+    var scope = 'resources/';
+    return navigator.serviceWorker.register(script, {scope: scope})
+      .then(function(registration) {
+          assert_true(registration instanceof ServiceWorkerRegistration,
+                      'Successfully registered.');
+          service_worker_unregister_and_done(t, scope);
+        })
+  }, 'Registering same scope as the script directory');
+
+promise_test(function(t) {
+    var script = 'resources/registration-worker.js';
+    var scope = 'resources';
+    return assert_promise_rejects(
+        navigator.serviceWorker.register(script, {scope: scope}),
+        'SecurityError',
+        'Registering same scope as the script directory without the last ' +
+            'slash should fail with SecurityError.');
+  }, 'Registering same scope as the script directory without the last slash');
+
+promise_test(function(t) {
+    var script = 'resources/registration-worker.js';
+    var scope = 'different-directory/';
+    return assert_promise_rejects(
+        navigator.serviceWorker.register(script, {scope: scope}),
+        'SecurityError',
+        'Registration scope outside the script directory should fail ' +
+            'with SecurityError.');
+  }, 'Registration scope outside the script directory');
+
+promise_test(function(t) {
+    var script = 'resources/registration-worker.js';
+    var scope = 'http://example.com/';
+    return assert_promise_rejects(
+        navigator.serviceWorker.register(script, {scope: scope}),
+        'SecurityError',
+        'Registration scope outside domain should fail with SecurityError.');
+  }, 'Registering scope outside domain');
+
+promise_test(function(t) {
+    var script = 'http://example.com/worker.js';
+    var scope = 'http://example.com/scope/';
+    return assert_promise_rejects(
+        navigator.serviceWorker.register(script, {scope: scope}),
+        'SecurityError',
+        'Registration script outside domain should fail with SecurityError.');
+  }, 'Registering script outside domain');
+
+promise_test(function(t) {
+    var script = 'resources/no-such-worker.js';
+    var scope = 'resources/scope/no-such-worker';
+    return assert_promise_rejects(
+        navigator.serviceWorker.register(script, {scope: scope}),
+        'NetworkError',
+        'Registration of non-existent script should fail.');
+  }, 'Registering non-existent script');
+
+promise_test(function(t) {
+    var script = 'resources/invalid-chunked-encoding.py';
+    var scope = 'resources/scope/invalid-chunked-encoding/';
+    return assert_promise_rejects(
+        navigator.serviceWorker.register(script, {scope: scope}),
+        'NetworkError',
+        'Registration of invalid chunked encoding script should fail.');
+  }, 'Registering invalid chunked encoding script');
+
+promise_test(function(t) {
+    var script = 'resources/invalid-chunked-encoding-with-flush.py';
+    var scope = 'resources/scope/invalid-chunked-encoding-with-flush/';
+    return assert_promise_rejects(
+        navigator.serviceWorker.register(script, {scope: scope}),
+        'NetworkError',
+        'Registration of invalid chunked encoding script should fail.');
+  }, 'Registering invalid chunked encoding script with flush');
+
+promise_test(function(t) {
+    var script = 'resources/mime-type-worker.py';
+    var scope = 'resources/scope/no-mime-type-worker/';
+    return assert_promise_rejects(
+        navigator.serviceWorker.register(script, {scope: scope}),
+        'SecurityError',
+        'Registration of no MIME type script should fail.');
+  }, 'Registering script with no MIME type');
+
+promise_test(function(t) {
+    var script = 'resources/mime-type-worker.py?mime=text/plain';
+    var scope = 'resources/scope/bad-mime-type-worker/';
+    return assert_promise_rejects(
+        navigator.serviceWorker.register(script, {scope: scope}),
+        'SecurityError',
+        'Registration of plain text script should fail.');
+  }, 'Registering script with bad MIME type');
+
+promise_test(function(t) {
+    var script = 'resources/redirect.py?Redirect=' +
+                  encodeURIComponent('/resources/registration-worker.js');
+    var scope = 'resources/scope/redirect/';
+    return assert_promise_rejects(
+        navigator.serviceWorker.register(script, {scope: scope}),
+        'SecurityError',
+        'Registration of redirected script should fail.');
+  }, 'Registering redirected script');
+
+promise_test(function(t) {
+    var script = 'resources/malformed-worker.py?parse-error';
+    var scope = 'resources/scope/parse-error';
+    return assert_promise_rejects(
+        navigator.serviceWorker.register(script, {scope: scope}),
+        'AbortError',
+        'Registration of script including parse error should fail.');
+  }, 'Registering script including parse error');
+
+promise_test(function(t) {
+    var script = 'resources/malformed-worker.py?undefined-error';
+    var scope = 'resources/scope/undefined-error';
+    return assert_promise_rejects(
+        navigator.serviceWorker.register(script, {scope: scope}),
+        'AbortError',
+        'Registration of script including undefined error should fail.');
+  }, 'Registering script including undefined error');
+
+promise_test(function(t) {
+    var script = 'resources/malformed-worker.py?uncaught-exception';
+    var scope = 'resources/scope/uncaught-exception';
+    return assert_promise_rejects(
+        navigator.serviceWorker.register(script, {scope: scope}),
+        'AbortError',
+        'Registration of script including uncaught exception should fail.');
+  }, 'Registering script including uncaught exception');
+
+promise_test(function(t) {
+    var script = 'resources/malformed-worker.py?caught-exception';
+    var scope = 'resources/scope/caught-exception';
+    return navigator.serviceWorker.register(script, {scope: scope})
+        .then(function(registration) {
+            assert_true(registration instanceof ServiceWorkerRegistration,
+                        'Successfully registered.');
+            service_worker_unregister_and_done(t, scope);
+          })
+  }, 'Registering script including caught exception');
+
+promise_test(function(t) {
+    var script = 'resources/malformed-worker.py?import-malformed-script';
+    var scope = 'resources/scope/import-malformed-script';
+    return assert_promise_rejects(
+        navigator.serviceWorker.register(script, {scope: scope}),
+        'AbortError',
+        'Registration of script importing malformed script should fail.');
+  }, 'Registering script importing malformed script');
+
+promise_test(function(t) {
+    var script = 'resources/malformed-worker.py?import-no-such-script';
+    var scope = 'resources/scope/import-no-such-script';
+    return assert_promise_rejects(
+        navigator.serviceWorker.register(script, {scope: scope}),
+        'AbortError',
+        'Registration of script importing non-existent script should fail.');
+  }, 'Registering script importing non-existent script');
+
+promise_test(function(t) {
+    // URL-encoded full-width 'scope'.
+    var name = '%ef%bd%93%ef%bd%83%ef%bd%8f%ef%bd%90%ef%bd%85';
+    var script = 'resources/empty-worker.js';
+    var scope = 'resources/' + name + '/escaped-multibyte-character-scope';
+    return navigator.serviceWorker.register(script, {scope: scope})
+      .then(function(registration) {
+          assert_equals(
+            registration.scope,
+            normalizeURL(scope),
+            'URL-encoded multibyte characters should be available.');
+          service_worker_unregister_and_done(t, scope);
+        });
+  }, 'Scope including URL-encoded multibyte characters');
+
+promise_test(function(t) {
+    // Non-URL-encoded full-width "scope".
+    var name = String.fromCodePoint(0xff53, 0xff43, 0xff4f, 0xff50, 0xff45);
+    var script = 'resources/empty-worker.js';
+    var scope = 'resources/' + name  + '/non-escaped-multibyte-character-scope';
+    return navigator.serviceWorker.register(script, {scope: scope})
+      .then(function(registration) {
+          assert_equals(
+            registration.scope,
+            normalizeURL(scope),
+            'Non-URL-encoded multibyte characters should be available.');
+          service_worker_unregister_and_done(t, scope);
+        });
+  }, 'Scope including non-escaped multibyte characters');
+
+promise_test(function(t) {
+    var script = 'resources%2fempty-worker.js';
+    var scope = 'resources/scope/encoded-slash-in-script-url';
+    return assert_promise_rejects(
+        navigator.serviceWorker.register(script, {scope: scope}),
+        'SecurityError',
+        'URL-encoded slash in the script URL should be rejected.');
+  }, 'Script URL including URL-encoded slash');
+
+promise_test(function(t) {
+    var script = 'resources/empty-worker.js';
+    var scope = 'resources/scope%2fencoded-slash-in-scope';
+    return assert_promise_rejects(
+        navigator.serviceWorker.register(script, {scope: scope}),
+        'SecurityError',
+        'URL-encoded slash in the scope should be rejected.');
+  }, 'Scope including URL-encoded slash');
+
+promise_test(function(t) {
+    var script = 'resources%5cempty-worker.js';
+    var scope = 'resources/scope/encoded-slash-in-script-url';
+    return assert_promise_rejects(
+        navigator.serviceWorker.register(script, {scope: scope}),
+        'SecurityError',
+        'URL-encoded backslash in the script URL should be rejected.');
+  }, 'Script URL including URL-encoded backslash');
+
+promise_test(function(t) {
+    var script = 'resources/empty-worker.js';
+    var scope = 'resources/scope%5cencoded-slash-in-scope';
+    return assert_promise_rejects(
+        navigator.serviceWorker.register(script, {scope: scope}),
+        'SecurityError',
+        'URL-encoded backslash in the scope should be rejected.');
+  }, 'Scope including URL-encoded backslash');
+
+promise_test(function(t) {
+    var script = 'resources/././empty-worker.js';
+    var scope = 'resources/scope/parent-reference-in-script-url';
+    return navigator.serviceWorker.register(script, {scope: scope})
+      .then(function(registration) {
+          assert_equals(
+            registration.installing.scriptURL,
+            normalizeURL('resources/empty-worker.js'),
+            'Script URL including self-reference should be normalized.');
+          service_worker_unregister_and_done(t, scope);
+        });
+  }, 'Script URL including self-reference');
+
+promise_test(function(t) {
+    var script = 'resources/empty-worker.js';
+    var scope = 'resources/././scope/self-reference-in-scope';
+    return navigator.serviceWorker.register(script, {scope: scope})
+      .then(function(registration) {
+          assert_equals(
+            registration.scope,
+            normalizeURL('resources/scope/self-reference-in-scope'),
+            'Scope including self-reference should be normalized.');
+          service_worker_unregister_and_done(t, scope);
+        });
+  }, 'Scope including self-reference');
+
+promise_test(function(t) {
+    var script = 'resources/../resources/empty-worker.js';
+    var scope = 'resources/scope/parent-reference-in-script-url';
+    return navigator.serviceWorker.register(script, {scope: scope})
+      .then(function(registration) {
+          assert_equals(
+            registration.installing.scriptURL,
+            normalizeURL('resources/empty-worker.js'),
+            'Script URL including parent-reference should be normalized.');
+          service_worker_unregister_and_done(t, scope);
+        });
+  }, 'Script URL including parent-reference');
+
+promise_test(function(t) {
+    var script = 'resources/empty-worker.js';
+    var scope = 'resources/../resources/scope/parent-reference-in-scope';
+    return navigator.serviceWorker.register(script, {scope: scope})
+      .then(function(registration) {
+          assert_equals(
+            registration.scope,
+            normalizeURL('resources/scope/parent-reference-in-scope'),
+            'Scope including parent-reference should be normalized.');
+          service_worker_unregister_and_done(t, scope);
+        });
+  }, 'Scope including parent-reference');
+
+promise_test(function(t) {
+    var script = 'resources/empty-worker.js';
+    var scope = 'resources/../scope/parent-reference-in-scope';
+    return assert_promise_rejects(
+        navigator.serviceWorker.register(script, {scope: scope}),
+        'SecurityError',
+        'Scope not under the script directory should be rejected.');
+  }, 'Scope including parent-reference and not under the script directory');
+
+promise_test(function(t) {
+    var script = 'resources////empty-worker.js';
+    var scope = 'resources/scope/consecutive-slashes-in-script-url';
+    return assert_promise_rejects(
+        navigator.serviceWorker.register(script, {scope: scope}),
+        'SecurityError',
+        'Consecutive slashes in the script url should not be unified.');
+  }, 'Script URL including consecutive slashes');
+
+promise_test(function(t) {
+    var script = 'resources/empty-worker.js';
+    var scope = 'resources/scope////consecutive-slashes-in-scope';
+    return navigator.serviceWorker.register(script, {scope: scope})
+      .then(function(registration) {
+          // Although consecutive slashes in the scope are not unified, the
+          // scope is under the script directory and registration should
+          // succeed.
+          assert_equals(
+            registration.scope,
+            normalizeURL(scope),
+            'Should successfully be registered.');
+          service_worker_unregister_and_done(t, scope);
+        })
+  }, 'Scope including consecutive slashes');
+
+promise_test(function(t) {
+    var script = 'filesystem:' + normalizeURL('resources/empty-worker.js');
+    var scope = 'resources/scope/filesystem-script-url';
+    return assert_promise_rejects(
+        navigator.serviceWorker.register(script, {scope: scope}),
+        'SecurityError',
+        'Registering a script which has same-origin filesystem: URL should ' +
+            'fail with SecurityError.');
+  }, 'Script URL is same-origin filesystem: URL');
+
+promise_test(function(t) {
+    var script = 'resources/empty-worker.js';
+    var scope = 'filesystem:' + normalizeURL('resources/scope/filesystem-scope-url');
+    return assert_promise_rejects(
+        navigator.serviceWorker.register(script, {scope: scope}),
+        'SecurityError',
+        'Registering with the scope that has same-origin filesystem: URL ' +
+            'should fail with SecurityError.');
+  }, 'Scope URL is same-origin filesystem: URL');
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/rejections.https.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<title>Service Worker: Rejection Types</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+(function() {
+    var t = async_test('Rejections are DOMExceptions');
+    t.step(function() {
+
+        navigator.serviceWorker.register('http://example.com').then(
+            t.step_func(function() { assert_unreached('Registration should fail'); }),
+            t.step_func(function(reason) {
+                assert_true(reason instanceof DOMException);
+                assert_true(reason instanceof Error);
+                t.done();
+            }));
+    });
+}());
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/request-end-to-end.https.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<title>Service Worker: Request end-to-end</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+var t = async_test('Request: end-to-end');
+t.step(function() {
+    var url = 'resources/request-end-to-end-worker.js';
+    var scope = 'resources/blank.html';
+
+    service_worker_unregister_and_register(t, url, scope)
+      .then(onRegister)
+      .catch(unreached_rejection(t));
+
+    function sendMessagePort(worker) {
+        var messageChannel = new MessageChannel();
+        worker.postMessage({port:messageChannel.port2}, [messageChannel.port2]);
+        return messageChannel.port1;
+    }
+
+    function onRegister(registration) {
+        var sw = registration.installing;
+        var port = sendMessagePort(sw);
+        port.addEventListener('message', t.step_func(function(event) {
+            onMessage(event);
+        }), false);
+        port.start();
+        sw.addEventListener('statechange', t.step_func(function(event) {
+            if (event.target.state == 'activated')
+                onActive();
+        }));
+    }
+
+    function onActive() {
+        with_iframe(scope);
+    }
+
+    function onMessage(event) {
+        assert_equals(
+            event.data.url,
+            location.href.substring(0, location.href.lastIndexOf('/') + 1) +
+            scope,
+            'request.url should be passed to onfetch event.');
+        assert_equals(event.data.method, 'GET',
+                      'request.method should be passed to onfetch event.');
+        assert_equals(event.data.referrer, location.href,
+                      'request.referrer should be passed to onfetch event.');
+        assert_equals(event.data.headers['user-agent'], navigator.userAgent,
+                      'User-Agent header should be passed to onfetch event.')
+        assert_equals(event.data.errorNameWhileAppendingHeader, 'TypeError',
+                      'Appending a new header to the request must throw a ' +
+                      'TypeError.')
+        service_worker_unregister_and_done(t, scope);
+    }
+});
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/resource-timing.https.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+function resourceUrl(path) {
+    return get_host_info()['HTTP_ORIGIN'] + base_path() + path;
+}
+
+function verify(performance, resource, description) {
+    var entry = performance.getEntriesByName(resourceUrl(resource))[0];
+    assert_greater_than(entry.workerStart, 0, description);
+    assert_greater_than_equal(entry.workerStart, entry.startTime, description);
+    assert_less_than_equal(entry.workerStart, entry.fetchStart, description);
+    if (resource.indexOf('redirect.py') != -1) {
+        assert_less_than_equal(entry.workerStart, entry.redirectStart,
+                               description);
+    } else {
+        assert_equals(entry.redirectStart, 0, description);
+    }
+}
+
+async_test(function(t) {
+    var worker_url = 'resources/resource-timing-worker.js';
+    var scope = 'resources/resource-timing-iframe.html';
+    var registration;
+
+    service_worker_unregister_and_register(t, worker_url, scope)
+      .then(function(r) {
+          registration = r;
+          return wait_for_state(t, r.installing, 'activated');
+        })
+      .then(function() {
+          return with_iframe(scope);
+        })
+      .then(function(frame) {
+          var performance = frame.contentWindow.performance;
+          verify(performance, 'resources/dummy.js', 'Generated response');
+          verify(performance, 'resources/empty.js', 'Network fallback');
+          verify(performance, 'resources/redirect.py?Redirect=empty.js',
+                 'Redirect');
+          frame.remove();
+          return registration.unregister();
+        })
+      .then(function() {
+          t.done();
+        })
+      .catch(unreached_rejection(t));
+}, 'Controlled resource loads');
+
+test(function() {
+    var url = resourceUrl('resources/test-helpers.sub.js');
+    var entry = window.performance.getEntriesByName(url)[0];
+    assert_equals(entry.workerStart, 0, 'Non-controlled');
+}, 'Non-controlled resource loads');
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/appcache-ordering.install.html
@@ -0,0 +1,26 @@
+<html manifest="appcache-ordering.manifest">
+<script>
+var handled = false;
+
+function installComplete() {
+  if (handled)
+    return;
+  handled = true;
+  window.parent.notify_appcache_installed(true);
+}
+
+function installFailed() {
+  if (handled)
+    return;
+  handled = true;
+  window.parent.notify_appcache_installed(false);
+}
+
+applicationCache.oncached = installComplete;
+applicationCache.onnoupdate = installComplete;
+applicationCache.onupdateready = installFailed;
+applicationCache.onerror = installFailed;
+applicationCache.onobsolete = installFailed;
+
+</script>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/appcache-ordering.is-appcached.html
@@ -0,0 +1,13 @@
+<html> <!-- Intentionally does NOT include a manifest attribute -->
+<body>
+<!-- This should FALLBACK to ordering.is_appcached.js as specified in manifest
+     when the appcache is present -->
+<script src="appcache-ordering.is-appcached404.js"></script>
+<script>
+
+// If the script of the fallback resource loaded, is_appcached will be defined.
+window.parent.notify_is_appcached(typeof is_appcached != 'undefined');
+
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/appcache-ordering.is-appcached.js
@@ -0,0 +1,1 @@
+var is_appcached = true;
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/appcache-ordering.manifest
@@ -0,0 +1,7 @@
+CACHE MANIFEST
+
+appcache-ordering.is-appcached.html
+
+FALLBACK:
+appcache-ordering.is-appcached404.js appcache-ordering.is-appcached.js
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/blank.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<title>Empty doc</title>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/claim-worker.js
@@ -0,0 +1,14 @@
+self.addEventListener('message', function(event) {