import assert from 'node:assert/strict'; import { readFile } from 'node:fs/promises'; import test, { after } from 'node:test'; import { fileURLToPath } from 'node:url'; import { createServer } from 'vite'; const storage = new Map(); globalThis.uni = { getStorageSync: (key) => storage.get(key) || '', setStorageSync: (key, value) => storage.set(key, value), removeStorageSync: (key) => storage.delete(key) }; const vite = await createServer({ root: fileURLToPath(new URL('..', import.meta.url)), configFile: false, optimizeDeps: { noDiscovery: true }, server: { middlewareMode: true, hmr: false }, appType: 'custom' }); after(async () => { await vite.close(); delete globalThis.uni; }); const { createPageRequestScope } = await vite.ssrLoadModule('/src/services/request-scope.ts'); const { getCurrentProject, reconcileCurrentProject, saveAuth, saveCurrentProject } = await vite.ssrLoadModule('/src/services/auth.ts'); const loginAs = (phone, token) => { storage.set('aihr_mobile_phone', phone); storage.set('aihr_mobile_client_id', 'mobile-client'); storage.set('aihr_mobile_access_token', token); }; test('同一加载通道只允许最新请求回写,不同通道可以并行', () => { loginAs('13800138000', 'token-a'); const scope = createPageRequestScope(); scope.activate(); const first = scope.begin('assignments'); const parallel = scope.begin('knowledge'); assert.equal(scope.isCurrent(first), true); assert.equal(scope.isCurrent(parallel), true); const second = scope.begin('assignments'); assert.equal(scope.isCurrent(first), false); assert.equal(scope.isCurrent(second), true); assert.equal(scope.isCurrent(parallel), true); }); test('切号、换 token 和页面隐藏后旧请求全部失效', () => { loginAs('13800138000', 'token-a'); const scope = createPageRequestScope(); scope.activate(); const oldAccount = scope.begin('page'); loginAs('13900139000', 'token-b'); assert.equal(scope.isCurrent(oldAccount), false); const newAccount = scope.begin('page'); assert.equal(scope.isCurrent(newAccount), true); storage.set('aihr_mobile_access_token', 'token-b-refreshed'); assert.equal(scope.isCurrent(newAccount), false); const refreshedToken = scope.begin('page'); assert.equal(scope.isCurrent(refreshedToken), true); scope.invalidate(); assert.equal(scope.isCurrent(refreshedToken), false); const hiddenRequest = scope.begin('page'); assert.equal(scope.isCurrent(hiddenRequest), false, '页面隐藏后启动的后续请求不能重新激活页面作用域'); }); test('五个账号敏感页在显示时捕获账号并在隐藏和卸载时失效', async () => { const pages = [ '../src/pages/user/today/index.vue', '../src/pages/user/learning/index.vue', '../src/pages/user/practice/index.vue', '../src/pages/supervisor/team/index.vue', '../src/pages/supervisor/index/index.vue' ]; const sources = await Promise.all(pages.map((page) => readFile(new URL(page, import.meta.url), 'utf8'))); for (const source of sources) { assert.match(source, /currentAccountKey\(\)/); assert.match(source, /requests\.activate\(\)/); assert.match(source, /onHide\(/); assert.match(source, /onUnload\(/); assert.match(source, /requests\.invalidate\(\)/); assert.match(source, /requests\.isCurrent\(/); } }); test('当前项目按租户和登录账号隔离并在权限变化后重新校验', () => { saveAuth({ access_token: 'token-a', client_id: 'mobile-client' }, '13800138000', '000000'); saveCurrentProject({ projectCode: 'P1', projectName: '星河湾一期' }); assert.equal(getCurrentProject()?.projectCode, 'P1'); saveAuth({ access_token: 'token-b', client_id: 'mobile-client' }, '13900139000', '000000'); assert.equal(getCurrentProject(), null); assert.equal(reconcileCurrentProject([ { projectCode: 'P2', projectName: '星河湾二期' } ])?.projectCode, 'P2'); assert.equal(reconcileCurrentProject([ { projectCode: 'P3', projectName: '星河湾三期' }, { projectCode: 'P4', projectName: '星河湾四期' } ]), null); assert.equal(getCurrentProject(), null); });