/* DCTS 平行集合图 sessionStorage 缓存单测(node:test,零依赖) * * 覆盖 parSets.js 的 savePsCache / restorePsCache:刷新页面后恢复数据、单槽位清理、 * 损坏数据回退。node 无 sessionStorage,测试前用内存 Map stub。 */ import { test } from 'node:test'; import assert from 'node:assert/strict'; // 内存 sessionStorage stub(setItem 可注入配额错误用于 QuotaExceeded 分支) let store = new Map(); let quotaExceeded = false; globalThis.sessionStorage = { get length() { return store.size; }, key: (i) => [...store.keys()][i] ?? null, getItem: (k) => (store.has(k) ? store.get(k) : null), setItem: (k, v) => { if (quotaExceeded) throw new Error('QuotaExceededError'); store.set(k, String(v)); }, removeItem: (k) => { store.delete(k); }, }; const { savePsCache, restorePsCache } = await import('../src/views/detail/parSets.js'); function ctx(name, points = [], ts = null) { return { name, psState: { points, ts } }; } test('savePsCache 写入 JSON 并可由 restorePsCache 恢复', () => { store.clear(); const before = Date.now(); const c = ctx('sdB_cno', [{ name: 'p1', teff: 20000, status: 'completed' }]); savePsCache(c); // 持久化 key 存在 assert.ok(store.has('dcts_ps_points_sdB_cno')); // 恢复后 points 一致;快照时间由 savePsCache 记录为保存时刻(Date.now 附近) const c2 = ctx('sdB_cno'); assert.equal(restorePsCache(c2), true); assert.deepEqual(c2.psState.points, c.psState.points); assert.ok(Number.isFinite(c2.psState.ts) && c2.psState.ts >= before); assert.ok(Math.abs(c2.psState.ts - Date.now()) < 5000); }); test('多工作流缓存并存:切换工作流不删除彼此的缓存', () => { store.clear(); savePsCache(ctx('wf_a', [{ name: 'a' }])); savePsCache(ctx('wf_b', [{ name: 'b' }])); savePsCache(ctx('wf_a', [{ name: 'a2' }])); // 再回 wf_a 更新,writes 覆盖自身 key // wf_a 与 wf_b 的缓存都保留 assert.ok(store.has('dcts_ps_points_wf_a')); assert.ok(store.has('dcts_ps_points_wf_b')); // 各自恢复出各自的数据(不串) const ca = ctx('wf_a'); const cb = ctx('wf_b'); assert.equal(restorePsCache(ca), true); assert.equal(restorePsCache(cb), true); assert.deepEqual(ca.psState.points, [{ name: 'a2' }]); // 更新后是最新值 assert.deepEqual(cb.psState.points, [{ name: 'b' }]); }); test('无缓存 / 空 key 时 restorePsCache 返回 false', () => { store.clear(); const c = ctx('no_such_wf'); assert.equal(restorePsCache(c), false); assert.deepEqual(c.psState.points, []); }); test('损坏的 JSON / 非数组数据返回 false(降级为重新拉取)', () => { store.clear(); store.set('dcts_ps_points_bad_json', 'not-json{{{'); store.set('dcts_ps_points_bad_shape', JSON.stringify({ foo: 1 })); assert.equal(restorePsCache(ctx('bad_json')), false); assert.equal(restorePsCache(ctx('bad_shape')), false); }); test('QuotaExceeded 时 savePsCache 静默失败,不抛错', () => { store.clear(); quotaExceeded = true; assert.doesNotThrow(() => savePsCache(ctx('big_wf', new Array(10000).fill({ x: 1 })))); quotaExceeded = false; });