/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; /** * When the Previous Month button is pressed, calendar should display * the dates for the previous month. */ add_task(async function test_datepicker_prev_month_btn() { const inputValue = "2016-12-15"; const prevMonth = "2016-11-01"; await helper.openPicker( `data:text/html, ` ); // Move focus from the selected date to the Previous Month button: EventUtils.synthesizeKey("KEY_Tab", { repeat: 2 }); EventUtils.synthesizeKey(" ", {}); // 2016-11-15: const focusableDay = getDayEl(15); Assert.equal( helper.getElement(MONTH_YEAR).textContent, DATE_FORMAT(new Date(prevMonth)) ); Assert.deepEqual( getCalendarText(), [ "30", "31", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", ], "The calendar is updated to show the previous month (2016-11)" ); Assert.ok( helper.getElement(BTN_PREV_MONTH).matches(":focus"), "Focus stays on a Previous Month button after it's pressed" ); Assert.equal( focusableDay.textContent, "15", "The same day of the month is present within a calendar grid" ); Assert.equal( focusableDay, helper.getElement(DAYS_VIEW).querySelector('[tabindex="0"]'), "The same day of the month is focusable within a calendar grid" ); // Move focus from the Previous Month button to the same day of the month (2016-11-15): EventUtils.synthesizeKey("KEY_Tab", { repeat: 3 }); Assert.ok( focusableDay.matches(":focus"), "The same day of the previous month can be focused with a keyboard" ); await helper.tearDown(); }); /** * When the Next Month button is clicked, calendar should display the dates for * the next month. */ add_task(async function test_datepicker_next_month_btn() { const inputValue = "2016-12-15"; const nextMonth = "2017-01-01"; await helper.openPicker( `data:text/html, ` ); // Move focus from the selected date to the Next Month button: EventUtils.synthesizeKey("KEY_Tab", { repeat: 4 }); EventUtils.synthesizeKey(" ", {}); // 2017-01-15: const focusableDay = getDayEl(15); Assert.equal( helper.getElement(MONTH_YEAR).textContent, DATE_FORMAT(new Date(nextMonth)) ); Assert.deepEqual( getCalendarText(), [ "25", "26", "27", "28", "29", "30", "31", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "1", "2", "3", "4", ], "The calendar is updated to show the next month (2017-01)." ); Assert.ok( helper.getElement(BTN_NEXT_MONTH).matches(":focus"), "Focus stays on a Next Month button after it's pressed" ); Assert.equal( focusableDay.textContent, "15", "The same day of the month is present within a calendar grid" ); Assert.equal( focusableDay, helper.getElement(DAYS_VIEW).querySelector('[tabindex="0"]'), "The same day of the month is focusable within a calendar grid" ); // Move focus from the Next Month button to the same day of the month (2017-01-15): EventUtils.synthesizeKey("KEY_Tab", {}); Assert.ok( focusableDay.matches(":focus"), "The same day of the next month can be focused with a keyboard" ); await helper.tearDown(); }); /** * When the Previous Month button is pressed, calendar should display * the dates for the previous month on RTL build (bug 1806823). */ add_task(async function test_datepicker_prev_month_btn_rtl() { const inputValue = "2016-12-15"; const prevMonth = "2016-11-01"; await SpecialPowers.pushPrefEnv({ set: [["intl.l10n.pseudo", "bidi"]] }); await helper.openPicker( `data:text/html, ` ); // Move focus from the selected date to the Previous Month button: EventUtils.synthesizeKey("KEY_Tab", { repeat: 2 }); EventUtils.synthesizeKey(" ", {}); // 2016-11-15: const focusableDay = getDayEl(15); Assert.equal( helper.getElement(MONTH_YEAR).textContent, DATE_FORMAT(new Date(prevMonth)), "The calendar is updated to show the previous month (2016-11)" ); Assert.ok( helper.getElement(BTN_PREV_MONTH).matches(":focus"), "Focus stays on a Previous Month button after it's pressed" ); Assert.equal( focusableDay.textContent, "15", "The same day of the month is present within a calendar grid" ); Assert.equal( focusableDay, helper.getElement(DAYS_VIEW).querySelector('[tabindex="0"]'), "The same day of the month is focusable within a calendar grid" ); // Move focus from the Previous Month button to the same day of the month (2016-11-15): EventUtils.synthesizeKey("KEY_Tab", { repeat: 3 }); Assert.ok( focusableDay.matches(":focus"), "The same day of the previous month can be focused with a keyboard" ); await helper.tearDown(); await SpecialPowers.popPrefEnv(); }); /** * When the Next Month button is clicked, calendar should display the dates for * the next month on RTL build (bug 1806823). */ add_task(async function test_datepicker_next_month_btn_rtl() { const inputValue = "2016-12-15"; const nextMonth = "2017-01-01"; await SpecialPowers.pushPrefEnv({ set: [["intl.l10n.pseudo", "bidi"]] }); await helper.openPicker( `data:text/html, ` ); // Move focus from the selected date to the Next Month button: EventUtils.synthesizeKey("KEY_Tab", { repeat: 4 }); EventUtils.synthesizeKey(" ", {}); // 2017-01-15: const focusableDay = getDayEl(15); Assert.equal( helper.getElement(MONTH_YEAR).textContent, DATE_FORMAT(new Date(nextMonth)), "The calendar is updated to show the next month (2017-01)." ); Assert.ok( helper.getElement(BTN_NEXT_MONTH).matches(":focus"), "Focus stays on a Next Month button after it's pressed" ); Assert.equal( focusableDay.textContent, "15", "The same day of the month is present within a calendar grid" ); Assert.equal( focusableDay, helper.getElement(DAYS_VIEW).querySelector('[tabindex="0"]'), "The same day of the month is focusable within a calendar grid" ); // Move focus from the Next Month button to the same day of the month (2017-01-15): EventUtils.synthesizeKey("KEY_Tab", {}); Assert.ok( focusableDay.matches(":focus"), "The same day of the next month can be focused with a keyboard" ); await helper.tearDown(); await SpecialPowers.popPrefEnv(); }); /** * When Previous/Next Month buttons or arrow keys are used to change a month view * when a time value is incomplete for datetime-local inputs, * calendar should update the month (bug 1817785). */ add_task(async function test_datepicker_reopened_prev_next_month_btn() { info("Setup a datetime-local datepicker to its reopened state for testing"); let inputValueDT = "2023-05-02T01:01"; let prevMonth = new Date("2023-04-02"); await helper.openPicker( `data:text/html, ` ); let closed = helper.promisePickerClosed(); EventUtils.synthesizeKey("KEY_Escape", {}); await closed; Assert.equal( helper.panel.state, "closed", "Date picker panel should be closed" ); await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => { const input = content.document.querySelector("input"); const shadowRoot = SpecialPowers.wrap(input).openOrClosedShadowRoot; const editFields = shadowRoot.querySelectorAll(".datetime-edit-field"); const amPm = editFields[5]; amPm.focus(); Assert.ok( amPm.matches(":focus"), "Period of the day within the input is focused" ); }); // Use Backspace key to clear the value of the AM/PM section of the input // and wait for input.value to change to null (bug 1833988): await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async () => { const input = content.document.querySelector("input"); const EventUtils = ContentTaskUtils.getEventUtils(content); EventUtils.synthesizeKey("KEY_Backspace", {}, content); await ContentTaskUtils.waitForMutationCondition( input, { attributeFilter: ["value"] }, () => input.value == "" ); Assert.ok( !input.value, `Expected an input value to be changed to 'null' when a time value became incomplete, instead got ${input.value}` ); }); let ready = helper.waitForPickerReady(); // Move focus to a day section of the input and open a picker: EventUtils.synthesizeKey("KEY_Tab", {}); EventUtils.synthesizeKey(" ", {}); await ready; Assert.equal( helper.panel.querySelector("#dateTimePopupFrame").contentDocument .activeElement.textContent, "2", "Picker is opened with a focus set to the currently selected date" ); info("Test the Previous Month button behavior"); // Move focus from the selected date to the Previous Month button, // and activate it to move calendar from 2023-05-02 to 2023-04-02: EventUtils.synthesizeKey("KEY_Tab", { repeat: 2, }); EventUtils.synthesizeKey(" ", {}); // Same date of the previous month should be visible and focusable // (2023-04-02) but the focus should remain on the Previous Month button: const focusableDayPrevMonth = getDayEl(2); const monthYearEl = helper.getElement(MONTH_YEAR); await BrowserTestUtils.waitForMutationCondition( monthYearEl, { childList: true, }, () => { return monthYearEl.textContent == DATE_FORMAT(new Date(prevMonth)); }, `Should change to the previous month (April 2023), instead got ${ helper.getElement(MONTH_YEAR).textContent }` ); Assert.ok( true, `The date on both the Calendar and Month-Year button was updated when Previous Month button was used` ); Assert.ok( helper.getElement(BTN_PREV_MONTH).matches(":focus"), "Focus stays on a Previous Month button after it's pressed" ); Assert.equal( focusableDayPrevMonth, helper.getElement(DAYS_VIEW).querySelector('[tabindex="0"]'), "The same day of the month is focusable within a calendar grid" ); Assert.equal( focusableDayPrevMonth.textContent, "2", "The same day of the month is present within a calendar grid" ); // Move focus from the Previous Month button to the same day of the month (2023-04-02): EventUtils.synthesizeKey("KEY_Tab", { repeat: 3, }); Assert.ok( focusableDayPrevMonth.matches(":focus"), "The same day of the previous month can be focused with a keyboard" ); info("Test the Next Month button behavior"); // Move focus from the focused date to the Next Month button and activate it, // (from 2023-04-02 to 2023-05-02): EventUtils.synthesizeKey("KEY_Tab", { repeat: 4, }); EventUtils.synthesizeKey(" ", {}); // Same date of the next month should be visible and focusable // (2023-05-02) but the focus should remain on the Next Month button: const focusableDayNextMonth = getDayEl(2); await BrowserTestUtils.waitForMutationCondition( monthYearEl, { childList: true, }, () => { return monthYearEl.textContent == DATE_FORMAT(new Date(inputValueDT)); }, `Should change to May 2023, instead got ${ helper.getElement(MONTH_YEAR).textContent }` ); Assert.ok( true, `The date on both the Calendar and Month-Year button was updated when Next Month button was used` ); Assert.ok( helper.getElement(BTN_NEXT_MONTH).matches(":focus"), "Focus stays on a Next Month button after it's pressed" ); Assert.equal( focusableDayNextMonth, helper.getElement(DAYS_VIEW).querySelector('[tabindex="0"]'), "The same day of the month is focusable within a calendar grid" ); Assert.equal( focusableDayNextMonth.textContent, "2", "The same day of the month is present within a calendar grid" ); // Move focus from the Next Month button to the focusable day of the month (2023-05-02): EventUtils.synthesizeKey("KEY_Tab", {}); Assert.ok( focusableDayNextMonth.matches(":focus"), "The same day of the month can be focused with a keyboard" ); info("Test the arrow navigation behavior"); // Move focus from the focused date to the same weekday of the previous month, // (From 2023-05-02 to 2023-04-25): EventUtils.synthesizeKey("KEY_ArrowUp", {}); await BrowserTestUtils.waitForMutationCondition( monthYearEl, { childList: true, }, () => { return monthYearEl.textContent == DATE_FORMAT(new Date(prevMonth)); }, `Should change to the previous month, instead got ${ helper.getElement(MONTH_YEAR).textContent }` ); Assert.ok( true, `The date on both the Calendar and Month-Year button was updated when an Up Arrow key was used` ); // Move focus from the focused date to the same weekday of the next month, // (from 2023-04-25 to 2023-05-02): EventUtils.synthesizeKey("KEY_ArrowDown", {}); await BrowserTestUtils.waitForMutationCondition( monthYearEl, { childList: true, }, () => { return monthYearEl.textContent == DATE_FORMAT(new Date(inputValueDT)); }, `Should change to the previous month, instead got ${ helper.getElement(MONTH_YEAR).textContent }` ); Assert.ok( true, `The date on both the Calendar and Month-Year button was updated when a Down Arrow key was used` ); await helper.tearDown(); });