tor-browser

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

test_getMatchingCSSRules.html (7255B)


      1 <!DOCTYPE HTML>
      2 <html>
      3 <head>
      4  <title>Test for bug 1359217</title>
      5  <script src="/tests/SimpleTest/SimpleTest.js"></script>
      6  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
      7 </head>
      8 <body>
      9 <iframe id="test"></iframe>
     10 <pre id="log">
     11 <script>
     12 /**
     13 * This test checks that getMatchingCSSRules returns correct style set in
     14 * various cases. To avoid effects from UA sheets, most of the tests use
     15 * an element with "unknowntagname".
     16 */
     17 
     18 const InspectorUtils = SpecialPowers.InspectorUtils;
     19 
     20 let iframe = document.getElementById("test");
     21 
     22 SimpleTest.waitForExplicitFinish();
     23 
     24 function getStyleRules(elem) {
     25  return InspectorUtils.getMatchingCSSRules(elem);
     26 }
     27 
     28 function getDeclarationWithOrigin(target, origin) {
     29  for (let rule of getStyleRules(target)) {
     30    if (rule.declarationOrigin == origin) {
     31      return rule;
     32    }
     33  }
     34  return null;
     35 }
     36 
     37 function checkDeclaration(doc, selector, origin, props) {
     38  info(`Checking ${origin} declarations for element "${selector}"`);
     39  ok(!!props, "Should pass some properties to check");
     40 
     41  const target = doc.querySelector(selector);
     42  let decl = getDeclarationWithOrigin(target, origin);
     43  ok(!!decl, `Should find a ${origin} declaration for "${selector}"`);
     44 
     45  const propsEntries = Object.entries(props);
     46  is(decl.style.length, propsEntries.length, `Got expected number of ${origin} declarations for "${selector}"`);
     47  for (let i = 0; i < decl.style.length; i++) {
     48    const [name, value] = propsEntries[i] || [];
     49    is(decl.style[i], name, `Should see "${name}" property on ${origin} declaration for "${selector}"`);
     50    is(decl.style[name], value, `"${name}" has expected "${value}" value on ${origin} declaration for "${selector}"`);
     51  }
     52  let modificationThrew = false;
     53  try {
     54    presHintDecl.style.width = "0px";
     55  } catch (e) {
     56    modificationThrew = true;
     57  }
     58  ok(modificationThrew, "Should not be mutable");
     59 }
     60 
     61 // This will check that value of z-index property declarations in the
     62 // rules from getMatchingCSSRules matches the given content.
     63 function checkRules(doc, rulesContent, queryStr = "unknowntagname") {
     64  let elem = doc.querySelector(queryStr);
     65  let rules = getStyleRules(elem);
     66  is(rules.length, rulesContent.length, "Rule length should match");
     67  if (rules.length != rulesContent.length) {
     68    return;
     69  }
     70  for (let i = 0; i < rules.length; i++) {
     71    let style = rules[i].style;
     72    let expectation = rulesContent[i].toString();
     73    is(style.length, 1, "Should contain only one declaration");
     74    is(style.zIndex, expectation, "Should match expectation");
     75  }
     76 }
     77 
     78 const tests = [
     79  {
     80    title: "Add new stylesheet",
     81    async run(doc) {
     82      checkRules(doc, [1]);
     83      let link = doc.createElement("link");
     84      link.rel = "stylesheet";
     85      link.href = "getMatchingCSSRules-2.css";
     86      let load = new Promise(resolve => { link.onload = resolve; });
     87      doc.head.appendChild(link);
     88      await load;
     89      checkRules(doc, [1, 2]);
     90    },
     91  },
     92  {
     93    title: "Remove stylesheet",
     94    async run(doc) {
     95      checkRules(doc, [1]);
     96      doc.querySelector("link").remove();
     97      checkRules(doc, []);
     98    },
     99  },
    100  {
    101    title: "Enable stylesheet",
    102    async run(doc) {
    103      // Set disabled flag before we invoke the utils.
    104      let link = doc.querySelector("link");
    105      link.sheet.disabled = true;
    106      checkRules(doc, []);
    107      link.sheet.disabled = false;
    108      checkRules(doc, [1]);
    109    },
    110  },
    111  {
    112    title: "Disable stylesheet",
    113    async run(doc) {
    114      checkRules(doc, [1]);
    115      doc.querySelector("link").sheet.disabled = true;
    116      checkRules(doc, []);
    117    },
    118  },
    119  {
    120    title: "Change stylesheet set",
    121    base: "alternate",
    122    async run(doc) {
    123      checkRules(doc, []);
    124      doc.selectedStyleSheetSet = "x";
    125      checkRules(doc, [1]);
    126      doc.selectedStyleSheetSet = "";
    127      checkRules(doc, []);
    128    },
    129  },
    130  {
    131    title: "Add and remove rules",
    132    async run(doc) {
    133      checkRules(doc, [1]);
    134 
    135      let sheet = doc.querySelector("link").sheet;
    136      info("Inserting style rule");
    137      sheet.insertRule("unknowntagname { z-index: 3; }", 1);
    138      checkRules(doc, [1, 3]);
    139 
    140      info("Removing style rule");
    141      sheet.deleteRule(0);
    142      checkRules(doc, [3]);
    143 
    144      info("Inserting media rule");
    145      sheet.insertRule("@media all { unknowntagname { z-index: 4; } }", 1);
    146      checkRules(doc, [3, 4]);
    147 
    148      info("Inserting supports rule");
    149      sheet.insertRule(
    150        "@supports (z-index: 0) { unknowntagname { z-index: 5; } }", 1);
    151      checkRules(doc, [3, 5, 4]);
    152 
    153      info("Inserting import rule");
    154      sheet.insertRule("@import url(getMatchingCSSRules-2.css);", 0);
    155      // There is no notification we can get when the associated style
    156      // sheet gets loaded, so we have to query it.
    157      while (true) {
    158        try {
    159          sheet.cssRules[0].styleSheet.cssRules;
    160          break;
    161        } catch (e) {
    162          if (e.name == "InvalidAccessError") {
    163            await new Promise(resolve => requestAnimationFrame(resolve));
    164          } else {
    165            throw e;
    166          }
    167        }
    168      }
    169      checkRules(doc, [2, 3, 5, 4]);
    170 
    171      info("Removing supports rule");
    172      sheet.deleteRule(2);
    173      checkRules(doc, [2, 3, 4]);
    174 
    175      info("Removing media rule");
    176      sheet.deleteRule(2);
    177      checkRules(doc, [2, 3]);
    178 
    179      info("Removing import rule");
    180      sheet.deleteRule(0);
    181      checkRules(doc, [3]);
    182    },
    183  },
    184  {
    185    title: "Check UA sheets",
    186    async run(doc) {
    187      doc.querySelector("link").remove();
    188      checkRules(doc, []);
    189      let elem = doc.querySelector("unknowntagname");
    190      elem.setAttribute("dir", "");
    191      let seenUnicodeBidi = false;
    192      for (let rule of getStyleRules(elem)) {
    193        if (rule.style.unicodeBidi == "isolate") {
    194          seenUnicodeBidi = true;
    195          break;
    196        }
    197      }
    198      ok(seenUnicodeBidi, "Should have unicode-bidi " +
    199         "declaration from UA stylesheet html.css");
    200    },
    201  },
    202  {
    203    title: "Check adopted sheets",
    204    async run(doc, win) {
    205      checkRules(doc, [1]);
    206      let sheet = new win.CSSStyleSheet();
    207      sheet.replaceSync(`unknowntagname { z-index: 5 }`);
    208      doc.adoptedStyleSheets.push(sheet);
    209      checkRules(doc, [1, 5]);
    210    },
    211  },
    212  {
    213    title: "Check pres hints",
    214    async run(doc, win) {
    215      checkDeclaration(doc, "img", "pres-hints", { width: "10px", height: "15px", "aspect-ratio": "auto 10 / 15" });
    216      checkDeclaration(doc, "table", "pres-hints", {color: "-moz-inherit-from-body-quirk"});
    217      checkDeclaration(doc, ".anim", "animations", {"z-index": "1"});
    218      checkDeclaration(doc, "[style]", "style-attribute", {"z-index": "1"});
    219      // TODO: transitions/SMIL are a bit more annoying to test.
    220    },
    221  }
    222 ];
    223 
    224 add_task(async function runTests() {
    225  for (let i = 0; i < tests.length; i++) {
    226    let test = tests[i];
    227    info(`Test ${i}: ${test.title}`);
    228    iframe.src = "about:blank";
    229    if (!test.base) {
    230      test.base = "default";
    231    }
    232    iframe.src = `file_getMatchingCSSRules-${test.base}.html`;
    233    await new Promise(resolve => { iframe.onload = resolve; });
    234    try {
    235      await test.run(iframe.contentDocument, iframe.contentWindow);
    236    } catch (e) {
    237      ok(false, "JavaScript error: " + e);
    238    }
    239  }
    240 });
    241 </script>
    242 </pre>
    243 </body>
    244 </html>