Files
2026-09-07 22:41:36 +08:00

94 lines
4.2 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// @vitest-environment jsdom
// privateLibraryPane.test.js —— 我的资料面板(T1 骨架,对齐 A1 交付)
// 对应用例: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 上传。」;加载失败显示重试按钮。
// 修正(A1 交付对齐):
// - 可变状态用 vi.hoisted(vi.mock 工厂被提升,引用顶层 let 会 TDZ);
// - A1 onDelete 内部 await setTimeout(0)(宏任务)后才刷新——用例必须等待宏任务
// (vitest 默认未启用 fake timers,setTimeout 真实执行,flushPromises 不排干它;
// 用小轮询或 vi.useFakeTimers+advanceTimersByTimeAsync;本文件用真实定时器轮询辅助函数)。
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { mount, flushPromises } from '@vue/test-utils';
import { setActivePinia, createPinia } from 'pinia';
const h = vi.hoisted(() => ({
listImpl: () => ({ ok: true, items: [] }),
removeImpl: () => ({ ok: true }),
}));
vi.mock('../../src/api/docgen.js', () => ({
listLibrary: vi.fn(async () => h.listImpl()),
removeLibrary: vi.fn(async (id) => h.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' };
/** 等待宏任务(A1 onDelete 的 setTimeout(0) 刷新点) */
async function waitMacroTask() {
await new Promise((resolve) => setTimeout(resolve, 0));
await flushPromises();
}
describe('PrivateLibraryPane(FR-PRIV-006)', () => {
beforeEach(() => {
setActivePinia(createPinia());
h.listImpl = () => ({ ok: true, items: [] });
h.removeImpl = () => ({ ok: true });
});
it('TC-PRIV-L3-04 列表加载:标题 + 计数 + 条目(名称)', async () => {
h.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);
h.listImpl = () => ({ ok: true, items: [ROW_A, ROW_B] });
h.removeImpl = vi.fn(async () => ({ ok: true }));
const wrapper = mount(PrivateLibraryPane);
await flushPromises();
const deleteBtn = wrapper.find('button[data-action="delete"]');
expect(deleteBtn.exists()).toBe(true);
await deleteBtn.trigger('click');
expect(window.confirm).toHaveBeenCalled();
// 删除后刷新:下一次 listLibrary 返回单条(A1 在宏任务后刷新)
h.listImpl = () => ({ ok: true, items: [ROW_B] });
await waitMacroTask();
expect(wrapper.text()).not.toContain('水稻资料.pdf');
expect(wrapper.text()).toContain('小麦试验.docx');
});
it('TC-PRIV-L3-07 加载失败显示重试按钮,重试后恢复', async () => {
let failFirst = true;
h.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');
});
});