test: 建立测试体系 - Vitest 单元+组件测试与测试策略文档

This commit is contained in:
2026-08-17 17:48:10 +08:00
parent ff0018e6d3
commit 008871aefc
10 changed files with 1500 additions and 13 deletions
+21
View File
@@ -0,0 +1,21 @@
import { describe, it, expect } from 'vitest'
import { render, screen } from '@testing-library/react'
import App from '../App'
describe('App - 初始空态', () => {
it('渲染应用名称 DiffLens', () => {
render(<App />)
expect(screen.getByText('DiffLens')).toBeInTheDocument()
})
it('展示左右两个空态文件面板', () => {
render(<App />)
expect(screen.getByText(/选择左侧文件/)).toBeInTheDocument()
expect(screen.getByText(/选择右侧文件/)).toBeInTheDocument()
})
it('未加载文件时不显示导出入口', () => {
render(<App />)
expect(screen.queryByText('导出报告')).not.toBeInTheDocument()
})
})
+94
View File
@@ -0,0 +1,94 @@
import { describe, it, expect } from 'vitest'
import { computeDiff } from './diffEngine'
describe('computeDiff - 空文本', () => {
it('空 vs 空 不产生任何行', () => {
const { rows, summary } = computeDiff('', '')
expect(rows).toHaveLength(0)
expect(summary.changedLines).toBe(0)
})
it('空 vs 非空 全部为新增行', () => {
const { rows, summary } = computeDiff('', 'a\nb')
expect(rows).toHaveLength(2)
expect(rows.every((r) => r.rowKind === 'added')).toBe(true)
expect(summary.inserted).toBe(2)
})
})
describe('computeDiff - 全同 / 无差异', () => {
it('内容完全相同:全部 unchanged', () => {
const { rows, summary } = computeDiff('line1\nline2', 'line1\nline2')
expect(summary.changedLines).toBe(0)
expect(rows.every((r) => r.rowKind === 'unchanged')).toBe(true)
})
})
describe('computeDiff - 行级增删', () => {
it('新增行', () => {
const { rows, summary } = computeDiff('a', 'a\nb')
const added = rows.filter((r) => r.rowKind === 'added')
expect(added).toHaveLength(1)
expect(added[0].right.lineNo).toBe(2)
expect(added[0].right.text).toBe('b')
expect(added[0].left.lineNo).toBeNull()
expect(summary.inserted).toBe(1)
})
it('删除行', () => {
const { rows, summary } = computeDiff('a\nb', 'a')
const removed = rows.filter((r) => r.rowKind === 'removed')
expect(removed).toHaveLength(1)
expect(removed[0].left.lineNo).toBe(2)
expect(removed[0].left.text).toBe('b')
expect(removed[0].right.lineNo).toBeNull()
expect(summary.deleted).toBe(1)
})
})
describe('computeDiff - 词级修改', () => {
it('同一删除/新增配对为 modified 并产生 segs', () => {
const { rows, summary } = computeDiff('hello world', 'hello moon')
expect(summary.modified).toBe(1)
const m = rows.find((r) => r.rowKind === 'modified')
expect(m).toBeDefined()
expect(m!.left.segs).not.toBeNull()
expect(m!.right.segs).not.toBeNull()
expect(m!.left.segs!.some((s) => s.kind === 'delete' && s.text.includes('world'))).toBe(true)
expect(m!.right.segs!.some((s) => s.kind === 'insert' && s.text.includes('moon'))).toBe(true)
expect(m!.left.lineNo).toBe(1)
expect(m!.right.lineNo).toBe(1)
})
it('删除多于新增时长侧补空槽', () => {
const { rows } = computeDiff('a\nb', 'a')
const removed = rows.find((r) => r.rowKind === 'removed')
expect(removed!.right.text).toBeNull()
})
})
describe('computeDiff - 忽略选项', () => {
it('忽略大小写', () => {
const { summary } = computeDiff('Alpha', 'alpha', { ignoreCase: true })
expect(summary.changedLines).toBe(0)
})
it('忽略行首尾空白', () => {
const { summary } = computeDiff(' value ', 'value', { trimWhitespace: true })
expect(summary.changedLines).toBe(0)
})
it('未开启忽略时同一纯净差异仍被识别', () => {
const { summary } = computeDiff(' value ', 'value')
expect(summary.changedLines).toBeGreaterThan(0)
})
})
describe('computeDiff - 行切分细节', () => {
it('结尾换行不产生多余空行', () => {
const { rows, summary } = computeDiff('a\n', 'a')
expect(rows).toHaveLength(1)
expect(rows[0].rowKind).toBe('unchanged')
expect(summary.changedLines).toBe(0)
})
})
+63
View File
@@ -0,0 +1,63 @@
import { describe, it, expect } from 'vitest'
import { computeDiff } from './diffEngine'
import { buildHtmlReport, buildTxtReport, buildMarkdownReport, buildReport, REPORT_EXT } from './report'
const ctx = { leftName: 'a.txt', rightName: 'b.txt', leftEncoding: 'UTF-8', rightEncoding: 'UTF-8' }
describe('buildHtmlReport', () => {
const { rows, summary } = computeDiff('line1\nline2', 'line1\nline3')
it('输出合法 HTML 文档并包含核心信息', () => {
const html = buildHtmlReport(rows, ctx, summary)
expect(html).toContain('<!doctype html>')
expect(html).toContain('DiffLens 差异报告')
expect(html).toContain('a.txt')
expect(html).toContain('b.txt')
})
it('包含差异统计与类型高亮语义', () => {
const html = buildHtmlReport(rows, ctx, summary)
expect(html).toContain('modified')
expect(html).toContain('<b>')
})
})
describe('buildTxtReport', () => {
it('输出带增删改标记的行式文本', () => {
const { rows, summary } = computeDiff('a', 'a\nb')
const txt = buildTxtReport(rows, ctx, summary)
expect(txt).toContain('DiffLens')
expect(txt).toContain('+')
})
})
describe('buildMarkdownReport', () => {
it('输出表格化报告', () => {
const { rows, summary } = computeDiff('a', 'b')
const md = buildMarkdownReport(rows, ctx, summary)
expect(md).toContain('# DiffLens 差异报告')
expect(md).toContain('| 类型 |')
expect(md).toContain('| 左行号 |')
})
it('管道符被转义以保持表格结构', () => {
const { rows, summary } = computeDiff('a|b', 'a')
const md = buildMarkdownReport(rows, ctx, summary)
expect(md).toContain('a\\|b')
})
})
describe('buildReport / REPORT_EXT', () => {
it('按格式分发', () => {
const { rows, summary } = computeDiff('x', 'y')
expect(buildReport(rows, ctx, summary, 'html')).toContain('<!doctype html>')
expect(buildReport(rows, ctx, summary, 'txt')).toContain('DiffLens')
expect(buildReport(rows, ctx, summary, 'md')).toContain('# DiffLens 差异报告')
})
it('扩展名映射正确', () => {
expect(REPORT_EXT.html).toBe('html')
expect(REPORT_EXT.txt).toBe('txt')
expect(REPORT_EXT.md).toBe('md')
})
})
+8
View File
@@ -0,0 +1,8 @@
import { afterEach } from 'vitest'
import { cleanup } from '@testing-library/react'
import '@testing-library/jest-dom/vitest'
// 每个用例结束自动卸载组件,避免多次 render 叠加污染 DOM
afterEach(() => {
cleanup()
})