tor-browser

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

on-dialog-behavior.html (24985B)


      1 <!doctype html>
      2 <meta charset="utf-8" />
      3 <meta name="author" title="Keith Cirkel" href="mailto:wpt@keithcirkel.co.uk" />
      4 <meta name="timeout" content="long">
      5 <link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
      6 <script src="/resources/testharness.js"></script>
      7 <script src="/resources/testharnessreport.js"></script>
      8 <script src="resources/invoker-utils.js"></script>
      9 
     10 <dialog id="invokee">
     11  <button id="containedinvoker" commandfor="invokee" command="close"></button>
     12 </dialog>
     13 <button id="invokerbutton" commandfor="invokee" command="show-modal"></button>
     14 
     15 <script>
     16  function resetState() {
     17    invokee.close();
     18    try { invokee.hidePopover(); } catch {}
     19    invokee.removeAttribute("popover");
     20    invokee.returnValue = '';
     21    invokerbutton.setAttribute("command", "show-modal");
     22    containedinvoker.setAttribute("command", "close");
     23    containedinvoker.removeAttribute("value");
     24  }
     25 
     26  // opening a dialog
     27 
     28  ["show-modal", /* test case sensitivity */ "sHoW-mOdAl"].forEach(
     29    (command) => {
     30      ["property", "attribute"].forEach((setType) => {
     31        test(
     32          function (t) {
     33            t.add_cleanup(resetState);
     34            assert_false(invokee.open, "invokee.open");
     35            assert_false(invokee.matches(":modal"), "invokee :modal");
     36            if (setType === "property") {
     37              invokerbutton.command = command;
     38            } else {
     39              invokerbutton.setAttribute("command", command);
     40            }
     41            invokerbutton.click();
     42            assert_true(invokee.open, "invokee.open");
     43            assert_true(invokee.matches(":modal"), "invokee :modal");
     44          },
     45          `invoking (with command ${setType} as ${command}) closed dialog opens as modal`,
     46        );
     47 
     48        test(
     49          function (t) {
     50            t.add_cleanup(resetState);
     51            assert_false(invokee.open, "invokee.open");
     52            assert_false(invokee.matches(":modal"), "invokee :modal");
     53            invokee.addEventListener("command", (e) => e.preventDefault(), {
     54              once: true,
     55            });
     56            if (setType === "property") {
     57              invokerbutton.command = command;
     58            } else {
     59              invokerbutton.setAttribute("command", command);
     60            }
     61            invokerbutton.click();
     62            assert_false(invokee.open, "invokee.open");
     63            assert_false(invokee.matches(":modal"), "invokee :modal");
     64          },
     65          `invoking (with command ${setType} as ${command}) closed dialog with preventDefault is noop`,
     66        );
     67 
     68        test(
     69          function (t) {
     70            t.add_cleanup(resetState);
     71            assert_false(invokee.open, "invokee.open");
     72            assert_false(invokee.matches(":modal"), "invokee :modal");
     73            invokee.addEventListener(
     74              "command",
     75              (e) => {
     76                invokerbutton.setAttribute("command", "close");
     77              },
     78              { once: true },
     79            );
     80            if (setType === "property") {
     81              invokerbutton.command = command;
     82            } else {
     83              invokerbutton.setAttribute("command", command);
     84            }
     85            invokerbutton.click();
     86            assert_true(invokee.open, "invokee.open");
     87            assert_true(invokee.matches(":modal"), "invokee :modal");
     88          },
     89          `invoking (with command ${setType} as ${command}) while changing command still opens as modal`,
     90        );
     91      });
     92    },
     93  );
     94 
     95  // closing an already open dialog
     96 
     97  ["close", /* test case sensitivity */ "cLoSe"].forEach((command) => {
     98    ["property", "attribute"].forEach((setType) => {
     99      test(
    100        function (t) {
    101          t.add_cleanup(resetState);
    102          invokee.show();
    103          assert_true(invokee.open, "invokee.open");
    104          assert_false(invokee.matches(":modal"), "invokee :modal");
    105          if (setType === "property") {
    106            containedinvoker.command = command;
    107          } else {
    108            containedinvoker.setAttribute("command", command);
    109          }
    110          containedinvoker.click();
    111          assert_equals(invokee.returnValue, "");
    112          assert_false(invokee.open, "invokee.open");
    113          assert_false(invokee.matches(":modal"), "invokee :modal");
    114        },
    115        `invoking to close (with command ${setType} as ${command}) open dialog closes`,
    116      );
    117 
    118      test(
    119        function (t) {
    120          t.add_cleanup(resetState);
    121          invokee.show();
    122          assert_true(invokee.open, "invokee.open");
    123          assert_false(invokee.matches(":modal"), "invokee :modal");
    124          if (setType === "property") {
    125            containedinvoker.command = command;
    126          } else {
    127            containedinvoker.setAttribute("command", command);
    128          }
    129          containedinvoker.setAttribute("value", "foo");
    130          containedinvoker.click();
    131          assert_equals(invokee.returnValue, "foo");
    132          assert_false(invokee.open, "invokee.open");
    133          assert_false(invokee.matches(":modal"), "invokee :modal");
    134        },
    135        `invoking to close (with command ${setType} as ${command}) open dialog closes and sets returnValue`,
    136      );
    137 
    138      test(
    139        function (t) {
    140          t.add_cleanup(resetState);
    141          invokee.show();
    142          assert_true(invokee.open, "invokee.open");
    143          assert_false(invokee.matches(":modal"), "invokee :modal");
    144          if (setType === "property") {
    145            containedinvoker.command = command;
    146          } else {
    147            containedinvoker.setAttribute("command", command);
    148          }
    149          invokee.returnValue = "test";
    150          containedinvoker.setAttribute("value", "foo");
    151          containedinvoker.click();
    152          assert_equals(invokee.returnValue, "foo");
    153          assert_false(invokee.open, "invokee.open");
    154          assert_false(invokee.matches(":modal"), "invokee :modal");
    155        },
    156        `invoking to close (with command ${setType} as ${command}) open dialog closes and overrides returnValue`,
    157      );
    158 
    159      test(
    160        function (t) {
    161          t.add_cleanup(resetState);
    162          invokee.show();
    163          assert_true(invokee.open, "invokee.open");
    164          assert_false(invokee.matches(":modal"), "invokee :modal");
    165          if (setType === "property") {
    166            containedinvoker.command = command;
    167          } else {
    168            containedinvoker.setAttribute("command", command);
    169          }
    170          invokee.returnValue = "test";
    171          containedinvoker.setAttribute("value", "");
    172          containedinvoker.click();
    173          assert_equals(invokee.returnValue, "");
    174          assert_false(invokee.open, "invokee.open");
    175          assert_false(invokee.matches(":modal"), "invokee :modal");
    176        },
    177        `invoking to close (with command ${setType} as ${command}) open dialog closes and overrides returnValue when empty string`,
    178      );
    179 
    180      test(
    181        function (t) {
    182          t.add_cleanup(resetState);
    183          invokee.show();
    184          assert_true(invokee.open, "invokee.open");
    185          assert_false(invokee.matches(":modal"), "invokee :modal");
    186          if (setType === "property") {
    187            containedinvoker.command = command;
    188          } else {
    189            containedinvoker.setAttribute("command", command);
    190          }
    191          invokee.returnValue = "test";
    192          containedinvoker.removeAttribute("value");
    193          containedinvoker.click();
    194          assert_equals(invokee.returnValue, "test");
    195          assert_false(invokee.open, "invokee.open");
    196          assert_false(invokee.matches(":modal"), "invokee :modal");
    197        },
    198        `invoking to close (with command ${setType} as ${command}) open dialog closes and doesn't override returnValue when missing value attribute`,
    199      );
    200 
    201      test(
    202        function (t) {
    203          t.add_cleanup(resetState);
    204          invokee.show();
    205          assert_true(invokee.open, "invokee.open");
    206          assert_false(invokee.matches(":modal"), "invokee :modal");
    207          if (typeof command === "string") {
    208            if (setType === "property") {
    209              containedinvoker.command = command;
    210            } else {
    211              containedinvoker.setAttribute("command", command);
    212            }
    213          }
    214          invokee.addEventListener("command", (e) => e.preventDefault(), {
    215            once: true,
    216          });
    217          containedinvoker.click();
    218          assert_true(invokee.open, "invokee.open");
    219          assert_false(invokee.matches(":modal"), "invokee :modal");
    220        },
    221        `invoking to close (with command ${setType} as ${command}) open dialog with preventDefault is no-op`,
    222      );
    223 
    224      test(
    225        function (t) {
    226          t.add_cleanup(resetState);
    227          invokee.showModal();
    228          assert_true(invokee.open, "invokee.open");
    229          assert_true(invokee.matches(":modal"), "invokee :modal");
    230          if (setType === "property") {
    231            containedinvoker.command = command;
    232          } else {
    233            containedinvoker.setAttribute("command", command);
    234          }
    235          invokee.addEventListener("command", (e) => e.preventDefault(), {
    236            once: true,
    237          });
    238          containedinvoker.click();
    239          assert_true(invokee.open, "invokee.open");
    240          assert_true(invokee.matches(":modal"), "invokee :modal");
    241        },
    242        `invoking to close (with command ${setType} as ${command}) open modal dialog with preventDefault is no-op`,
    243      );
    244 
    245      test(
    246        function (t) {
    247          t.add_cleanup(resetState);
    248          invokee.show();
    249          assert_true(invokee.open, "invokee.open");
    250          assert_false(invokee.matches(":modal"), "invokee :modal");
    251          if (setType === "property") {
    252            containedinvoker.command = command;
    253          } else {
    254            containedinvoker.setAttribute("command", command);
    255          }
    256          invokee.addEventListener(
    257            "command",
    258            (e) => {
    259              containedinvoker.setAttribute("command", "show");
    260            },
    261            { once: true },
    262          );
    263          containedinvoker.click();
    264          assert_false(invokee.open, "invokee.open");
    265          assert_false(invokee.matches(":modal"), "invokee :modal");
    266        },
    267        `invoking to close (with command ${setType} as ${command}) open dialog while changing command still closes`,
    268      );
    269 
    270      test(
    271        function (t) {
    272          t.add_cleanup(resetState);
    273          invokee.showModal();
    274          assert_true(invokee.open, "invokee.open");
    275          assert_true(invokee.matches(":modal"), "invokee :modal");
    276          if (setType === "property") {
    277            containedinvoker.command = command;
    278          } else {
    279            containedinvoker.setAttribute("command", command);
    280          }
    281          invokee.addEventListener(
    282            "command",
    283            (e) => {
    284              containedinvoker.setAttribute("command", "show");
    285            },
    286            { once: true },
    287          );
    288          containedinvoker.click();
    289          assert_false(invokee.open, "invokee.open");
    290          assert_false(invokee.matches(":modal"), "invokee :modal");
    291        },
    292        `invoking to close (with command ${setType} as ${command}) open modal dialog while changing command still closes`,
    293      );
    294    });
    295  });
    296 
    297  // request to close an already open dialog
    298 
    299  ["request-close", /* test case sensitivity */ "reQuEst-Close"].forEach((command) => {
    300    ["property", "attribute"].forEach((setType) => {
    301      test(
    302        function (t) {
    303          t.add_cleanup(resetState);
    304          invokee.show();
    305          assert_true(invokee.open, "invokee.open");
    306          assert_false(invokee.matches(":modal"), "invokee :modal");
    307          if (setType === "property") {
    308            containedinvoker.command = command;
    309          } else {
    310            containedinvoker.setAttribute("command", command);
    311          }
    312          containedinvoker.click();
    313          assert_equals(invokee.returnValue, "");
    314          assert_false(invokee.open, "invokee.open");
    315          assert_false(invokee.matches(":modal"), "invokee :modal");
    316        },
    317        `invoking to request-close (with command ${setType} as ${command}) open dialog closes`,
    318      );
    319 
    320      test(
    321        function (t) {
    322          t.add_cleanup(resetState);
    323          invokee.show();
    324          assert_true(invokee.open, "invokee.open");
    325          assert_false(invokee.matches(":modal"), "invokee :modal");
    326          if (setType === "property") {
    327            containedinvoker.command = command;
    328          } else {
    329            containedinvoker.setAttribute("command", command);
    330          }
    331          containedinvoker.setAttribute("value", "foo");
    332          containedinvoker.click();
    333          assert_equals(invokee.returnValue, "foo");
    334          assert_false(invokee.open, "invokee.open");
    335          assert_false(invokee.matches(":modal"), "invokee :modal");
    336        },
    337        `invoking to request-close with value (with command ${setType} as ${command}) open dialog closes and sets returnValue`,
    338      );
    339 
    340      test(
    341        function (t) {
    342          t.add_cleanup(resetState);
    343          invokee.show();
    344          assert_true(invokee.open, "invokee.open");
    345          assert_false(invokee.matches(":modal"), "invokee :modal");
    346          if (setType === "property") {
    347            containedinvoker.command = command;
    348          } else {
    349            containedinvoker.setAttribute("command", command);
    350          }
    351          invokee.returnValue = "test";
    352          containedinvoker.setAttribute("value", "foo");
    353          containedinvoker.click();
    354          assert_equals(invokee.returnValue, "foo");
    355          assert_false(invokee.open, "invokee.open");
    356          assert_false(invokee.matches(":modal"), "invokee :modal");
    357        },
    358        `invoking to request-close with value (with command ${setType} as ${command}) open dialog closes and overrides returnValue`,
    359      );
    360 
    361      test(
    362        function (t) {
    363          t.add_cleanup(resetState);
    364          invokee.show();
    365          assert_true(invokee.open, "invokee.open");
    366          assert_false(invokee.matches(":modal"), "invokee :modal");
    367          if (setType === "property") {
    368            containedinvoker.command = command;
    369          } else {
    370            containedinvoker.setAttribute("command", command);
    371          }
    372          invokee.returnValue = "test";
    373          containedinvoker.setAttribute("value", "");
    374          containedinvoker.click();
    375          assert_equals(invokee.returnValue, "");
    376          assert_false(invokee.open, "invokee.open");
    377          assert_false(invokee.matches(":modal"), "invokee :modal");
    378        },
    379        `invoking to request-close with value (with command ${setType} as ${command}) open dialog closes and overrides returnValue when empty string`,
    380      );
    381 
    382      test(
    383        function (t) {
    384          t.add_cleanup(resetState);
    385          invokee.show();
    386          assert_true(invokee.open, "invokee.open");
    387          assert_false(invokee.matches(":modal"), "invokee :modal");
    388          if (setType === "property") {
    389            containedinvoker.command = command;
    390          } else {
    391            containedinvoker.setAttribute("command", command);
    392          }
    393          invokee.returnValue = "test";
    394          containedinvoker.removeAttribute("value");
    395          containedinvoker.click();
    396          assert_equals(invokee.returnValue, "test");
    397          assert_false(invokee.open, "invokee.open");
    398          assert_false(invokee.matches(":modal"), "invokee :modal");
    399        },
    400        `invoking to request-close with value (with command ${setType} as ${command}) open dialog closes and doesn't override returnValue when missing value attribute`,
    401      );
    402 
    403      test(
    404        function (t) {
    405          t.add_cleanup(resetState);
    406          invokee.show();
    407          assert_true(invokee.open, "invokee.open");
    408          assert_false(invokee.matches(":modal"), "invokee :modal");
    409          if (typeof command === "string") {
    410            if (setType === "property") {
    411              containedinvoker.command = command;
    412            } else {
    413              containedinvoker.setAttribute("command", command);
    414            }
    415          }
    416          invokee.addEventListener("command", (e) => e.preventDefault(), {
    417            once: true,
    418          });
    419          containedinvoker.click();
    420          assert_true(invokee.open, "invokee.open");
    421          assert_false(invokee.matches(":modal"), "invokee :modal");
    422        },
    423        `invoking to request-close (with command ${setType} as ${command}) open dialog with preventDefault is no-op`,
    424      );
    425 
    426      test(
    427        function (t) {
    428          t.add_cleanup(resetState);
    429          invokee.showModal();
    430          assert_true(invokee.open, "invokee.open");
    431          assert_true(invokee.matches(":modal"), "invokee :modal");
    432          if (setType === "property") {
    433            containedinvoker.command = command;
    434          } else {
    435            containedinvoker.setAttribute("command", command);
    436          }
    437          invokee.addEventListener("command", (e) => e.preventDefault(), {
    438            once: true,
    439          });
    440          containedinvoker.click();
    441          assert_true(invokee.open, "invokee.open");
    442          assert_true(invokee.matches(":modal"), "invokee :modal");
    443        },
    444        `invoking to request-close (with command ${setType} as ${command}) open modal dialog with preventDefault is no-op`,
    445      );
    446 
    447      test(
    448        function (t) {
    449          t.add_cleanup(resetState);
    450          invokee.show();
    451          assert_true(invokee.open, "invokee.open");
    452          assert_false(invokee.matches(":modal"), "invokee :modal");
    453          if (setType === "property") {
    454            containedinvoker.command = command;
    455          } else {
    456            containedinvoker.setAttribute("command", command);
    457          }
    458          invokee.addEventListener(
    459            "command",
    460            (e) => {
    461              containedinvoker.setAttribute("command", "show");
    462            },
    463            { once: true },
    464          );
    465          containedinvoker.click();
    466          assert_false(invokee.open, "invokee.open");
    467          assert_false(invokee.matches(":modal"), "invokee :modal");
    468        },
    469        `invoking to request-close (with command ${setType} as ${command}) open dialog while changing command still closes`,
    470      );
    471 
    472      test(
    473        function (t) {
    474          t.add_cleanup(resetState);
    475          invokee.showModal();
    476          assert_true(invokee.open, "invokee.open");
    477          assert_true(invokee.matches(":modal"), "invokee :modal");
    478          if (setType === "property") {
    479            containedinvoker.command = command;
    480          } else {
    481            containedinvoker.setAttribute("command", command);
    482          }
    483          invokee.addEventListener(
    484            "command",
    485            (e) => {
    486              containedinvoker.setAttribute("command", "show");
    487            },
    488            { once: true },
    489          );
    490          containedinvoker.click();
    491          assert_false(invokee.open, "invokee.open");
    492          assert_false(invokee.matches(":modal"), "invokee :modal");
    493        },
    494        `invoking to request-close (with command ${setType} as ${command}) open modal dialog while changing command still closes`,
    495      );
    496    });
    497  });
    498 
    499  // show-modal explicit behaviours
    500 
    501  promise_test(async function (t) {
    502    t.add_cleanup(resetState);
    503    containedinvoker.setAttribute("command", "show-Modal");
    504    invokee.show();
    505    assert_true(invokee.open, "invokee.open");
    506    assert_false(invokee.matches(":modal"), "invokee :modal");
    507    containedinvoker.click();
    508    assert_true(invokee.open, "invokee.open");
    509    assert_false(invokee.matches(":modal"), "invokee :modal");
    510  }, "invoking (as show-modal) open dialog is noop");
    511 
    512  promise_test(async function (t) {
    513    t.add_cleanup(resetState);
    514    containedinvoker.setAttribute("command", "show-modal");
    515    invokee.showModal();
    516    assert_true(invokee.open, "invokee.open");
    517    assert_true(invokee.matches(":modal"), "invokee :modal");
    518    invokee.addEventListener(
    519      "command",
    520      (e) => {
    521        containedinvoker.setAttribute("command", "close");
    522      },
    523      { once: true },
    524    );
    525    invokerbutton.click();
    526    assert_true(invokee.open, "invokee.open");
    527    assert_true(invokee.matches(":modal"), "invokee :modal");
    528  }, "invoking (as show-modal) open modal, while changing command still a no-op");
    529 
    530  promise_test(async function (t) {
    531    t.add_cleanup(resetState);
    532    invokerbutton.setAttribute("command", "show-modal");
    533    assert_false(invokee.open, "invokee.open");
    534    assert_false(invokee.matches(":modal"), "invokee :modal");
    535    invokee.setAttribute("popover", "auto");
    536    invokerbutton.click();
    537    assert_true(invokee.open, "invokee.open");
    538    assert_true(invokee.matches(":modal"), "invokee :modal");
    539  }, "invoking (as show-modal) closed popover dialog opens as modal");
    540 
    541  // close explicit behaviours
    542 
    543  promise_test(async function (t) {
    544    t.add_cleanup(resetState);
    545    invokerbutton.setAttribute("command", "close");
    546    assert_false(invokee.open, "invokee.open");
    547    assert_false(invokee.matches(":modal"), "invokee :modal");
    548    containedinvoker.click();
    549    assert_false(invokee.open, "invokee.open");
    550    assert_false(invokee.matches(":modal"), "invokee :modal");
    551  }, "invoking (as close) already closed dialog is noop");
    552 
    553 
    554  // request-close explicit behaviours
    555 
    556  promise_test(async function (t) {
    557    t.add_cleanup(resetState);
    558    invokerbutton.setAttribute("command", "request-close");
    559    assert_false(invokee.open, "invokee.open");
    560    assert_false(invokee.matches(":modal"), "invokee :modal");
    561    containedinvoker.click();
    562    assert_false(invokee.open, "invokee.open");
    563    assert_false(invokee.matches(":modal"), "invokee :modal");
    564  }, "invoking (as request-close) already closed dialog is noop");
    565 
    566  // Open Popovers using Dialog actions
    567  ["show-modal", "close", "request-close"].forEach((command) => {
    568    ["manual", "auto"].forEach((popoverState) => {
    569      test(
    570        function (t) {
    571          t.add_cleanup(resetState);
    572          invokee.setAttribute("popover", popoverState);
    573          invokee.showPopover();
    574          containedinvoker.setAttribute("command", command);
    575          assert_true(
    576            invokee.matches(":popover-open"),
    577            "invokee :popover-open",
    578          );
    579          assert_false(invokee.open, "invokee.open");
    580          assert_false(invokee.matches(":modal"), "invokee :modal");
    581          invokee.addEventListener("command", (e) => e.preventDefault(), {
    582            once: true,
    583          });
    584          containedinvoker.click();
    585          assert_true(
    586            invokee.matches(":popover-open"),
    587            "invokee :popover-open",
    588          );
    589          assert_false(invokee.open, "invokee.open");
    590          assert_false(invokee.matches(":modal"), "invokee :modal");
    591        },
    592        `invoking (as ${command}) dialog as open popover=${popoverState} is noop`,
    593      );
    594    });
    595  });
    596 
    597  // Elements being disconnected during invoke steps
    598  ["show-modal", "close", "request-close"].forEach((command) => {
    599    promise_test(
    600      async function (t) {
    601        t.add_cleanup(() => {
    602          document.body.prepend(invokee);
    603          resetState();
    604        });
    605        const invokee = document.querySelector("#invokee");
    606        invokerbutton.setAttribute("command", command);
    607        assert_false(invokee.open, "invokee.open");
    608        assert_false(invokee.matches(":modal"), "invokee :modal");
    609        invokee.addEventListener(
    610          "command",
    611          (e) => {
    612            invokee.remove();
    613          },
    614          {
    615            once: true,
    616          },
    617        );
    618        invokerbutton.click();
    619        assert_false(invokee.open, "invokee.open");
    620        assert_false(invokee.matches(":modal"), "invokee :modal");
    621      },
    622      `invoking (as ${command}) dialog that is removed is noop`,
    623    );
    624 
    625    promise_test(
    626      async function (t) {
    627        const invokerbutton = document.createElement("button");
    628        invokerbutton.commandForElement = invokee;
    629        invokerbutton.setAttribute("command", command);
    630        assert_false(invokee.open, "invokee.open");
    631        assert_false(invokee.matches(":modal"), "invokee :modal");
    632        invokerbutton.click();
    633        assert_false(invokee.open, "invokee.open");
    634        assert_false(invokee.matches(":modal"), "invokee :modal");
    635      },
    636      `invoking (as ${command}) dialog from a detached invoker`,
    637    );
    638 
    639    promise_test(
    640      async function (t) {
    641        const invokerbutton = document.createElement("button");
    642        const invokee = document.createElement("dialog");
    643        invokerbutton.commandForElementt = invokee;
    644        invokerbutton.setAttribute("command", command);
    645        assert_false(invokee.open, "invokee.open");
    646        assert_false(invokee.matches(":modal"), "invokee :modal");
    647        invokerbutton.click();
    648        assert_false(invokee.open, "invokee.open");
    649        assert_false(invokee.matches(":modal"), "invokee :modal");
    650      },
    651      `invoking (as ${command}) detached dialog from a detached invoker`,
    652    );
    653  });
    654 </script>