tor-browser

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

browser_changes_nested_rules.js (5090B)


      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 the Changes panel works with nested rules.
      7 
      8 // Declare rule individually so we can use them for the assertions as well
      9 // In the end, we should have nested rule looking like:
     10 // - @media screen and (height > 5px) {
     11 // -- @layer myLayer {
     12 // --- @container myContainer (width > 10px) {
     13 // ----- div {
     14 // ------- & > span { … }
     15 // ------- & .mySpan {
     16 // --------- &:not(:focus) {
     17 
     18 const spanNotFocusedRule = `&:not(:focus) {
     19  text-decoration: underline;
     20 }`;
     21 
     22 const spanClassRule = `.mySpan {
     23  font-weight: bold;
     24  ${spanNotFocusedRule}
     25 }`;
     26 
     27 const spanRule = `& > span {
     28  outline: 1px solid gold;
     29 }`;
     30 
     31 const divRule = `div {
     32  color: tomato;
     33  ${spanRule}
     34  ${spanClassRule}
     35 }`;
     36 
     37 const containerRule = `@container myContainer (width > 10px) {
     38  /* in container */
     39  ${divRule}
     40 }`;
     41 const layerRule = `@layer myLayer {
     42  /* in layer */
     43  ${containerRule}
     44 }`;
     45 const mediaRule = `@media screen and (height > 5px) {
     46  /* in media */
     47    ${layerRule}
     48 }`;
     49 
     50 const TEST_URI = `
     51  <style>
     52  body {
     53    container: myContainer / inline-size
     54  }
     55  ${mediaRule}
     56  </style>
     57  <div>hello <span class="mySpan">world</span></div>
     58 `;
     59 
     60 const applyModificationAfterDivPropertyChange = ruleText =>
     61  ruleText.replace("tomato", "cyan");
     62 
     63 const EXPECTED_AFTER_DIV_PROP_CHANGE = [
     64  {
     65    text: "@media screen and (height > 5px) {",
     66    copyRuleClipboard: applyModificationAfterDivPropertyChange(mediaRule),
     67  },
     68  {
     69    text: "@layer myLayer {",
     70    copyRuleClipboard: applyModificationAfterDivPropertyChange(layerRule),
     71  },
     72  {
     73    text: "@container myContainer (width > 10px) {",
     74    copyRuleClipboard: applyModificationAfterDivPropertyChange(containerRule),
     75  },
     76  {
     77    text: "div {",
     78    copyRuleClipboard: applyModificationAfterDivPropertyChange(divRule),
     79  },
     80 ];
     81 
     82 const applyModificationAfterSpanPropertiesChange = ruleText =>
     83  ruleText
     84    .replace("1px solid gold", "4px solid gold")
     85    .replace("bold", "bolder")
     86    .replace("underline", "underline dotted");
     87 
     88 const EXPECTED_AFTER_SPAN_PROP_CHANGES = EXPECTED_AFTER_DIV_PROP_CHANGE.map(
     89  expected => ({
     90    ...expected,
     91    copyRuleClipboard: applyModificationAfterSpanPropertiesChange(
     92      expected.copyRuleClipboard
     93    ),
     94  })
     95 ).concat([
     96  {
     97    text: "& .mySpan {",
     98    copyRuleClipboard:
     99      applyModificationAfterSpanPropertiesChange(spanClassRule),
    100  },
    101  {
    102    text: "&:not(:focus) {",
    103    copyRuleClipboard:
    104      applyModificationAfterSpanPropertiesChange(spanNotFocusedRule),
    105  },
    106  {
    107    text: "& > span {",
    108    copyRuleClipboard: applyModificationAfterSpanPropertiesChange(spanRule),
    109  },
    110 ]);
    111 
    112 add_task(async function () {
    113  await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
    114  const { inspector, view: ruleView } = await openRuleView();
    115  const changesView = selectChangesView(inspector);
    116  const { document: panelDoc, store } = changesView;
    117  const panel = panelDoc.querySelector("#sidebar-panel-changes");
    118 
    119  await selectNode("div", inspector);
    120  let onTrackChange = waitForDispatch(store, "TRACK_CHANGE");
    121  await updateDeclaration(ruleView, 1, { color: "tomato" }, { color: "cyan" });
    122  await onTrackChange;
    123 
    124  await assertSelectors(panel, EXPECTED_AFTER_DIV_PROP_CHANGE);
    125 
    126  await selectNode(".mySpan", inspector);
    127  onTrackChange = waitForDispatch(store, "TRACK_CHANGE");
    128  await updateDeclaration(
    129    ruleView,
    130    1,
    131    { "text-decoration": "underline" },
    132    { "text-decoration": "underline dotted" }
    133  );
    134  await onTrackChange;
    135 
    136  onTrackChange = waitForDispatch(store, "TRACK_CHANGE");
    137  await updateDeclaration(
    138    ruleView,
    139    2,
    140    { "font-weight": "bold" },
    141    { "font-weight": "bolder" }
    142  );
    143  await onTrackChange;
    144 
    145  onTrackChange = waitForDispatch(store, "TRACK_CHANGE");
    146  await updateDeclaration(
    147    ruleView,
    148    3,
    149    { outline: "1px solid gold" },
    150    { outline: "4px solid gold" }
    151  );
    152  await onTrackChange;
    153 
    154  await assertSelectors(panel, EXPECTED_AFTER_SPAN_PROP_CHANGES);
    155 });
    156 
    157 async function assertSelectors(panel, expected) {
    158  await waitFor(
    159    () => getSelectors(panel).length === expected.length,
    160    "Wait for the expected number of selectors item"
    161  );
    162 
    163  const selectorsEl = getSelectors(panel);
    164  is(
    165    selectorsEl.length,
    166    expected.length,
    167    "Got the expected number of selectors item"
    168  );
    169 
    170  for (let i = 0; i < expected.length; i++) {
    171    const selectorEl = selectorsEl[i];
    172    const expectedItem = expected[i];
    173 
    174    is(
    175      selectorEl.innerText,
    176      expectedItem.text,
    177      `Got expected selector text at index ${i}`
    178    );
    179    info(`Click the Copy Rule button for the "${expectedItem.text}" rule`);
    180    const button = selectorEl
    181      .closest(".changes__rule")
    182      .querySelector(".changes__copy-rule-button");
    183    await waitForClipboardPromise(
    184      () => button.click(),
    185      () => checkClipboardData(expectedItem.copyRuleClipboard)
    186    );
    187  }
    188 }
    189 
    190 function checkClipboardData(expected) {
    191  const actual = SpecialPowers.getClipboardData("text/plain");
    192  return actual.trim() === expected.trim();
    193 }