tor-browser

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

browser_resources_css_registered_properties.js (10632B)


      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_REGISTERED_PROPERTIES.
      7 
      8 const ResourceCommand = require("resource://devtools/shared/commands/resource/resource-command.js");
      9 
     10 const IFRAME_URL = `https://example.org/document-builder.sjs?html=${encodeURIComponent(`
     11  <style>
     12    @property --css-a {
     13      syntax: "<color>";
     14      inherits: true;
     15      initial-value: gold;
     16    }
     17  </style>
     18  <script>
     19    CSS.registerProperty({
     20      name: "--js-a",
     21      syntax: "<length>",
     22      inherits: true,
     23      initialValue: "20px"
     24    });
     25  </script>
     26  <h1>iframe</h1>
     27 `)}`;
     28 
     29 const TEST_URL = `https://example.org/document-builder.sjs?html=
     30  <head>
     31    <style>
     32      @property --css-a {
     33        syntax: "*";
     34        inherits: false;
     35      }
     36 
     37      @property --css-b {
     38        syntax: "<color>";
     39        inherits: true;
     40        initial-value: tomato;
     41      }
     42    </style>
     43    <script>
     44      CSS.registerProperty({
     45        name: "--js-a",
     46        syntax: "*",
     47        inherits: false,
     48      });
     49      CSS.registerProperty({
     50        name: "--js-b",
     51        syntax: "<length>",
     52        inherits: true,
     53        initialValue: "10px"
     54      });
     55    </script>
     56  </head>
     57  <h1>CSS_REGISTERED_PROPERTIES</h1>
     58  <iframe src="${encodeURIComponent(IFRAME_URL)}"></iframe>`;
     59 
     60 add_task(async function () {
     61  await pushPref("layout.css.properties-and-values.enabled", true);
     62  const tab = await addTab(TEST_URL);
     63 
     64  const { client, resourceCommand, targetCommand } =
     65    await initResourceCommand(tab);
     66 
     67  // Wait for targets
     68  await targetCommand.startListening();
     69  const targets = [];
     70  const onAvailable = ({ targetFront }) => targets.push(targetFront);
     71  await targetCommand.watchTargets({
     72    types: [targetCommand.TYPES.FRAME],
     73    onAvailable,
     74  });
     75  await waitFor(() => targets.length === 2);
     76  const [topLevelTarget, iframeTarget] = targets.sort((a, _) =>
     77    a.isTopLevel ? -1 : 1
     78  );
     79 
     80  // Watching for new stylesheets shouldn't be
     81  const stylesheets = [];
     82  await resourceCommand.watchResources([resourceCommand.TYPES.STYLESHEET], {
     83    onAvailable: resources => stylesheets.push(...resources),
     84    ignoreExistingResources: true,
     85  });
     86 
     87  info("Check that we get existing registered properties");
     88  const availableResources = [];
     89  const updatedResources = [];
     90  const destroyedResources = [];
     91  await resourceCommand.watchResources(
     92    [resourceCommand.TYPES.CSS_REGISTERED_PROPERTIES],
     93    {
     94      onAvailable: resources => availableResources.push(...resources),
     95      onUpdated: resources => updatedResources.push(...resources),
     96      onDestroyed: resources => destroyedResources.push(...resources),
     97    }
     98  );
     99 
    100  is(
    101    availableResources.length,
    102    6,
    103    "The 6 existing registered properties where retrieved"
    104  );
    105 
    106  // Sort resources so we get them alphabetically ordered by their name, with the ones for
    107  // the top level target displayed first.
    108  availableResources.sort((a, b) => {
    109    if (a.targetFront !== b.targetFront) {
    110      return a.targetFront.isTopLevel ? -1 : 1;
    111    }
    112    return a.name < b.name ? -1 : 1;
    113  });
    114 
    115  assertResource(availableResources[0], {
    116    name: "--css-a",
    117    syntax: "*",
    118    inherits: false,
    119    initialValue: null,
    120    fromJS: false,
    121    targetFront: topLevelTarget,
    122  });
    123  assertResource(availableResources[1], {
    124    name: "--css-b",
    125    syntax: "<color>",
    126    inherits: true,
    127    initialValue: "tomato",
    128    fromJS: false,
    129    targetFront: topLevelTarget,
    130  });
    131  assertResource(availableResources[2], {
    132    name: "--js-a",
    133    syntax: "*",
    134    inherits: false,
    135    initialValue: null,
    136    fromJS: true,
    137    targetFront: topLevelTarget,
    138  });
    139  assertResource(availableResources[3], {
    140    name: "--js-b",
    141    syntax: "<length>",
    142    inherits: true,
    143    initialValue: "10px",
    144    fromJS: true,
    145    targetFront: topLevelTarget,
    146  });
    147  assertResource(availableResources[4], {
    148    name: "--css-a",
    149    syntax: "<color>",
    150    inherits: true,
    151    initialValue: "gold",
    152    fromJS: false,
    153    targetFront: iframeTarget,
    154  });
    155  assertResource(availableResources[5], {
    156    name: "--js-a",
    157    syntax: "<length>",
    158    inherits: true,
    159    initialValue: "20px",
    160    fromJS: true,
    161    targetFront: iframeTarget,
    162  });
    163 
    164  info("Check that we didn't get notified about existing stylesheets");
    165  // wait a bit so we'd have the time to be notified about stylesheet resources
    166  await wait(500);
    167  is(
    168    stylesheets.length,
    169    0,
    170    "Watching for registered properties does not notify about existing stylesheets resources"
    171  );
    172 
    173  info("Check that we get properties from new stylesheets");
    174  await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
    175    const s = content.document.createElement("style");
    176    s.textContent = `
    177        @property --css-c {
    178          syntax: "<custom-ident>";
    179          inherits: true;
    180          initial-value: custom;
    181        }
    182 
    183        @property --css-d {
    184          syntax: "big | bigger";
    185          inherits: true;
    186          initial-value: big;
    187        }
    188    `;
    189    content.document.head.append(s);
    190  });
    191 
    192  info("Wait for registered properties to be available");
    193  await waitFor(() => availableResources.length === 8);
    194  ok(true, "Got notified about 2 new registered properties");
    195  assertResource(availableResources[6], {
    196    name: "--css-c",
    197    syntax: "<custom-ident>",
    198    inherits: true,
    199    initialValue: "custom",
    200    fromJS: false,
    201    targetFront: topLevelTarget,
    202  });
    203  assertResource(availableResources[7], {
    204    name: "--css-d",
    205    syntax: "big | bigger",
    206    inherits: true,
    207    initialValue: "big",
    208    fromJS: false,
    209    targetFront: topLevelTarget,
    210  });
    211 
    212  info("Wait to be notified about the new stylesheet");
    213  await waitFor(() => stylesheets.length === 1);
    214  ok(true, "we do get notified about stylesheets");
    215 
    216  info(
    217    "Check that we get notified about properties registered via CSS.registerProperty"
    218  );
    219  await SpecialPowers.spawn(tab.linkedBrowser, [], () => {
    220    content.CSS.registerProperty({
    221      name: "--js-c",
    222      syntax: "*",
    223      inherits: false,
    224      initialValue: 42,
    225    });
    226    content.CSS.registerProperty({
    227      name: "--js-d",
    228      syntax: "<color>#",
    229      inherits: true,
    230      initialValue: "blue,cyan",
    231    });
    232  });
    233 
    234  await waitFor(() => availableResources.length === 10);
    235  ok(true, "Got notified about 2 new registered properties");
    236  assertResource(availableResources[8], {
    237    name: "--js-c",
    238    syntax: "*",
    239    inherits: false,
    240    initialValue: "42",
    241    fromJS: true,
    242    targetFront: topLevelTarget,
    243  });
    244  assertResource(availableResources[9], {
    245    name: "--js-d",
    246    syntax: "<color>#",
    247    inherits: true,
    248    initialValue: "blue,cyan",
    249    fromJS: true,
    250    targetFront: topLevelTarget,
    251  });
    252 
    253  info(
    254    "Check that we get notified about properties registered via CSS.registerProperty in iframe"
    255  );
    256  const iframeBrowsingContext = await SpecialPowers.spawn(
    257    tab.linkedBrowser,
    258    [],
    259    () => content.document.querySelector("iframe").browsingContext
    260  );
    261 
    262  await SpecialPowers.spawn(iframeBrowsingContext, [], () => {
    263    content.CSS.registerProperty({
    264      name: "--js-iframe",
    265      syntax: "<color>#",
    266      inherits: true,
    267      initialValue: "red,salmon",
    268    });
    269  });
    270 
    271  await waitFor(() => availableResources.length === 11);
    272  ok(true, "Got notified about 2 new registered properties");
    273  assertResource(availableResources[10], {
    274    name: "--js-iframe",
    275    syntax: "<color>#",
    276    inherits: true,
    277    initialValue: "red,salmon",
    278    fromJS: true,
    279    targetFront: iframeTarget,
    280  });
    281 
    282  info(
    283    "Check that we get notified about destroyed properties when removing stylesheet"
    284  );
    285  // sanity check
    286  is(destroyedResources.length, 0, "No destroyed resources yet");
    287  await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
    288    content.document.querySelector("style").remove();
    289  });
    290  await waitFor(() => destroyedResources.length == 2);
    291  ok(true, "We got notified about destroyed resources");
    292  destroyedResources.sort((a, b) => a < b);
    293  is(
    294    destroyedResources[0].resourceType,
    295    ResourceCommand.TYPES.CSS_REGISTERED_PROPERTIES,
    296    "resource type is correct"
    297  );
    298  is(
    299    destroyedResources[0].resourceId,
    300    `${topLevelTarget.actorID}:css-registered-property:--css-a`,
    301    "expected css property was destroyed"
    302  );
    303  is(
    304    destroyedResources[1].resourceType,
    305    ResourceCommand.TYPES.CSS_REGISTERED_PROPERTIES,
    306    "resource type is correct"
    307  );
    308  is(
    309    destroyedResources[1].resourceId,
    310    `${topLevelTarget.actorID}:css-registered-property:--css-b`,
    311    "expected css property was destroyed"
    312  );
    313 
    314  info(
    315    "Check that we get notified about updated properties when modifying stylesheet"
    316  );
    317  is(updatedResources.length, 0, "No updated resources yet");
    318  await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
    319    content.document.querySelector("style").textContent = `
    320     /* not updated */
    321      @property --css-c {
    322        syntax: "<custom-ident>";
    323        inherits: true;
    324        initial-value: custom;
    325      }
    326 
    327      @property --css-d {
    328        syntax: "big | bigger";
    329        inherits: true;
    330        /* only change initial value (was big) */
    331        initial-value: bigger;
    332      }
    333 
    334      /* add a new property */
    335      @property --css-e {
    336        syntax: "<color>";
    337        inherits: false;
    338        initial-value: green;
    339      }
    340    `;
    341  });
    342  await waitFor(() => updatedResources.length === 1);
    343  ok(true, "One property was updated");
    344  assertResource(updatedResources[0].resource, {
    345    name: "--css-d",
    346    syntax: "big | bigger",
    347    inherits: true,
    348    initialValue: "bigger",
    349    fromJS: false,
    350    targetFront: topLevelTarget,
    351  });
    352 
    353  await waitFor(() => availableResources.length === 12);
    354  ok(true, "We got notified about the new property");
    355  assertResource(availableResources.at(-1), {
    356    name: "--css-e",
    357    syntax: "<color>",
    358    inherits: false,
    359    initialValue: "green",
    360    fromJS: false,
    361    targetFront: topLevelTarget,
    362  });
    363 
    364  await client.close();
    365 });
    366 
    367 async function assertResource(resource, expected) {
    368  is(
    369    resource.resourceType,
    370    ResourceCommand.TYPES.CSS_REGISTERED_PROPERTIES,
    371    "Resource type is correct"
    372  );
    373  is(resource.name, expected.name, "name is correct");
    374  is(resource.syntax, expected.syntax, "syntax is correct");
    375  is(resource.inherits, expected.inherits, "inherits is correct");
    376  is(resource.initialValue, expected.initialValue, "initialValue is correct");
    377  is(resource.fromJS, expected.fromJS, "fromJS is correct");
    378  is(
    379    resource.targetFront,
    380    expected.targetFront,
    381    "resource is associated with expected target"
    382  );
    383 }