From 36755884e45975ee6ae0a5dba5581dacced5ce45 Mon Sep 17 00:00:00 2001 From: latin-panda <66472237+latin-panda@users.noreply.github.com> Date: Wed, 5 Mar 2025 00:05:11 -0800 Subject: [PATCH 1/3] Set timezone for xpath unit tests --- packages/xpath/test/setup.ts | 42 ++++++++++++++++++++++++++ packages/xpath/test/xforms/now.test.ts | 2 -- packages/xpath/vite.config.ts | 17 +++++++++-- 3 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 packages/xpath/test/setup.ts diff --git a/packages/xpath/test/setup.ts b/packages/xpath/test/setup.ts new file mode 100644 index 000000000..315fa9032 --- /dev/null +++ b/packages/xpath/test/setup.ts @@ -0,0 +1,42 @@ +import { afterEach, beforeEach } from 'vitest'; +import { vi } from 'vitest'; + +/** + * Global constants injected via Vite's `define` configuration option. + * These values are replaced at build time and are available throughout + * the test suite. + * + * @global + */ +declare global { + /** + * The timezone identifier used for all date and time operations in tests. + * This string follows the IANA Time Zone Database format (e.g., 'America/Phoenix'). + * It determines the offset and DST behavior for `Date` objects and + * related functions. + * + * @example 'America/Phoenix' // Fixed UTC-7, no DST + * @example 'Europe/London' // UTC+0 (GMT) or UTC+1 (BST) with DST + */ + const TZ: string; + + /** + * The locale string defining the language and regional formatting for tests. + * This follows the BCP 47 language tag format (e.g., 'en-US'). It ensures consistent formatting + * across tests. + * + * @example 'en-US' // American English + */ + const locale: string; +} + +beforeEach(() => { + const dateOnTimezone = new Date().toLocaleString(locale, { timeZone: TZ }); + vi.useFakeTimers({ + now: new Date(dateOnTimezone).getTime(), + }); +}); + +afterEach(() => { + vi.useRealTimers(); +}); diff --git a/packages/xpath/test/xforms/now.test.ts b/packages/xpath/test/xforms/now.test.ts index ccc251f1f..3454c0645 100644 --- a/packages/xpath/test/xforms/now.test.ts +++ b/packages/xpath/test/xforms/now.test.ts @@ -14,8 +14,6 @@ describe('#now()', () => { // > including timezone offset (i.e. not normalized to UTC) as described // > under the dateTime datatype. it('should return a timestamp for this instant', () => { - // this check might fail if run at precisely midnight ;-) - // given const now = new Date(); const today = `${now.getFullYear()}-${(1 + now.getMonth()).toString().padStart(2, '0')}-${now diff --git a/packages/xpath/vite.config.ts b/packages/xpath/vite.config.ts index bc0aa8f29..bb6194f62 100644 --- a/packages/xpath/vite.config.ts +++ b/packages/xpath/vite.config.ts @@ -44,13 +44,25 @@ const TEST_ENVIRONMENT = BROWSER_ENABLED ? 'node' : 'jsdom'; */ const TEST_TIME_ZONE = 'America/Phoenix'; +/** + * The locale used for formatting dates and times in all test cases. + * This ensures consistent language and regional settings across tests. + * Currently set to 'en-US' (American English), which affects date formats + * (e.g., MM/DD/YYYY) and time separators. + * + * @constant + * @default 'en-US' + */ +const TEST_LOCALE = 'en-US'; + export default defineConfig(({ mode }) => { const isTest = mode === 'test'; let timeZoneId: string | null = process.env.TZ ?? null; - + let locale: string | null = process.env.locale ?? null; if (isTest) { timeZoneId = timeZoneId ?? TEST_TIME_ZONE; + locale = locale ?? TEST_LOCALE; } // `expressionParser.ts` is built as a separate entry so it can be consumed @@ -83,6 +95,7 @@ export default defineConfig(({ mode }) => { }, define: { TZ: JSON.stringify(timeZoneId), + locale: JSON.stringify(locale), }, esbuild: { target: 'esnext', @@ -122,7 +135,7 @@ export default defineConfig(({ mode }) => { headless: true, screenshotFailures: false, }, - + setupFiles: ['test/setup.ts'], environment: TEST_ENVIRONMENT, globals: false, include: ['test/**/*.test.ts'], From 19113dd7ed1be752d04d95abfcd089de87edca12 Mon Sep 17 00:00:00 2001 From: latin-panda <66472237+latin-panda@users.noreply.github.com> Date: Wed, 5 Mar 2025 00:18:04 -0800 Subject: [PATCH 2/3] Aligning with code style --- .github/workflows/ci.yml | 1 + packages/xpath/test/setup.ts | 4 ++-- packages/xpath/vite.config.ts | 7 ++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c6e2ce486..fb6f32252 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,6 +21,7 @@ defaults: env: TZ: 'America/Phoenix' + LOCALE_ID: 'en-US' jobs: install-and-build: diff --git a/packages/xpath/test/setup.ts b/packages/xpath/test/setup.ts index 315fa9032..d27b1cca4 100644 --- a/packages/xpath/test/setup.ts +++ b/packages/xpath/test/setup.ts @@ -27,11 +27,11 @@ declare global { * * @example 'en-US' // American English */ - const locale: string; + const LOCALE_ID: string; } beforeEach(() => { - const dateOnTimezone = new Date().toLocaleString(locale, { timeZone: TZ }); + const dateOnTimezone = new Date().toLocaleString(LOCALE_ID, { timeZone: TZ }); vi.useFakeTimers({ now: new Date(dateOnTimezone).getTime(), }); diff --git a/packages/xpath/vite.config.ts b/packages/xpath/vite.config.ts index bb6194f62..bbd636b81 100644 --- a/packages/xpath/vite.config.ts +++ b/packages/xpath/vite.config.ts @@ -59,10 +59,11 @@ export default defineConfig(({ mode }) => { const isTest = mode === 'test'; let timeZoneId: string | null = process.env.TZ ?? null; - let locale: string | null = process.env.locale ?? null; + let localeId: string | null = process.env.LOCALE_ID ?? null; + if (isTest) { timeZoneId = timeZoneId ?? TEST_TIME_ZONE; - locale = locale ?? TEST_LOCALE; + localeId = localeId ?? TEST_LOCALE; } // `expressionParser.ts` is built as a separate entry so it can be consumed @@ -95,7 +96,7 @@ export default defineConfig(({ mode }) => { }, define: { TZ: JSON.stringify(timeZoneId), - locale: JSON.stringify(locale), + LOCALE_ID: JSON.stringify(localeId), }, esbuild: { target: 'esnext', From f37c2898d807baddbfcb10a1ea01fffce56d61ac Mon Sep 17 00:00:00 2001 From: latin-panda <66472237+latin-panda@users.noreply.github.com> Date: Mon, 3 Mar 2025 22:02:07 -0600 Subject: [PATCH 3/3] Fixes type check --- packages/xpath/test/helpers.ts | 23 +++++++++++++++++++++++ packages/xpath/test/setup.ts | 32 ++------------------------------ 2 files changed, 25 insertions(+), 30 deletions(-) diff --git a/packages/xpath/test/helpers.ts b/packages/xpath/test/helpers.ts index 9ce0427f7..7c9bd13be 100644 --- a/packages/xpath/test/helpers.ts +++ b/packages/xpath/test/helpers.ts @@ -10,14 +10,33 @@ type AnyParentNode = | XMLDocument; declare global { + /** + * The timezone identifier used for all date and time operations in tests. + * This string follows the IANA Time Zone Database format (e.g., 'America/Phoenix'). + * It determines the offset and DST behavior for `Date` objects and + * related functions. + * + * @example 'America/Phoenix' // Fixed UTC-7, no DST + * @example 'Europe/London' // UTC+0 (GMT) or UTC+1 (BST) with DST + */ // eslint-disable-next-line no-var var TZ: string | undefined; // eslint-disable-next-line no-var + var LOCALE_ID: string | undefined; + /** + * The locale string defining the language and regional formatting for tests. + * This follows the BCP 47 language tag format (e.g., 'en-US'). It ensures consistent formatting + * across tests. + * + * @example 'en-US' // American English + */ + // eslint-disable-next-line no-var var IMPLEMENTATION: string | undefined; } globalThis.IMPLEMENTATION = typeof IMPLEMENTATION === 'string' ? IMPLEMENTATION : undefined; globalThis.TZ = typeof TZ === 'string' ? TZ : undefined; +globalThis.LOCALE_ID = typeof LOCALE_ID === 'string' ? LOCALE_ID : undefined; const namespaces: Record = { xhtml: 'http://www.w3.org/1999/xhtml', @@ -338,3 +357,7 @@ export const getNonNamespaceAttributes = (element: Element): readonly Attr[] => return attrs.filter(({ name }) => name !== 'xmlns' && !name.startsWith('xmlns:')); }; + +export const getDefaultDateTimeLocale = (): string => { + return new Date().toLocaleString(LOCALE_ID, { timeZone: TZ }); +}; diff --git a/packages/xpath/test/setup.ts b/packages/xpath/test/setup.ts index d27b1cca4..b4ce741bb 100644 --- a/packages/xpath/test/setup.ts +++ b/packages/xpath/test/setup.ts @@ -1,37 +1,9 @@ import { afterEach, beforeEach } from 'vitest'; import { vi } from 'vitest'; - -/** - * Global constants injected via Vite's `define` configuration option. - * These values are replaced at build time and are available throughout - * the test suite. - * - * @global - */ -declare global { - /** - * The timezone identifier used for all date and time operations in tests. - * This string follows the IANA Time Zone Database format (e.g., 'America/Phoenix'). - * It determines the offset and DST behavior for `Date` objects and - * related functions. - * - * @example 'America/Phoenix' // Fixed UTC-7, no DST - * @example 'Europe/London' // UTC+0 (GMT) or UTC+1 (BST) with DST - */ - const TZ: string; - - /** - * The locale string defining the language and regional formatting for tests. - * This follows the BCP 47 language tag format (e.g., 'en-US'). It ensures consistent formatting - * across tests. - * - * @example 'en-US' // American English - */ - const LOCALE_ID: string; -} +import { getDefaultDateTimeLocale } from './helpers.ts'; beforeEach(() => { - const dateOnTimezone = new Date().toLocaleString(LOCALE_ID, { timeZone: TZ }); + const dateOnTimezone = getDefaultDateTimeLocale(); vi.useFakeTimers({ now: new Date(dateOnTimezone).getTime(), });