browser_console_modes.js (7844B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 // Test that messages from different contexts appears in the Browser Console and that their 6 // visibility can be controlled through the UI (either with the ChromeDebugToolbar mode whe 7 // Fission is enabled, or through the "Show Content Messages" setting when it's not). 8 9 "use strict"; 10 11 const FILTER_PREFIX = "BC_TEST|"; 12 13 const contentArgs = { 14 log: FILTER_PREFIX + "MyLog", 15 warn: FILTER_PREFIX + "MyWarn", 16 error: FILTER_PREFIX + "MyError", 17 exception: FILTER_PREFIX + "MyException", 18 info: FILTER_PREFIX + "MyInfo", 19 debug: FILTER_PREFIX + "MyDebug", 20 counterName: FILTER_PREFIX + "MyCounter", 21 timerName: FILTER_PREFIX + "MyTimer", 22 }; 23 24 const TEST_URI = `data:text/html,<!DOCTYPE html><meta charset=utf8>console API calls<script> 25 console.log("${contentArgs.log}", {hello: "world"}); 26 console.warn("${contentArgs.warn}", {hello: "world"}); 27 console.error("${contentArgs.error}", {hello: "world"}); 28 console.exception("${contentArgs.exception}", {hello: "world"}); 29 console.info("${contentArgs.info}", {hello: "world"}); 30 console.debug("${contentArgs.debug}", {hello: "world"}); 31 console.count("${contentArgs.counterName}"); 32 console.time("${contentArgs.timerName}"); 33 console.timeLog("${contentArgs.timerName}", "MyTimeLog", {hello: "world"}); 34 console.timeEnd("${contentArgs.timerName}"); 35 console.trace("${FILTER_PREFIX}", {hello: "world"}); 36 console.assert(false, "${FILTER_PREFIX}", {hello: "world"}); 37 console.table(["${FILTER_PREFIX}", {hello: "world"}]); 38 </script>`; 39 40 // Test can be a bit long 41 requestLongerTimeout(2); 42 43 add_task(async function () { 44 // Show the content messages 45 await pushPref("devtools.browsertoolbox.scope", "everything"); 46 // Show context selector 47 await pushPref("devtools.chrome.enabled", true); 48 49 // Open the WebConsole on the tab to check changing mode won't focus the tab 50 await openNewTabAndConsole(TEST_URI); 51 52 // Open the Browser Console 53 const hud = await BrowserConsoleManager.toggleBrowserConsole(); 54 // Set a filter to have predictable results, otherwise we may get messages from Firefox 55 // polluting the test. 56 await setFilterState(hud, { text: FILTER_PREFIX }); 57 58 const chromeDebugToolbar = hud.ui.document.querySelector( 59 ".chrome-debug-toolbar" 60 ); 61 ok( 62 !!chromeDebugToolbar, 63 "ChromeDebugToolbar is displayed when the Browser Console has fission support" 64 ); 65 is( 66 hud.chromeWindow.document.title, 67 "Multiprocess Browser Console", 68 "Browser Console window has expected title" 69 ); 70 71 const evaluationContextSelectorButton = await waitFor(() => 72 hud.ui.outputNode.querySelector(".webconsole-evaluation-selector-button") 73 ); 74 75 info("Select the content process target"); 76 const pid = 77 gBrowser.selectedTab.linkedBrowser.browsingContext.currentWindowGlobal 78 .osPid; 79 getContextSelectorItems(hud) 80 .find(item => 81 item.querySelector(".label")?.innerText?.startsWith(`(pid ${pid})`) 82 ) 83 .click(); 84 85 await waitFor(() => 86 evaluationContextSelectorButton.classList.contains("checked") 87 ); 88 89 // We can't directly throw in the script as it would be treated as an evaluation result 90 // and wouldn't be hidden when switching modes. 91 // Here we use an async-iife in which we throw so this will trigger the proper error 92 // reporting path. 93 await executeAndWaitForResultMessage( 94 hud, 95 `(async function(){ 96 throw new Error("${FILTER_PREFIX}Content error") 97 })(); 98 21+21`, 99 42 100 ); 101 102 await waitFor(() => findErrorMessage(hud, "Content error")); 103 ok(true, "Error message from content process is displayed"); 104 105 // Emit an error message from the parent process 106 executeSoon(() => { 107 expectUncaughtException(); 108 throw new Error(`${FILTER_PREFIX}Parent error`); 109 }); 110 111 await waitFor(() => findErrorMessage(hud, "Parent error")); 112 ok(true, "Parent process message is displayed"); 113 114 const suffix = ` Object { hello: "world" }`; 115 const expectedMessages = [ 116 contentArgs.log + suffix, 117 contentArgs.warn + suffix, 118 contentArgs.error + suffix, 119 contentArgs.exception + suffix, 120 contentArgs.info + suffix, 121 contentArgs.debug + suffix, 122 `${contentArgs.counterName}: 1`, 123 `MyTimeLog${suffix}`, 124 `timer ended`, 125 `console.trace() ${FILTER_PREFIX}${suffix}`, 126 `Assertion failed: ${FILTER_PREFIX}${suffix}`, 127 `console.table()`, 128 ]; 129 130 info("wait for all the messages to be displayed"); 131 await waitFor( 132 () => 133 expectedMessages.every( 134 expectedMessage => 135 findMessagePartsByType(hud, { 136 text: expectedMessage, 137 typeSelector: ".console-api", 138 partSelector: ".message-body", 139 }).length == 1 140 ), 141 "wait for all the messages to be displayed", 142 100 143 ); 144 ok(true, "Expected messages are displayed in the browser console"); 145 146 const tableMessage = findConsoleAPIMessage(hud, "console.table()", ".table"); 147 148 const table = await waitFor(() => 149 tableMessage.querySelector(".consoletable") 150 ); 151 ok(table, "There is a table element"); 152 const tableTextContent = table.textContent; 153 ok( 154 tableTextContent.includes(FILTER_PREFIX) && 155 tableTextContent.includes(`world`) && 156 tableTextContent.includes(`hello`), 157 "Table has expected content" 158 ); 159 160 info("Set Browser Console Mode to parent process only"); 161 chromeDebugToolbar 162 .querySelector( 163 `.chrome-debug-toolbar input[name="chrome-debug-mode"][value="parent-process"]` 164 ) 165 .click(); 166 info("Wait for content messages to be hidden"); 167 await waitFor(() => !findConsoleAPIMessage(hud, contentArgs.log)); 168 169 for (const expectedMessage of expectedMessages) { 170 ok( 171 !findConsoleAPIMessage(hud, expectedMessage), 172 `"${expectedMessage}" is hidden` 173 ); 174 } 175 176 is( 177 hud.chromeWindow.document.title, 178 "Parent process Browser Console", 179 "Browser Console window title was updated" 180 ); 181 182 ok(hud.iframeWindow.document.hasFocus(), "Browser Console is still focused"); 183 184 await waitFor( 185 () => !evaluationContextSelectorButton.classList.contains("checked") 186 ); 187 ok(true, "Changing mode did reset the context selector"); 188 ok( 189 findMessageByType(hud, "21+21", ".command"), 190 "The evaluation message is still displayed" 191 ); 192 ok( 193 findEvaluationResultMessage(hud, `42`), 194 "The evaluation result is still displayed" 195 ); 196 197 info( 198 "Check that message from parent process is still visible in the Browser Console" 199 ); 200 ok( 201 !!findErrorMessage(hud, "Parent error"), 202 "Parent process message is still displayed" 203 ); 204 205 info("Set Browser Console Mode to Multiprocess"); 206 chromeDebugToolbar 207 .querySelector( 208 `.chrome-debug-toolbar input[name="chrome-debug-mode"][value="everything"]` 209 ) 210 .click(); 211 212 info("Wait for content messages to be displayed"); 213 await waitFor(() => 214 expectedMessages.every(expectedMessage => 215 findConsoleAPIMessage(hud, expectedMessage) 216 ) 217 ); 218 219 for (const expectedMessage of expectedMessages) { 220 // Search into the message body as the message location could have some of the 221 // searched text. 222 is( 223 findMessagePartsByType(hud, { 224 text: expectedMessage, 225 typeSelector: ".console-api", 226 partSelector: ".message-body", 227 }).length, 228 1, 229 `"${expectedMessage}" is visible` 230 ); 231 } 232 233 is( 234 findErrorMessages(hud, "Content error").length, 235 1, 236 "error message from content process is only displayed once" 237 ); 238 239 is( 240 hud.chromeWindow.document.title, 241 "Multiprocess Browser Console", 242 "Browser Console window title was updated again" 243 ); 244 245 info("Clear and close the Browser Console"); 246 await safeCloseBrowserConsole({ clearOutput: true }); 247 });