fix(test): make desktop ui tests locale-agnostic

Three desktop UI tests froze en-US-formatted strings while the
implementation formatters deliberately use the runtime locale
(new Intl.DateTimeFormat(undefined, ...) / Intl.NumberFormat(undefined,
...)) — runtime-locale output is the intended behavior for a localized
UI. On any non-en-US dev machine the tests fail even though the code is
correct:

    # zh-CN host:
    time.test.ts -> expected '三月' to be 'March'
    billing      -> Unable to find text 'Threshold: minimum is $10.'
                    (zh-CN renders USD as 'US$10')
    billing      -> Unable to find text '$25 added. Balance is refreshing.'

Assert the behavior contract instead of the frozen snapshot, per the
repo's testing guidance (behavior contracts over snapshots):

- time.test.ts: same-year month buckets render via fmtMonth, prior-year
  via fmtMonthYear — assert sessionBucketLabel(bucket) equals the shared
  formatter's output for bucket.at, with bucket-kind narrowing.
- billing/index.test.tsx: interpolate formatMoney(10) / formatMoney(25)
  into the expected strings.

No production code changes.

Verified: zh-CN host 40/40, LANG=C.UTF-8 40/40, tsc clean, eslint clean.
This commit is contained in:
ypQQ1984 2026-07-28 12:24:19 +08:00 committed by Teknium
parent a619616736
commit 4c9e1e8223
2 changed files with 18 additions and 7 deletions

View File

@ -4,6 +4,7 @@ import type { ReactNode } from 'react'
import { MemoryRouter } from 'react-router'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { formatMoney } from './billing-amounts'
import {
billingDevFixtures,
loggedOutBillingState,
@ -168,7 +169,7 @@ describe('BillingSettings', () => {
target: { value: '7.50' }
})
expect(screen.getByText('Threshold: minimum is $10.')).toBeTruthy()
expect(screen.getByText(`Threshold: minimum is ${formatMoney(10)}.`)).toBeTruthy()
expect(screen.getByRole('button', { name: 'Save' }).hasAttribute('disabled')).toBe(true)
fireEvent.click(screen.getByRole('button', { name: 'Save' }))
@ -219,7 +220,7 @@ describe('BillingSettings', () => {
fireEvent.click(await screen.findByRole('button', { name: 'Manage' }))
expect(screen.getByRole('spinbutton', { name: 'Auto-refill threshold' })).toBeTruthy()
expect(screen.queryByText('Threshold: minimum is $10.')).toBeNull()
expect(screen.queryByText(`Threshold: minimum is ${formatMoney(10)}.`)).toBeNull()
// Save is disabled because the prefilled config is invalid — but no error yet.
expect(screen.getByRole('button', { name: 'Save' }).hasAttribute('disabled')).toBe(true)
})
@ -592,7 +593,7 @@ describe('BillingSettings', () => {
ok: true
})
await waitFor(() => expect(screen.getByText('$25 added. Balance is refreshing.')).toBeTruthy())
await waitFor(() => expect(screen.getByText(`${formatMoney(25)} added. Balance is refreshing.`)).toBeTruthy())
})
it('renders logged-out as a connect card without normal account rows', async () => {

View File

@ -1,6 +1,6 @@
import { describe, expect, it } from 'vitest'
import { calendarBucket, DAY, formatAgo, HOUR, MINUTE, nominalDayStart, SECOND, sessionBucketLabel } from './time'
import { calendarBucket, DAY, fmtMonth, fmtMonthYear, formatAgo, HOUR, MINUTE, nominalDayStart, SECOND, sessionBucketLabel } from './time'
const labels = {
ageNow: 'now',
@ -117,8 +117,18 @@ describe('sessionBucketLabel', () => {
})
it('formats month (same year) and month + year (prior year) via Intl', () => {
// en-US default in the test env: month name, plus year for the prior year.
expect(labelAt(2026, 2, 3)).toBe('March')
expect(labelAt(2025, 11, 3)).toBe('December 2025')
// Locale-agnostic contract: same-year month buckets render via fmtMonth,
// prior-year buckets via fmtMonthYear. Assert against the shared
// formatters instead of frozen en-US strings so the test passes under
// any host locale (the formatters intentionally use the runtime locale).
const monthBucket = calendarBucket(secondsAt(2026, 2, 3), THU_NOON, 1)
if (monthBucket.kind !== 'month') {throw new Error(`expected month bucket, got ${monthBucket.kind}`)}
expect(sessionBucketLabel(monthBucket, labels)).toBe(fmtMonth.format(monthBucket.at))
const monthYearBucket = calendarBucket(secondsAt(2025, 11, 3), THU_NOON, 1)
if (monthYearBucket.kind !== 'monthYear') {throw new Error(`expected monthYear bucket, got ${monthYearBucket.kind}`)}
expect(sessionBucketLabel(monthYearBucket, labels)).toBe(fmtMonthYear.format(monthYearBucket.at))
})
})