tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }