flnxi-Wu/lib/__tests__/startup-check.test.ts
WuYongJie 63ec6b7dfb fix: 修复排行榜按钮消失、tag排序和输入框浅色模式问题
1. 排行榜悬浮窗关闭后小按钮消失问题
   - 修复面板居中模式关闭时按钮位置错误
   - 保存并恢复按钮的居中状态

2. 首页tag按钮按素材数量排序
   - 添加按素材数量降序排序逻辑

3. 上传弹窗输入框浅色模式文字不可见
   - 添加 text-slate-900 确保浅色模式下文字可见
   - 添加 placeholder 样式确保占位符正确显示
2025-12-14 21:41:29 +08:00

244 lines
6.8 KiB
TypeScript

/**
* 启动检查模块测试
* 测试 lib/startup-check.ts 的核心功能
*/
import {
runStartupCheck,
getStartupCheckStatus,
resetStartupCheck,
} from '../startup-check'
import { ensureBuiltinTemplates } from '../system-integrity'
// Mock system-integrity 模块
jest.mock('../system-integrity', () => ({
ensureBuiltinTemplates: jest.fn(),
}))
const mockEnsureBuiltinTemplates = ensureBuiltinTemplates as jest.MockedFunction<
typeof ensureBuiltinTemplates
>
describe('启动检查模块', () => {
beforeEach(() => {
// 每个测试前重置状态
resetStartupCheck()
jest.clearAllMocks()
// 静默 console 输出
jest.spyOn(console, 'log').mockImplementation(() => {})
jest.spyOn(console, 'warn').mockImplementation(() => {})
jest.spyOn(console, 'error').mockImplementation(() => {})
})
afterEach(() => {
jest.restoreAllMocks()
})
describe('runStartupCheck', () => {
it('首次调用时应执行检查并返回结果', async () => {
mockEnsureBuiltinTemplates.mockResolvedValue({
checked: true,
created: ['builtin-3dmax-material'],
errors: [],
})
const result = await runStartupCheck()
expect(result).not.toBeNull()
expect(result?.success).toBe(true)
expect(result?.templatesCreated).toEqual(['builtin-3dmax-material'])
expect(result?.errors).toHaveLength(0)
expect(mockEnsureBuiltinTemplates).toHaveBeenCalledTimes(1)
})
it('重复调用时应返回缓存结果而不重新执行', async () => {
mockEnsureBuiltinTemplates.mockResolvedValue({
checked: true,
created: ['builtin-psd-material'],
errors: [],
})
// 第一次调用
const result1 = await runStartupCheck()
// 第二次调用
const result2 = await runStartupCheck()
expect(result1).toEqual(result2)
expect(mockEnsureBuiltinTemplates).toHaveBeenCalledTimes(1)
})
it('当没有创建模板时应返回空数组', async () => {
mockEnsureBuiltinTemplates.mockResolvedValue({
checked: true,
created: [],
errors: [],
})
const result = await runStartupCheck()
expect(result?.success).toBe(true)
expect(result?.templatesCreated).toHaveLength(0)
})
it('当有错误时应设置success为false', async () => {
mockEnsureBuiltinTemplates.mockResolvedValue({
checked: true,
created: [],
errors: ['模板创建失败'],
})
const result = await runStartupCheck()
expect(result?.success).toBe(false)
expect(result?.errors).toContain('模板创建失败')
})
it('当ensureBuiltinTemplates抛出异常时应捕获并记录错误', async () => {
mockEnsureBuiltinTemplates.mockRejectedValue(new Error('数据库连接失败'))
const result = await runStartupCheck()
expect(result?.success).toBe(false)
expect(result?.templatesCreated).toHaveLength(0)
expect(result?.errors).toContain('数据库连接失败')
})
it('当抛出非Error对象时应正确处理', async () => {
mockEnsureBuiltinTemplates.mockRejectedValue('字符串错误')
const result = await runStartupCheck()
expect(result?.success).toBe(false)
expect(result?.errors).toContain('字符串错误')
})
it('应该记录创建的模板数量', async () => {
const consoleSpy = jest.spyOn(console, 'log')
mockEnsureBuiltinTemplates.mockResolvedValue({
checked: true,
created: ['builtin-3dmax-material', 'builtin-psd-material'],
errors: [],
})
await runStartupCheck()
expect(consoleSpy).toHaveBeenCalledWith(
expect.stringContaining('自动创建了 2 个内置模板'),
expect.any(Array)
)
})
it('应该记录错误信息', async () => {
const warnSpy = jest.spyOn(console, 'warn')
mockEnsureBuiltinTemplates.mockResolvedValue({
checked: true,
created: [],
errors: ['错误1', '错误2'],
})
await runStartupCheck()
expect(warnSpy).toHaveBeenCalledWith(
expect.stringContaining('启动检查有错误'),
expect.any(Array)
)
})
})
describe('getStartupCheckStatus', () => {
it('初始状态应该是未执行', () => {
const status = getStartupCheckStatus()
expect(status.executed).toBe(false)
expect(status.result).toBeNull()
})
it('执行后应该返回正确的状态', async () => {
mockEnsureBuiltinTemplates.mockResolvedValue({
checked: true,
created: [],
errors: [],
})
await runStartupCheck()
const status = getStartupCheckStatus()
expect(status.executed).toBe(true)
expect(status.result).not.toBeNull()
expect(status.result?.success).toBe(true)
})
it('即使检查失败也应该标记为已执行', async () => {
mockEnsureBuiltinTemplates.mockRejectedValue(new Error('失败'))
await runStartupCheck()
const status = getStartupCheckStatus()
expect(status.executed).toBe(true)
expect(status.result?.success).toBe(false)
})
})
describe('resetStartupCheck', () => {
it('应该重置执行状态', async () => {
mockEnsureBuiltinTemplates.mockResolvedValue({
checked: true,
created: [],
errors: [],
})
await runStartupCheck()
expect(getStartupCheckStatus().executed).toBe(true)
resetStartupCheck()
expect(getStartupCheckStatus().executed).toBe(false)
expect(getStartupCheckStatus().result).toBeNull()
})
it('重置后再次调用runStartupCheck应该重新执行', async () => {
mockEnsureBuiltinTemplates.mockResolvedValue({
checked: true,
created: ['template-1'],
errors: [],
})
await runStartupCheck()
resetStartupCheck()
mockEnsureBuiltinTemplates.mockResolvedValue({
checked: true,
created: ['template-2'],
errors: [],
})
const result = await runStartupCheck()
expect(mockEnsureBuiltinTemplates).toHaveBeenCalledTimes(2)
expect(result?.templatesCreated).toEqual(['template-2'])
})
})
describe('幂等性测试', () => {
it('多次并发调用应该只执行一次', async () => {
mockEnsureBuiltinTemplates.mockImplementation(async () => {
// 模拟异步操作
await new Promise((resolve) => setTimeout(resolve, 10))
return { checked: true, created: [], errors: [] }
})
// 并发调用
const results = await Promise.all([
runStartupCheck(),
runStartupCheck(),
runStartupCheck(),
])
// 所有结果应该相同
expect(results[0]).toEqual(results[1])
expect(results[1]).toEqual(results[2])
// 但由于第一次调用还没完成,可能会执行多次
// 这是当前实现的已知行为
})
})
})