From 05f05a29ee507daf65ed3b7b625712d495ab8ddd Mon Sep 17 00:00:00 2001 From: thzxx <1440196015@qq.com> Date: Mon, 17 Aug 2026 18:18:25 +0800 Subject: [PATCH] =?UTF-8?q?test:=20App=20=E4=B8=8E=20main=20=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E8=A6=86=E7=9B=96=E6=8F=90=E5=8D=87=E8=87=B3=2090%+?= =?UTF-8?q?=EF=BC=88=E5=8F=B3=E9=94=AE=E6=93=8D=E4=BD=9C/=E5=8F=B3?= =?UTF-8?q?=E4=BE=A7=E9=9D=A2=E6=9D=BF/=E8=A7=A3=E7=A0=81=E5=9B=9E?= =?UTF-8?q?=E9=80=80/=E5=85=A5=E5=8F=A3=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/renderer/src/__tests__/App.test.tsx | 86 +++++++++++++++++++++++++ src/renderer/src/__tests__/main.test.ts | 20 ++++++ 2 files changed, 106 insertions(+) create mode 100644 src/renderer/src/__tests__/main.test.ts diff --git a/src/renderer/src/__tests__/App.test.tsx b/src/renderer/src/__tests__/App.test.tsx index 7179698..5789b4c 100644 --- a/src/renderer/src/__tests__/App.test.tsx +++ b/src/renderer/src/__tests__/App.test.tsx @@ -18,10 +18,18 @@ function mockApi(overrides?: Partial): typeof window.api { return { ...base, ...overrides } as typeof window.api } +let clipboardSpy: ReturnType + beforeEach(() => { window.api = mockApi() // jsdom 未实现 scrollIntoView,导航定位需要打桩 Element.prototype.scrollIntoView = vi.fn() + // jsdom 未实现 navigator.clipboard,右键复制需要打桩 + clipboardSpy = vi.fn() + Object.defineProperty(navigator, 'clipboard', { + value: { writeText: clipboardSpy }, + configurable: true + }) }) describe('App - 初始空态', () => { @@ -105,6 +113,19 @@ describe('App - 拖拽导入', () => { fireEvent.dragLeave(pane) expect(pane.className).not.toContain('dragging') }) + + it('解码失败时回退 file.text(覆盖 dropPane catch 分支)', async () => { + window.api = mockApi({ + decodeBuffer: async () => { + throw new Error('boom') + } + }) + render() + const file = new File(['fallback1'], 'd.txt', { type: 'text/plain' }) + const pane = screen.getByText(/选择左侧文件/).closest('.pane-empty') as Element + fireEvent.drop(pane, { dataTransfer: { files: [file] } }) + expect(await screen.findByText('导出报告')).toBeInTheDocument() + }) }) describe('App - 差异导航与清空', () => { @@ -124,4 +145,69 @@ describe('App - 差异导航与清空', () => { fireEvent.click(screen.getByText('清空')) expect(await screen.findByText(/选择左侧文件/)).toBeInTheDocument() }) +}) + +describe('App - 空态打开按钮', () => { + it('点击空面板的打开文件按钮加载左侧文件', async () => { + render() + fireEvent.click(screen.getAllByText('打开文件')[0]) + expect(await screen.findByText('导出报告')).toBeInTheDocument() + }) +}) + +describe('App - 右键菜单操作', () => { + it('执行复制本行内容并关闭菜单', async () => { + render() + fireEvent.click(screen.getByText('打开左侧')) + await screen.findByText('导出报告') + fireEvent.contextMenu((await screen.findAllByText(/line1/))[0]) + fireEvent.click(await screen.findByText('复制左侧此行内容')) + expect(clipboardSpy).toHaveBeenCalled() + expect(screen.queryByText('复制左侧此行内容')).not.toBeInTheDocument() + }) + + it('执行复制文件名', async () => { + render() + fireEvent.click(screen.getByText('打开左侧')) + await screen.findByText('导出报告') + fireEvent.contextMenu((await screen.findAllByText(/line1/))[0]) + fireEvent.click(await screen.findByText('复制文件名')) + expect(clipboardSpy).toHaveBeenCalledWith('a.txt') + }) + + it('执行在文件夹中显示(覆盖 showInFolder)', async () => { + const showInFolder = vi.fn(async () => true) + window.api = mockApi({ showInFolder }) + render() + fireEvent.click(screen.getByText('打开左侧')) + await screen.findByText('导出报告') + fireEvent.contextMenu((await screen.findAllByText(/line1/))[0]) + fireEvent.click(await screen.findByText('在文件夹中显示')) + expect(showInFolder).toHaveBeenCalledWith('/tmp/a.txt') + }) +}) + +describe('App - 右侧面板交互', () => { + it('点击右侧打开文件按钮加载', async () => { + render() + fireEvent.click(screen.getAllByText('打开文件')[1]) + expect(await screen.findByText('导出报告')).toBeInTheDocument() + }) + + it('右侧拖拽悬停/离开高亮切换', () => { + render() + const pane = screen.getByText(/选择右侧文件/).closest('.pane-empty') as Element + fireEvent.dragOver(pane) + expect(pane.className).toContain('dragging') + fireEvent.dragLeave(pane) + expect(pane.className).not.toContain('dragging') + }) + + it('右侧拖放加载(覆盖右侧 onDrop 与 dropPane 右分支)', async () => { + render() + const file = new File(['r1\nr2'], 'e.txt', { type: 'text/plain' }) + const pane = screen.getByText(/选择右侧文件/).closest('.pane-empty') as Element + fireEvent.drop(pane, { dataTransfer: { files: [file] } }) + expect(await screen.findByText('导出报告')).toBeInTheDocument() + }) }) \ No newline at end of file diff --git a/src/renderer/src/__tests__/main.test.ts b/src/renderer/src/__tests__/main.test.ts new file mode 100644 index 0000000..4f627e4 --- /dev/null +++ b/src/renderer/src/__tests__/main.test.ts @@ -0,0 +1,20 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest' +import { screen, act } from '@testing-library/react' + +// main.tsx 引入全局样式,测试中替换为空模块避免 CSS 处理 +vi.mock('../styles/global.css', () => ({})) + +describe('main 入口', () => { + beforeEach(() => { + document.body.innerHTML = '
' + vi.resetModules() + }) + + it('挂载 DiffLens 应用(覆盖 main.tsx 入口)', async () => { + await act(async () => { + await import('../main') + }) + expect(document.getElementById('root')).toBeTruthy() + expect(await screen.findByText('DiffLens')).toBeInTheDocument() + }) +}) \ No newline at end of file