1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
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) {
const worker = new Worker(workerURL);
let firstErrorEvent;
// When the test mode is "catch"
worker.onmessage = function (event) {
delayedPostMessage({
nestedMessage: event.data,
errorEvent: firstErrorEvent,
});
};
worker.onerror = function (event) {
firstErrorEvent = normalizeErrorEvent(event);
event.preventDefault();
};
a.data.nested = false;
worker.postMessage(a.data);
return;
}
// Local test.
if (a.data.mode === "catch") {
try {
importScripts(a.data.url);
workerMethod();
} catch (ex) {
delayedPostMessage({
args,
error: normalizeError(ex),
});
}
} else if (a.data.mode === "uncaught") {
const onerrorPromise = new Promise(resolve => {
self.onerror = (...onerrorArgs) => {
resolve(normalizeOnError(...onerrorArgs));
};
});
const listenerPromise = new Promise(resolve => {
self.addEventListener("error", evt => {
resolve(normalizeErrorEvent(evt));
});
});
Promise.all([onerrorPromise, listenerPromise]).then(
([onerrorEvent, listenerEvent]) => {
delayedPostMessage({
args,
onerrorEvent,
listenerEvent,
});
}
);
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.");
}
};
|