import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import { join } from 'node:path'; import test from 'node:test'; function source(path: string) { return readFileSync(join(process.cwd(), path), 'utf8'); } const migratedBusinessStores = [ ['stores/useProductStore.ts', 'products-overview'], ['stores/useRequirementStore.ts', 'requirements'], ['stores/useVersionPlanStore.ts', 'version-plans'], ['stores/useDevTaskStore.ts', 'dev-tasks'], ['stores/useTestCaseStore.ts', 'test-cases'], ['stores/useBugStore.ts', 'bugs'], ['stores/useTaskCategoryStore.ts', 'task-categories'], ['stores/useTaskWorklogStore.ts', 'task-worklogs'], ['stores/useWorkActivityStore.ts', 'work-activities'], ] as const; test('migrated business stores do not read or write AppData documents at runtime', () => { for (const [file, key] of migratedBusinessStores) { const text = source(file); assert.doesNotMatch(text, new RegExp(`loadServerData<[^>]*>\\('${key}'`), `${file} must not read ${key}`); assert.doesNotMatch(text, new RegExp(`loadServerData\\([^)]*'${key}'`), `${file} must not read ${key}`); assert.doesNotMatch(text, new RegExp(`saveServerData\\('${key}'`), `${file} must not write ${key}`); assert.doesNotMatch(text, /\.catch\(loadStored\)/, `${file} must not fall back to legacy AppData reads`); } }); test('only explicit legacy config stores keep AppData access', () => { assert.match(source('stores/useMemberStore.ts'), /saveServerData\('members'/); assert.match(source('stores/useMemberStore.ts'), /loadServerData<[^>]+>\('members'/); assert.match(source('stores/useOvertimeStore.ts'), /loadServerData<[^>]+>\('overtime'/); }); test('read-only Xiaobao AppData archive keys are not used by runtime stores', () => { for (const file of ['stores/useXiaobaoRiskStore.ts', 'stores/useXiaobaoWarningReadStore.ts']) { const text = source(file); assert.doesNotMatch(text, /loadServerData<[^>]+>\('xiaobao-risk-snapshots'/, `${file} must not read Xiaobao snapshots AppData`); assert.doesNotMatch(text, /loadServerData<[^>]+>\('xiaobao-risk-insights'/, `${file} must not read Xiaobao insights AppData`); assert.doesNotMatch(text, /loadServerData<[^>]+>\('xiaobao-warning-views'/, `${file} must not read Xiaobao warning read-state AppData`); assert.doesNotMatch(text, /saveServerData\('xiaobao-risk-snapshots'/, `${file} must not write Xiaobao snapshots AppData`); assert.doesNotMatch(text, /saveServerData\('xiaobao-risk-insights'/, `${file} must not write Xiaobao insights AppData`); assert.doesNotMatch(text, /saveServerData\('xiaobao-warning-views'/, `${file} must not write Xiaobao warning read-state AppData`); } }); test('auth reads member identities from the member domain API instead of members AppData', () => { const text = source('stores/useAuthStore.ts'); assert.match(text, /listMembersDomain/); assert.doesNotMatch(text, /loadServerData<[^>]+>\('members'/); assert.doesNotMatch(text, /from '@\/lib\/server-data'/); }); test('member store keeps members AppData as config only, not member identity fallback', () => { const text = source('stores/useMemberStore.ts'); assert.doesNotMatch(text, /cached\.members/); assert.doesNotMatch(text, /members: get\(\)\.members,/); assert.match(text, /saveServerData\('members', \{ departments: state\.departments, members: \[\], roles: state\.roles, passwordRule: state\.passwordRule \}\)/); });