TL 复查达标放行:92 defined = 92 used、unmatched 0、unreferenced 0; 假设 1/9 已按实施方案 §1.2/§3.2 裁决修订(表格原位聚合/outline 不参与 切块/跨轮归属行为级判据)。骨架:test_chunks.py 416 行 + vitest 4 文件。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
86 lines
3.7 KiB
JavaScript
86 lines
3.7 KiB
JavaScript
// @vitest-environment jsdom
|
||
// privateLibraryPane.test.js —— 我的资料面板(T1 骨架)
|
||
// 对应用例:TC-PRIV-L3-04 ~ TC-PRIV-L3-07(docs/team/TEST_CASES_PRIVATE.md)
|
||
// UI_SPEC §9.2:标题「📁 我的资料」+ 计数;列表项 name/size/time;删除 confirm → removeLibrary → 刷新;
|
||
// 空态「尚无上传资料。在对话框拖拽 PDF / DOCX / TXT 上传。」;加载失败显示重试按钮。
|
||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||
import { mount, flushPromises } from '@vue/test-utils';
|
||
import { setActivePinia, createPinia } from 'pinia';
|
||
|
||
let listImpl = () => ({ ok: true, items: [] });
|
||
let removeImpl = () => ({ ok: true });
|
||
|
||
vi.mock('../../src/api/docgen.js', () => ({
|
||
listLibrary: vi.fn(async () => listImpl()),
|
||
removeLibrary: vi.fn(async (id) => removeImpl(id)),
|
||
}));
|
||
|
||
import PrivateLibraryPane from '../../src/components/bench/PrivateLibraryPane.vue';
|
||
|
||
const ROW_A = { id: 'a', name: '水稻资料.pdf', category: '', tags: '', description: '', as_template: false, active: true, created_at: '2026-09-01T00:00:00Z' };
|
||
const ROW_B = { id: 'b', name: '小麦试验.docx', category: '', tags: '', description: '', as_template: false, active: true, created_at: '2026-09-02T00:00:00Z' };
|
||
|
||
describe('PrivateLibraryPane(FR-PRIV-006)', () => {
|
||
beforeEach(() => {
|
||
setActivePinia(createPinia());
|
||
listImpl = () => ({ ok: true, items: [] });
|
||
removeImpl = () => ({ ok: true });
|
||
});
|
||
|
||
it('TC-PRIV-L3-04 列表加载:标题 + 计数 + 条目(名称)', async () => {
|
||
listImpl = () => ({ ok: true, items: [ROW_A, ROW_B] });
|
||
const wrapper = mount(PrivateLibraryPane);
|
||
await flushPromises();
|
||
expect(wrapper.text()).toContain('我的资料');
|
||
expect(wrapper.text()).toContain('2');
|
||
expect(wrapper.text()).toContain('水稻资料.pdf');
|
||
expect(wrapper.text()).toContain('小麦试验.docx');
|
||
});
|
||
|
||
it('TC-PRIV-L3-05 空态文案', async () => {
|
||
const wrapper = mount(PrivateLibraryPane);
|
||
await flushPromises();
|
||
expect(wrapper.text()).toContain('尚无上传资料');
|
||
expect(wrapper.text()).toContain('PDF / DOCX / TXT');
|
||
});
|
||
|
||
it('TC-PRIV-L3-06 删除:confirm 二次确认 → removeLibrary → 列表刷新', async () => {
|
||
vi.spyOn(window, 'confirm').mockReturnValue(true);
|
||
listImpl = () => ({ ok: true, items: [ROW_A, ROW_B] });
|
||
removeImpl = vi.fn(async () => ({ ok: true }));
|
||
const wrapper = mount(PrivateLibraryPane);
|
||
await flushPromises();
|
||
|
||
const deleteBtn = wrapper.find('button[data-action="delete"], .pane-btn');
|
||
// 删除按钮 hover 出现;直接触发存在的按钮
|
||
if (deleteBtn.exists()) {
|
||
await deleteBtn.trigger('click');
|
||
expect(window.confirm).toHaveBeenCalled();
|
||
// 删除后刷新:下一次 listLibrary 返回单条
|
||
listImpl = () => ({ ok: true, items: [ROW_B] });
|
||
await flushPromises();
|
||
expect(wrapper.text()).not.toContain('水稻资料.pdf');
|
||
expect(wrapper.text()).toContain('小麦试验.docx');
|
||
} else {
|
||
// 骨架防御:删除按钮未渲染时标记失败(A1 需实现 hover 删除按钮)
|
||
expect(deleteBtn.exists()).toBe(true);
|
||
}
|
||
});
|
||
|
||
it('TC-PRIV-L3-07 加载失败显示重试按钮,重试后恢复', async () => {
|
||
let failFirst = true;
|
||
listImpl = () => {
|
||
if (failFirst) throw new Error('network');
|
||
return { ok: true, items: [ROW_A] };
|
||
};
|
||
const wrapper = mount(PrivateLibraryPane);
|
||
await flushPromises();
|
||
const retryBtn = wrapper.find('button');
|
||
expect(retryBtn.exists()).toBe(true);
|
||
failFirst = false;
|
||
await retryBtn.trigger('click');
|
||
await flushPromises();
|
||
expect(wrapper.text()).toContain('水稻资料.pdf');
|
||
});
|
||
});
|