tor-browser

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

behaves-like-button-with-command.tentative.html (9259B)


      1 <!DOCTYPE HTML>
      2 <html>
      3 <head>
      4  <script src="/resources/testharness.js"></script>
      5  <script src="/resources/testharnessreport.js"></script>
      6  <script src="/resources/testdriver.js"></script>
      7  <script src="/resources/testdriver-vendor.js"></script>
      8  <script src="/resources/testdriver-actions.js"></script>
      9  <script src="/wai-aria/scripts/aria-utils.js"></script>
     10 </head>
     11 <body>
     12  <custom-element id="customElement"></custom-element>
     13  <custom-button id="customButton"></custom-button>
     14 
     15  <!-- Targets -->
     16  <div id="target" popover>Popover content</div>
     17  <dialog id="dialog">Dialog content</dialog>
     18 
     19  <script>
     20    class CustomElement extends HTMLElement {
     21      constructor() {
     22        super();
     23        this.internals_ = this.attachInternals();
     24      }
     25    }
     26    customElements.define('custom-element', CustomElement);
     27 
     28    class CustomButton extends HTMLElement {
     29      static formAssociated = true;
     30      constructor() {
     31        super();
     32        this.internals_ = this.attachInternals();
     33        this.internals_.type = "button";
     34      }
     35 
     36      get disabled() {
     37        return this.hasAttribute('disabled');
     38      }
     39 
     40      set disabled(value) {
     41        if (value) {
     42          this.setAttribute('disabled', '');
     43        } else {
     44          this.removeAttribute('disabled');
     45        }
     46      }
     47    }
     48    customElements.define('custom-button', CustomButton);
     49 
     50    function resetState() {
     51      document.getElementById("target").hidePopover();
     52      document.getElementById("dialog").close();
     53      document.getElementById('customButton').outerHTML = '<custom-button id="customButton">';
     54      document.getElementById('customElement').outerHTML = '<custom-element id="customElement">';
     55    }
     56 
     57    // Test popover commands
     58    test(t => {
     59      const customElement = document.getElementById("customElement");
     60      const target = document.getElementById("target");
     61      customElement.setAttribute('commandfor', 'target');
     62      customElement.setAttribute('command', 'toggle-popover');
     63      t.add_cleanup(() => resetState());
     64 
     65      // Custom element without type=button should not work with commandfor
     66      assert_false(target.matches(':popover-open'), "Popover should start closed");
     67      customElement.click();
     68      assert_false(target.matches(':popover-open'), "Custom element without type=button should not trigger popover");
     69    }, "Custom element without type=button does not support commandfor attribute.");
     70 
     71    test(t => {
     72      const customButton = document.getElementById("customButton");
     73      const target = document.getElementById("target");
     74      customButton.setAttribute('commandfor', 'target');
     75      customButton.setAttribute('command', 'toggle-popover');
     76      t.add_cleanup(() => resetState());
     77 
     78      // Custom button with type=button should work
     79      assert_false(target.matches(':popover-open'), "Popover should start closed");
     80      customButton.click();
     81      assert_true(target.matches(':popover-open'), "Custom button with type=button should open popover");
     82 
     83      // Second click should close
     84      customButton.click();
     85      assert_false(target.matches(':popover-open'), "Second click should close popover");
     86    }, "Custom button with type=button and command='toggle-popover' toggles popover.");
     87 
     88    test(t => {
     89      const customButton = document.getElementById("customButton");
     90      const target = document.getElementById("target");
     91      customButton.setAttribute('commandfor', 'target');
     92      customButton.setAttribute('command', 'show-popover');
     93      t.add_cleanup(() => resetState());
     94 
     95      assert_false(target.matches(':popover-open'), "Popover should start closed");
     96      customButton.click();
     97      assert_true(target.matches(':popover-open'), "show-popover should open popover");
     98 
     99      // Second click should not close (show action only opens)
    100      customButton.click();
    101      assert_true(target.matches(':popover-open'), "show-popover should not close popover on second click");
    102    }, "Custom button with command='show-popover' only opens popover.");
    103 
    104    test(t => {
    105      const customButton = document.getElementById("customButton");
    106      const target = document.getElementById("target");
    107      customButton.setAttribute('commandfor', 'target');
    108      customButton.setAttribute('command', 'hide-popover');
    109      t.add_cleanup(() => resetState());
    110 
    111      // Start with popover open
    112      target.showPopover();
    113      assert_true(target.matches(':popover-open'), "Popover should start open");
    114 
    115      customButton.click();
    116      assert_false(target.matches(':popover-open'), "hide-popover should close popover");
    117 
    118      // Second click should not open (hide action only closes)
    119      customButton.click();
    120      assert_false(target.matches(':popover-open'), "hide-popover should not open popover on second click");
    121    }, "Custom button with command='hide-popover' only closes popover.");
    122 
    123    test(t => {
    124      const customButton = document.getElementById("customButton");
    125      const target = document.getElementById("target");
    126      customButton.setAttribute('commandfor', 'target');
    127      customButton.setAttribute('command', 'toggle-popover');
    128      customButton.disabled = true;
    129      t.add_cleanup(() => resetState());
    130 
    131      // Disabled custom button should not work
    132      assert_true(customButton.disabled, "Custom button should be disabled");
    133      assert_false(target.matches(':popover-open'), "Popover should start closed");
    134      customButton.click();
    135      assert_false(target.matches(':popover-open'), "Disabled custom button should not open popover");
    136    }, "Disabled custom button does not support commandfor.");
    137 
    138    // Test dialog commands
    139    test(t => {
    140      const customButton = document.getElementById("customButton");
    141      const dialog = document.getElementById("dialog");
    142      customButton.setAttribute('commandfor', 'dialog');
    143      customButton.setAttribute('command', 'show-modal');
    144      t.add_cleanup(() => resetState());
    145 
    146      assert_false(dialog.open, "Dialog should start closed");
    147      customButton.click();
    148      assert_true(dialog.open, "show-modal should open dialog");
    149    }, "Custom button with command='show-modal' opens dialog.");
    150 
    151    test(t => {
    152      const customButton = document.getElementById("customButton");
    153      const dialog = document.getElementById("dialog");
    154      customButton.setAttribute('commandfor', 'dialog');
    155      customButton.setAttribute('command', 'close');
    156      t.add_cleanup(() => resetState());
    157 
    158      // Start with dialog open
    159      dialog.showModal();
    160      assert_true(dialog.open, "Dialog should start open");
    161      customButton.click();
    162      assert_false(dialog.open, "close command should close dialog");
    163    }, "Custom button with command='close' closes dialog.");
    164 
    165    test(t => {
    166      const customButton = document.getElementById("customButton");
    167      const dialog = document.getElementById("dialog");
    168      customButton.setAttribute('commandfor', 'dialog');
    169      customButton.setAttribute('command', 'request-close');
    170      t.add_cleanup(() => resetState());
    171 
    172      // Test with dialog open - should close it
    173      dialog.showModal();
    174      assert_true(dialog.open, "Dialog should start open");
    175      customButton.click();
    176      assert_false(dialog.open, "request-close command should close open dialog");
    177 
    178      // Test with dialog already closed - should do nothing
    179      assert_false(dialog.open, "Dialog should be closed");
    180      customButton.click();
    181      assert_false(dialog.open, "request-close command should not open closed dialog");
    182    }, "Custom button with command='request-close' closes open dialog and does nothing when dialog is already closed.");
    183 
    184    // Test custom commands
    185    test(t => {
    186      const customButton = document.getElementById("customButton");
    187      const target = document.getElementById("target");
    188      let commandEventFired = false;
    189      let receivedCommand = '';
    190      customButton.setAttribute('commandfor', 'target');
    191      customButton.setAttribute('command', '--my-custom-action');
    192 
    193      const commandListener = (e) => {
    194        commandEventFired = true;
    195        receivedCommand = e.command;
    196      };
    197      target.addEventListener('command', commandListener, { signal: t.get_signal() });
    198      t.add_cleanup(() => resetState());
    199 
    200      customButton.click();
    201      assert_true(commandEventFired, "Custom command should fire command event");
    202      assert_equals(receivedCommand, '--my-custom-action', "Command event should contain custom command");
    203    }, "Custom button with custom command fires command event.");
    204 
    205    // Test invalid commands
    206    test(t => {
    207      const customButton = document.getElementById("customButton");
    208      const target = document.getElementById("target");
    209      let commandEventFired = false;
    210      customButton.setAttribute('commandfor', 'target');
    211      customButton.setAttribute('command', 'invalid-action');
    212      const commandListener = (e) => {
    213        commandEventFired = true;
    214      };
    215      target.addEventListener('command', commandListener, { signal: t.get_signal() });
    216      t.add_cleanup(() => resetState());
    217 
    218      customButton.click();
    219      assert_false(commandEventFired, "Invalid command should not fire command event");
    220    }, "Custom button with invalid command does not fire command event.");
    221  </script>
    222 </body>
    223 </html>