tor-browser

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

browser_resources_stylesheets_navigation.js (8474B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 // Test the ResourceCommand API around STYLESHEET and navigation (reloading, creation of new browsing context, …)
      7 
      8 const ORG_DOC_BUILDER = "https://example.org/document-builder.sjs";
      9 const COM_DOC_BUILDER = "https://example.com/document-builder.sjs";
     10 
     11 // Since the order of resources is not guaranteed, we put a number in the title attribute
     12 // of the <style> elements so we can sort them in a way that makes it easier for us to assert.
     13 let currentStyleTitle = 0;
     14 
     15 const TEST_URI =
     16  `${ORG_DOC_BUILDER}?html=1<h1>top-level example.org</h1>` +
     17  `<style title="${currentStyleTitle++}">.top-level-org{}</style>` +
     18  `<iframe id="same-origin-1" src="${ORG_DOC_BUILDER}?html=<h2>example.org 1</h2><style title=${currentStyleTitle++}>.frame-org-1{}</style>"></iframe>` +
     19  `<iframe id="same-origin-2" src="${ORG_DOC_BUILDER}?html=<h2>example.org 2</h2><style title=${currentStyleTitle++}>.frame-org-2{}</style>"></iframe>` +
     20  `<iframe id="remote-origin-1" src="${COM_DOC_BUILDER}?html=<h2>example.com 1</h2><style title=${currentStyleTitle++}>.frame-com-1{}</style>"></iframe>` +
     21  `<iframe id="remote-origin-2" src="${COM_DOC_BUILDER}?html=<h2>example.com 2</h2><style title=${currentStyleTitle++}>.frame-com-2{}</style>"></iframe>`;
     22 
     23 const COOP_HEADERS = "Cross-Origin-Opener-Policy:same-origin";
     24 const TEST_URI_NEW_BROWSING_CONTEXT =
     25  `${ORG_DOC_BUILDER}?headers=${COOP_HEADERS}` +
     26  `&html=<h1>top-level example.org</div>` +
     27  `<style>.top-level-org-new-bc{}</style>`;
     28 
     29 add_task(async function () {
     30  info(
     31    "Open a new tab and check that styleSheetChangeEventsEnabled is false by default"
     32  );
     33  const tab = await addTab(TEST_URI);
     34 
     35  is(
     36    await getDocumentStyleSheetChangeEventsEnabled(tab.linkedBrowser),
     37    false,
     38    `styleSheetChangeEventsEnabled is false at the beginning`
     39  );
     40 
     41  const { client, resourceCommand, targetCommand } =
     42    await initResourceCommand(tab);
     43 
     44  let availableResources = [];
     45  await resourceCommand.watchResources([resourceCommand.TYPES.STYLESHEET], {
     46    onAvailable: resources => {
     47      availableResources.push(...resources);
     48    },
     49  });
     50 
     51  info("Wait for all the stylesheets resources of main document and iframes");
     52  await waitFor(() => availableResources.length === 5);
     53  is(availableResources.length, 5, "Retrieved the expected stylesheets");
     54 
     55  // the order of the resources is not guaranteed.
     56  sortResourcesByExpectedOrder(availableResources);
     57  await assertResource(availableResources[0], {
     58    styleText: `.top-level-org{}`,
     59  });
     60  await assertResource(availableResources[1], {
     61    styleText: `.frame-org-1{}`,
     62  });
     63  await assertResource(availableResources[2], {
     64    styleText: `.frame-org-2{}`,
     65  });
     66  await assertResource(availableResources[3], {
     67    styleText: `.frame-com-1{}`,
     68  });
     69  await assertResource(availableResources[4], {
     70    styleText: `.frame-com-2{}`,
     71  });
     72 
     73  // clear availableResources so it's easier to test
     74  availableResources = [];
     75 
     76  is(
     77    await getDocumentStyleSheetChangeEventsEnabled(tab.linkedBrowser),
     78    true,
     79    `styleSheetChangeEventsEnabled is true after watching stylesheets`
     80  );
     81 
     82  info("Navigate a remote frame to a different page");
     83  const iframeNewUrl =
     84    `https://example.com/document-builder.sjs?` +
     85    `html=<h2>example.com new bc</h2><style title=6>.frame-com-new-bc{}</style>`;
     86  await SpecialPowers.spawn(tab.linkedBrowser, [iframeNewUrl], url => {
     87    const { browsingContext } =
     88      content.document.querySelector("#remote-origin-2");
     89    return SpecialPowers.spawn(browsingContext, [url], innerUrl => {
     90      content.document.location = innerUrl;
     91    });
     92  });
     93  await waitFor(() => availableResources.length == 1);
     94  ok(true, "We're notified about the iframe new document stylesheet");
     95  await assertResource(availableResources[0], {
     96    styleText: `.frame-com-new-bc{}`,
     97  });
     98  const iframeNewBrowsingContext = await SpecialPowers.spawn(
     99    tab.linkedBrowser,
    100    [],
    101    () => content.document.querySelector("#remote-origin-2").browsingContext
    102  );
    103 
    104  is(
    105    await getDocumentStyleSheetChangeEventsEnabled(iframeNewBrowsingContext),
    106    true,
    107    `styleSheetChangeEventsEnabled is still true after navigating the iframe`
    108  );
    109 
    110  // clear availableResources so it's easier to test
    111  availableResources = [];
    112 
    113  info("Check that styleSheetChangeEventsEnabled persist after reloading");
    114  await reloadBrowser();
    115 
    116  const expectedStylesheetResources = 5;
    117  info(
    118    "Wait until we're notified about all the stylesheets (top-level document + iframe)"
    119  );
    120  await waitFor(
    121    () => availableResources.length === expectedStylesheetResources
    122  );
    123  is(
    124    availableResources.length,
    125    expectedStylesheetResources,
    126    "Retrieved the expected stylesheets after the page was reloaded"
    127  );
    128 
    129  // the order of the resources is not guaranteed.
    130  sortResourcesByExpectedOrder(availableResources);
    131  await assertResource(availableResources[0], {
    132    styleText: `.top-level-org{}`,
    133  });
    134  await assertResource(availableResources[1], {
    135    styleText: `.frame-org-1{}`,
    136  });
    137  await assertResource(availableResources[2], {
    138    styleText: `.frame-org-2{}`,
    139  });
    140  await assertResource(availableResources[3], {
    141    styleText: `.frame-com-1{}`,
    142  });
    143  await assertResource(availableResources[4], {
    144    styleText: `.frame-com-new-bc{}`,
    145  });
    146 
    147  is(
    148    await getDocumentStyleSheetChangeEventsEnabled(tab.linkedBrowser),
    149    true,
    150    `styleSheetChangeEventsEnabled is still true on the top level document after reloading`
    151  );
    152 
    153  const bc = await SpecialPowers.spawn(
    154    tab.linkedBrowser,
    155    [],
    156    () => content.document.querySelector("#same-origin-1").browsingContext
    157  );
    158  is(
    159    await getDocumentStyleSheetChangeEventsEnabled(bc),
    160    true,
    161    `styleSheetChangeEventsEnabled is still true on the iframe after reloading`
    162  );
    163 
    164  // clear availableResources so it's easier to test
    165  availableResources = [];
    166 
    167  info(
    168    "Check that styleSheetChangeEventsEnabled persist when navigating to a page that creates a new browsing context"
    169  );
    170  const previousBrowsingContextId = tab.linkedBrowser.browsingContext.id;
    171  const onLoaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
    172  BrowserTestUtils.startLoadingURIString(
    173    tab.linkedBrowser,
    174    TEST_URI_NEW_BROWSING_CONTEXT
    175  );
    176  await onLoaded;
    177 
    178  isnot(
    179    tab.linkedBrowser.browsingContext.id,
    180    previousBrowsingContextId,
    181    "A new browsing context was created"
    182  );
    183 
    184  info("Wait to get the stylesheet for the new document");
    185  await waitFor(() => availableResources.length === 1);
    186  ok(true, "We received the stylesheet for the new document");
    187  await assertResource(availableResources[0], {
    188    styleText: `.top-level-org-new-bc{}`,
    189  });
    190  is(
    191    await getDocumentStyleSheetChangeEventsEnabled(tab.linkedBrowser),
    192    true,
    193    `styleSheetChangeEventsEnabled is still true after navigating to a new browsing context`
    194  );
    195 
    196  targetCommand.destroy();
    197  await client.close();
    198 });
    199 
    200 /**
    201 * Returns the value of the browser/browsingContext document `styleSheetChangeEventsEnabled`
    202 * property.
    203 *
    204 * @param {Browser|BrowsingContext} browserOrBrowsingContext: The browser element or a
    205 *        browsing context.
    206 * @returns {Promise<boolean>}
    207 */
    208 function getDocumentStyleSheetChangeEventsEnabled(browserOrBrowsingContext) {
    209  return SpecialPowers.spawn(browserOrBrowsingContext, [], () => {
    210    return content.document.styleSheetChangeEventsEnabled;
    211  });
    212 }
    213 
    214 /**
    215 * Sort the passed array of stylesheet resources.
    216 *
    217 * Since the order of resources are not guaranteed, the <style> elements we use in this test
    218 * have a "title" attribute that represent their expected order so we can sort them in
    219 * a way that makes it easier for us to assert.
    220 *
    221 * @param {Array<object>} resources: Array of stylesheet resources
    222 */
    223 function sortResourcesByExpectedOrder(resources) {
    224  resources.sort((a, b) => {
    225    return Number(a.title) > Number(b.title);
    226  });
    227 }
    228 
    229 /**
    230 * Check that the resources have the expected text
    231 *
    232 * @param {Array<object>} resources: Array of stylesheet resources
    233 * @param {Array<object>} expected: Array of object of the following shape:
    234 * @param {object} expected[]
    235 * @param {object} expected[].styleText: Expected text content of the stylesheet
    236 */
    237 async function assertResource(resource, expected) {
    238  const styleText = (await getStyleSheetResourceText(resource)).trim();
    239  is(styleText, expected.styleText, "Style text is correct");
    240 }