mirror of
https://wget.la/https://github.com/Wxw-Gu/WechatExplorer
synced 2026-08-17 03:27:00 +08:00
196 lines
6.7 KiB
TypeScript
196 lines
6.7 KiB
TypeScript
import { render, screen, type RenderResult } from '@testing-library/react'
|
||
import userEvent from '@testing-library/user-event'
|
||
import type { ComponentProps } from 'react'
|
||
import { describe, expect, it, vi } from 'vitest'
|
||
import { DatabaseConnectionPage } from '../../src/renderer/src/components/DatabaseConnectionPage'
|
||
|
||
function renderPage(
|
||
overrides: Partial<ComponentProps<typeof DatabaseConnectionPage>> = {}
|
||
): RenderResult & { props: ComponentProps<typeof DatabaseConnectionPage> } {
|
||
const props = {
|
||
platform: 'win32',
|
||
mode: 'manual' as const,
|
||
dbKey: '',
|
||
dbRoot: '',
|
||
showDbKey: false,
|
||
isFetching: false,
|
||
isConnecting: false,
|
||
guideStep: 1 as const,
|
||
environment: {
|
||
platform: 'win32',
|
||
osVersion: 'Windows fixture',
|
||
appVersion: 'v2.1.6',
|
||
wechatVersion: '4.1.9.57',
|
||
dataStructureVersion: '微信 4.x(WCDB)',
|
||
dataDirectoryDetected: true,
|
||
diagnosticSummary: 'WechatExplorer: v2.1.6',
|
||
autoDetectSupported: true,
|
||
wechatRunning: true,
|
||
accountIdentified: false,
|
||
dbConnected: false,
|
||
encryptionAvailable: true
|
||
},
|
||
accounts: [
|
||
{
|
||
id: 'account-a',
|
||
accountRoot: 'C:\\fixture\\account-a',
|
||
directoryName: 'account-a',
|
||
nickname: '脱敏账号 A',
|
||
wxid: 'wxid_fixture_a',
|
||
hasSavedDbKey: true,
|
||
loginStatus: 'unknown' as const,
|
||
selectedByInput: true
|
||
}
|
||
],
|
||
selectedAccountId: 'account-a',
|
||
status: '',
|
||
statusKind: 'normal' as const,
|
||
showMacKeyFaq: false,
|
||
macKeyFaqUrl: 'https://fixture.invalid/mac',
|
||
onModeChange: vi.fn(),
|
||
onDbKeyChange: vi.fn(),
|
||
onDbRootChange: vi.fn(),
|
||
onSelectAccount: vi.fn(),
|
||
onSelectDbRoot: vi.fn(),
|
||
onToggleDbKey: vi.fn(),
|
||
onAutoGetKey: vi.fn(),
|
||
onRefreshEnvironment: vi.fn(),
|
||
onGuideNext: vi.fn(),
|
||
onGuideBack: vi.fn(),
|
||
onGuideCancel: vi.fn(),
|
||
onValidateConnection: vi.fn(),
|
||
onCopyDiagnostics: vi.fn(),
|
||
onManualConnect: vi.fn(),
|
||
onPasteKey: vi.fn(),
|
||
onClearKey: vi.fn(),
|
||
...overrides
|
||
}
|
||
return { props, ...render(<DatabaseConnectionPage {...props} />) }
|
||
}
|
||
|
||
describe('DatabaseConnectionPage', () => {
|
||
it('renders a discovered nickname and avatar before connection', () => {
|
||
const { container } = renderPage({
|
||
mode: 'automatic',
|
||
accounts: [
|
||
{
|
||
id: 'account-a',
|
||
accountRoot: 'C:\\fixture\\account-a',
|
||
directoryName: 'account-a',
|
||
nickname: '首次识别账号',
|
||
wxid: 'fixture_account',
|
||
avatar: 'https://wx.qlogo.cn/fixture/avatar',
|
||
hasSavedDbKey: false,
|
||
loginStatus: 'unknown',
|
||
selectedByInput: true
|
||
}
|
||
]
|
||
})
|
||
|
||
expect(screen.getByText('首次识别账号')).toBeVisible()
|
||
expect(screen.getByText('fixture_account')).toBeVisible()
|
||
expect(container.querySelector('.database-account-avatar img')).toHaveAttribute(
|
||
'src',
|
||
'https://wx.qlogo.cn/fixture/avatar'
|
||
)
|
||
})
|
||
|
||
it('shows a directory-derived wxid without pretending profile data is available', () => {
|
||
renderPage({
|
||
mode: 'automatic',
|
||
accounts: [
|
||
{
|
||
id: 'account-b',
|
||
accountRoot: 'C:\\fixture\\wxid_fixture_b_ab12',
|
||
directoryName: 'wxid_fixture_b_ab12',
|
||
wxid: 'wxid_fixture',
|
||
hasSavedDbKey: false,
|
||
loginStatus: 'other',
|
||
selectedByInput: false
|
||
}
|
||
],
|
||
selectedAccountId: ''
|
||
})
|
||
|
||
expect(screen.getByText('微信账号 wxid_fixture')).toBeVisible()
|
||
expect(screen.getByText('昵称和头像需连接此账号后读取')).toBeVisible()
|
||
})
|
||
|
||
it('keeps connect disabled until a valid 64-character key is supplied', () => {
|
||
const { rerender, props } = renderPage()
|
||
expect(screen.getByRole('button', { name: '连接数据库' })).toBeDisabled()
|
||
rerender(<DatabaseConnectionPage {...props} dbKey={'a'.repeat(64)} />)
|
||
expect(screen.getByRole('button', { name: '连接数据库' })).toBeEnabled()
|
||
})
|
||
|
||
it('shows a recoverable error and keeps form actions available', async () => {
|
||
const onManualConnect = vi.fn()
|
||
renderPage({
|
||
dbKey: 'b'.repeat(64),
|
||
status: '数据库密钥无效,请重新输入',
|
||
statusKind: 'error',
|
||
onManualConnect
|
||
})
|
||
expect(screen.getByText('数据库密钥无效,请重新输入')).toBeVisible()
|
||
await userEvent.click(screen.getByRole('button', { name: '连接数据库' }))
|
||
expect(onManualConnect).toHaveBeenCalledOnce()
|
||
expect(screen.getByRole('button', { name: '从剪贴板粘贴并安全保存' })).toBeEnabled()
|
||
})
|
||
|
||
it('restores directory editing and selection after a failed connection', async () => {
|
||
const onDbRootChange = vi.fn()
|
||
const onSelectDbRoot = vi.fn()
|
||
renderPage({
|
||
dbKey: 'b'.repeat(64),
|
||
dbRoot: 'Z:\\missing-wechat-data',
|
||
status: '微信数据目录不存在,请重新选择目录',
|
||
statusKind: 'error',
|
||
onDbRootChange,
|
||
onSelectDbRoot
|
||
})
|
||
|
||
await userEvent.clear(screen.getByLabelText('微信数据目录'))
|
||
await userEvent.type(screen.getByLabelText('微信数据目录'), 'C:\\fixture-account')
|
||
await userEvent.click(screen.getByRole('button', { name: '选择目录' }))
|
||
|
||
expect(onDbRootChange).toHaveBeenCalled()
|
||
expect(onSelectDbRoot).toHaveBeenCalledOnce()
|
||
expect(screen.getByRole('button', { name: '连接数据库' })).toBeEnabled()
|
||
})
|
||
|
||
it('supports forward, back, cancel and safe diagnostic actions in onboarding', async () => {
|
||
const onGuideNext = vi.fn()
|
||
const onCopyDiagnostics = vi.fn()
|
||
const { rerender, props } = renderPage({
|
||
mode: 'automatic',
|
||
guideStep: 1,
|
||
onGuideNext,
|
||
onCopyDiagnostics
|
||
})
|
||
|
||
expect(screen.getByText('4.1.9.57')).toBeVisible()
|
||
expect(screen.getByText('微信 4.x(WCDB)')).toBeVisible()
|
||
await userEvent.click(screen.getByRole('button', { name: '复制脱敏诊断摘要' }))
|
||
await userEvent.click(screen.getByRole('button', { name: '检查完成,继续' }))
|
||
expect(onCopyDiagnostics).toHaveBeenCalledOnce()
|
||
expect(onGuideNext).toHaveBeenCalledOnce()
|
||
|
||
rerender(<DatabaseConnectionPage {...props} mode="automatic" guideStep={2} />)
|
||
expect(screen.getByRole('button', { name: '我已准备好' })).toBeEnabled()
|
||
expect(screen.getByRole('button', { name: '返回上一步' })).toBeEnabled()
|
||
expect(screen.getByRole('button', { name: '取消并重新检查' })).toBeEnabled()
|
||
})
|
||
it('provides the official Visual C++ runtime download on Windows', () => {
|
||
renderPage({
|
||
status: '当前 Windows 缺少 Microsoft Visual C++ 运行库',
|
||
statusKind: 'error'
|
||
})
|
||
|
||
expect(screen.getByRole('link', { name: '下载运行库' })).toHaveAttribute(
|
||
'href',
|
||
'https://aka.ms/vc14/vc_redist.x64.exe'
|
||
)
|
||
})
|
||
|
||
})
|