import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' import test from 'node:test' const appSource = readFileSync(new URL('../src/app/App.tsx', import.meta.url), 'utf8') function functionSource(name, nextName) { const start = appSource.indexOf(`function ${name}`) const end = appSource.indexOf(`function ${nextName}`, start + 1) assert.notEqual(start, -1, `missing ${name}`) assert.notEqual(end, -1, `missing boundary ${nextName}`) return appSource.slice(start, end) } test('modal mutations close at the save boundary and refresh only their affected projects', () => { for (const [name, nextName] of [ ['handleCreateProject', 'handleCreateTask'], ['handleCreateTask', 'handleUploadSource'], ['handleUploadSource', 'handleCreateCronPlan'], ['handleCreateCronPlan', 'handleCreateProjectTag'], ['handleCreateProjectTag', 'openTask'], ]) { const source = functionSource(name, nextName) assert.match(source, /runAction\(/, `${name} must use the saved-mutation boundary`) } assert.doesNotMatch(appSource, /refreshAfterAction/) assert.match(functionSource('handleUpdateWorkspaceTask', 'handleUpdateProject'), /refreshProjectWorkspaces/) }) test('project settings and Inbox capture keep save success separate from refresh failure', () => { assert.match(functionSource('handleUpdateProject', 'handleAnalyzeInbox'), /executeSavedMutation/) assert.match(functionSource('handleCaptureInbox', 'handleConfirmInbox'), /executeSavedMutation/) const confirmSource = functionSource('handleConfirmInbox', 'handleSelectSearchResult') assert.match(confirmSource, /offerRefreshRecovery/) assert.match(confirmSource, /createdCount: response\.createdCount/) }) test('refresh recovery remains actionable after a save', () => { assert.match(appSource, /数据已保存,但页面刷新失败/) assert.match(appSource, />刷新数据<\/Button>/) assert.match(appSource, /pendingRefreshProjectIDs/) assert.match(appSource, /refreshProjectWorkspaces\(requireSession\(\), targets\)/) assert.match(appSource, /clearPendingRefreshProjects\(current, \[projectID\]\)/) })