tor-browser

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

browser_computed_custom_properties.js (11054B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 // Test that custom properties are displayed in the computed view.
      7 
      8 const TEST_URI = `
      9  <style type="text/css">
     10    @property --registered-color {
     11      syntax: '<color>';
     12      inherits: true;
     13      initial-value: rgb(0, 100, 200);
     14    }
     15 
     16    @property --registered-color-secondary {
     17      syntax: '<color>';
     18      inherits: true;
     19      initial-value: rgb(200, 100, 00);
     20    }
     21 
     22    @property --registered-length {
     23      syntax: '<length>';
     24      inherits: false;
     25      initial-value: 10px;
     26    }
     27 
     28    /* This property should not be used. It shares the same suffix than previous property
     29       names to assert our check isn't too loose */
     30    @property --registered {
     31      syntax: '<length>';
     32      inherits: false;
     33      initial-value: 10px;
     34    }
     35 
     36    body {
     37      --global-custom-property: red;
     38      /* invalid at computed value time */
     39      --registered-color-secondary: 1em;
     40    }
     41 
     42    main {
     43      --registered-color-secondary: rgb(3, 7, 11);
     44    }
     45 
     46    h1 {
     47      color: var(--global-custom-property);
     48    }
     49 
     50    #match-1 {
     51      --global-custom-property: blue;
     52      --custom-property-1: lime;
     53      /* invalid at computed value time */
     54      --registered-color-secondary: 10px;
     55    }
     56    #match-2 {
     57      --global-custom-property: gold;
     58      --custom-property-2: cyan;
     59      --custom-property-empty: ;
     60      --registered-color-secondary: rgb(13, 17, 23);
     61      outline: var(--registered-length) solid var( /* color */ --registered-color );
     62    }
     63  </style>
     64  <main>
     65    <h1 id="match-1">Hello</h1>
     66    <h1 id="match-2">World</h1>
     67  <main>
     68 `;
     69 
     70 add_task(async function () {
     71  await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
     72  const { inspector, view } = await openComputedView();
     73 
     74  await assertComputedPropertiesForNode(inspector, view, "body", [
     75    {
     76      name: "--global-custom-property",
     77      value: "red",
     78      matchedRules: [
     79        {
     80          selector: "body",
     81          value: "red",
     82          invalidAtComputedValueTime: false,
     83        },
     84      ],
     85    },
     86    {
     87      name: "--registered-color-secondary",
     88      value: "rgb(200, 100, 0)",
     89      invalidAtComputedValueTime: false,
     90      syntax: "<color>",
     91      matchedRules: [
     92        {
     93          selector: "body",
     94          value: "1em",
     95          invalidAtComputedValueTime: true,
     96        },
     97        {
     98          selector: "initial-value",
     99          value: "rgb(200, 100, 00)",
    100          invalidAtComputedValueTime: false,
    101        },
    102      ],
    103    },
    104  ]);
    105 
    106  await assertComputedPropertiesForNode(inspector, view, "main", [
    107    {
    108      name: "--global-custom-property",
    109      value: "red",
    110      matchedRules: [
    111        {
    112          selector: "body",
    113          value: "red",
    114          invalidAtComputedValueTime: false,
    115        },
    116      ],
    117    },
    118    {
    119      name: "--registered-color-secondary",
    120      value: "rgb(3, 7, 11)",
    121      syntax: "<color>",
    122      matchedRules: [
    123        {
    124          selector: "main",
    125          value: "rgb(3, 7, 11)",
    126          invalidAtComputedValueTime: false,
    127        },
    128        {
    129          selector: "body",
    130          value: "1em",
    131          invalidAtComputedValueTime: true,
    132        },
    133        {
    134          selector: "initial-value",
    135          value: "rgb(200, 100, 00)",
    136          invalidAtComputedValueTime: false,
    137        },
    138      ],
    139    },
    140  ]);
    141 
    142  await assertComputedPropertiesForNode(inspector, view, "#match-1", [
    143    {
    144      name: "color",
    145      value: "rgb(0, 0, 255)",
    146    },
    147    {
    148      name: "--custom-property-1",
    149      value: "lime",
    150    },
    151    {
    152      name: "--global-custom-property",
    153      value: "blue",
    154    },
    155    {
    156      name: "--registered-color-secondary",
    157      // value inherited from `main`, as the one set in #match-1 is invalid at comptued value time
    158      value: "rgb(3, 7, 11)",
    159      syntax: "<color>",
    160      matchedRules: [
    161        {
    162          selector: "#match-1",
    163          value: "10px",
    164          invalidAtComputedValueTime: true,
    165        },
    166        {
    167          selector: "main",
    168          value: "rgb(3, 7, 11)",
    169          invalidAtComputedValueTime: false,
    170        },
    171        {
    172          selector: "body",
    173          value: "1em",
    174          invalidAtComputedValueTime: true,
    175        },
    176        {
    177          selector: "initial-value",
    178          value: "rgb(200, 100, 00)",
    179          invalidAtComputedValueTime: false,
    180        },
    181      ],
    182    },
    183  ]);
    184 
    185  await assertComputedPropertiesForNode(inspector, view, "#match-2", [
    186    {
    187      name: "color",
    188      value: "rgb(255, 215, 0)",
    189    },
    190    {
    191      name: "outline-color",
    192      value: "rgb(0, 100, 200)",
    193    },
    194    {
    195      name: "outline-style",
    196      value: "solid",
    197    },
    198    {
    199      name: "outline-width",
    200      value: "10px",
    201    },
    202    {
    203      name: "--custom-property-2",
    204      value: "cyan",
    205    },
    206    {
    207      name: "--custom-property-empty",
    208      value: "<empty>",
    209    },
    210    {
    211      name: "--global-custom-property",
    212      value: "gold",
    213    },
    214    {
    215      name: "--registered-color",
    216      value: "rgb(0, 100, 200)",
    217      matchedRules: [
    218        {
    219          selector: "initial-value",
    220          value: "rgb(0, 100, 200)",
    221          invalidAtComputedValueTime: false,
    222        },
    223      ],
    224    },
    225    {
    226      name: "--registered-color-secondary",
    227      value: "rgb(13, 17, 23)",
    228      syntax: "<color>",
    229      matchedRules: [
    230        {
    231          selector: "#match-2",
    232          value: "rgb(13, 17, 23)",
    233          invalidAtComputedValueTime: false,
    234        },
    235        {
    236          selector: "main",
    237          value: "rgb(3, 7, 11)",
    238          invalidAtComputedValueTime: false,
    239        },
    240        {
    241          selector: "body",
    242          value: "1em",
    243          invalidAtComputedValueTime: true,
    244        },
    245        {
    246          selector: "initial-value",
    247          value: "rgb(200, 100, 00)",
    248          invalidAtComputedValueTime: false,
    249        },
    250      ],
    251    },
    252    {
    253      name: "--registered-length",
    254      value: "10px",
    255      matchedRules: [
    256        {
    257          selector: "initial-value",
    258          value: "10px",
    259          invalidAtComputedValueTime: false,
    260        },
    261      ],
    262    },
    263  ]);
    264 
    265  info(
    266    "Checking matched selectors for shorthand property defined in longhand with CSS variable"
    267  );
    268  const container = await getComputedViewMatchedRules(view, "outline-color");
    269  Assert.deepEqual(
    270    [...container.querySelectorAll("p")].map(matchEl =>
    271      [...matchEl.querySelectorAll("div")].map(el => el.textContent)
    272    ),
    273    [
    274      [
    275        "#match-2",
    276 
    277        // FIXME: At the moment, we only have an empty string value, which is the result of
    278        // `CSSStyleDeclaration.getPropertyValue`.
    279        // See Bug 2003264.
    280        "",
    281      ],
    282    ],
    283    "Got the expected matched selectors"
    284  );
    285 
    286  await assertComputedPropertiesForNode(inspector, view, "html", []);
    287 });
    288 
    289 async function assertComputedPropertiesForNode(
    290  inspector,
    291  view,
    292  selector,
    293  expected
    294 ) {
    295  const onRefreshed = inspector.once("computed-view-refreshed");
    296  await selectNode(selector, inspector);
    297  await onRefreshed;
    298 
    299  const computedItems = getComputedViewProperties(view);
    300  is(
    301    computedItems.length,
    302    expected.length,
    303    `Computed view has the expected number of items for "${selector}"`
    304  );
    305  for (let i = 0; i < computedItems.length; i++) {
    306    const expectedData = expected[i];
    307    const computedEl = computedItems[i];
    308    const nameSpan = computedEl.querySelector(".computed-property-name");
    309    const propertyName = nameSpan.firstChild.textContent;
    310    const valueSpan = computedEl.querySelector(".computed-property-value");
    311    const iacvtIcon = computedEl.querySelector(
    312      ".computed-property-value-container .invalid-at-computed-value-time-warning:not([hidden])"
    313    );
    314 
    315    is(
    316      propertyName,
    317      expectedData.name,
    318      `computed item #${i} for "${selector}" is the expected one`
    319    );
    320    is(
    321      valueSpan.textContent,
    322      expectedData.value,
    323      `computed item #${i} for "${selector}" has expected value`
    324    );
    325    if (expectedData.invalidAtComputedValueTime) {
    326      ok(
    327        !!iacvtIcon,
    328        `computed item #${i} for "${selector}" has the invalid-at-computed-value-time icon`
    329      );
    330      is(
    331        iacvtIcon.getAttribute("title"),
    332        `Property value does not match expected "${expectedData.syntax}" syntax`,
    333        `iacvt icon on computed item #${i} for "${selector}" has expected title`
    334      );
    335    } else {
    336      is(
    337        iacvtIcon,
    338        null,
    339        `computed item #${i} for "${selector}" does not have the invalid-at-computed-value-time icon`
    340      );
    341    }
    342 
    343    if (expectedData.matchedRules) {
    344      info(`Check matched rules for computed item #${i} for "${selector}"`);
    345      const matchedRulesContainerEl = await getComputedViewMatchedRules(
    346        view,
    347        propertyName
    348      );
    349      const matchedRulesEls = matchedRulesContainerEl.querySelectorAll("p");
    350      is(
    351        matchedRulesEls.length,
    352        expectedData.matchedRules.length,
    353        `computed item #${i} for "${selector}" have the expected number of matched rules`
    354      );
    355 
    356      for (let j = 0; j < matchedRulesEls.length; j++) {
    357        const expectedMatchRuleData = expectedData.matchedRules[j];
    358        const matchedRuleEl = matchedRulesEls[j];
    359        const matchedRuleSelector =
    360          matchedRuleEl.querySelector(".fix-get-selection").textContent;
    361        const matchedRuleValue = matchedRuleEl.querySelector(
    362          ".computed-other-property-value"
    363        ).textContent;
    364        const matchedRuleIacvtIcon = matchedRuleEl.querySelector(
    365          ".invalid-at-computed-value-time-warning"
    366        );
    367        is(
    368          matchedRuleSelector,
    369          expectedMatchRuleData.selector,
    370          `Got expected selector for matched rule #${j} of computed item #${i} for "${selector}"`
    371        );
    372        is(
    373          matchedRuleValue,
    374          expectedMatchRuleData.value,
    375          `Got expected value for matched rule #${j} of computed item #${i} for "${selector}"`
    376        );
    377 
    378        if (expectedMatchRuleData.invalidAtComputedValueTime) {
    379          ok(
    380            !!matchedRuleIacvtIcon,
    381            `matched rule #${j} of computed item #${i} for "${selector}" has the invalid-at-computed-value-time icon`
    382          );
    383          is(
    384            matchedRuleIacvtIcon.getAttribute("title"),
    385            `Property value does not match expected "${expectedData.syntax}" syntax`,
    386            `iacvt icon on computed item #${i} for "${expectedMatchRuleData.selector}" has expected title`
    387          );
    388        } else {
    389          is(
    390            matchedRuleIacvtIcon,
    391            null,
    392            `matched rule #${j} of computed item #${i} for "${selector}" does not have the invalid-at-computed-value-time icon`
    393          );
    394        }
    395      }
    396 
    397      // Close the match rules to avoid issues in next iteration
    398      const onMatchedRulesCollapsed = inspector.once(
    399        "computed-view-property-collapsed"
    400      );
    401      computedEl.querySelector(".computed-expandable").click();
    402      await onMatchedRulesCollapsed;
    403    }
    404  }
    405 }