diff options
Diffstat (limited to 'dom/workers/test/importScripts_3rdParty_worker.js')
-rw-r--r-- | dom/workers/test/importScripts_3rdParty_worker.js | 199 |
1 files changed, 136 insertions, 63 deletions
diff --git a/dom/workers/test/importScripts_3rdParty_worker.js b/dom/workers/test/importScripts_3rdParty_worker.js index 326d48f77a..e55fdc514b 100644 --- a/dom/workers/test/importScripts_3rdParty_worker.js +++ b/dom/workers/test/importScripts_3rdParty_worker.js @@ -1,18 +1,113 @@ const workerURL = "http://mochi.test:8888/tests/dom/workers/test/importScripts_3rdParty_worker.js"; +/** + * An Error can be a JS Error or a DOMException. The primary difference is that + * JS Errors have a SpiderMonkey specific `fileName` for the filename and + * DOMEXCEPTION uses `filename`. + */ +function normalizeError(err) { + if (!err) { + return null; + } + + const isDOMException = "filename" in err; + + return { + message: err.message, + name: err.name, + isDOMException, + code: err.code, + // normalize to fileName + fileName: isDOMException ? err.filename : err.fileName, + hasFileName: !!err.fileName, + hasFilename: !!err.filename, + lineNumber: err.lineNumber, + columnNumber: err.columnNumber, + stack: err.stack, + stringified: err.toString(), + }; +} + +function normalizeErrorEvent(event) { + if (!event) { + return null; + } + + return { + message: event.message, + filename: event.filename, + lineno: event.lineno, + colno: event.colno, + error: normalizeError(event.error), + stringified: event.toString(), + }; +} + +/** + * Normalize the `OnErrorEventHandlerNonNull onerror` invocation. The + * special handling in JSEventHandler::HandleEvent ends up spreading out the + * contents of the ErrorEvent into discrete arguments. The one thing lost is + * we can't toString the ScriptEvent itself, but this should be the same as the + * message anyways. + * + * The spec for the invocation is the "special error event handling" logic + * described in step 4 at: + * https://html.spec.whatwg.org/multipage/webappapis.html#the-event-handler-processing-algorithm + * noting that the step somewhat glosses over that it's only "onerror" that is + * OnErrorEventHandlerNonNull and capable of processing 5 arguments and that's + * why an addEventListener "error" listener doesn't get this handling. + * + * Argument names here are made to match the call-site in JSEventHandler. + */ +function normalizeOnError( + msgOrEvent, + fileName, + lineNumber, + columnNumber, + error +) { + return { + message: msgOrEvent, + filename: fileName, + lineno: lineNumber, + colno: columnNumber, + error: normalizeError(error), + stringified: null, + }; +} + +/** + * Helper to postMessage the provided data after a setTimeout(0) so that any + * error event currently being dispatched that will bubble to our parent will + * be delivered before our postMessage. + */ +function delayedPostMessage(data) { + setTimeout(() => { + postMessage(data); + }, 0); +} + onmessage = function (a) { + const args = a.data; + // Messages are either nested (forward to a nested worker) or should be + // processed locally. if (a.data.nested) { - var worker = new Worker(workerURL); + const worker = new Worker(workerURL); + let firstErrorEvent; + + // When the test mode is "catch" + worker.onmessage = function (event) { - postMessage(event.data); + delayedPostMessage({ + nestedMessage: event.data, + errorEvent: firstErrorEvent, + }); }; worker.onerror = function (event) { + firstErrorEvent = normalizeErrorEvent(event); event.preventDefault(); - postMessage({ - error: event instanceof ErrorEvent && event.filename == workerURL, - }); }; a.data.nested = false; @@ -20,69 +115,47 @@ onmessage = function (a) { return; } - // This first URL will use the same origin of this script. - var sameOriginURL = new URL(a.data.url); - var fileName1 = 42; - - // This is cross-origin URL. - var crossOriginURL = new URL(a.data.url); - crossOriginURL.host = "example.com"; - crossOriginURL.port = 80; - var fileName2 = 42; - - if (a.data.test == "none") { - importScripts(crossOriginURL.href); - return; - } - - try { - importScripts(sameOriginURL.href); - } catch (e) { - if (!(e instanceof SyntaxError)) { - postMessage({ result: false }); - return; - } - - fileName1 = e.fileName; - } - - if (fileName1 != sameOriginURL.href || !fileName1) { - postMessage({ result: false }); - return; - } - - if (a.data.test == "try") { - var exception; + // Local test. + if (a.data.mode === "catch") { try { - importScripts(crossOriginURL.href); - } catch (e) { - fileName2 = e.filename; - exception = e; + importScripts(a.data.url); + workerMethod(); + } catch (ex) { + delayedPostMessage({ + args, + error: normalizeError(ex), + }); } - - postMessage({ - result: - fileName2 == workerURL && - exception.name == "NetworkError" && - exception.code == DOMException.NETWORK_ERR, + } else if (a.data.mode === "uncaught") { + const onerrorPromise = new Promise(resolve => { + self.onerror = (...onerrorArgs) => { + resolve(normalizeOnError(...onerrorArgs)); + }; }); - return; - } - - if (a.data.test == "eventListener") { - addEventListener("error", function (event) { - event.preventDefault(); - postMessage({ - result: event instanceof ErrorEvent && event.filename == workerURL, + const listenerPromise = new Promise(resolve => { + self.addEventListener("error", evt => { + resolve(normalizeErrorEvent(evt)); }); }); - } - if (a.data.test == "onerror") { - onerror = function (...args) { - postMessage({ result: args[1] == workerURL }); - }; - } + Promise.all([onerrorPromise, listenerPromise]).then( + ([onerrorEvent, listenerEvent]) => { + delayedPostMessage({ + args, + onerrorEvent, + listenerEvent, + }); + } + ); - importScripts(crossOriginURL.href); + importScripts(a.data.url); + workerMethod(); + // we will have thrown by this point, which will trigger an "error" event + // on our global and then will propagate to our parent (which could be a + // window or a worker, if nested). + // + // To avoid hangs, throw a different error here that will fail equivalence + // tests. + throw new Error("We expected an error and this is a failsafe for hangs."); + } }; |