From 4c9e1e82236cbcfa2d48296b1bdc28a3ebe86ccb Mon Sep 17 00:00:00 2001 From: ypQQ1984 <128565103+ypQQ1984@users.noreply.github.com> Date: Tue, 28 Jul 2026 12:24:19 +0800 Subject: [PATCH] fix(test): make desktop ui tests locale-agnostic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .../src/app/settings/billing/index.test.tsx | 7 ++++--- apps/desktop/src/lib/time.test.ts | 18 ++++++++++++++---- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/apps/desktop/src/app/settings/billing/index.test.tsx b/apps/desktop/src/app/settings/billing/index.test.tsx index 1836c03917b9e..bae90df9973f8 100644 --- a/apps/desktop/src/app/settings/billing/index.test.tsx +++ b/apps/desktop/src/app/settings/billing/index.test.tsx @@ -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 () => { diff --git a/apps/desktop/src/lib/time.test.ts b/apps/desktop/src/lib/time.test.ts index f767934c58b8b..4c7c39829c2e3 100644 --- a/apps/desktop/src/lib/time.test.ts +++ b/apps/desktop/src/lib/time.test.ts @@ -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)) }) })