tor-browser

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

browser_resources_css_messages.js (7096B)


      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 CSS_MESSAGE
      7 // Reproduces the CSS message assertions from devtools/shared/webconsole/test/chrome/test_page_errors.html
      8 
      9 const { MESSAGE_CATEGORY } = require("resource://devtools/shared/constants.js");
     10 
     11 // Create a simple server so we have a nice sourceName in the resources packets.
     12 const httpServer = createTestHTTPServer();
     13 httpServer.registerPathHandler(`/test_css_messages.html`, (req, res) => {
     14  res.setStatusLine(req.httpVersion, 200, "OK");
     15  res.setHeader("Content-Type", "text/html");
     16  res.write(`<meta charset=utf8>
     17    <style>
     18      html {
     19        body {
     20          color: bloup;
     21        }
     22      }
     23    </style>Test CSS Messages`);
     24 });
     25 
     26 const TEST_URI = `http://localhost:${httpServer.identity.primaryPort}/test_css_messages.html`;
     27 
     28 add_task(async function () {
     29  await testWatchingCssMessages();
     30  await testWatchingCachedCssMessages();
     31 });
     32 
     33 async function testWatchingCssMessages() {
     34  // Disable the preloaded process as it creates processes intermittently
     35  // which forces the emission of RDP requests we aren't correctly waiting for.
     36  await pushPref("dom.ipc.processPrelaunch.enabled", false);
     37 
     38  // Open a test tab
     39  const tab = await addTab(TEST_URI);
     40 
     41  const { client, resourceCommand, targetCommand } =
     42    await initResourceCommand(tab);
     43 
     44  const receivedMessages = [];
     45  const { onAvailable, onAllMessagesReceived } = setupOnAvailableFunction(
     46    targetCommand,
     47    receivedMessages,
     48    false
     49  );
     50  await resourceCommand.watchResources([resourceCommand.TYPES.CSS_MESSAGE], {
     51    onAvailable,
     52  });
     53 
     54  info(
     55    "Now log CSS warning *after* the call to ResourceCommand.watchResources and after " +
     56      "having received the existing message"
     57  );
     58  // We need to wait for the first CSS Warning as it is not a cached message; when we
     59  // start watching, the `cssErrorReportingEnabled` is checked on the target docShell, and
     60  // if it is false, we re-parse the stylesheets to get the messages.
     61  await BrowserTestUtils.waitForCondition(() => receivedMessages.length === 1);
     62 
     63  info("Trigger a CSS Warning");
     64  triggerCSSWarning(tab);
     65 
     66  info("Waiting for all expected CSS messages to be received");
     67  await onAllMessagesReceived;
     68  ok(true, "All the expected CSS messages were received");
     69 
     70  Services.console.reset();
     71  targetCommand.destroy();
     72  await client.close();
     73 }
     74 
     75 async function testWatchingCachedCssMessages() {
     76  // Disable the preloaded process as it creates processes intermittently
     77  // which forces the emission of RDP requests we aren't correctly waiting for.
     78  await pushPref("dom.ipc.processPrelaunch.enabled", false);
     79 
     80  // Open a test tab
     81  const tab = await addTab(TEST_URI);
     82 
     83  // By default, the CSS Parser does not emit warnings at all, for performance matter.
     84  // Since we actually want the Parser to emit those messages _before_ we start listening
     85  // for CSS messages, we need to set the cssErrorReportingEnabled flag on the docShell.
     86  await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function () {
     87    content.docShell.cssErrorReportingEnabled = true;
     88    ChromeUtils.clearResourceCache({
     89      types: ["stylesheet"],
     90    });
     91  });
     92 
     93  // Setting the docShell flag only indicates to the Parser that from now on, it should
     94  // emit warnings. But it does not automatically emit warnings for the existing CSS
     95  // errors in the stylesheets. So here we reload the tab, which will make the Parser
     96  // parse the stylesheets again, this time emitting warnings.
     97  await reloadBrowser();
     98  // and trigger more CSS warnings
     99  await triggerCSSWarning(tab);
    100 
    101  // At this point, all messages should be in the ConsoleService cache, and we can begin
    102  // to watch and check that we do retrieve those messages.
    103  const { client, resourceCommand, targetCommand } =
    104    await initResourceCommand(tab);
    105 
    106  const receivedMessages = [];
    107  const { onAvailable } = setupOnAvailableFunction(
    108    targetCommand,
    109    receivedMessages,
    110    true
    111  );
    112  await resourceCommand.watchResources([resourceCommand.TYPES.CSS_MESSAGE], {
    113    onAvailable,
    114  });
    115  is(receivedMessages.length, 3, "Cached messages were retrieved as expected");
    116 
    117  Services.console.reset();
    118  targetCommand.destroy();
    119  await client.close();
    120 }
    121 
    122 function setupOnAvailableFunction(
    123  targetCommand,
    124  receivedMessages,
    125  isAlreadyExistingResource
    126 ) {
    127  // timeStamp are the result of a number in microsecond divided by 1000.
    128  // so we can't expect a precise number of decimals, or even if there would
    129  // be decimals at all.
    130  const FRACTIONAL_NUMBER_REGEX = /^\d+(\.\d{1,3})?$/;
    131 
    132  // The expected messages are the CSS warnings:
    133  // - one for the rule in the style element
    134  // - two for the JS modified style we're doing in the test.
    135  const expectedMessages = [
    136    {
    137      pageError: {
    138        errorMessage: /Expected color but found ‘bloup’/,
    139        sourceName: /test_css_messages/,
    140        category: MESSAGE_CATEGORY.CSS_PARSER,
    141        timeStamp: FRACTIONAL_NUMBER_REGEX,
    142        error: false,
    143        warning: true,
    144      },
    145      cssSelectors: ":is(html) body",
    146      isAlreadyExistingResource,
    147    },
    148    {
    149      pageError: {
    150        errorMessage: /Error in parsing value for ‘width’/,
    151        sourceName: /test_css_messages/,
    152        category: MESSAGE_CATEGORY.CSS_PARSER,
    153        timeStamp: FRACTIONAL_NUMBER_REGEX,
    154        error: false,
    155        warning: true,
    156      },
    157      isAlreadyExistingResource,
    158    },
    159    {
    160      pageError: {
    161        errorMessage: /Error in parsing value for ‘height’/,
    162        sourceName: /test_css_messages/,
    163        category: MESSAGE_CATEGORY.CSS_PARSER,
    164        timeStamp: FRACTIONAL_NUMBER_REGEX,
    165        error: false,
    166        warning: true,
    167      },
    168      isAlreadyExistingResource,
    169    },
    170  ];
    171 
    172  let done;
    173  const onAllMessagesReceived = new Promise(resolve => (done = resolve));
    174  const onAvailable = resources => {
    175    for (const resource of resources) {
    176      const { pageError } = resource;
    177 
    178      is(
    179        resource.targetFront,
    180        targetCommand.targetFront,
    181        "The targetFront property is the expected one"
    182      );
    183 
    184      if (!pageError.sourceName.includes("test_css_messages")) {
    185        info(`Ignore error from unknown source: "${pageError.sourceName}"`);
    186        continue;
    187      }
    188 
    189      const index = receivedMessages.length;
    190      receivedMessages.push(resource);
    191 
    192      info(
    193        `checking received css message #${index}: ${pageError.errorMessage}`
    194      );
    195      ok(pageError, "The resource has a pageError attribute");
    196      checkObject(resource, expectedMessages[index]);
    197 
    198      if (receivedMessages.length == expectedMessages.length) {
    199        done();
    200      }
    201    }
    202  };
    203  return { onAvailable, onAllMessagesReceived };
    204 }
    205 
    206 /**
    207 * Sets invalid values for width and height on the document's body style attribute.
    208 */
    209 function triggerCSSWarning(tab) {
    210  return ContentTask.spawn(tab.linkedBrowser, null, function frameScript() {
    211    content.document.body.style.width = "red";
    212    content.document.body.style.height = "blue";
    213  });
    214 }