<!doctype html>
<title>HTMLSelectMenuElement Test: keyboard accessibility</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
  <selectmenu id="selectMenu0">
    <div id="selectMenu0-button0" slot="button" behavior="button" tabindex="0">button</div>
    <option>one</option>
    <option>two</option>
    <option>three</option>
  </selectmenu>

  <selectmenu id="selectMenu1">
    <option id="selectMenu1-child0">one</option>
  </selectmenu>

  <selectmenu id="selectMenu2" disabled>
    <div id="selectMenu2-button0" slot="button" behavior="button" tabindex="0">button</div>
    <option disabled>one</option>
    <option>two</option>
    <option>three</option>
  </selectmenu>

  <selectmenu id="selectMenu3">
    <div id="selectMenu3-button0" slot="button" behavior="button" tabindex="0">button</div>
    <option>one</option>
    <option disabled>two</option>
    <option>three</option>
  </selectmenu>
<script>
// See https://w3c.github.io/webdriver/#keyboard-actions
const KEY_CODE_MAP = {
  'Enter':      '\uE007',
  'Space':      '\uE00D',
  'ArrowUp':    '\uE013',
  'ArrowDown':  '\uE015'
};

function clickOn(element) {
    const actions = new test_driver.Actions();
    return actions.pointerMove(0, 0, {origin: element})
      .pointerDown({button: actions.ButtonType.LEFT})
      .pointerUp({button: actions.ButtonType.LEFT})
      .send();
  }

promise_test(async t => {
  const selectMenu = document.querySelector("#selectMenu0");
  const button = document.querySelector("#selectMenu0-button0");
  assert_false(selectMenu.open, "selectmenu should not be initially open");

  await test_driver.send_keys(button, KEY_CODE_MAP.Enter);
  assert_true(selectMenu.open, "Enter key should open selectmenu");
  assert_equals(selectMenu.value, "one");

  await test_driver.send_keys(selectMenu, KEY_CODE_MAP.ArrowDown);
  assert_equals(selectMenu.value, "two", "Down arrow should go to next option");

  await test_driver.send_keys(selectMenu, KEY_CODE_MAP.ArrowDown);
  assert_equals(selectMenu.value, "three", "Down arrow should go to next option");

  await test_driver.send_keys(selectMenu, KEY_CODE_MAP.ArrowDown);
  assert_equals(selectMenu.value, "three", "Down arrow should do nothing if already at the last option");

  await test_driver.send_keys(selectMenu, KEY_CODE_MAP.ArrowUp);
  assert_equals(selectMenu.value, "two", "Up arrow should go to the previous option");

  await test_driver.send_keys(selectMenu, KEY_CODE_MAP.ArrowUp);
  assert_equals(selectMenu.value, "one", "Up arrow should go to the previous option");

  await test_driver.send_keys(selectMenu, KEY_CODE_MAP.ArrowUp);
  assert_equals(selectMenu.value, "one", "Up arrow should do nothing if already at the first option");

  await test_driver.send_keys(selectMenu, KEY_CODE_MAP.Enter);
  assert_false(selectMenu.open, "Enter key should close selectmenu");

  await test_driver.send_keys(selectMenu, " ");
  assert_true(selectMenu.open, "Space key should open selectmenu");

  // This behavior is suspicious (since Space key can open the selectmenu),
  // but it maches <select>. See https://github.com/openui/open-ui/issues/386
  await test_driver.send_keys(selectMenu, " ");
  assert_true(selectMenu.open, "Space key should *not* close selectmenu");

  await test_driver.send_keys(selectMenu, KEY_CODE_MAP.Enter);
  assert_false(selectMenu.open, "Enter key should close selectmenu");
}, "Validate Enter, Up/Down Arrow, and Space keyboard accessibility support for <selectmenu>");

promise_test(async t => {
  const selectMenuOption = document.getElementById("selectMenu1-child0");
  const event = document.createEvent("Event");
  event.initEvent("keydown");
  selectMenuOption.dispatchEvent(event);
}, "Firing a synthetic event at a selectmenu's option doesn't crash");

promise_test(async t => {
  const selectMenu2 = document.querySelector("#selectMenu2");
  const selectMenu2Button = document.querySelector("#selectMenu2-button0");
  assert_false(selectMenu2.open, "selectmenu should not be initially open");

  await test_driver.send_keys(selectMenu2Button, KEY_CODE_MAP.Enter);
  assert_false(selectMenu2.open, "Enter key should not open a disabled selectmenu");
  await clickOn(selectMenu2);
  assert_false(selectMenu2.open, "Click should not open a disabled selectmenu");
  assert_equals(selectMenu2.value, "one");

  const selectMenu3 = document.querySelector("#selectMenu3");
  const selectMenu3Button = document.querySelector("#selectMenu3-button0");
  assert_false(selectMenu3.open, "selectmenu should not be initially open");

  await test_driver.send_keys(selectMenu3Button, KEY_CODE_MAP.Enter);
  assert_true(selectMenu3.open, "Enter key should open selectmenu");
  assert_equals(selectMenu3.value, "one");

  await test_driver.send_keys(selectMenu3, KEY_CODE_MAP.ArrowDown);
  assert_equals(selectMenu3.value, "three", "Down arrow should go to next non-disabled option");

  await test_driver.send_keys(selectMenu3, KEY_CODE_MAP.ArrowUp);
  assert_equals(selectMenu3.value, "one", "Up arrow should go to the previous non-disabled option");
}, "Validate Enter, Up/Down Arrow keyboard accessibility support for disabled <selectmenu>");
</script>
