import test from 'node:test'; import assert from 'node:assert/strict'; import { mutationOutcomeUnknown, needsSaveVerification, subjectSaveLabel, subjectMatchesUpdate, verifiedSaveStatus } from '../src/pages/subject-save.ts'; const original = { id: 'synthetic-elder', household_id: 'synthetic-home', version: 4, preferred_name: '合成长者', profile_data: { interests: ['养花'], background: '合成背景' } }; const input = { preferred_name: '合成长者(已编辑)', profile_data: { background: '合成背景', interests: ['养花'] } }; const attempt = { householdID: original.household_id, baseVersion: 4, input, status: 'uncertain' }; test('lost and gateway responses are unknown, while explicit rejection is distinct', () => { for (const status of [0, 408, 500, 502, 503, 504]) assert.equal(mutationOutcomeUnknown({ status }), true); for (const status of [400, 401, 403, 409, 412, 422, 429]) assert.equal(mutationOutcomeUnknown({ status }), false); assert.equal(mutationOutcomeUnknown(new TypeError('network failure')), true); assert.equal(mutationOutcomeUnknown(new SyntaxError('invalid JSON')), true); }); test('a background refresh does not convert an uncertain save into a success label', () => { assert.match(subjectSaveLabel(attempt, false), /尚未确认/); assert.equal(needsSaveVerification(attempt), true); assert.doesNotMatch(subjectSaveLabel(undefined, false), /已保存|最新版本/); }); test('read-only verification requires matching all submitted fields and a non-stale version', () => { const committed = { ...original, ...input, version: 5 }; assert.equal(subjectMatchesUpdate(committed, input), true); assert.equal(verifiedSaveStatus(committed, attempt), 'verified'); assert.equal(verifiedSaveStatus(original, attempt), 'uncertain'); assert.equal(verifiedSaveStatus({ ...committed, version: 3 }, attempt), 'uncertain'); assert.equal(verifiedSaveStatus({ ...committed, preferred_name: '另一项并发修改' }, attempt), 'conflict'); assert.equal(verifiedSaveStatus({ ...committed, profile_data: { ...input.profile_data, interests: [] } }, attempt), 'conflict'); }); test('editing after an acknowledged save has a draft label again', () => { assert.equal(subjectSaveLabel({ ...attempt, status: 'saved' }, true), '修改尚未保存'); assert.equal(subjectSaveLabel({ ...attempt, status: 'saved' }, false), '服务器已确认保存'); assert.equal(needsSaveVerification({ ...attempt, status: 'saved' }), false); });