// @vitest-environment jsdom // components.private.test.js —— AssistantMessage private_doc 块渲染(T1 骨架,对齐 A1 交付) // 对应用例:TC-PRIV-L3-01 ~ TC-PRIV-L3-03(docs/team/TEST_CASES_PRIVATE.md) // 风格:沿用 tests/frontend/unit/b2/components.test.js(mount + DOM 断言)。 // A1 交付类名对齐:.private-doc-block / .private-doc-answer / .private-doc-item[data-private-item]。 import { describe, it, expect, beforeEach } from 'vitest'; import { mount } from '@vue/test-utils'; import { setActivePinia, createPinia } from 'pinia'; import AssistantMessage from '../../src/components/chat/AssistantMessage.vue'; function messageWithBlock(block) { return { id: 'm1', role: 'assistant', kind: 'qa', status: 'done', blocks: [ { type: 'pipeline', status: 'done', steps: [] }, block, ], raw: null, created_at: '2026-09-01T00:00:00Z', updated_at: '2026-09-01T00:00:01Z', }; } const BASE_BLOCK = { type: 'private_doc', answer: '依据[资料1],水稻SPL家族共19个成员。', items: [ { ref: 1, name: '水稻SPL资料.pdf', score: 0.92, snippet: '水稻SPL家族共有19个成员……' }, ], }; describe('AssistantMessage private_doc 块渲染(FR-PRIV-005)', () => { beforeEach(() => { setActivePinia(createPinia()); }); it('TC-PRIV-L3-01 卡体/标题/条目齐全', () => { const wrapper = mount(AssistantMessage, { props: { message: messageWithBlock(BASE_BLOCK) }, }); expect(wrapper.find('.private-doc-block').exists()).toBe(true); expect(wrapper.text()).toContain('私有资料参考'); // 短答经 markdown 渲染为 HTML 后展示(引用编号文本) expect(wrapper.find('.private-doc-answer').exists()).toBe(true); expect(wrapper.text()).toContain('依据[资料1]'); // 条目:编号/名称/相关度(两位小数)/片段(A1 实现) const itemEl = wrapper.find('.private-doc-item[data-private-item]'); expect(itemEl.exists()).toBe(true); expect(itemEl.text()).toContain('[资料1]'); expect(itemEl.text()).toContain('水稻SPL资料.pdf'); expect(itemEl.text()).toContain('0.92'); expect(itemEl.text()).toContain('水稻SPL家族共有19个成员'); }); it('TC-PRIV-L3-02 answer 为空仅显示条目列表(无空白答区)', () => { const block = { ...BASE_BLOCK, answer: '' }; const wrapper = mount(AssistantMessage, { props: { message: messageWithBlock(block) }, }); expect(wrapper.find('.private-doc-block').exists()).toBe(true); // UI_SPEC §9.1 空答态:不渲染空白答区(A1:v-if="b.answer") expect(wrapper.find('.private-doc-answer').exists()).toBe(false); expect(wrapper.find('.private-doc-item[data-private-item]').exists()).toBe(true); }); it('TC-PRIV-L3-03 markdown 消毒:script 移除、**加粗** 渲染', () => { const block = { ...BASE_BLOCK, answer: '结论**成立**。', }; const wrapper = mount(AssistantMessage, { props: { message: messageWithBlock(block) }, }); const html = wrapper.find('.private-doc-block').html(); expect(html).not.toContain('成立'); }); it('无 private_doc 块的消息不渲染该卡(零回归)', () => { const wrapper = mount(AssistantMessage, { props: { message: messageWithBlock({ type: 'text', html: '

普通答案

' }) }, }); expect(wrapper.find('.private-doc-block').exists()).toBe(false); }); });