Files
Hermes-ui/tests/client/highlight-helper.test.ts
T
Butter Rice Cake of Gemini f6df0fecfa perf: 优化体积,highlight.js按需导入与i18n按需加载 (#696)
* perf: 优化打包体积,highlight.js按需导入与i18n按需加载

1. highlight.js: 从全量导入改为 core + 注册27种常用语言,减少约500~800KB
2. i18n: 只同步加载en语言包,其他8种语言改为异步加载,首屏减少约350~400KB
3. 使用vue-i18n的setLocaleMessage API动态注册语言包
4. 新增switchLocale函数统一处理语言切换
5. 同步更新相关测试文件的mock路径和API适配

* 修复类型断言
2026-05-14 12:39:36 +08:00

82 lines
2.8 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest'
const highlightJsMock = vi.hoisted(() => ({
getLanguage: vi.fn((lang?: string) => ['shell', 'xml', 'yaml', 'bash', 'json'].includes(lang || '')),
highlight: vi.fn((content: string, { language }: { language: string }) => ({
value: `<span class="mock-${language}">${content}</span>`,
})),
registerLanguage: vi.fn(),
}))
vi.mock('highlight.js/lib/core', () => ({
default: highlightJsMock,
}))
import { normalizeHighlightLanguage, renderHighlightedCodeBlock } from '@/components/hermes/chat/highlight'
describe('highlight helper', () => {
beforeEach(() => {
vi.clearAllMocks()
highlightJsMock.getLanguage.mockImplementation((lang?: string) => ['shell', 'xml', 'yaml', 'bash', 'json'].includes(lang || ''))
highlightJsMock.highlight.mockImplementation((content: string, { language }: { language: string }) => ({
value: `<span class="mock-${language}">${content}</span>`,
}))
})
it.each([
['vue', 'xml'],
['yml', 'yaml'],
['sh', 'bash'],
['zsh', 'bash'],
['shellscript', 'bash'],
['shell', 'shell'],
])('normalizes %s to %s', (input, expected) => {
expect(normalizeHighlightLanguage(input)).toBe(expected)
})
it('uses a delegated copy attribute instead of inline javascript', () => {
const html = renderHighlightedCodeBlock('x', 'json', 'Copy')
expect(html).toContain('data-copy-code="true"')
expect(html).not.toContain('onclick=')
})
it('preserves shell-session highlighting instead of remapping shell fences to bash', () => {
const html = renderHighlightedCodeBlock('$ ls\nfoo.txt\n', 'shell', 'Copy')
expect(highlightJsMock.highlight).toHaveBeenCalledWith('$ ls\nfoo.txt\n', {
language: 'shell',
ignoreIllegals: true,
})
expect(html).toContain('class="code-lang">shell</span>')
})
it('skips highlighting for large known-language blocks when a render limit is set', () => {
const html = renderHighlightedCodeBlock('x'.repeat(5000), 'vue', 'Copy', {
maxHighlightLength: 2000,
})
expect(highlightJsMock.highlight).not.toHaveBeenCalled()
expect(html).toContain('class="code-lang">vue</span>')
})
it('falls back to escaped plaintext for unsupported fence labels', () => {
const html = renderHighlightedCodeBlock('<tag>', 'unknown', 'Copy')
expect(highlightJsMock.highlight).not.toHaveBeenCalled()
expect(html).toContain('&lt;tag&gt;')
expect(html).toContain('class="code-lang">unknown</span>')
})
it('falls back to escaped plaintext when direct highlighting throws', () => {
highlightJsMock.highlight.mockImplementationOnce(() => {
throw new Error('boom')
})
const html = renderHighlightedCodeBlock('<tag>', 'vue', 'Copy')
expect(html).toContain('&lt;tag&gt;')
expect(html).toContain('class="code-lang">vue</span>')
})
})