summaryrefslogtreecommitdiffstats
path: root/toolkit/content/tests/browser/datetime/browser_datetime_datepicker_keynav.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/content/tests/browser/datetime/browser_datetime_datepicker_keynav.js')
-rw-r--r--toolkit/content/tests/browser/datetime/browser_datetime_datepicker_keynav.js576
1 files changed, 576 insertions, 0 deletions
diff --git a/toolkit/content/tests/browser/datetime/browser_datetime_datepicker_keynav.js b/toolkit/content/tests/browser/datetime/browser_datetime_datepicker_keynav.js
new file mode 100644
index 0000000000..0b271ed77a
--- /dev/null
+++ b/toolkit/content/tests/browser/datetime/browser_datetime_datepicker_keynav.js
@@ -0,0 +1,576 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * Ensure picker opens, closes, and updates its value with key bindings appropriately.
+ */
+add_task(async function test_datepicker_keyboard_nav() {
+ info(
+ "Ensure picker opens, closes, and updates its value with key bindings appropriately."
+ );
+
+ const inputValue = "2016-12-15";
+ const prevMonth = "2016-11-01";
+ await helper.openPicker(
+ `data:text/html,<input id=date type=date value=${inputValue}>`
+ );
+ let browser = helper.tab.linkedBrowser;
+ Assert.equal(helper.panel.state, "open", "Panel should be opened");
+
+ await testCalendarBtnAttribute("aria-expanded", "true");
+
+ let closed = helper.promisePickerClosed();
+
+ // Close on Escape anywhere
+ EventUtils.synthesizeKey("KEY_Escape", {});
+
+ await closed;
+
+ Assert.equal(
+ helper.panel.state,
+ "closed",
+ "Panel should be closed after Escape from anywhere on the window"
+ );
+
+ await testCalendarBtnAttribute("aria-expanded", "false");
+
+ let ready = helper.waitForPickerReady();
+
+ // Ensure focus is on the input field
+ await SpecialPowers.spawn(browser, [], () => {
+ content.document.querySelector("#date").focus();
+ });
+
+ info("Test that input updates with the keyboard update the picker");
+
+ // NOTE: After a Tab, the first input field (the month one) is focused,
+ // so down arrow will change the selected month.
+ //
+ // This assumes en-US locale, which seems fine for testing purposes (as
+ // DATE_FORMAT and other bits around do the same).
+ BrowserTestUtils.synthesizeKey("KEY_ArrowDown", {}, browser);
+
+ // Toggle the picker on Space anywhere within the input
+ BrowserTestUtils.synthesizeKey(" ", {}, browser);
+
+ await ready;
+
+ await testCalendarBtnAttribute("aria-expanded", "true");
+
+ Assert.equal(
+ helper.panel.state,
+ "open",
+ "Panel should be opened on Space from anywhere within the input field"
+ );
+
+ Assert.equal(
+ helper.panel.querySelector("#dateTimePopupFrame").contentDocument
+ .activeElement.textContent,
+ "15",
+ "Picker is opened with a focus set to the currently selected date"
+ );
+
+ let monthYearEl = helper.getElement(MONTH_YEAR);
+ await BrowserTestUtils.waitForMutationCondition(
+ monthYearEl,
+ { childList: true },
+ () => {
+ return monthYearEl.textContent == DATE_FORMAT(new Date(prevMonth));
+ },
+ `Should change to November 2016, instead got ${
+ helper.getElement(MONTH_YEAR).textContent
+ }`
+ );
+
+ Assert.ok(
+ true,
+ "The date on both the Calendar and Month-Year button was updated when updating months with Down arrow key"
+ );
+
+ closed = helper.promisePickerClosed();
+
+ // Close on Escape and return the focus to the input field (the month input in en-US locale)
+ EventUtils.synthesizeKey("KEY_Escape", {}, window);
+
+ await closed;
+
+ Assert.equal(
+ helper.panel.state,
+ "closed",
+ "Panel should be closed on Escape"
+ );
+
+ // Check the focus is returned to the Month field
+ await SpecialPowers.spawn(browser, [], async () => {
+ const input = content.document.querySelector("input");
+ const shadowRoot = SpecialPowers.wrap(input).openOrClosedShadowRoot;
+ // Separators "/" are odd children of the wrapper
+ const monthField = shadowRoot.getElementById("edit-wrapper").children[0];
+ // Testing the focus position within content:
+ Assert.equal(
+ input,
+ content.document.activeElement,
+ `The input field includes programmatic focus`
+ );
+ // Testing the focus indication within the shadow-root:
+ Assert.ok(
+ monthField.matches(":focus"),
+ `The keyboard focus was returned to the Month field`
+ );
+ });
+
+ // Move focus to the second field (the day input in en-US locale)
+ BrowserTestUtils.synthesizeKey("KEY_ArrowRight", {}, browser);
+
+ // Change the day to 2016-12-16
+ BrowserTestUtils.synthesizeKey("KEY_ArrowUp", {}, browser);
+
+ ready = helper.waitForPickerReady();
+
+ // Open the picker on Space within the input to check the date update
+ await BrowserTestUtils.synthesizeKey(" ", {}, browser);
+
+ await ready;
+
+ await testCalendarBtnAttribute("aria-expanded", "true");
+
+ Assert.equal(helper.panel.state, "open", "Panel should be opened on Space");
+
+ let selectedDayEl = helper.getElement(DAY_SELECTED);
+ await BrowserTestUtils.waitForMutationCondition(
+ selectedDayEl,
+ { childList: true },
+ () => {
+ return selectedDayEl.textContent === "16";
+ },
+ `Should change to the 16th, instead got ${
+ helper.getElement(DAY_SELECTED).textContent
+ }`
+ );
+
+ Assert.ok(
+ true,
+ "The date on the Calendar was updated when updating days with Up arrow key"
+ );
+
+ closed = helper.promisePickerClosed();
+
+ // Close on Escape and return the focus to the input field (the day input in en-US locale)
+ EventUtils.synthesizeKey("KEY_Escape", {}, window);
+
+ await closed;
+
+ Assert.equal(
+ helper.panel.state,
+ "closed",
+ "Panel should be closed on Escape"
+ );
+
+ await testCalendarBtnAttribute("aria-expanded", "false");
+
+ // Check the focus is returned to the Day field
+ await SpecialPowers.spawn(browser, [], async () => {
+ const input = content.document.querySelector("input");
+ const shadowRoot = SpecialPowers.wrap(input).openOrClosedShadowRoot;
+ // Separators "/" are odd children of the wrapper
+ const dayField = shadowRoot.getElementById("edit-wrapper").children[2];
+ // Testing the focus position within content:
+ Assert.equal(
+ input,
+ content.document.activeElement,
+ `The input field includes programmatic focus`
+ );
+ // Testing the focus indication within the shadow-root:
+ Assert.ok(
+ dayField.matches(":focus"),
+ `The keyboard focus was returned to the Day field`
+ );
+ });
+
+ info("Test the Calendar button can toggle the picker with Enter/Space");
+
+ // Move focus to the Calendar button
+ BrowserTestUtils.synthesizeKey("KEY_Tab", {}, browser);
+ BrowserTestUtils.synthesizeKey("KEY_Tab", {}, browser);
+
+ // Toggle the picker on Enter on Calendar button
+ await BrowserTestUtils.synthesizeKey("KEY_Enter", {}, browser);
+
+ await helper.waitForPickerReady();
+
+ Assert.equal(
+ helper.panel.state,
+ "open",
+ "Panel should be opened on Enter from the Calendar button"
+ );
+
+ await testCalendarBtnAttribute("aria-expanded", "true");
+
+ // Move focus from 2016-11-16 to 2016-11-17
+ EventUtils.synthesizeKey("KEY_ArrowRight", {});
+
+ // Make a selection by pressing Space on date gridcell
+ await EventUtils.synthesizeKey(" ", {});
+
+ await helper.promisePickerClosed();
+
+ Assert.equal(
+ helper.panel.state,
+ "closed",
+ "Panel should be closed on Space from the date gridcell"
+ );
+ await testCalendarBtnAttribute("aria-expanded", "false");
+
+ // Check the focus is returned to the Calendar button
+ await SpecialPowers.spawn(browser, [], async () => {
+ const input = content.document.querySelector("input");
+ const shadowRoot = SpecialPowers.wrap(input).openOrClosedShadowRoot;
+ const calendarBtn = shadowRoot.getElementById("calendar-button");
+ // Testing the focus position within content:
+ Assert.equal(
+ input,
+ content.document.activeElement,
+ `The input field includes programmatic focus`
+ );
+ // Testing the focus indication within the shadow-root:
+ Assert.ok(
+ calendarBtn.matches(":focus"),
+ `The keyboard focus was returned to the Calendar button`
+ );
+ });
+
+ // Check the Backspace on Calendar button is not doing anything
+ await EventUtils.synthesizeKey("KEY_Backspace", {});
+
+ // The Calendar button is on its place and the input value is not changed
+ // (bug 1804669)
+ await SpecialPowers.spawn(browser, [], () => {
+ const input = content.document.querySelector("input");
+ const shadowRoot = SpecialPowers.wrap(input).openOrClosedShadowRoot;
+ const calendarBtn = shadowRoot.getElementById("calendar-button");
+ Assert.equal(
+ calendarBtn.children[0].tagName,
+ "svg",
+ `Calendar button has an <svg> child`
+ );
+ Assert.equal(input.value, "2016-11-17", `Input's value is not removed`);
+ });
+
+ // Toggle the picker on Space on Calendar button
+ await EventUtils.synthesizeKey(" ", {});
+
+ await helper.waitForPickerReady();
+
+ Assert.equal(
+ helper.panel.state,
+ "open",
+ "Panel should be opened on Space from the Calendar button"
+ );
+
+ await testCalendarBtnAttribute("aria-expanded", "true");
+
+ await helper.tearDown();
+});
+
+/**
+ * Ensure calendar follows Arrow key bindings appropriately.
+ */
+add_task(async function test_datepicker_keyboard_arrows() {
+ info("Ensure calendar follows Arrow key bindings appropriately.");
+
+ const inputValue = "2016-12-10";
+ const prevMonth = "2016-11-01";
+ await helper.openPicker(
+ `data:text/html,<input id=date type=date value=${inputValue}>`
+ );
+ let pickerDoc = helper.panel.querySelector(
+ "#dateTimePopupFrame"
+ ).contentDocument;
+ Assert.equal(helper.panel.state, "open", "Panel should be opened");
+
+ // Move focus from 2016-12-10 to 2016-12-11:
+ EventUtils.synthesizeKey("KEY_ArrowRight", {});
+
+ Assert.equal(
+ pickerDoc.activeElement.textContent,
+ "11",
+ "Arrow Right moves focus to the next day"
+ );
+
+ // Move focus from 2016-12-11 to 2016-12-04:
+ EventUtils.synthesizeKey("KEY_ArrowUp", {});
+
+ Assert.equal(
+ pickerDoc.activeElement.textContent,
+ "4",
+ "Arrow Up moves focus to the same weekday of the previous week"
+ );
+
+ // Move focus from 2016-12-04 to 2016-12-03:
+ EventUtils.synthesizeKey("KEY_ArrowLeft", {});
+
+ Assert.equal(
+ pickerDoc.activeElement.textContent,
+ "3",
+ "Arrow Left moves focus to the previous day"
+ );
+
+ // Move focus from 2016-12-03 to 2016-11-26:
+ EventUtils.synthesizeKey("KEY_ArrowUp", {});
+
+ Assert.equal(
+ pickerDoc.activeElement.textContent,
+ "26",
+ "Arrow Up updates the view to be on the previous month, if needed"
+ );
+ Assert.equal(
+ helper.getElement(MONTH_YEAR).textContent,
+ DATE_FORMAT(new Date(prevMonth)),
+ "Arrow Up updates the spinner to show the previous month, if needed"
+ );
+
+ // Move focus from 2016-11-26 to 2016-12-03:
+ EventUtils.synthesizeKey("KEY_ArrowDown", {});
+ Assert.equal(
+ pickerDoc.activeElement.textContent,
+ "3",
+ "Arrow Down updates the view to be on the next month, if needed"
+ );
+ Assert.equal(
+ helper.getElement(MONTH_YEAR).textContent,
+ DATE_FORMAT(new Date(inputValue)),
+ "Arrow Down updates the spinner to show the next month, if needed"
+ );
+
+ // Move focus from 2016-12-03 to 2016-12-10:
+ EventUtils.synthesizeKey("KEY_ArrowDown", {});
+
+ Assert.equal(
+ pickerDoc.activeElement.textContent,
+ "10",
+ "Arrow Down moves focus to the same day of the next week"
+ );
+
+ await helper.tearDown();
+});
+
+/**
+ * Ensure calendar follows Home/End key bindings appropriately.
+ */
+add_task(async function test_datepicker_keyboard_home_end() {
+ info("Ensure calendar follows Home/End key bindings appropriately.");
+
+ const inputValue = "2016-12-15";
+ const prevMonth = "2016-11-01";
+ await helper.openPicker(
+ `data:text/html,<input id=date type=date value=${inputValue}>`
+ );
+ let pickerDoc = helper.panel.querySelector(
+ "#dateTimePopupFrame"
+ ).contentDocument;
+ Assert.equal(helper.panel.state, "open", "Panel should be opened");
+
+ // Move focus from 2016-12-15 to 2016-12-11 (in the en-US locale):
+ EventUtils.synthesizeKey("KEY_Home", {});
+
+ Assert.equal(
+ pickerDoc.activeElement.textContent,
+ "11",
+ "Home key moves focus to the first day/Sunday of the current week"
+ );
+
+ // Move focus from 2016-12-11 to 2016-12-17 (in the en-US locale):
+ EventUtils.synthesizeKey("KEY_End", {});
+
+ Assert.equal(
+ pickerDoc.activeElement.textContent,
+ "17",
+ "End key moves focus to the last day/Saturday of the current week"
+ );
+
+ // Move focus from 2016-12-17 to 2016-12-31:
+ EventUtils.synthesizeKey("KEY_End", { ctrlKey: true });
+
+ Assert.equal(
+ pickerDoc.activeElement.textContent,
+ "31",
+ "Ctrl + End keys move focus to the last day of the current month"
+ );
+
+ // Move focus from 2016-12-31 to 2016-12-01:
+ EventUtils.synthesizeKey("KEY_Home", { ctrlKey: true });
+
+ Assert.equal(
+ pickerDoc.activeElement.textContent,
+ "1",
+ "Ctrl + Home keys move focus to the first day of the current month"
+ );
+
+ // Move focus from 2016-12-01 to 2016-11-27 (in the en-US locale):
+ EventUtils.synthesizeKey("KEY_Home", {});
+
+ Assert.equal(
+ pickerDoc.activeElement.textContent,
+ "27",
+ "Home key updates the view to be on the previous month, if needed"
+ );
+ Assert.equal(
+ helper.getElement(MONTH_YEAR).textContent,
+ DATE_FORMAT(new Date(prevMonth)),
+ "Home key updates the spinner to show the previous month, if needed"
+ );
+
+ // Move focus from 2016-11-27 to 2016-12-03 (in the en-US locale):
+ EventUtils.synthesizeKey("KEY_End", {});
+
+ Assert.equal(
+ pickerDoc.activeElement.textContent,
+ "3",
+ "End key updates the view to be on the next month, if needed"
+ );
+ Assert.equal(
+ helper.getElement(MONTH_YEAR).textContent,
+ DATE_FORMAT(new Date(inputValue)),
+ "End key updates the spinner to show the next month, if needed"
+ );
+
+ await helper.tearDown();
+});
+
+/**
+ * Ensure calendar follows Page Up/Down key bindings appropriately.
+ */
+add_task(async function test_datepicker_keyboard_pgup_pgdown() {
+ info("Ensure calendar follows Page Up/Down key bindings appropriately.");
+
+ const inputValue = "2023-01-31";
+ const prevMonth = "2022-12-31";
+ const prevYear = "2021-12-01";
+ const nextMonth = "2023-01-31";
+ const nextShortMonth = "2023-03-03";
+ await helper.openPicker(
+ `data:text/html,<input id=date type=date value=${inputValue}>`
+ );
+ let pickerDoc = helper.panel.querySelector(
+ "#dateTimePopupFrame"
+ ).contentDocument;
+ Assert.equal(helper.panel.state, "open", "Panel should be opened");
+
+ // Move focus from 2023-01-31 to 2022-12-31:
+ EventUtils.synthesizeKey("KEY_PageUp", {});
+
+ Assert.equal(
+ pickerDoc.activeElement.textContent,
+ "31",
+ "Page Up key moves focus to the same day of the previous month"
+ );
+ Assert.equal(
+ helper.getElement(MONTH_YEAR).textContent,
+ DATE_FORMAT(new Date(prevMonth)),
+ "Page Up key updates the month-year button to show the previous month"
+ );
+
+ // Move focus from 2022-12-31 to 2022-12-01
+ // (because 2022-11-31 does not exist):
+ EventUtils.synthesizeKey("KEY_PageUp", {});
+
+ Assert.equal(
+ pickerDoc.activeElement.textContent,
+ "1",
+ `When the same day does not exists in the previous month Page Up key moves
+ focus to the same day of the same week of the current month`
+ );
+ Assert.equal(
+ helper.getElement(MONTH_YEAR).textContent,
+ DATE_FORMAT(new Date(prevMonth)),
+ `When the same day does not exist in the previous month
+ Page Up key does not update the month-year button and shows the current month`
+ );
+
+ // Move focus from 2022-12-01 to 2021-12-01:
+ EventUtils.synthesizeKey("KEY_PageUp", { shiftKey: true });
+ Assert.equal(
+ pickerDoc.activeElement.textContent,
+ "1",
+ "Page Up with Shift key moves focus to the same day of the same month of the previous year"
+ );
+ Assert.equal(
+ helper.getElement(MONTH_YEAR).textContent,
+ DATE_FORMAT(new Date(prevYear)),
+ "Page Up with Shift key updates the month-year button to show the same month of the previous year"
+ );
+
+ // Move focus from 2021-12-01 to 2022-12-01 month by month (bug 1806645):
+ EventUtils.synthesizeKey("KEY_PageDown", { repeat: 12 });
+ Assert.equal(
+ pickerDoc.activeElement.textContent,
+ "1",
+ "When repeated, Page Down key moves focus to the same day of the same month of the next year"
+ );
+ Assert.equal(
+ helper.getElement(MONTH_YEAR).textContent,
+ DATE_FORMAT(new Date(prevMonth)),
+ "When repeated, Page Down key updates the month-year button to show the same month of the next year"
+ );
+
+ // Move focus from 2022-12-01 to 2021-12-01 month by month (bug 1806645):
+ EventUtils.synthesizeKey("KEY_PageUp", { repeat: 12 });
+ Assert.equal(
+ pickerDoc.activeElement.textContent,
+ "1",
+ "When repeated, Page Up moves focus to the same day of the same month of the previous year"
+ );
+ Assert.equal(
+ helper.getElement(MONTH_YEAR).textContent,
+ DATE_FORMAT(new Date(prevYear)),
+ "When repeated, Page Up key updates the month-year button to show the same month of the previous year"
+ );
+
+ // Move focus from 2021-12-01 to 2022-12-01:
+ EventUtils.synthesizeKey("KEY_PageDown", { shiftKey: true });
+ Assert.equal(
+ pickerDoc.activeElement.textContent,
+ "1",
+ "Page Down with Shift key moves focus to the same day of the same month of the next year"
+ );
+ Assert.equal(
+ helper.getElement(MONTH_YEAR).textContent,
+ DATE_FORMAT(new Date(prevMonth)),
+ "Page Down with Shift key updates the month-year button to show the same month of the next year"
+ );
+
+ // Move focus from 2016-12-01 to 2016-12-31:
+ EventUtils.synthesizeKey("KEY_End", { ctrlKey: true });
+ // Move focus from 2022-12-31 to 2023-01-31:
+ EventUtils.synthesizeKey("KEY_PageDown", {});
+
+ Assert.equal(
+ pickerDoc.activeElement.textContent,
+ "31",
+ "Page Down key moves focus to the same day of the next month"
+ );
+ Assert.equal(
+ helper.getElement(MONTH_YEAR).textContent,
+ DATE_FORMAT(new Date(nextMonth)),
+ "Page Down key updates the month-year button to show the next month"
+ );
+
+ // Move focus from 2023-01-31 to 2023-03-03:
+ EventUtils.synthesizeKey("KEY_PageDown", {});
+
+ Assert.equal(
+ pickerDoc.activeElement.textContent,
+ "3",
+ `When the same day does not exists in the next month, Page Down key moves
+ focus to the same day of the same week of the month after`
+ );
+ Assert.equal(
+ helper.getElement(MONTH_YEAR).textContent,
+ DATE_FORMAT(new Date(nextShortMonth)),
+ "Page Down key updates the month-year button to show the month after"
+ );
+
+ await helper.tearDown();
+});