tor-browser

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

focus-fixup-rule-one-no-dialogs.html (3778B)


      1 <!DOCTYPE html>
      2 <meta charset="utf-8">
      3 <title>Focus fixup rule one (no &lt;dialog>s involved)</title>
      4 <link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
      5 <link rel="help" href="https://html.spec.whatwg.org/multipage/interaction.html#focus-fixup-rule">
      6 <link rel="help" href="https://html.spec.whatwg.org/multipage/forms.html#attr-fieldset-disabled">
      7 <script src="/resources/testharness.js"></script>
      8 <script src="/resources/testharnessreport.js"></script>
      9 
     10 <div>
     11  <button id="button1">Button 1</button>
     12  <button id="button2">Button 2</button>
     13  <button id="button3">Button 3</button>
     14  <fieldset id="fieldset1"><button id="button4">Button 4</button></fieldset>
     15  <fieldset id="fieldset2" disabled><legend><button id="button5">Button 5</button></legend></fieldset>
     16  <div id="div" tabindex="0">Div</div>
     17  <div id="editable" contenteditable=true>editor</div>
     18  <button id="button6">Button 6</button>
     19 </div>
     20 
     21 <script>
     22 "use strict";
     23 
     24 function test_focus_fixup(selector, change, expectSync = false) {
     25  promise_test(async function(t) {
     26    // Make sure we're not running from a ResizeObserver / etc notification.
     27    await new Promise(r => t.step_timeout(r, 0));
     28 
     29    const el = document.querySelector(selector);
     30    el.focus();
     31 
     32    assert_equals(document.activeElement, el, `Sanity check: ${selector} must start focused`);
     33 
     34    change(el);
     35 
     36    {
     37      const fn = expectSync ? assert_not_equals : assert_equals;
     38      fn(document.activeElement, el, `active element ${expectSync ? "is" : "isn't"} fixed-up sync`);
     39    }
     40 
     41    // We don't expect blur events in the sync case per spec yet, at least.
     42    if (!expectSync) {
     43      // Fixup should run after animation frame callbacks, right before the end of
     44      // "update the rendering", so after resize observations.
     45      let ranFirstRaf = false;
     46      let ranRO = false;
     47 
     48      let resolveDone;
     49      let done = new Promise(r => { resolveDone = r; });
     50 
     51      requestAnimationFrame(t.step_func(() => {
     52        ranFirstRaf = true;
     53        assert_equals(document.activeElement, el, "activeElement shouldn't have changed yet (rAF)");
     54        requestAnimationFrame(t.step_func(() => {
     55          assert_true(ranRO, "ResizeObserver should've ran on the previous frame");
     56          resolveDone();
     57        }));
     58      }));
     59 
     60      let ro = new ResizeObserver(t.step_func(() => {
     61        assert_true(ranFirstRaf, "requestAnimationFrame should run before ResizeObserver");
     62        ranRO = true;
     63        assert_equals(document.activeElement, el, "activeElement shouldn't have changed yet (ResizeObserver)");
     64      }));
     65 
     66      // TODO: Test IntersectionObserver timing. It's a bit trickier because it
     67      // uses its own task source and so on.
     68      ro.observe(document.documentElement);
     69 
     70      await done;
     71 
     72      ro.disconnect();
     73    }
     74 
     75    assert_not_equals(document.activeElement, el, "focus is fixed up");
     76    assert_equals(document.activeElement, document.body, "Body is focused");
     77  }, selector);
     78 }
     79 
     80 test_focus_fixup("#button1", function(button) {
     81  button.disabled = true;
     82 });
     83 
     84 test_focus_fixup("#button2", function(button) {
     85  button.hidden = true;
     86 });
     87 
     88 test_focus_fixup("#button3", function(button) {
     89  button.remove();
     90 }, /* expectSync = */ true);
     91 
     92 test_focus_fixup("#button4", function(button) {
     93  document.querySelector("#fieldset1").disabled = true;
     94 });
     95 
     96 test_focus_fixup("#button5", function(button) {
     97  const fieldset = document.querySelector("#fieldset2");
     98  fieldset.insertBefore(document.createElement("legend"), fieldset.firstChild);
     99 });
    100 
    101 test_focus_fixup("#div", function(div) {
    102  div.removeAttribute("tabindex");
    103 });
    104 
    105 test_focus_fixup("#editable", function(div) {
    106  div.contentEditable = false;
    107 });
    108 
    109 test_focus_fixup("#button6", function(button) {
    110  button.style.visibility = "hidden";
    111 });
    112 </script>