browser_webconsole_persist.js (10979B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 // Check that message persistence works - bug 705921 / bug 1307881 5 6 "use strict"; 7 8 const TEST_FILE = "test-console.html"; 9 const TEST_COM_URI = URL_ROOT_COM_SSL + TEST_FILE; 10 const TEST_ORG_URI = URL_ROOT_ORG_SSL + TEST_FILE; 11 // TEST_MOCHI_URI uses a non standart port and hence 12 // is not subject to https-first mode 13 const TEST_MOCHI_URI = URL_ROOT_MOCHI_8888 + TEST_FILE; 14 15 const INITIAL_LOGS_NUMBER = 5; 16 17 const { 18 MESSAGE_TYPE, 19 } = require("resource://devtools/client/webconsole/constants.js"); 20 const { 21 WILL_NAVIGATE_TIME_SHIFT, 22 } = require("resource://devtools/server/actors/webconsole/listeners/document-events.js"); 23 24 async function logAndAssertInitialMessages(hud) { 25 await SpecialPowers.spawn( 26 gBrowser.selectedBrowser, 27 [INITIAL_LOGS_NUMBER], 28 count => { 29 content.wrappedJSObject.doLogs(count); 30 } 31 ); 32 await waitFor(() => findAllMessages(hud).length === INITIAL_LOGS_NUMBER); 33 ok(true, "Messages showed up initially"); 34 } 35 36 add_task(async function () { 37 info("Testing that messages disappear on a refresh if logs aren't persisted"); 38 const hud = await openNewTabAndConsole(TEST_COM_URI); 39 40 await logAndAssertInitialMessages(hud); 41 42 const onReloaded = hud.ui.once("reloaded"); 43 await reloadBrowser(); 44 await onReloaded; 45 46 info("Wait for messages to be cleared"); 47 await waitFor(() => findAllMessages(hud).length === 0); 48 ok(true, "Messages disappeared"); 49 50 await closeToolboxIfOpen(); 51 }); 52 53 add_task(async function () { 54 info( 55 "Testing that messages disappear on a cross origin navigation if logs aren't persisted" 56 ); 57 const hud = await openNewTabAndConsole(TEST_COM_URI); 58 59 await logAndAssertInitialMessages(hud); 60 61 await navigateTo(TEST_ORG_URI); 62 await waitFor(() => findAllMessages(hud).length === 0); 63 ok(true, "Messages disappeared"); 64 65 await closeToolboxIfOpen(); 66 }); 67 68 add_task(async function () { 69 info("Testing that messages disappear on bfcache navigations"); 70 const firstLocation = 71 "data:text/html,<!DOCTYPE html><script>console.log('first document load');window.onpageshow=()=>console.log('first document show');</script>"; 72 const secondLocation = 73 "data:text/html,<!DOCTYPE html><script>console.log('second document load');window.onpageshow=()=>console.log('second document show');</script>"; 74 const hud = await openNewTabAndConsole(firstLocation); 75 76 info("Wait for first page messages"); 77 // Look into .message-body as the default selector also include the frame, 78 // which is the document url, which also include the logged string... 79 await waitFor( 80 () => 81 findMessagePartsByType(hud, { 82 text: "first document load", 83 typeSelector: ".console-api", 84 partSelector: ".message-body", 85 }).length === 1 && 86 findMessagePartsByType(hud, { 87 text: "first document show", 88 typeSelector: ".console-api", 89 partSelector: ".message-body", 90 }).length === 1 91 ); 92 const firstPageInnerWindowId = 93 gBrowser.selectedBrowser.browsingContext.currentWindowGlobal.innerWindowId; 94 95 await navigateTo(secondLocation); 96 97 const secondPageInnerWindowId = 98 gBrowser.selectedBrowser.browsingContext.currentWindowGlobal.innerWindowId; 99 isnot( 100 firstPageInnerWindowId, 101 secondPageInnerWindowId, 102 "The second page is having a distinct inner window id" 103 ); 104 await waitFor( 105 () => 106 findMessagePartsByType(hud, { 107 text: "second", 108 typeSelector: ".console-api", 109 partSelector: ".message-body", 110 }).length === 2 111 ); 112 ok("Second page message appeared"); 113 is( 114 findMessagePartsByType(hud, { 115 text: "first", 116 typeSelector: ".console-api", 117 partSelector: ".message-body", 118 }).length, 119 0, 120 "First page message disappeared" 121 ); 122 123 info("Go back to the first page"); 124 gBrowser.selectedBrowser.goBack(); 125 126 // When going back, the page isn't reloaded, so in theory we should only get 127 // the pageshow event. 128 await waitFor( 129 () => 130 findMessagePartsByType(hud, { 131 text: "first document show", 132 typeSelector: ".console-api", 133 partSelector: ".message-body", 134 }).length === 1 135 ); 136 ok("First page message re-appeared"); 137 138 // However `clearMessagesCache` can fail on navigation, and in this case the 139 // cache will still contain the two initial logs: 140 // - "first document load" 141 // - "first document show" 142 let isLoadMessageDisplayed = findMessagePartsByType(hud, { 143 text: "first document load", 144 typeSelector: ".console-api", 145 partSelector: ".message-body", 146 }).length; 147 148 // With the additional "first document show" from the new bfcache navigation 149 // this means we should wait for "first document show" to have a repeated 150 // count of 2. 151 // Otherwise the second "first document show" resource might be throttled and 152 // handled later in the test. 153 if (isLoadMessageDisplayed) { 154 await waitForRepeatedMessageByType( 155 hud, 156 "first document show", 157 ".console-api", 158 2 159 ); 160 } 161 162 is( 163 gBrowser.selectedBrowser.browsingContext.currentWindowGlobal.innerWindowId, 164 firstPageInnerWindowId, 165 "The first page is really a bfcache navigation, keeping the same WindowGlobal" 166 ); 167 is( 168 findMessagePartsByType(hud, { 169 text: "second", 170 typeSelector: ".console-api", 171 partSelector: ".message-body", 172 }).length, 173 0, 174 "Second page message disappeared" 175 ); 176 177 info("Go forward to the original second page"); 178 gBrowser.selectedBrowser.goForward(); 179 await waitFor( 180 () => 181 findMessagePartsByType(hud, { 182 text: "second document show", 183 typeSelector: ".console-api", 184 partSelector: ".message-body", 185 }).length === 1 186 ); 187 ok("Second page message appeared"); 188 189 isLoadMessageDisplayed = findMessagePartsByType(hud, { 190 text: "second document load", 191 typeSelector: ".console-api", 192 partSelector: ".message-body", 193 }).length; 194 if (isLoadMessageDisplayed) { 195 await waitForRepeatedMessageByType( 196 hud, 197 "second document show", 198 ".console-api", 199 2 200 ); 201 } 202 is( 203 gBrowser.selectedBrowser.browsingContext.currentWindowGlobal.innerWindowId, 204 secondPageInnerWindowId, 205 "The second page is really a bfcache navigation, keeping the same WindowGlobal" 206 ); 207 is( 208 findMessagePartsByType(hud, { 209 text: "first", 210 typeSelector: ".console-api", 211 partSelector: ".message-body", 212 }).length, 213 0, 214 "First page message disappeared" 215 ); 216 217 await closeToolboxIfOpen(); 218 }); 219 220 add_task(async function () { 221 info("Testing that messages persist on a refresh if logs are persisted"); 222 223 const hud = await openNewTabAndConsole(TEST_COM_URI); 224 225 await toggleConsoleSetting( 226 hud, 227 ".webconsole-console-settings-menu-item-persistentLogs" 228 ); 229 230 await logAndAssertInitialMessages(hud); 231 232 const onNavigatedMessage = waitForMessageByType( 233 hud, 234 "Navigated to " + TEST_COM_URI, 235 ".navigationMarker" 236 ); 237 const onReloaded = hud.ui.once("reloaded"); 238 // Because will-navigate DOCUMENT_EVENT timestamp is shifted to workaround some other limitation, 239 // the reported time of navigation may actually be slightly off and be older than the real navigation start 240 let timeBeforeNavigation = Date.now() - WILL_NAVIGATE_TIME_SHIFT; 241 reloadBrowser(); 242 await onNavigatedMessage; 243 await onReloaded; 244 245 ok(true, "Navigation message appeared as expected"); 246 is( 247 findAllMessages(hud).length, 248 INITIAL_LOGS_NUMBER + 1, 249 "Messages logged before navigation are still visible" 250 ); 251 252 assertLastMessageIsNavigationMessage(hud, timeBeforeNavigation, TEST_COM_URI); 253 254 info( 255 "Testing that messages also persist when doing a cross origin navigation if logs are persisted" 256 ); 257 const onNavigatedMessage2 = waitForMessageByType( 258 hud, 259 "Navigated to " + TEST_ORG_URI, 260 ".navigationMarker" 261 ); 262 timeBeforeNavigation = Date.now() - WILL_NAVIGATE_TIME_SHIFT; 263 await navigateTo(TEST_ORG_URI); 264 await onNavigatedMessage2; 265 266 ok(true, "Second navigation message appeared as expected"); 267 is( 268 findAllMessages(hud).length, 269 INITIAL_LOGS_NUMBER + 2, 270 "Messages logged before the second navigation are still visible" 271 ); 272 273 assertLastMessageIsNavigationMessage(hud, timeBeforeNavigation, TEST_ORG_URI); 274 275 info( 276 "Test doing a second cross origin navigation in order to triger a target switching with a target following the window global lifecycle" 277 ); 278 const onNavigatedMessage3 = waitForMessageByType( 279 hud, 280 "Navigated to " + TEST_MOCHI_URI, 281 ".navigationMarker" 282 ); 283 timeBeforeNavigation = Date.now() - WILL_NAVIGATE_TIME_SHIFT; 284 await navigateTo(TEST_MOCHI_URI); 285 await onNavigatedMessage3; 286 287 ok(true, "Third navigation message appeared as expected"); 288 is( 289 findAllMessages(hud).length, 290 INITIAL_LOGS_NUMBER + 3, 291 "Messages logged before the third navigation are still visible" 292 ); 293 294 assertLastMessageIsNavigationMessage( 295 hud, 296 timeBeforeNavigation, 297 TEST_MOCHI_URI 298 ); 299 300 await closeToolboxIfOpen(); 301 }); 302 303 add_task(async function consoleClearPersist() { 304 info("Testing that messages persist on console.clear if logs are persisted"); 305 306 await pushPref("devtools.webconsole.persistlog", true); 307 const hud = await openNewTabAndConsole(TEST_COM_URI); 308 309 await logAndAssertInitialMessages(hud); 310 311 info("Send a console.clear() and another log from the content page"); 312 const onConsoleClearPrevented = waitForMessageByType( 313 hud, 314 "console.clear() was prevented", 315 ".console-api" 316 ); 317 SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => { 318 content.wrappedJSObject.console.clear(); 319 content.wrappedJSObject.console.log("after clear"); 320 }); 321 322 await waitForMessageByType(hud, "after clear", ".log"); 323 await onConsoleClearPrevented; 324 ok(true, "console.clear was handled by the client"); 325 326 Assert.strictEqual( 327 findAllMessages(hud).length, 328 INITIAL_LOGS_NUMBER + 2, 329 "All initial messages are still displayed, with the 2 new ones" 330 ); 331 332 await closeToolboxIfOpen(); 333 }); 334 335 function assertLastMessageIsNavigationMessage(hud, timeBeforeNavigation, url) { 336 const { visibleMessages, mutableMessagesById } = hud.ui.wrapper 337 .getStore() 338 .getState().messages; 339 const lastMessageId = visibleMessages.at(-1); 340 const lastMessage = mutableMessagesById.get(lastMessageId); 341 342 is( 343 lastMessage.type, 344 MESSAGE_TYPE.NAVIGATION_MARKER, 345 "The last message is a navigation marker" 346 ); 347 is( 348 lastMessage.messageText, 349 "Navigated to " + url, 350 "The navigation message is correct" 351 ); 352 // It is surprising, but the navigation may be timestamped at the same exact time 353 // as timeBeforeNavigation time record. 354 Assert.greaterOrEqual( 355 lastMessage.timeStamp, 356 timeBeforeNavigation, 357 "The navigation message has a timestamp newer (or equal) than the time before the navigation..." 358 ); 359 Assert.less( 360 lastMessage.timeStamp, 361 Date.now(), 362 "...and older than current time" 363 ); 364 }