import test from 'node:test'; import assert from 'node:assert/strict'; import { householdSelectionKey, readHouseholdSelection, writeHouseholdSelection, resolveHouseholdSelection, timezoneError, parseContextList, contextListError, privacyStatusLabel, privacyRequestStatus, isPrivacyRequestProcessing } from '../src/pages/portal-validation.ts'; test('family choice survives reload and only resolves accessible families', () => { const values = new Map(); globalThis.window = { localStorage: { getItem: key => values.get(key), setItem: (key, value) => values.set(key, value), removeItem: key => values.delete(key) } }; const accounts = [{ tenant_id: 'tenant-a', user_id: 'user-a' }, { tenant_id: 'tenant-b', user_id: 'user-b' }]; const key = householdSelectionKey(accounts); assert.equal(key, householdSelectionKey([...accounts].reverse())); writeHouseholdSelection(key, 'A'); assert.equal(resolveHouseholdSelection([{ id: 'B' }, { id: 'A' }], readHouseholdSelection(key)), 'A'); assert.equal(resolveHouseholdSelection([{ id: 'B' }], readHouseholdSelection(key)), 'B'); assert.equal(readHouseholdSelection(householdSelectionKey([{ tenant_id: 'tenant-a', user_id: 'other-user' }])), undefined); assert.equal(resolveHouseholdSelection([], 'A'), undefined); writeHouseholdSelection(key); assert.equal(readHouseholdSelection(key), undefined); globalThis.window = { get localStorage() { throw new Error('Storage unavailable'); } }; assert.doesNotThrow(() => writeHouseholdSelection(key, 'A')); assert.equal(readHouseholdSelection(key), undefined); delete globalThis.window; }); test('invalid timezones fail before confirmation', () => { assert.equal(timezoneError('Asia/Shanghai'), ''); assert.equal(timezoneError('America/New_York'), ''); assert.equal(timezoneError('UTC'), ''); assert.ok(timezoneError('Invalid/Zone')); assert.ok(timezoneError('')); }); test('topic parsing preserves excess entries for explicit validation', () => { const items = parseContextList('1、2,3,4、5、6、7、8、9'); assert.equal(items.length, 9); assert.ok(contextListError(items)); assert.equal(contextListError(items.slice(0, 8)), ''); assert.ok(contextListError(['很'.repeat(51)])); }); test('every privacy request state has a Chinese label', () => { for (const state of ['SUBMITTED', 'VERIFYING', 'EXECUTING', 'COMPLETED', 'PARTIAL_FAILED']) { assert.notEqual(privacyStatusLabel(state), state); assert.equal(privacyStatusLabel(state.toLowerCase()), privacyStatusLabel(state)); } }); test('failed deletion subtasks override a stale executing status until reconciliation completes', () => { const request = { status: 'EXECUTING', subtasks: [{ status: 'COMPLETED' }, { status: 'FAILED' }] }; assert.equal(privacyRequestStatus(request), 'PARTIAL_FAILED'); assert.equal(isPrivacyRequestProcessing(request), false); assert.equal(isPrivacyRequestProcessing({ ...request, subtasks: [{ status: 'RUNNING' }] }), true); assert.equal(privacyRequestStatus({ status: 'COMPLETED', subtasks: [{ status: 'COMPLETED' }] }), 'COMPLETED'); assert.equal(isPrivacyRequestProcessing({ status: 'COMPLETED' }), false); });