const test = require('node:test') const assert = require('node:assert/strict') const fs = require('node:fs') const path = require('node:path') const vm = require('node:vm') const ts = require('typescript') const root = path.resolve(__dirname, '..') function load(file, requireImpl = require, globals = {}) { const source = fs.readFileSync(path.join(root, file), 'utf8') const exports = {} vm.runInNewContext(ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2019 } }).outputText, { exports, require: requireImpl, ...globals }) return exports } const { createResourceCache } = load('src/utils/resourceCache.ts') test('三个主页面均注册为Tab,切换不使用push/redirect', () => { let config load('src/app.config.ts', require, { defineAppConfig: value => { config = value } }) assert.deepEqual(Array.from(config.tabBar.list, item => item.pagePath), ['pages/home/index', 'pages/fortune/index', 'pages/my/index']) const bar = fs.readFileSync(path.join(root, 'src/components/AppTabBar.tsx'), 'utf8') assert.doesNotMatch(bar, /navigateTo|redirectTo/) }) test('连续点击只切换一次,完成或失败后均可继续点击', async () => { const urls = [], notices = [] let complete const { switchMainTab } = load('src/services/tabNavigation.ts', id => id === './loginAccess' ? { hasLoginAccess: () => true } : ({ default: { switchTab: ({ url }) => { urls.push(url); return new Promise(resolve => { complete = resolve }) }, showToast: value => notices.push(value.title) } })) await switchMainTab('home', 'home') assert.equal(urls.length, 0) const first = switchMainTab('fortune', 'home') await switchMainTab('my', 'home') assert.equal(urls.length, 1) complete(); await first const next = switchMainTab('my', 'fortune') complete(); await next assert.deepEqual(urls, ['/pages/fortune/index', '/pages/my/index']) const failing = load('src/services/tabNavigation.ts', id => id === './loginAccess' ? { hasLoginAccess: () => true } : ({ default: { switchTab: () => Promise.reject(new Error('offline')), showToast: value => notices.push(value.title) } })) await failing.switchMainTab('my') await failing.switchMainTab('fortune') assert.equal(notices.length, 2) }) test('资料缓存合并并发请求,过期保留快照并重取;失败可重试', async () => { let now = 0, calls = 0 const cache = createResourceCache(30, () => now) const loader = async () => { calls++; return { nickname: 'A' } } const [a,b] = await Promise.all([cache.load('a', loader), cache.load('a', loader)]) assert.equal(a, b); assert.equal(calls, 1) await cache.load('a', loader); assert.equal(calls, 1) assert.equal(cache.peekFresh('a').nickname, 'A') now = 31 assert.equal(cache.peek('a').nickname, 'A') assert.equal(cache.peekFresh('a'), undefined) await assert.rejects(cache.load('a', async () => { throw new Error('offline') }), /offline/) await cache.load('a', loader); assert.equal(calls, 2) await cache.load('a', loader, true); assert.equal(calls, 3) }) test('保存后的新资料不会被旧请求覆盖,不同账号不共用缓存', async () => { const cache = createResourceCache(30) let finish const old = cache.load('a', () => new Promise(resolve => { finish = resolve })) await Promise.resolve() cache.seed('a', { nickname: 'New' }) finish({ nickname: 'Old' }) assert.equal((await old).nickname, 'New') assert.equal(cache.peek('b'), undefined) assert.equal(cache.peekFresh('b'), undefined) let resolveA const readA = cache.load('a', () => new Promise(resolve => { resolveA = resolve })) await Promise.resolve() cache.seed('b', { nickname: 'B' }) resolveA({ nickname: 'A' }) await assert.rejects(readA, /登录状态已变更/) assert.equal(cache.peek('b').nickname, 'B') let resolveOldA const oldA = cache.load('a', () => new Promise(resolve => { resolveOldA = resolve })) await Promise.resolve() cache.peek('b'); cache.peek('a') resolveOldA({ nickname: 'Outdated A' }) await assert.rejects(oldA, /资料状态已变更/) assert.equal(cache.peek('a'), undefined) })