test: 建立测试体系 - Vitest 单元+组件测试与测试策略文档
This commit is contained in:
@@ -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()
|
||||
})
|
||||
})
|
||||
@@ -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)
|
||||
})
|
||||
})
|
||||
@@ -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')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,8 @@
|
||||
import { afterEach } from 'vitest'
|
||||
import { cleanup } from '@testing-library/react'
|
||||
import '@testing-library/jest-dom/vitest'
|
||||
|
||||
// 每个用例结束自动卸载组件,避免多次 render 叠加污染 DOM
|
||||
afterEach(() => {
|
||||
cleanup()
|
||||
})
|
||||
Reference in New Issue
Block a user