// tests/r3debug/bench.test.js —— #27 聚合 ID / #40 轮询暂停策略 import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { setActivePinia, createPinia } from 'pinia'; import { useBenchStore, __setHttpGet } from '../../src/stores/bench.js'; function makePiniaWithChat(chatState) { const pinia = createPinia(); setActivePinia(pinia); // chat store 未注册时 currentSources 回退 null——注册一个假 chat store 提供 currentMessage pinia.state.value.chat = chatState; return pinia; } describe('#27 会话级来源聚合(后端结果为准)', () => { beforeEach(() => { vi.useFakeTimers(); }); afterEach(() => { vi.useRealTimers(); vi.restoreAllMocks(); }); it('sessionSources.sources 原样透出(不重复聚合、不 +1)', () => { makePiniaWithChat({ messages: [] }); const bench = useBenchStore(); bench.sourceScope = 'session'; bench.sessionSources = { ok: true, sources: [ { paper_id: 'P1', id: 'x1', title: 'A', count: 2 }, { paper_id: 'P2', id: 'x2', title: 'B', count: 1 }, ], }; const items = bench.sources; expect(items).toHaveLength(2); expect(items[0].src.paper_id).toBe('P1'); expect(items[0].label).toBe(2); expect(items[1].label).toBe(1); }); it('后端已去重:重复 paper_id 不再被前端二次聚合', () => { makePiniaWithChat({ messages: [] }); const bench = useBenchStore(); bench.sourceScope = 'session'; bench.sessionSources = { sources: [ { paper_id: 'P1', count: 1 }, { paper_id: 'P1', count: 1 }, // 后端若漏去重(防御):前端也不合并(修复后语义) ], }; // 修复后:前端不再做 Map 聚合,直接透传 expect(bench.sources).toHaveLength(2); }); it('setHighlightSource 改 key 语义:key 匹配 paper_id/id,旧 index 兼容', () => { makePiniaWithChat({ messages: [] }); const bench = useBenchStore(); bench.setHighlightSource('P-123'); expect(bench.highlightSource.key).toBe('P-123'); bench.setHighlightSource(2); // 数字 → 兼容旧 index 调用 expect(bench.highlightSource.index).toBe(2); bench.setHighlightSource(null); // 清除 expect(bench.highlightSource).toBeNull(); }); }); describe('#40 轮询暂停/恢复策略', () => { beforeEach(() => { vi.useFakeTimers(); __setHttpGet(null); }); afterEach(() => { vi.useRealTimers(); vi.restoreAllMocks(); __setHttpGet(null); }); it('任何离开 extract 的切换 → pollPaused 且定时器清空', () => { const pinia = createPinia(); setActivePinia(pinia); const bench = useBenchStore(); bench.activeTab = 'extract'; bench.jobs = [{ job_id: 'j1', status: 'running' }]; const started = bench.startPolling({ timeoutFn: setTimeout, clearFn: clearTimeout, delay: 5000 }); expect(started).toBe(true); expect(bench.isPolling()).toBe(true); bench.setActiveTab('retrieval'); expect(bench.pollPaused).toBe(true); expect(bench.isPolling()).toBe(false); // fake timer 前进:无残留轮询请求(loadJobs 不会被调) const spy = vi.spyOn(bench, 'loadJobs'); vi.advanceTimersByTime(20000); expect(spy).not.toHaveBeenCalled(); }); it('进入 extract 恢复轮询资格(pollPaused=false);有 running 时 pane 会重启', () => { const pinia = createPinia(); setActivePinia(pinia); const bench = useBenchStore(); bench.activeTab = 'sources'; bench.pollPaused = true; bench.jobs = [{ job_id: 'j1', status: 'running' }]; bench.setActiveTab('extract'); expect(bench.pollPaused).toBe(false); expect(bench.activeTab).toBe('extract'); const started = bench.startPolling({ timeoutFn: setTimeout, clearFn: clearTimeout, delay: 5000 }); expect(started).toBe(true); }); it('全部终态:_tickPoll 不再续定时器', async () => { const pinia = createPinia(); setActivePinia(pinia); const bench = useBenchStore(); bench.activeTab = 'extract'; bench.jobs = [{ job_id: 'j1', status: 'completed' }]; bench.startPolling({ timeoutFn: setTimeout, clearFn: clearTimeout, delay: 5000 }); const spy = vi.spyOn(bench, 'loadJobs').mockResolvedValue({ jobs: [] }); vi.advanceTimersByTime(5000); await Promise.resolve(); expect(spy).not.toHaveBeenCalled(); // 无 active 任务:tick 直接 return 不再续 expect(bench.isPolling()).toBe(false); }); it('#40 详情/日志展开态存 store:resetSessionData 清理', () => { const pinia = createPinia(); setActivePinia(pinia); const bench = useBenchStore(); bench.detailOpenId = 'job-1'; bench.logOpen = true; bench.runLog = 'log line'; expect(bench.detailOpenId).toBe('job-1'); bench.resetSessionData(); expect(bench.detailOpenId).toBeNull(); expect(bench.logOpen).toBe(false); expect(bench.runLog).toBe(''); }); });