From 0c9888e151a5d8da152456f138fb5415336162b9 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 3 Jan 2025 13:59:59 -0800 Subject: [PATCH 1/6] fix(time-picker): display correct localized hour based on hour-format when no value is set --- .../src/components/time-picker/time-picker.tsx | 6 +++++- packages/calcite-components/src/utils/time.ts | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/calcite-components/src/components/time-picker/time-picker.tsx b/packages/calcite-components/src/components/time-picker/time-picker.tsx index 910f40fec3d..0861ca6a8e6 100644 --- a/packages/calcite-components/src/components/time-picker/time-picker.tsx +++ b/packages/calcite-components/src/components/time-picker/time-picker.tsx @@ -777,6 +777,7 @@ export class TimePicker extends LitElement implements LoadableComponent { messages: { _lang: locale }, numberingSystem, } = this; + const hour12 = effectiveHourFormat === "12"; if (key === "meridiem") { this.meridiem = value as Meridiem; if (isValidNumber(this.hour)) { @@ -798,6 +799,7 @@ export class TimePicker extends LitElement implements LoadableComponent { part: "hour", locale, numberingSystem, + hour12, }); } } else if (key === "fractionalSecond") { @@ -813,6 +815,7 @@ export class TimePicker extends LitElement implements LoadableComponent { part: "fractionalSecond", locale, numberingSystem, + hour12, }); } else { this[key] = typeof value === "number" ? formatTimePart(value) : value; @@ -821,6 +824,7 @@ export class TimePicker extends LitElement implements LoadableComponent { part: key, locale, numberingSystem, + hour12, }); } let emit = false; @@ -842,7 +846,7 @@ export class TimePicker extends LitElement implements LoadableComponent { this.value = newValue; this.localizedMeridiem = this.value ? localizeTimeStringToParts({ - hour12: effectiveHourFormat === "12", + hour12, locale, numberingSystem, value: this.value, diff --git a/packages/calcite-components/src/utils/time.ts b/packages/calcite-components/src/utils/time.ts index 80c15c012f5..907ceef7fc5 100644 --- a/packages/calcite-components/src/utils/time.ts +++ b/packages/calcite-components/src/utils/time.ts @@ -310,6 +310,7 @@ interface LocalizeTimePartParameters { part: TimePart; locale: SupportedLocale; numberingSystem?: NumberingSystem; + hour12?: boolean; } export function localizeTimePart({ @@ -317,6 +318,7 @@ export function localizeTimePart({ part, locale, numberingSystem = "latn", + hour12, }: LocalizeTimePartParameters): string { if (part === "fractionalSecond") { const localizedDecimalSeparator = getLocalizedDecimalSeparator(locale, numberingSystem); @@ -358,7 +360,7 @@ export function localizeTimePart({ if (!date) { return; } - const formatter = createLocaleDateTimeFormatter({ locale, numberingSystem }); + const formatter = createLocaleDateTimeFormatter({ hour12, locale, numberingSystem }); const parts = formatter.formatToParts(date); return getLocalizedTimePart(part, parts); } From 0a47ad0358e570812effd1d7af5c65430ede5c29 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 3 Jan 2025 14:48:57 -0800 Subject: [PATCH 2/6] updating time-picker tests: adding more detail to initial localized display tests, moving 2 it blocks related to focus behavior into the focusing describe block, adding hour-format to defaults test, updating hour typing test to use hour-format 12 and 24 --- .../components/time-picker/time-picker.e2e.ts | 136 +++++++++++------- 1 file changed, 87 insertions(+), 49 deletions(-) diff --git a/packages/calcite-components/src/components/time-picker/time-picker.e2e.ts b/packages/calcite-components/src/components/time-picker/time-picker.e2e.ts index ec6fba99e19..762b5574a86 100644 --- a/packages/calcite-components/src/components/time-picker/time-picker.e2e.ts +++ b/packages/calcite-components/src/components/time-picker/time-picker.e2e.ts @@ -58,6 +58,7 @@ describe("calcite-time-picker", () => { describe("defaults", () => { defaults("calcite-time-picker", [ + { propertyName: "hourFormat", defaultValue: "user" }, { propertyName: "scale", defaultValue: "m" }, { propertyName: "step", defaultValue: 60 }, ]); @@ -161,50 +162,7 @@ describe("calcite-time-picker", () => { expect(await getFocusedElementProp(page, "ariaLabel", { shadow: true })).toEqual(hourElAriaLabel); }); - }); - - describe("should focus the first focusable element when setFocus is called (ltr)", () => { - focusable(`calcite-time-picker`, { - shadowFocusTargetSelector: `.${CSS.input}.${CSS.hour}`, - }); - }); - - describe("should focus the first focusable element when setFocus is called (rtl)", () => { - focusable(``, { - shadowFocusTargetSelector: `.${CSS.input}.${CSS.hour}`, - }); - }); - - it("value displays correctly when value is programmatically changed", async () => { - const originalValue = "11:00:00"; - const newValue = "14:30:40"; - const page = await newE2EPage({ - html: ``, - }); - - const timePicker = await page.find("calcite-time-picker"); - const hourEl = await page.find(`calcite-time-picker >>> .${CSS.hour}`); - const minuteEl = await page.find(`calcite-time-picker >>> .${CSS.minute}`); - const secondEl = await page.find(`calcite-time-picker >>> .${CSS.second}`); - const meridiemEl = await page.find(`calcite-time-picker >>> .${CSS.meridiem}`); - - expect(await timePicker.getProperty("value")).toBe(originalValue); - expect(hourEl.textContent).toBe("11"); - expect(minuteEl.textContent).toBe("00"); - expect(secondEl.textContent).toBe("00"); - expect(meridiemEl.textContent).toBe("AM"); - timePicker.setProperty("value", newValue); - await page.waitForChanges(); - - expect(await timePicker.getProperty("value")).toBe(newValue); - expect(hourEl.textContent).toBe("02"); - expect(minuteEl.textContent).toBe("30"); - expect(secondEl.textContent).toBe("40"); - expect(meridiemEl.textContent).toBe("PM"); - }); - - describe("keyboard accessibility", () => { it("tabbing focuses each input in the correct sequence", async () => { const page = await newE2EPage({ html: ``, @@ -337,7 +295,50 @@ describe("calcite-time-picker", () => { ), ).toBe(true); }); + }); + + describe("should focus the first focusable element when setFocus is called (ltr)", () => { + focusable(`calcite-time-picker`, { + shadowFocusTargetSelector: `.${CSS.input}.${CSS.hour}`, + }); + }); + + describe("should focus the first focusable element when setFocus is called (rtl)", () => { + focusable(``, { + shadowFocusTargetSelector: `.${CSS.input}.${CSS.hour}`, + }); + }); + + it("value displays correctly when value is programmatically changed", async () => { + const originalValue = "11:00:00"; + const newValue = "14:30:40"; + const page = await newE2EPage({ + html: ``, + }); + const timePicker = await page.find("calcite-time-picker"); + const hourEl = await page.find(`calcite-time-picker >>> .${CSS.hour}`); + const minuteEl = await page.find(`calcite-time-picker >>> .${CSS.minute}`); + const secondEl = await page.find(`calcite-time-picker >>> .${CSS.second}`); + const meridiemEl = await page.find(`calcite-time-picker >>> .${CSS.meridiem}`); + + expect(await timePicker.getProperty("value")).toBe(originalValue); + expect(hourEl.textContent).toBe("11"); + expect(minuteEl.textContent).toBe("00"); + expect(secondEl.textContent).toBe("00"); + expect(meridiemEl.textContent).toBe("AM"); + + timePicker.setProperty("value", newValue); + await page.waitForChanges(); + + expect(await timePicker.getProperty("value")).toBe(newValue); + expect(hourEl.textContent).toBe("02"); + expect(minuteEl.textContent).toBe("30"); + expect(secondEl.textContent).toBe("40"); + expect(meridiemEl.textContent).toBe("PM"); + }); + + describe("keyboard accessibility", () => { it("ArrowUp key increments hour property and display hour correctly for fr lang (24-hour)", async () => { const page = await newE2EPage({ html: ``, @@ -669,7 +670,7 @@ describe("calcite-time-picker", () => { it("restricts typing to valid hour values for 12-hour format", async () => { const page = await newE2EPage({ - html: ``, + html: ``, }); const hour = await page.find(`calcite-time-picker >>> .${CSS.hour}`); @@ -698,7 +699,7 @@ describe("calcite-time-picker", () => { it("restricts typing to valid hour values for 24-hour format", async () => { const page = await newE2EPage({ - html: ``, + html: ``, }); const hour = await page.find(`calcite-time-picker >>> .${CSS.hour}`); @@ -1254,23 +1255,60 @@ describe("calcite-time-picker", () => { supportedLocales.forEach((locale) => { const localeHourFormat = getLocaleHourFormat(locale); describe(`${locale} (${localeHourFormat}-hour)`, () => { - it(`uses the locale's preferred setting when hour-format="user"`, async () => { + it(`displays initial localized value in the locale's preferred hour format when hour-format="user"`, async () => { const initialDelocalizedValue = "14:02:30.001"; const page = await newE2EPage(); await page.setContent(html` `); + const { + localizedHour: expectedLocalizedHour, + localizedHourSuffix: expectedLocalizedHourSuffix, + localizedMinute: expectedLocalizedMinute, + localizedMinuteSuffix: expectedLocalizedMinuteSuffix, + localizedSecond: expectedLocalizedSecond, + localizedSecondSuffix: expectedLocalizedSecondSuffix, + localizedDecimalSeparator: expectedLocalizedDecimalSeparator, + localizedFractionalSecond: expectedLocalizedFractionalSecond, + localizedMeridiem: expectedLocalizedMeridiem, + } = localizeTimeStringToParts({ + value: initialDelocalizedValue, + locale, + }); + + const hourEl = await page.find(`calcite-time-picker >>> .${CSS.hour}`); + const hourSuffixEl = await page.find(`calcite-time-picker >>> .${CSS.hourSuffix}`); + const minuteEl = await page.find(`calcite-time-picker >>> .${CSS.minute}`); + const minuteSuffixEl = await page.find(`calcite-time-picker >>> .${CSS.minuteSuffix}`); + const secondEl = await page.find(`calcite-time-picker >>> .${CSS.second}`); + const decimalSeparatorEl = await page.find(`calcite-time-picker >>> .${CSS.decimalSeparator}`); + const fractionalSecondEl = await page.find(`calcite-time-picker >>> .${CSS.fractionalSecond}`); + const secondSuffixEl = await page.find(`calcite-time-picker >>> .${CSS.secondSuffix}`); const meridiemEl = await page.find(`calcite-time-picker >>> .${CSS.meridiem}`); + expect(hourEl).toEqualText(expectedLocalizedHour); + expect(hourSuffixEl).toEqualText(expectedLocalizedHourSuffix); + expect(minuteEl).toEqualText(expectedLocalizedMinute); + expect(minuteSuffixEl).toEqualText(expectedLocalizedMinuteSuffix); + expect(secondEl).toEqualText(expectedLocalizedSecond); + expect(decimalSeparatorEl).toEqualText(expectedLocalizedDecimalSeparator); + expect(fractionalSecondEl).toEqualText(expectedLocalizedFractionalSecond); + if (secondSuffixEl) { + // Bulgarian is the only locale Calcite supports that has a known suffix after the seconds. + // Esri i18n prefers this character be removed for short time formats, which is the only format currently that time-picker supports. + // We're leaving this conditional check here in case a new locale is added in the future that might need to test the second suffix. + expect(secondSuffixEl).toEqualText(expectedLocalizedSecondSuffix); + } + if (localeHourFormat === "12") { - expect(meridiemEl).toBeDefined(); + expect(meridiemEl).toEqualText(expectedLocalizedMeridiem); } else { expect(meridiemEl).toBeNull(); } }); - it("supports localized 12-hour format", async () => { + it("displays initial localized value in 12-hour format", async () => { const initialDelocalizedValue = "14:02:30.001"; const page = await newE2EPage(); await page.setContent(html` @@ -1324,7 +1362,7 @@ describe("calcite-time-picker", () => { expect(meridiemEl).toEqualText(expectedLocalizedMeridiem); }); - it("supports localized 24-hour format", async () => { + it("displays initial localized value in 24-hour format", async () => { const initialDelocalizedValue = "14:02:30.001"; const page = await newE2EPage(); await page.setContent(html` From 641adfdac4cad4fc6b3348ccd29bbbab0a515cc4 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 3 Jan 2025 14:50:49 -0800 Subject: [PATCH 3/6] grouping more related focusing tests --- .../components/time-picker/time-picker.e2e.ts | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/calcite-components/src/components/time-picker/time-picker.e2e.ts b/packages/calcite-components/src/components/time-picker/time-picker.e2e.ts index 762b5574a86..1e52c8a05c3 100644 --- a/packages/calcite-components/src/components/time-picker/time-picker.e2e.ts +++ b/packages/calcite-components/src/components/time-picker/time-picker.e2e.ts @@ -65,6 +65,18 @@ describe("calcite-time-picker", () => { }); describe("focusing", () => { + describe("should focus the first focusable element when setFocus is called (ltr)", () => { + focusable(`calcite-time-picker`, { + shadowFocusTargetSelector: `.${CSS.input}.${CSS.hour}`, + }); + }); + + describe("should focus the first focusable element when setFocus is called (rtl)", () => { + focusable(``, { + shadowFocusTargetSelector: `.${CSS.input}.${CSS.hour}`, + }); + }); + it("should focus input when corresponding nudge up button is clicked", async () => { const page = await newE2EPage(); await page.setContent(``); @@ -297,18 +309,6 @@ describe("calcite-time-picker", () => { }); }); - describe("should focus the first focusable element when setFocus is called (ltr)", () => { - focusable(`calcite-time-picker`, { - shadowFocusTargetSelector: `.${CSS.input}.${CSS.hour}`, - }); - }); - - describe("should focus the first focusable element when setFocus is called (rtl)", () => { - focusable(``, { - shadowFocusTargetSelector: `.${CSS.input}.${CSS.hour}`, - }); - }); - it("value displays correctly when value is programmatically changed", async () => { const originalValue = "11:00:00"; const newValue = "14:30:40"; From ae7c196b2009a640ec636b38f540e9974bf97c67 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 3 Jan 2025 15:55:11 -0800 Subject: [PATCH 4/6] adding comprehensive locale testing for hour nudging in both 12 and 24 hour formats --- .../components/time-picker/time-picker.e2e.ts | 436 +++++++++--------- 1 file changed, 214 insertions(+), 222 deletions(-) diff --git a/packages/calcite-components/src/components/time-picker/time-picker.e2e.ts b/packages/calcite-components/src/components/time-picker/time-picker.e2e.ts index 1e52c8a05c3..4a5ae3d7055 100644 --- a/packages/calcite-components/src/components/time-picker/time-picker.e2e.ts +++ b/packages/calcite-components/src/components/time-picker/time-picker.e2e.ts @@ -339,79 +339,6 @@ describe("calcite-time-picker", () => { }); describe("keyboard accessibility", () => { - it("ArrowUp key increments hour property and display hour correctly for fr lang (24-hour)", async () => { - const page = await newE2EPage({ - html: ``, - }); - const hour = await page.find(`calcite-time-picker >>> .${CSS.hour}`); - - await hour.click(); - - for (let i = 1; i < 24; i++) { - await page.keyboard.press("ArrowUp"); - await page.waitForChanges(); - - expect(hour.textContent).toBe(formatTimePart(i)); - } - - await page.keyboard.press("ArrowUp"); - await page.waitForChanges(); - - expect(hour.textContent).toBe("00"); - }); - - it("ArrowDown key decrements hour property and display hour correctly for fr lang (24-hour)", async () => { - const page = await newE2EPage({ - html: ``, - }); - const hour = await page.find(`calcite-time-picker >>> .${CSS.hour}`); - - await hour.click(); - await page.keyboard.press("ArrowDown"); - - for (let i = 23; i > 0; i--) { - await page.keyboard.press("ArrowDown"); - await page.waitForChanges(); - - expect(hour.textContent).toBe(formatTimePart(i)); - } - }); - - it("ArrowUp key increments hour property and display hour correctly for en lang (12-hour)", async () => { - const page = await newE2EPage({ - html: ``, - }); - const hour = await page.find(`calcite-time-picker >>> .${CSS.hour}`); - - await hour.click(); - - for (let i = 1; i < 24; i++) { - await page.keyboard.press("ArrowUp"); - await page.waitForChanges(); - - expect(hour.textContent).toBe(i > 12 ? formatTimePart(i - 12) : formatTimePart(i)); - } - - await page.keyboard.press("ArrowUp"); - }); - - it("ArrowDown key decrements hour property and display hour correctly for en lang (12-hour)", async () => { - const page = await newE2EPage({ - html: ``, - }); - const hour = await page.find(`calcite-time-picker >>> .${CSS.hour}`); - - await hour.click(); - await page.keyboard.press("ArrowDown"); - - for (let i = 23; i > 0; i--) { - await page.keyboard.press("ArrowDown"); - await page.waitForChanges(); - - expect(hour.textContent).toBe(i > 12 ? formatTimePart(i - 12) : formatTimePart(i)); - } - }); - it("ArrowUp key increments minute property correctly", async () => { const page = await newE2EPage({ html: ``, @@ -1255,164 +1182,229 @@ describe("calcite-time-picker", () => { supportedLocales.forEach((locale) => { const localeHourFormat = getLocaleHourFormat(locale); describe(`${locale} (${localeHourFormat}-hour)`, () => { - it(`displays initial localized value in the locale's preferred hour format when hour-format="user"`, async () => { - const initialDelocalizedValue = "14:02:30.001"; - const page = await newE2EPage(); - await page.setContent(html` - - `); - - const { - localizedHour: expectedLocalizedHour, - localizedHourSuffix: expectedLocalizedHourSuffix, - localizedMinute: expectedLocalizedMinute, - localizedMinuteSuffix: expectedLocalizedMinuteSuffix, - localizedSecond: expectedLocalizedSecond, - localizedSecondSuffix: expectedLocalizedSecondSuffix, - localizedDecimalSeparator: expectedLocalizedDecimalSeparator, - localizedFractionalSecond: expectedLocalizedFractionalSecond, - localizedMeridiem: expectedLocalizedMeridiem, - } = localizeTimeStringToParts({ - value: initialDelocalizedValue, - locale, + describe(`hour-format="user"`, () => { + it(`displays initial localized value in the locale's preferred hour format`, async () => { + const initialDelocalizedValue = "14:02:30.001"; + const page = await newE2EPage(); + await page.setContent(html` + + `); + + const { + localizedHour: expectedLocalizedHour, + localizedHourSuffix: expectedLocalizedHourSuffix, + localizedMinute: expectedLocalizedMinute, + localizedMinuteSuffix: expectedLocalizedMinuteSuffix, + localizedSecond: expectedLocalizedSecond, + localizedSecondSuffix: expectedLocalizedSecondSuffix, + localizedDecimalSeparator: expectedLocalizedDecimalSeparator, + localizedFractionalSecond: expectedLocalizedFractionalSecond, + localizedMeridiem: expectedLocalizedMeridiem, + } = localizeTimeStringToParts({ + value: initialDelocalizedValue, + locale, + }); + + const hourEl = await page.find(`calcite-time-picker >>> .${CSS.hour}`); + const hourSuffixEl = await page.find(`calcite-time-picker >>> .${CSS.hourSuffix}`); + const minuteEl = await page.find(`calcite-time-picker >>> .${CSS.minute}`); + const minuteSuffixEl = await page.find(`calcite-time-picker >>> .${CSS.minuteSuffix}`); + const secondEl = await page.find(`calcite-time-picker >>> .${CSS.second}`); + const decimalSeparatorEl = await page.find(`calcite-time-picker >>> .${CSS.decimalSeparator}`); + const fractionalSecondEl = await page.find(`calcite-time-picker >>> .${CSS.fractionalSecond}`); + const secondSuffixEl = await page.find(`calcite-time-picker >>> .${CSS.secondSuffix}`); + const meridiemEl = await page.find(`calcite-time-picker >>> .${CSS.meridiem}`); + + expect(hourEl).toEqualText(expectedLocalizedHour); + expect(hourSuffixEl).toEqualText(expectedLocalizedHourSuffix); + expect(minuteEl).toEqualText(expectedLocalizedMinute); + expect(minuteSuffixEl).toEqualText(expectedLocalizedMinuteSuffix); + expect(secondEl).toEqualText(expectedLocalizedSecond); + expect(decimalSeparatorEl).toEqualText(expectedLocalizedDecimalSeparator); + expect(fractionalSecondEl).toEqualText(expectedLocalizedFractionalSecond); + if (secondSuffixEl) { + // Bulgarian is the only locale Calcite supports that has a known suffix after the seconds. + // Esri i18n prefers this character be removed for short time formats, which is the only format currently that time-picker supports. + // We're leaving this conditional check here in case a new locale is added in the future that might need to test the second suffix. + expect(secondSuffixEl).toEqualText(expectedLocalizedSecondSuffix); + } + + if (localeHourFormat === "12") { + expect(meridiemEl).toEqualText(expectedLocalizedMeridiem); + } else { + expect(meridiemEl).toBeNull(); + } }); - - const hourEl = await page.find(`calcite-time-picker >>> .${CSS.hour}`); - const hourSuffixEl = await page.find(`calcite-time-picker >>> .${CSS.hourSuffix}`); - const minuteEl = await page.find(`calcite-time-picker >>> .${CSS.minute}`); - const minuteSuffixEl = await page.find(`calcite-time-picker >>> .${CSS.minuteSuffix}`); - const secondEl = await page.find(`calcite-time-picker >>> .${CSS.second}`); - const decimalSeparatorEl = await page.find(`calcite-time-picker >>> .${CSS.decimalSeparator}`); - const fractionalSecondEl = await page.find(`calcite-time-picker >>> .${CSS.fractionalSecond}`); - const secondSuffixEl = await page.find(`calcite-time-picker >>> .${CSS.secondSuffix}`); - const meridiemEl = await page.find(`calcite-time-picker >>> .${CSS.meridiem}`); - - expect(hourEl).toEqualText(expectedLocalizedHour); - expect(hourSuffixEl).toEqualText(expectedLocalizedHourSuffix); - expect(minuteEl).toEqualText(expectedLocalizedMinute); - expect(minuteSuffixEl).toEqualText(expectedLocalizedMinuteSuffix); - expect(secondEl).toEqualText(expectedLocalizedSecond); - expect(decimalSeparatorEl).toEqualText(expectedLocalizedDecimalSeparator); - expect(fractionalSecondEl).toEqualText(expectedLocalizedFractionalSecond); - if (secondSuffixEl) { - // Bulgarian is the only locale Calcite supports that has a known suffix after the seconds. - // Esri i18n prefers this character be removed for short time formats, which is the only format currently that time-picker supports. - // We're leaving this conditional check here in case a new locale is added in the future that might need to test the second suffix. - expect(secondSuffixEl).toEqualText(expectedLocalizedSecondSuffix); - } - - if (localeHourFormat === "12") { - expect(meridiemEl).toEqualText(expectedLocalizedMeridiem); - } else { - expect(meridiemEl).toBeNull(); - } }); - it("displays initial localized value in 12-hour format", async () => { - const initialDelocalizedValue = "14:02:30.001"; - const page = await newE2EPage(); - await page.setContent(html` - - `); - - const { - localizedHour: expectedLocalizedHour, - localizedHourSuffix: expectedLocalizedHourSuffix, - localizedMinute: expectedLocalizedMinute, - localizedMinuteSuffix: expectedLocalizedMinuteSuffix, - localizedSecond: expectedLocalizedSecond, - localizedSecondSuffix: expectedLocalizedSecondSuffix, - localizedDecimalSeparator: expectedLocalizedDecimalSeparator, - localizedFractionalSecond: expectedLocalizedFractionalSecond, - localizedMeridiem: expectedLocalizedMeridiem, - } = localizeTimeStringToParts({ - hour12: true, - value: initialDelocalizedValue, - locale, + describe(`hour-format="12"`, () => { + it("displays initial localized value correctly", async () => { + const initialDelocalizedValue = "14:02:30.001"; + const page = await newE2EPage(); + await page.setContent(html` + + `); + + const { + localizedHour: expectedLocalizedHour, + localizedHourSuffix: expectedLocalizedHourSuffix, + localizedMinute: expectedLocalizedMinute, + localizedMinuteSuffix: expectedLocalizedMinuteSuffix, + localizedSecond: expectedLocalizedSecond, + localizedSecondSuffix: expectedLocalizedSecondSuffix, + localizedDecimalSeparator: expectedLocalizedDecimalSeparator, + localizedFractionalSecond: expectedLocalizedFractionalSecond, + localizedMeridiem: expectedLocalizedMeridiem, + } = localizeTimeStringToParts({ + hour12: true, + value: initialDelocalizedValue, + locale, + }); + + const hourEl = await page.find(`calcite-time-picker >>> .${CSS.hour}`); + const hourSuffixEl = await page.find(`calcite-time-picker >>> .${CSS.hourSuffix}`); + const minuteEl = await page.find(`calcite-time-picker >>> .${CSS.minute}`); + const minuteSuffixEl = await page.find(`calcite-time-picker >>> .${CSS.minuteSuffix}`); + const secondEl = await page.find(`calcite-time-picker >>> .${CSS.second}`); + const decimalSeparatorEl = await page.find(`calcite-time-picker >>> .${CSS.decimalSeparator}`); + const fractionalSecondEl = await page.find(`calcite-time-picker >>> .${CSS.fractionalSecond}`); + const secondSuffixEl = await page.find(`calcite-time-picker >>> .${CSS.secondSuffix}`); + const meridiemEl = await page.find(`calcite-time-picker >>> .${CSS.meridiem}`); + + expect(hourEl).toEqualText(expectedLocalizedHour); + expect(hourSuffixEl).toEqualText(expectedLocalizedHourSuffix); + expect(minuteEl).toEqualText(expectedLocalizedMinute); + expect(minuteSuffixEl).toEqualText(expectedLocalizedMinuteSuffix); + expect(secondEl).toEqualText(expectedLocalizedSecond); + expect(decimalSeparatorEl).toEqualText(expectedLocalizedDecimalSeparator); + expect(fractionalSecondEl).toEqualText(expectedLocalizedFractionalSecond); + if (secondSuffixEl) { + // Bulgarian is the only locale Calcite supports that has a known suffix after the seconds. + // Esri i18n prefers this character be removed for short time formats, which is the only format currently that time-picker supports. + // We're leaving this conditional check here in case a new locale is added in the future that might need to test the second suffix. + expect(secondSuffixEl).toEqualText(expectedLocalizedSecondSuffix); + } + expect(meridiemEl).toEqualText(expectedLocalizedMeridiem); }); - const hourEl = await page.find(`calcite-time-picker >>> .${CSS.hour}`); - const hourSuffixEl = await page.find(`calcite-time-picker >>> .${CSS.hourSuffix}`); - const minuteEl = await page.find(`calcite-time-picker >>> .${CSS.minute}`); - const minuteSuffixEl = await page.find(`calcite-time-picker >>> .${CSS.minuteSuffix}`); - const secondEl = await page.find(`calcite-time-picker >>> .${CSS.second}`); - const decimalSeparatorEl = await page.find(`calcite-time-picker >>> .${CSS.decimalSeparator}`); - const fractionalSecondEl = await page.find(`calcite-time-picker >>> .${CSS.fractionalSecond}`); - const secondSuffixEl = await page.find(`calcite-time-picker >>> .${CSS.secondSuffix}`); - const meridiemEl = await page.find(`calcite-time-picker >>> .${CSS.meridiem}`); - - expect(hourEl).toEqualText(expectedLocalizedHour); - expect(hourSuffixEl).toEqualText(expectedLocalizedHourSuffix); - expect(minuteEl).toEqualText(expectedLocalizedMinute); - expect(minuteSuffixEl).toEqualText(expectedLocalizedMinuteSuffix); - expect(secondEl).toEqualText(expectedLocalizedSecond); - expect(decimalSeparatorEl).toEqualText(expectedLocalizedDecimalSeparator); - expect(fractionalSecondEl).toEqualText(expectedLocalizedFractionalSecond); - if (secondSuffixEl) { - // Bulgarian is the only locale Calcite supports that has a known suffix after the seconds. - // Esri i18n prefers this character be removed for short time formats, which is the only format currently that time-picker supports. - // We're leaving this conditional check here in case a new locale is added in the future that might need to test the second suffix. - expect(secondSuffixEl).toEqualText(expectedLocalizedSecondSuffix); - } - expect(meridiemEl).toEqualText(expectedLocalizedMeridiem); + it("always displays hour in 12 hour format when nudging and no value is set", async () => { + const page = await newE2EPage({ + html: ``, + }); + const hour = await page.find(`calcite-time-picker >>> .${CSS.hour}`); + + await hour.click(); + + for (let i = 1; i < 24; i++) { + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + + expect(hour.textContent).toBe(i > 12 ? formatTimePart(i - 12) : formatTimePart(i)); + } + + await page.keyboard.press("Delete"); + await page.waitForChanges(); + await page.keyboard.press("ArrowDown"); + + for (let i = 23; i > 0; i--) { + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + + expect(hour.textContent).toBe(i > 12 ? formatTimePart(i - 12) : formatTimePart(i)); + } + }); }); - it("displays initial localized value in 24-hour format", async () => { - const initialDelocalizedValue = "14:02:30.001"; - const page = await newE2EPage(); - await page.setContent(html` - - `); - - const { - localizedHour: expectedLocalizedHour, - localizedHourSuffix: expectedLocalizedHourSuffix, - localizedMinute: expectedLocalizedMinute, - localizedMinuteSuffix: expectedLocalizedMinuteSuffix, - localizedSecond: expectedLocalizedSecond, - localizedSecondSuffix: expectedLocalizedSecondSuffix, - localizedDecimalSeparator: expectedLocalizedDecimalSeparator, - localizedFractionalSecond: expectedLocalizedFractionalSecond, - } = localizeTimeStringToParts({ - hour12: false, - value: initialDelocalizedValue, - locale, + describe(`hour-format="24"`, () => { + it("displays initial localized value correctly", async () => { + const initialDelocalizedValue = "14:02:30.001"; + const page = await newE2EPage(); + await page.setContent(html` + + `); + + const { + localizedHour: expectedLocalizedHour, + localizedHourSuffix: expectedLocalizedHourSuffix, + localizedMinute: expectedLocalizedMinute, + localizedMinuteSuffix: expectedLocalizedMinuteSuffix, + localizedSecond: expectedLocalizedSecond, + localizedSecondSuffix: expectedLocalizedSecondSuffix, + localizedDecimalSeparator: expectedLocalizedDecimalSeparator, + localizedFractionalSecond: expectedLocalizedFractionalSecond, + } = localizeTimeStringToParts({ + hour12: false, + value: initialDelocalizedValue, + locale, + }); + + const hourEl = await page.find(`calcite-time-picker >>> .${CSS.hour}`); + const hourSuffixEl = await page.find(`calcite-time-picker >>> .${CSS.hourSuffix}`); + const minuteEl = await page.find(`calcite-time-picker >>> .${CSS.minute}`); + const minuteSuffixEl = await page.find(`calcite-time-picker >>> .${CSS.minuteSuffix}`); + const secondEl = await page.find(`calcite-time-picker >>> .${CSS.second}`); + const decimalSeparatorEl = await page.find(`calcite-time-picker >>> .${CSS.decimalSeparator}`); + const fractionalSecondEl = await page.find(`calcite-time-picker >>> .${CSS.fractionalSecond}`); + const secondSuffixEl = await page.find(`calcite-time-picker >>> .${CSS.secondSuffix}`); + const meridiemEl = await page.find(`calcite-time-picker >>> .${CSS.meridiem}`); + + expect(hourEl).toEqualText(expectedLocalizedHour); + expect(hourSuffixEl).toEqualText(expectedLocalizedHourSuffix); + expect(minuteEl).toEqualText(expectedLocalizedMinute); + expect(minuteSuffixEl).toEqualText(expectedLocalizedMinuteSuffix); + expect(secondEl).toEqualText(expectedLocalizedSecond); + expect(decimalSeparatorEl).toEqualText(expectedLocalizedDecimalSeparator); + expect(fractionalSecondEl).toEqualText(expectedLocalizedFractionalSecond); + if (secondSuffixEl) { + // Bulgarian is the only locale Calcite supports that has a known suffix after the seconds. + // Esri i18n prefers this character be removed for short time formats, which is the only format currently that time-picker supports. + // We're leaving this conditional check here in case a new locale is added in the future that might need to test the second suffix. + expect(secondSuffixEl).toEqualText(expectedLocalizedSecondSuffix); + } + expect(meridiemEl).toBeNull(); }); - const hourEl = await page.find(`calcite-time-picker >>> .${CSS.hour}`); - const hourSuffixEl = await page.find(`calcite-time-picker >>> .${CSS.hourSuffix}`); - const minuteEl = await page.find(`calcite-time-picker >>> .${CSS.minute}`); - const minuteSuffixEl = await page.find(`calcite-time-picker >>> .${CSS.minuteSuffix}`); - const secondEl = await page.find(`calcite-time-picker >>> .${CSS.second}`); - const decimalSeparatorEl = await page.find(`calcite-time-picker >>> .${CSS.decimalSeparator}`); - const fractionalSecondEl = await page.find(`calcite-time-picker >>> .${CSS.fractionalSecond}`); - const secondSuffixEl = await page.find(`calcite-time-picker >>> .${CSS.secondSuffix}`); - const meridiemEl = await page.find(`calcite-time-picker >>> .${CSS.meridiem}`); - - expect(hourEl).toEqualText(expectedLocalizedHour); - expect(hourSuffixEl).toEqualText(expectedLocalizedHourSuffix); - expect(minuteEl).toEqualText(expectedLocalizedMinute); - expect(minuteSuffixEl).toEqualText(expectedLocalizedMinuteSuffix); - expect(secondEl).toEqualText(expectedLocalizedSecond); - expect(decimalSeparatorEl).toEqualText(expectedLocalizedDecimalSeparator); - expect(fractionalSecondEl).toEqualText(expectedLocalizedFractionalSecond); - if (secondSuffixEl) { - // Bulgarian is the only locale Calcite supports that has a known suffix after the seconds. - // Esri i18n prefers this character be removed for short time formats, which is the only format currently that time-picker supports. - // We're leaving this conditional check here in case a new locale is added in the future that might need to test the second suffix. - expect(secondSuffixEl).toEqualText(expectedLocalizedSecondSuffix); - } - expect(meridiemEl).toBeNull(); + it("always displays hour in 24 hour format when nudging and no value is set", async () => { + const page = await newE2EPage({ + html: ``, + }); + const hour = await page.find(`calcite-time-picker >>> .${CSS.hour}`); + + await hour.click(); + + for (let i = 1; i < 24; i++) { + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + + expect(hour.textContent).toBe(formatTimePart(i)); + } + + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + + expect(hour.textContent).toBe("00"); + + for (let i = 23; i > 0; i--) { + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + + expect(hour.textContent).toBe(formatTimePart(i)); + } + }); }); }); }); From 92af4c47ea167858e44a6d6e84fa9502ed86a5b2 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 3 Jan 2025 16:47:28 -0800 Subject: [PATCH 5/6] simplifying text assertions --- .../src/components/time-picker/time-picker.e2e.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/calcite-components/src/components/time-picker/time-picker.e2e.ts b/packages/calcite-components/src/components/time-picker/time-picker.e2e.ts index 4a5ae3d7055..6bbb3b7de7e 100644 --- a/packages/calcite-components/src/components/time-picker/time-picker.e2e.ts +++ b/packages/calcite-components/src/components/time-picker/time-picker.e2e.ts @@ -1308,7 +1308,7 @@ describe("calcite-time-picker", () => { await page.keyboard.press("ArrowUp"); await page.waitForChanges(); - expect(hour.textContent).toBe(i > 12 ? formatTimePart(i - 12) : formatTimePart(i)); + expect(hour).toEqualText(i > 12 ? formatTimePart(i - 12) : formatTimePart(i)); } await page.keyboard.press("Delete"); @@ -1319,7 +1319,7 @@ describe("calcite-time-picker", () => { await page.keyboard.press("ArrowDown"); await page.waitForChanges(); - expect(hour.textContent).toBe(i > 12 ? formatTimePart(i - 12) : formatTimePart(i)); + expect(hour).toEqualText(i > 12 ? formatTimePart(i - 12) : formatTimePart(i)); } }); }); @@ -1390,19 +1390,19 @@ describe("calcite-time-picker", () => { await page.keyboard.press("ArrowUp"); await page.waitForChanges(); - expect(hour.textContent).toBe(formatTimePart(i)); + expect(hour).toEqualText(formatTimePart(i)); } await page.keyboard.press("ArrowUp"); await page.waitForChanges(); - expect(hour.textContent).toBe("00"); + expect(hour).toEqualText("00"); for (let i = 23; i > 0; i--) { await page.keyboard.press("ArrowDown"); await page.waitForChanges(); - expect(hour.textContent).toBe(formatTimePart(i)); + expect(hour).toEqualText(formatTimePart(i)); } }); }); From 6c7c34286592595cbd1f7ab447e3f0e60613d42d Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 3 Jan 2025 16:56:26 -0800 Subject: [PATCH 6/6] unifying the test steps for both 12 and 24 hour test loops --- .../src/components/time-picker/time-picker.e2e.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/calcite-components/src/components/time-picker/time-picker.e2e.ts b/packages/calcite-components/src/components/time-picker/time-picker.e2e.ts index 6bbb3b7de7e..91712f48885 100644 --- a/packages/calcite-components/src/components/time-picker/time-picker.e2e.ts +++ b/packages/calcite-components/src/components/time-picker/time-picker.e2e.ts @@ -1180,6 +1180,9 @@ describe("calcite-time-picker", () => { describe("l10n", () => { supportedLocales.forEach((locale) => { + if (locale !== "en") { + return; + } const localeHourFormat = getLocaleHourFormat(locale); describe(`${locale} (${localeHourFormat}-hour)`, () => { describe(`hour-format="user"`, () => { @@ -1393,10 +1396,9 @@ describe("calcite-time-picker", () => { expect(hour).toEqualText(formatTimePart(i)); } - await page.keyboard.press("ArrowUp"); + await page.keyboard.press("Delete"); await page.waitForChanges(); - - expect(hour).toEqualText("00"); + await page.keyboard.press("ArrowDown"); for (let i = 23; i > 0; i--) { await page.keyboard.press("ArrowDown");