90 lines
3.5 KiB
JavaScript
90 lines
3.5 KiB
JavaScript
// @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: '结论**成立**。<script>alert(1)</script>',
|
||
};
|
||
const wrapper = mount(AssistantMessage, {
|
||
props: { message: messageWithBlock(block) },
|
||
});
|
||
const html = wrapper.find('.private-doc-block').html();
|
||
expect(html).not.toContain('<script');
|
||
expect(html).not.toContain('alert(1)');
|
||
expect(html).toContain('<strong>成立</strong>');
|
||
});
|
||
|
||
it('无 private_doc 块的消息不渲染该卡(零回归)', () => {
|
||
const wrapper = mount(AssistantMessage, {
|
||
props: { message: messageWithBlock({ type: 'text', html: '<p>普通答案</p>' }) },
|
||
});
|
||
expect(wrapper.find('.private-doc-block').exists()).toBe(false);
|
||
});
|
||
});
|