| ... | ... | @@ -8,37 +8,9 @@ import { |
| 8 | 8 | formatRelativeTimeLabel, |
| 9 | 9 | formatShortTimestamp, |
| 10 | 10 | getRelativeTimeState, |
| 11 | | getTimestampFormatOptions, |
| 12 | 11 | resolveTimestampLocale, |
| 13 | 12 | } from "./timestampFormat"; |
| 14 | 13 | |
| 15 | | describe("getTimestampFormatOptions", () => { |
| 16 | | it("omits hour12 when locale formatting is requested", () => { |
| 17 | | expect(getTimestampFormatOptions("locale", true)).toEqual({ |
| 18 | | hour: "numeric", |
| 19 | | minute: "2-digit", |
| 20 | | second: "2-digit", |
| 21 | | }); |
| 22 | | }); |
| 23 | | |
| 24 | | it("builds a 12-hour formatter with seconds when requested", () => { |
| 25 | | expect(getTimestampFormatOptions("12-hour", true)).toEqual({ |
| 26 | | hour: "numeric", |
| 27 | | minute: "2-digit", |
| 28 | | second: "2-digit", |
| 29 | | hour12: true, |
| 30 | | }); |
| 31 | | }); |
| 32 | | |
| 33 | | it("builds a 24-hour formatter without seconds when requested", () => { |
| 34 | | expect(getTimestampFormatOptions("24-hour", false)).toEqual({ |
| 35 | | hour: "numeric", |
| 36 | | minute: "2-digit", |
| 37 | | hour12: false, |
| 38 | | }); |
| 39 | | }); |
| 40 | | }); |
| 41 | | |
| 42 | 14 | describe("resolveTimestampLocale", () => { |
| 43 | 15 | it("defers to the runtime default when the host reports no locale", () => { |
| 44 | 16 | expect(resolveTimestampLocale(null)).toBeUndefined(); |
| ... | ... | @@ -57,19 +29,26 @@ describe("resolveTimestampLocale", () => { |
| 57 | 29 | expect(resolveTimestampLocale("not a locale")).toBeUndefined(); |
| 58 | 30 | expect(resolveTimestampLocale("en_GB")).toBeUndefined(); |
| 59 | 31 | }); |
| 32 | }); |
| 60 | 33 | |
| 61 | | it("renders the host locale's hour cycle under the locale setting", () => { |
| 62 | | const formatAt1544 = (systemLocale: string | null) => |
| 63 | | new Intl.DateTimeFormat(resolveTimestampLocale(systemLocale), { |
| 64 | | ...getTimestampFormatOptions("locale", false), |
| 65 | | timeZone: "UTC", |
| 66 | | }) |
| 67 | | .format(new Date("2026-04-07T15:44:00.000Z")) |
| 68 | | // ICU separates the day period with a narrow no-break space. |
| 69 | | .replace(/[  ]/g, " "); |
| 34 | describe("formatShortTimestamp", () => { |
| 35 | afterEach(() => { |
| 36 | vi.unstubAllGlobals(); |
| 37 | vi.resetModules(); |
| 38 | }); |
| 70 | 39 | |
| 71 | | expect(formatAt1544("en-GB")).toBe("15:44"); |
| 72 | | expect(formatAt1544("en-US")).toBe("3:44 PM"); |
| 40 | it.each([ |
| 41 | ["en-GB", "15:44"], |
| 42 | ["en-US", "3:44 PM"], |
| 43 | ])("honors %s and the explicit hour-cycle settings", async (locale, localTime) => { |
| 44 | vi.stubGlobal("window", { desktopBridge: { getSystemLocale: () => locale } }); |
| 45 | vi.resetModules(); |
| 46 | const { formatShortTimestamp: format } = await import("./timestampFormat"); |
| 47 | const date = new Date(2026, 3, 7, 15, 44).toISOString(); |
| 48 | // ICU can separate the day period with a narrow no-break space. |
| 49 | expect(format(date, "locale").replace(/[  ]/g, " ")).toBe(localTime); |
| 50 | expect(format(date, "12-hour").replace(/[  ]/g, " ")).toMatch(/^3:44 [ap]m$/i); |
| 51 | expect(format(date, "24-hour")).toBe("15:44"); |
| 73 | 52 | }); |
| 74 | 53 | }); |
| 75 | 54 | |