browser_webconsole_stubs_page_error.js (4100B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 const { 7 STUBS_UPDATE_ENV, 8 createCommandsForTab, 9 getCleanedPacket, 10 getSerializedPacket, 11 getStubFile, 12 writeStubsToFile, 13 } = require(`${CHROME_URL_ROOT}stub-generator-helpers`); 14 15 const TEST_URI = 16 "https://example.com/browser/devtools/client/webconsole/test/browser/test-console-api.html"; 17 const STUB_FILE = "pageError.js"; 18 19 add_task(async function () { 20 await pushPref("javascript.options.asyncstack_capture_debuggee_only", false); 21 22 const isStubsUpdate = Services.env.get(STUBS_UPDATE_ENV) == "true"; 23 info(`${isStubsUpdate ? "Update" : "Check"} ${STUB_FILE}`); 24 25 const generatedStubs = await generatePageErrorStubs(); 26 27 if (isStubsUpdate) { 28 await writeStubsToFile(STUB_FILE, generatedStubs); 29 ok(true, `${STUB_FILE} was updated`); 30 return; 31 } 32 33 const existingStubs = getStubFile(STUB_FILE); 34 const FAILURE_MSG = 35 "The pageError stubs file needs to be updated by running `" + 36 `mach test ${getCurrentTestFilePath()} --headless --setenv WEBCONSOLE_STUBS_UPDATE=true` + 37 "`"; 38 39 if (generatedStubs.size !== existingStubs.rawPackets.size) { 40 ok(false, FAILURE_MSG); 41 return; 42 } 43 44 let failed = false; 45 for (const [key, packet] of generatedStubs) { 46 const packetStr = getSerializedPacket(packet, { 47 sortKeys: true, 48 replaceActorIds: true, 49 }); 50 const existingPacketStr = getSerializedPacket( 51 existingStubs.rawPackets.get(key), 52 { sortKeys: true, replaceActorIds: true } 53 ); 54 is(packetStr, existingPacketStr, `"${key}" packet has expected value`); 55 failed = failed || packetStr !== existingPacketStr; 56 } 57 58 if (failed) { 59 ok(false, FAILURE_MSG); 60 } else { 61 ok(true, "Stubs are up to date"); 62 } 63 }); 64 65 async function generatePageErrorStubs() { 66 const stubs = new Map(); 67 68 const tab = await addTab(TEST_URI); 69 const commands = await createCommandsForTab(tab); 70 await commands.targetCommand.startListening(); 71 const resourceCommand = commands.resourceCommand; 72 73 // Ensure waiting for sources in order to populate message.sourceId correctly. 74 await resourceCommand.watchResources([resourceCommand.TYPES.SOURCE], { 75 onAvailable() {}, 76 }); 77 78 // The resource-watcher only supports a single call to watch/unwatch per 79 // instance, so we attach a unique watch callback, which will forward the 80 // resource to `handleErrorMessage`, dynamically updated for each command. 81 let handleErrorMessage = function () {}; 82 83 const onErrorMessageAvailable = resources => { 84 for (const resource of resources) { 85 handleErrorMessage(resource); 86 } 87 }; 88 await resourceCommand.watchResources([resourceCommand.TYPES.ERROR_MESSAGE], { 89 onAvailable: onErrorMessageAvailable, 90 }); 91 92 for (const [key, code] of getCommands()) { 93 const onPageError = new Promise(resolve => { 94 handleErrorMessage = packet => resolve(packet); 95 }); 96 97 // On e10s, the exception is triggered in child process 98 // and is ignored by test harness 99 // expectUncaughtException should be called for each uncaught exception. 100 if (!Services.appinfo.browserTabsRemoteAutostart) { 101 expectUncaughtException(); 102 } 103 104 // Note: This needs to use ContentTask rather than SpecialPowers.spawn 105 // because the latter includes cross-process stack information. 106 await ContentTask.spawn(gBrowser.selectedBrowser, code, function (subCode) { 107 const script = content.document.createElement("script"); 108 script.append(content.document.createTextNode(subCode)); 109 content.document.body.append(script); 110 script.remove(); 111 }); 112 113 const packet = await onPageError; 114 stubs.set(key, getCleanedPacket(key, packet)); 115 } 116 117 return stubs; 118 } 119 120 function getCommands() { 121 const pageError = new Map(); 122 123 pageError.set( 124 "ReferenceError: asdf is not defined", 125 ` 126 function bar() { 127 asdf() 128 } 129 function foo() { 130 bar() 131 } 132 133 foo() 134 ` 135 ); 136 137 pageError.set( 138 "TypeError longString message", 139 `throw new Error("Long error ".repeat(10000))` 140 ); 141 return pageError; 142 }