- git mv 保留历史:ui/(Vue3+Vite)、sdk/(BFF 中间层)
- 路径语义修正:db_path/figures_cache 改相对 sdk/(BFF cwd),
历史库 sdk/backend/data 迁移至 sdk/data/(会话/图片缓存无损)
- 引用修复 ~15 处:config.py、deploy/*.sh、vitest/playwright 配置、
单测导入路径、docs、README、gitignore、.env.example
- 骨架:agent/{qa,methodology,legacy-rag,vendor}、knowledge/manifest.yaml、
tooling/{compile,kb,crypto,assemble,audit,tools,scripts} + README
- 门禁验证:sdk pytest 125 通过、ui vitest 158 通过、
生产 BFF 脚本重启四上游全绿 + 静态托管 + 会话库无损
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
109 lines
4.3 KiB
JavaScript
109 lines
4.3 KiB
JavaScript
// extraction.pane.test.js —— B3 单测:ExtractionPane(progress_pct 派生展示、failed 错误态、轮询条件)
|
||
import { describe, it, expect, vi } from 'vitest';
|
||
import { mount } from '@vue/test-utils';
|
||
import { createPinia, setActivePinia } from 'pinia';
|
||
import { deriveProgressPct, shouldPoll } from '../../../../ui/src/components/bench/kgPaneCompat.js';
|
||
import { useBenchStore } from '../../../../ui/src/stores/bench.js';
|
||
import ProgressItem from '../../../../ui/src/components/bench/ProgressItem.vue';
|
||
|
||
vi.mock('../../../../ui/src/api/extraction.js', () => ({
|
||
listJobs: vi.fn().mockResolvedValue({ jobs: [], count: 0 }),
|
||
getJob: vi.fn(),
|
||
uploadPaper: vi.fn(),
|
||
getRunLog: vi.fn().mockResolvedValue({ text: '' }),
|
||
getProcessingStatus: vi.fn(),
|
||
getSummary: vi.fn(),
|
||
}));
|
||
|
||
describe('ExtractionPane progress_pct 派生(FR-EXTRACT-001)', () => {
|
||
it('按 stage 派生:queued=5 / mineru=35 / llm=75 / completed=100 / failed=null', () => {
|
||
expect(deriveProgressPct({ stage: 'queued' })).toBe(5);
|
||
expect(deriveProgressPct({ stage: 'mineru' })).toBe(35);
|
||
expect(deriveProgressPct({ stage: 'llm' })).toBe(75);
|
||
expect(deriveProgressPct({ stage: 'completed' })).toBe(100);
|
||
expect(deriveProgressPct({ stage: 'failed' })).toBeNull();
|
||
expect(deriveProgressPct({ stage: 'unknown' })).toBeNull();
|
||
expect(deriveProgressPct(null)).toBeNull();
|
||
});
|
||
|
||
it('BFF 已给 progress_pct 时优先使用', () => {
|
||
expect(deriveProgressPct({ stage: 'llm', progress_pct: 77 })).toBe(77);
|
||
});
|
||
|
||
it('ProgressItem:failed 显示错误态且不渲染进度条', () => {
|
||
const wrapper = mount(ProgressItem, {
|
||
props: {
|
||
job: {
|
||
job_id: 'j3',
|
||
title: 'Rice_NAC_2020.pdf',
|
||
status: 'failed',
|
||
stage: 'failed',
|
||
progress_pct: null,
|
||
message: 'MinerU 解析失败:/home/xia-lab/miniconda3/envs/minerupy311/bin/mineru 不存在',
|
||
},
|
||
open: false,
|
||
},
|
||
});
|
||
expect(wrapper.find('.pi-pct.err').text()).toBe('失败');
|
||
expect(wrapper.find('.prog-track').exists()).toBe(false); // 不显示进度条
|
||
expect(wrapper.find('.pi-errmsg').exists()).toBe(true);
|
||
expect(wrapper.find('.pi-errmsg').text()).toContain('MinerU 解析失败');
|
||
});
|
||
|
||
it('ProgressItem:completed 显示 100% success 停扫光', () => {
|
||
const wrapper = mount(ProgressItem, {
|
||
props: {
|
||
job: { job_id: 'j1', title: 'wang2019.pdf', status: 'completed', stage: 'completed', progress_pct: 100 },
|
||
open: false,
|
||
},
|
||
});
|
||
expect(wrapper.find('.pi-pct.ok').text()).toBe('100%');
|
||
expect(wrapper.find('.prog-fill.full').exists()).toBe(true);
|
||
});
|
||
|
||
it('ProgressItem:running 显示派生的 75% 渐变进度条', () => {
|
||
const wrapper = mount(ProgressItem, {
|
||
props: {
|
||
job: { job_id: 'j2', title: 'Pecan_SPL_2021.pdf', status: 'running', stage: 'llm', progress_pct: 75 },
|
||
open: false,
|
||
},
|
||
});
|
||
expect(wrapper.find('.pi-pct').text()).toBe('75%');
|
||
expect(wrapper.find('.prog-fill').exists()).toBe(true);
|
||
expect(wrapper.find('.prog-fill.full').exists()).toBe(false);
|
||
});
|
||
});
|
||
|
||
describe('ExtractionPane 轮询条件(FR-EXTRACT-005)', () => {
|
||
it('存在 running/queued 才轮询;全终态停止', () => {
|
||
expect(shouldPoll([{ status: 'completed' }, { status: 'failed' }])).toBe(false);
|
||
expect(shouldPoll([{ status: 'completed' }, { status: 'running' }])).toBe(true);
|
||
expect(shouldPoll([{ status: 'queued' }])).toBe(true);
|
||
expect(shouldPoll([])).toBe(false);
|
||
});
|
||
|
||
it('store.hasActiveJobs 与 shouldPoll 一致', () => {
|
||
setActivePinia(createPinia());
|
||
const store = useBenchStore();
|
||
store.jobs = [
|
||
{ job_id: 'a', status: 'completed' },
|
||
{ job_id: 'b', status: 'failed' },
|
||
];
|
||
expect(store.hasActiveJobs).toBe(false);
|
||
store.jobs.push({ job_id: 'c', status: 'running' });
|
||
expect(store.hasActiveJobs).toBe(true);
|
||
});
|
||
|
||
it('tab 切走即暂停:setActiveTab 离开 extract 调用 pausePolling', () => {
|
||
setActivePinia(createPinia());
|
||
const store = useBenchStore();
|
||
store.pollPaused = false;
|
||
store.setActiveTab('extract');
|
||
store.pollPaused = true; // 轮询曾启动
|
||
store.setActiveTab('retrieval');
|
||
expect(store.pollPaused).toBe(true); // 保持暂停
|
||
store.setActiveTab('extract');
|
||
expect(store.pollPaused).toBe(false); // 回到 extract 解除暂停
|
||
});
|
||
});
|