importScripts_3rdParty_worker.js (4366B)
1 const workerURL = 2 "http://mochi.test:8888/tests/dom/workers/test/importScripts_3rdParty_worker.js"; 3 4 /** 5 * An Error can be a JS Error or a DOMException. The primary difference is that 6 * JS Errors have a SpiderMonkey specific `fileName` for the filename and 7 * DOMEXCEPTION uses `filename`. 8 */ 9 function normalizeError(err) { 10 if (!err) { 11 return null; 12 } 13 14 const isDOMException = "filename" in err; 15 16 return { 17 message: err.message, 18 name: err.name, 19 isDOMException, 20 code: err.code, 21 // normalize to fileName 22 fileName: isDOMException ? err.filename : err.fileName, 23 hasFileName: !!err.fileName, 24 hasFilename: !!err.filename, 25 lineNumber: err.lineNumber, 26 columnNumber: err.columnNumber, 27 stack: err.stack, 28 stringified: err.toString(), 29 }; 30 } 31 32 function normalizeErrorEvent(event) { 33 if (!event) { 34 return null; 35 } 36 37 return { 38 message: event.message, 39 filename: event.filename, 40 lineno: event.lineno, 41 colno: event.colno, 42 error: normalizeError(event.error), 43 stringified: event.toString(), 44 }; 45 } 46 47 /** 48 * Normalize the `OnErrorEventHandlerNonNull onerror` invocation. The 49 * special handling in JSEventHandler::HandleEvent ends up spreading out the 50 * contents of the ErrorEvent into discrete arguments. The one thing lost is 51 * we can't toString the ScriptEvent itself, but this should be the same as the 52 * message anyways. 53 * 54 * The spec for the invocation is the "special error event handling" logic 55 * described in step 4 at: 56 * https://html.spec.whatwg.org/multipage/webappapis.html#the-event-handler-processing-algorithm 57 * noting that the step somewhat glosses over that it's only "onerror" that is 58 * OnErrorEventHandlerNonNull and capable of processing 5 arguments and that's 59 * why an addEventListener "error" listener doesn't get this handling. 60 * 61 * Argument names here are made to match the call-site in JSEventHandler. 62 */ 63 function normalizeOnError( 64 msgOrEvent, 65 fileName, 66 lineNumber, 67 columnNumber, 68 error 69 ) { 70 return { 71 message: msgOrEvent, 72 filename: fileName, 73 lineno: lineNumber, 74 colno: columnNumber, 75 error: normalizeError(error), 76 stringified: null, 77 }; 78 } 79 80 /** 81 * Helper to postMessage the provided data after a setTimeout(0) so that any 82 * error event currently being dispatched that will bubble to our parent will 83 * be delivered before our postMessage. 84 */ 85 function delayedPostMessage(data) { 86 setTimeout(() => { 87 postMessage(data); 88 }, 0); 89 } 90 91 onmessage = function (a) { 92 const args = a.data; 93 // Messages are either nested (forward to a nested worker) or should be 94 // processed locally. 95 if (a.data.nested) { 96 const worker = new Worker(workerURL); 97 let firstErrorEvent; 98 99 // When the test mode is "catch" 100 101 worker.onmessage = function (event) { 102 delayedPostMessage({ 103 nestedMessage: event.data, 104 errorEvent: firstErrorEvent, 105 }); 106 }; 107 108 worker.onerror = function (event) { 109 firstErrorEvent = normalizeErrorEvent(event); 110 event.preventDefault(); 111 }; 112 113 a.data.nested = false; 114 worker.postMessage(a.data); 115 return; 116 } 117 118 // Local test. 119 if (a.data.mode === "catch") { 120 try { 121 importScripts(a.data.url); 122 workerMethod(); 123 } catch (ex) { 124 delayedPostMessage({ 125 args, 126 error: normalizeError(ex), 127 }); 128 } 129 } else if (a.data.mode === "uncaught") { 130 const onerrorPromise = new Promise(resolve => { 131 self.onerror = (...onerrorArgs) => { 132 resolve(normalizeOnError(...onerrorArgs)); 133 }; 134 }); 135 const listenerPromise = new Promise(resolve => { 136 self.addEventListener("error", evt => { 137 resolve(normalizeErrorEvent(evt)); 138 }); 139 }); 140 141 Promise.all([onerrorPromise, listenerPromise]).then( 142 ([onerrorEvent, listenerEvent]) => { 143 delayedPostMessage({ 144 args, 145 onerrorEvent, 146 listenerEvent, 147 }); 148 } 149 ); 150 151 importScripts(a.data.url); 152 workerMethod(); 153 // we will have thrown by this point, which will trigger an "error" event 154 // on our global and then will propagate to our parent (which could be a 155 // window or a worker, if nested). 156 // 157 // To avoid hangs, throw a different error here that will fail equivalence 158 // tests. 159 throw new Error("We expected an error and this is a failsafe for hangs."); 160 } 161 };