mirror of
https://wget.la/https://github.com/Wxw-Gu/WechatExplorer
synced 2026-08-18 03:57:02 +08:00
1. 拆分读取、解析、转写、媒体处理、写入和压缩阶段,完善任务进度展示。 2. 增量导出复用语音资源与转写结果,并为缺失转写补充识别。 3. 稳定远程头像文件名并保留同源头像版本更新。 4. 支持音频附件直接播放、新窗口打开附件,并解码分享标题 XML 实体。 5. 补充导出进度、语音、头像、附件和消息解析回归测试。
164 lines
6.3 KiB
TypeScript
164 lines
6.3 KiB
TypeScript
import { render, screen, waitFor } from '@testing-library/react'
|
|
import userEvent from '@testing-library/user-event'
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { ExportWorkspace } from '../../src/renderer/src/components/export/ExportWorkspace'
|
|
import { ExportTaskCenter } from '../../src/renderer/src/components/export/ExportTaskCenter'
|
|
import type { ExportTaskRecord } from '../../src/shared/export'
|
|
import type { Contact, Message } from '../../src/shared/types'
|
|
|
|
const contacts: Contact[] = Array.from({ length: 6 }, (_, index) => ({
|
|
md5: `contact-${index + 1}`,
|
|
m_nsUsrName: `wxid_contact_${index + 1}`,
|
|
m_nsNickName: `聊天 ${String.fromCharCode(65 + index)}`,
|
|
type: index === 2 ? 'group' : 'user'
|
|
}))
|
|
|
|
const previewMessage = (contact: Contact): Message => ({
|
|
id: `preview-${contact.md5}`,
|
|
from: 'user',
|
|
type: '普通文本',
|
|
datetime: '',
|
|
content: `${contact.m_nsNickName} 的预览`,
|
|
isSender: false,
|
|
createTime: contacts.indexOf(contact) + 1
|
|
})
|
|
|
|
describe('ExportWorkspace multi-chat selection', () => {
|
|
beforeEach(() => {
|
|
Object.defineProperty(window, 'api', {
|
|
configurable: true,
|
|
value: {
|
|
onExportProgress: vi.fn(() => vi.fn()),
|
|
getVoiceModelStatus: vi.fn().mockRejectedValue(new Error('fixture model unavailable')),
|
|
getGroupSnapshot: vi.fn(async () => ({ members: [] })),
|
|
cancelExport: vi.fn(async () => ({ success: true })),
|
|
revealExport: vi.fn(async () => ({ success: true }))
|
|
}
|
|
})
|
|
})
|
|
|
|
const renderWorkspace = (
|
|
onStartExport = vi.fn(async () => ({ success: false }))
|
|
): { loadPreviewMessages: ReturnType<typeof vi.fn> } => {
|
|
const loadPreviewMessages = vi.fn(async (contact: Contact) => [previewMessage(contact)])
|
|
render(
|
|
<ExportWorkspace
|
|
contacts={contacts}
|
|
initialContact={contacts[0]}
|
|
selfInfo={{ wxid: 'self', nickname: '本人', accountRoot: '/fixture' }}
|
|
dbReady
|
|
loadPreviewMessages={loadPreviewMessages}
|
|
onOpenSettings={vi.fn()}
|
|
exportTasks={[]}
|
|
onStartExport={onStartExport}
|
|
onCancelExport={vi.fn(async () => undefined)}
|
|
/>
|
|
)
|
|
return { loadPreviewMessages }
|
|
}
|
|
|
|
it('defaults to one chat, forces HTML after adding another, merges the preview, and resets locally', async () => {
|
|
const onStartExport = vi.fn(async () => ({ success: false }))
|
|
const { loadPreviewMessages } = renderWorkspace(onStartExport)
|
|
|
|
expect(screen.getAllByText('聊天 A')).toHaveLength(2)
|
|
expect(screen.getByRole('button', { name: 'CSV' })).toBeEnabled()
|
|
expect(await screen.findByText('聊天 A 的预览')).toBeVisible()
|
|
|
|
await userEvent.click(screen.getByRole('button', { name: '+ 添加聊天' }))
|
|
await userEvent.click(screen.getByRole('button', { name: /聊天 B/ }))
|
|
|
|
expect(screen.getByText('已选 2 / 5 个')).toBeVisible()
|
|
expect(screen.getByRole('button', { name: 'CSV' })).toBeDisabled()
|
|
expect(screen.getByRole('button', { name: 'JSON' })).toBeDisabled()
|
|
expect(screen.getByRole('button', { name: 'Markdown' })).toBeDisabled()
|
|
expect(screen.getByRole('button', { name: /HTML/ })).toHaveClass('active')
|
|
expect(await screen.findByText('聊天 B 的预览')).toBeVisible()
|
|
expect(screen.getByText('2 个聊天 · 合并预览')).toBeVisible()
|
|
|
|
await userEvent.click(screen.getByRole('button', { name: '开始导出' }))
|
|
await waitFor(() => expect(onStartExport).toHaveBeenCalledOnce())
|
|
expect(onStartExport.mock.calls[0][0]).toMatchObject({
|
|
format: 'html',
|
|
outputName: '聊天 A等2个聊天_合并档案',
|
|
targets: [
|
|
{ userMd5: 'contact-1', name: '聊天 A' },
|
|
{ userMd5: 'contact-2', name: '聊天 B' }
|
|
]
|
|
})
|
|
|
|
await userEvent.click(screen.getByRole('button', { name: '恢复默认' }))
|
|
expect(screen.queryByText('已选 2 / 5 个')).not.toBeInTheDocument()
|
|
expect(screen.getByRole('button', { name: 'CSV' })).toBeEnabled()
|
|
expect(screen.getAllByText('聊天 A').length).toBeGreaterThanOrEqual(2)
|
|
expect(loadPreviewMessages).toHaveBeenCalledWith(contacts[0])
|
|
expect(contacts[0].md5).toBe('contact-1')
|
|
})
|
|
|
|
it('does not allow removing the last chat and disables unselected chats at five', async () => {
|
|
renderWorkspace()
|
|
await userEvent.click(screen.getByRole('button', { name: '+ 添加聊天' }))
|
|
|
|
await userEvent.click(screen.getByRole('button', { name: /聊天 A/ }))
|
|
expect(screen.getByText('已选 1 / 5 个')).toBeVisible()
|
|
|
|
for (const name of ['聊天 B', '聊天 C', '聊天 D', '聊天 E']) {
|
|
await userEvent.click(screen.getByRole('button', { name: new RegExp(name) }))
|
|
}
|
|
expect(screen.getByText('已选 5 / 5 个')).toBeVisible()
|
|
expect(screen.getByRole('button', { name: /聊天 F/ })).toBeDisabled()
|
|
|
|
await userEvent.click(screen.getByRole('button', { name: /聊天 B/ }))
|
|
expect(screen.getByText('已选 4 / 5 个')).toBeVisible()
|
|
expect(screen.getByRole('button', { name: /聊天 F/ })).toBeEnabled()
|
|
})
|
|
})
|
|
|
|
describe('ExportTaskCenter details', () => {
|
|
it('shows the exported message count for success and the reason for failure', () => {
|
|
const tasks: ExportTaskRecord[] = [
|
|
{
|
|
jobId: 'success',
|
|
targetIds: ['contact-1'],
|
|
targetNames: ['聊天 A'],
|
|
targetLabel: '聊天 A',
|
|
format: 'html',
|
|
status: 'completed',
|
|
progress: {
|
|
jobId: 'success',
|
|
phase: 'completed',
|
|
processed: 125,
|
|
total: 125,
|
|
percent: 100
|
|
},
|
|
createdAt: 1
|
|
},
|
|
{
|
|
jobId: 'failure',
|
|
targetIds: ['contact-1', 'contact-2'],
|
|
targetNames: ['聊天 A', '聊天 B'],
|
|
targetLabel: '聊天 A 等 2 个聊天',
|
|
format: 'html',
|
|
status: 'failed',
|
|
progress: {
|
|
jobId: 'failure',
|
|
phase: 'failed',
|
|
processed: 0,
|
|
percent: 0,
|
|
error: '视频文件没有写入权限'
|
|
},
|
|
createdAt: 2
|
|
}
|
|
]
|
|
|
|
render(
|
|
<ExportTaskCenter open taskCount={0} tasks={tasks} onToggle={vi.fn()} onCancel={vi.fn()} />
|
|
)
|
|
|
|
expect(screen.getByText('HTML · 已完成')).toBeVisible()
|
|
expect(screen.getByText('成功导出 125 条消息')).toBeVisible()
|
|
expect(screen.getByText('HTML · 导出失败')).toBeVisible()
|
|
expect(screen.getByText('失败原因:视频文件没有写入权限')).toBeVisible()
|
|
})
|
|
})
|