1 function waitForState(worker, state, context) {
2 return new Promise(resolve => {
3 function onStateChange() {
4 if (worker.state === state) {
5 worker.removeEventListener("statechange", onStateChange);
10 // First add an event listener, so we won't miss any change that happens
11 // before we check the current state.
12 worker.addEventListener("statechange", onStateChange);
14 // Now check if the worker is already in the desired state.
20 * Helper for browser tests to issue register calls from the content global and
21 * wait for the SW to progress to the active state, as most tests desire.
22 * From the ContentTask.spawn, use via
23 * `content.wrappedJSObject.registerAndWaitForActive`.
25 async function registerAndWaitForActive(script, maybeScope) {
26 console.log("...calling register");
29 opts = { scope: maybeScope };
31 const reg = await navigator.serviceWorker.register(script, opts);
32 // Unless registration resurrection happens, the SW should be in the
34 console.log("...waiting for activation");
35 await waitForState(reg.installing, "activated", reg);
36 console.log("...activated!");
41 * Helper to create an iframe with the given URL and return the first
42 * postMessage payload received. This is intended to be used when creating
43 * cross-origin iframes.
45 * A promise will be returned that resolves with the payload of the postMessage
48 function createIframeAndWaitForMessage(url) {
49 const iframe = document.createElement("iframe");
50 document.body.appendChild(iframe);
51 return new Promise(resolve => {
52 window.addEventListener(
64 * Helper to create a nested iframe into the iframe created by
65 * createIframeAndWaitForMessage().
67 * A promise will be returned that resolves with the payload of the postMessage
70 function createNestedIframeAndWaitForMessage(url) {
71 const iframe = document.getElementsByTagName("iframe")[0];
72 iframe.contentWindow.postMessage("create nested iframe", "*");
73 return new Promise(resolve => {
74 window.addEventListener(
84 async function unregisterAll() {
85 const registrations = await navigator.serviceWorker.getRegistrations();
86 for (const reg of registrations) {
87 await reg.unregister();
92 * Make a blob that contains random data and therefore shouldn't compress all
95 function makeRandomBlob(size) {
96 const arr = new Uint8Array(size);
99 * getRandomValues will only provide a maximum of 64k of data at a time and
100 * will error if we ask for more, so using a while loop for get a random value
101 * which much larger than 64k.
102 * https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues#exceptions
104 while (offset < size) {
105 const nextSize = Math.min(size - offset, 65536);
106 window.crypto.getRandomValues(new Uint8Array(arr.buffer, offset, nextSize));
109 return new Blob([arr], { type: "application/octet-stream" });
112 async function fillStorage(cacheBytes, idbBytes) {
113 // ## Fill Cache API Storage
114 const cache = await caches.open("filler");
115 await cache.put("fill", new Response(makeRandomBlob(cacheBytes)));
118 const storeName = "filler";
119 let db = await new Promise((resolve, reject) => {
120 let openReq = indexedDB.open("filler", 1);
121 openReq.onerror = event => {
122 reject(event.target.error);
124 openReq.onsuccess = event => {
125 resolve(event.target.result);
127 openReq.onupgradeneeded = event => {
128 const useDB = event.target.result;
129 useDB.onerror = error => {
132 const store = useDB.createObjectStore(storeName);
133 store.put({ blob: makeRandomBlob(idbBytes) }, "filler-blob");