360 lines
11 KiB
TypeScript
360 lines
11 KiB
TypeScript
/**
|
|
* use-template-generation-actions.test.ts
|
|
*
|
|
* TDD 测试文件 - 测试模板生成记录的删除功能
|
|
*
|
|
* 测试覆盖:
|
|
* 1. 单个删除成功场景
|
|
* 2. 单个删除失败场景
|
|
* 3. 批量删除成功场景(可选)
|
|
* 4. 批量删除失败场景(可选)
|
|
*/
|
|
|
|
import { renderHook, act, waitFor } from '@testing-library/react-native'
|
|
import { root } from '@repo/core'
|
|
import { TemplateGenerationController } from '@repo/sdk'
|
|
import { useDeleteGeneration, useBatchDeleteGenerations } from '@/hooks/use-template-generation-actions'
|
|
|
|
// Mock SDK
|
|
jest.mock('@repo/core', () => ({
|
|
root: {
|
|
get: jest.fn(),
|
|
},
|
|
}))
|
|
|
|
describe('use-template-generation-actions', () => {
|
|
// 在每个测试前重置所有 mocks
|
|
beforeEach(() => {
|
|
jest.clearAllMocks()
|
|
})
|
|
|
|
describe('useDeleteGeneration', () => {
|
|
it('应该成功删除单个生成记录', async () => {
|
|
// Arrange: 准备测试数据
|
|
const mockDelete = jest.fn().mockResolvedValue({ message: '删除成功' })
|
|
const mockController = {
|
|
delete: mockDelete,
|
|
} as unknown as TemplateGenerationController
|
|
|
|
;(root.get as jest.Mock).mockReturnValue(mockController)
|
|
|
|
// Act: 渲染 hook 并执行删除
|
|
const { result } = renderHook(() => useDeleteGeneration())
|
|
|
|
await act(async () => {
|
|
const response = await result.current.deleteGeneration('test-id-123')
|
|
// Assert: 验证返回值
|
|
expect(response).toEqual({
|
|
data: { message: '删除成功' },
|
|
error: null,
|
|
})
|
|
})
|
|
|
|
// Assert: 验证控制器被正确调用
|
|
expect(root.get).toHaveBeenCalledWith(TemplateGenerationController)
|
|
expect(mockDelete).toHaveBeenCalledWith({ id: 'test-id-123' })
|
|
expect(mockDelete).toHaveBeenCalledTimes(1)
|
|
})
|
|
|
|
it('删除失败时应该返回错误信息', async () => {
|
|
// Arrange: 准备测试数据和模拟错误
|
|
const mockError = {
|
|
message: '删除失败:记录不存在',
|
|
code: 'NOT_FOUND',
|
|
}
|
|
const mockDelete = jest.fn().mockRejectedValue(mockError)
|
|
const mockController = {
|
|
delete: mockDelete,
|
|
} as unknown as TemplateGenerationController
|
|
|
|
;(root.get as jest.Mock).mockReturnValue(mockController)
|
|
|
|
// Act: 渲染 hook 并执行删除
|
|
const { result } = renderHook(() => useDeleteGeneration())
|
|
|
|
await act(async () => {
|
|
const response = await result.current.deleteGeneration('non-existent-id')
|
|
// Assert: 验证返回的错误信息
|
|
expect(response).toEqual({
|
|
data: null,
|
|
error: mockError,
|
|
})
|
|
})
|
|
|
|
// Assert: 验证控制器被调用
|
|
expect(mockDelete).toHaveBeenCalledWith({ id: 'non-existent-id' })
|
|
})
|
|
|
|
it('删除过程中应该设置正确的加载状态', async () => {
|
|
// Arrange: 准备异步测试
|
|
const mockDelete = jest.fn().mockImplementation(
|
|
() =>
|
|
new Promise((resolve) => {
|
|
setTimeout(() => resolve({ message: '删除成功' }), 100)
|
|
}),
|
|
)
|
|
const mockController = {
|
|
delete: mockDelete,
|
|
} as unknown as TemplateGenerationController
|
|
|
|
;(root.get as jest.Mock).mockReturnValue(mockController)
|
|
|
|
// Act: 渲染 hook
|
|
const { result } = renderHook(() => useDeleteGeneration())
|
|
|
|
// Assert: 初始状态应该是未加载
|
|
expect(result.current.loading).toBe(false)
|
|
|
|
// Act: 开始删除
|
|
const deletePromise = act(async () => {
|
|
await result.current.deleteGeneration('test-id')
|
|
})
|
|
|
|
// Assert: 删除过程中应该是加载状态
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(true)
|
|
})
|
|
|
|
await deletePromise
|
|
|
|
// Assert: 删除完成后应该重置加载状态
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false)
|
|
})
|
|
})
|
|
|
|
it('删除失败后应该更新错误状态', async () => {
|
|
// Arrange
|
|
const mockError = {
|
|
message: '网络错误',
|
|
code: 'NETWORK_ERROR',
|
|
}
|
|
const mockDelete = jest.fn().mockRejectedValue(mockError)
|
|
const mockController = {
|
|
delete: mockDelete,
|
|
} as unknown as TemplateGenerationController
|
|
|
|
;(root.get as jest.Mock).mockReturnValue(mockController)
|
|
|
|
// Act
|
|
const { result } = renderHook(() => useDeleteGeneration())
|
|
|
|
await act(async () => {
|
|
await result.current.deleteGeneration('test-id')
|
|
})
|
|
|
|
// Assert: 验证错误状态
|
|
expect(result.current.error).toEqual(mockError)
|
|
})
|
|
|
|
it('连续调用多次删除应该正确处理', async () => {
|
|
// Arrange
|
|
const mockDelete = jest.fn()
|
|
.mockResolvedValueOnce({ message: '第一次删除成功' })
|
|
.mockResolvedValueOnce({ message: '第二次删除成功' })
|
|
const mockController = {
|
|
delete: mockDelete,
|
|
} as unknown as TemplateGenerationController
|
|
|
|
;(root.get as jest.Mock).mockReturnValue(mockController)
|
|
|
|
// Act
|
|
const { result } = renderHook(() => useDeleteGeneration())
|
|
|
|
await act(async () => {
|
|
const response1 = await result.current.deleteGeneration('id-1')
|
|
const response2 = await result.current.deleteGeneration('id-2')
|
|
|
|
// Assert
|
|
expect(response1.data?.message).toBe('第一次删除成功')
|
|
expect(response2.data?.message).toBe('第二次删除成功')
|
|
})
|
|
|
|
// Assert: 验证调用次数
|
|
expect(mockDelete).toHaveBeenCalledTimes(2)
|
|
expect(mockDelete).toHaveBeenNthCalledWith(1, { id: 'id-1' })
|
|
expect(mockDelete).toHaveBeenNthCalledWith(2, { id: 'id-2' })
|
|
})
|
|
})
|
|
|
|
describe('useBatchDeleteGenerations', () => {
|
|
it('应该成功批量删除生成记录', async () => {
|
|
// Arrange
|
|
const mockBatchDelete = jest.fn().mockResolvedValue({
|
|
message: '批量删除成功',
|
|
deletedCount: 3,
|
|
})
|
|
const mockController = {
|
|
batchDelete: mockBatchDelete,
|
|
} as unknown as TemplateGenerationController
|
|
|
|
;(root.get as jest.Mock).mockReturnValue(mockController)
|
|
|
|
// Act
|
|
const { result } = renderHook(() => useBatchDeleteGenerations())
|
|
|
|
await act(async () => {
|
|
const response = await result.current.batchDeleteGenerations([
|
|
'id-1',
|
|
'id-2',
|
|
'id-3',
|
|
])
|
|
|
|
// Assert
|
|
expect(response).toEqual({
|
|
data: {
|
|
message: '批量删除成功',
|
|
deletedCount: 3,
|
|
},
|
|
error: null,
|
|
})
|
|
})
|
|
|
|
// Assert: 验证控制器被正确调用
|
|
expect(root.get).toHaveBeenCalledWith(TemplateGenerationController)
|
|
expect(mockBatchDelete).toHaveBeenCalledWith({
|
|
ids: ['id-1', 'id-2', 'id-3'],
|
|
})
|
|
})
|
|
|
|
it('批量删除失败时应该返回错误信息', async () => {
|
|
// Arrange
|
|
const mockError = {
|
|
message: '批量删除失败:部分记录不存在',
|
|
code: 'PARTIAL_FAILURE',
|
|
}
|
|
const mockBatchDelete = jest.fn().mockRejectedValue(mockError)
|
|
const mockController = {
|
|
batchDelete: mockBatchDelete,
|
|
} as unknown as TemplateGenerationController
|
|
|
|
;(root.get as jest.Mock).mockReturnValue(mockController)
|
|
|
|
// Act
|
|
const { result } = renderHook(() => useBatchDeleteGenerations())
|
|
|
|
await act(async () => {
|
|
const response = await result.current.batchDeleteGenerations([
|
|
'id-1',
|
|
'id-2',
|
|
])
|
|
|
|
// Assert
|
|
expect(response).toEqual({
|
|
data: null,
|
|
error: mockError,
|
|
})
|
|
})
|
|
|
|
expect(mockBatchDelete).toHaveBeenCalledWith({
|
|
ids: ['id-1', 'id-2'],
|
|
})
|
|
})
|
|
|
|
it('批量删除时应该设置正确的加载状态', async () => {
|
|
// Arrange
|
|
const mockBatchDelete = jest.fn().mockImplementation(
|
|
() =>
|
|
new Promise((resolve) => {
|
|
setTimeout(() => resolve({ message: '批量删除成功' }), 100)
|
|
}),
|
|
)
|
|
const mockController = {
|
|
batchDelete: mockBatchDelete,
|
|
} as unknown as TemplateGenerationController
|
|
|
|
;(root.get as jest.Mock).mockReturnValue(mockController)
|
|
|
|
// Act
|
|
const { result } = renderHook(() => useBatchDeleteGenerations())
|
|
|
|
expect(result.current.loading).toBe(false)
|
|
|
|
// Act
|
|
const deletePromise = act(async () => {
|
|
await result.current.batchDeleteGenerations(['id-1', 'id-2'])
|
|
})
|
|
|
|
// Assert: 删除过程中
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(true)
|
|
})
|
|
|
|
await deletePromise
|
|
|
|
// Assert: 删除完成后
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false)
|
|
})
|
|
})
|
|
|
|
it('传入空数组时应该正常处理', async () => {
|
|
// Arrange
|
|
const mockBatchDelete = jest.fn().mockResolvedValue({
|
|
message: '批量删除成功',
|
|
deletedCount: 0,
|
|
})
|
|
const mockController = {
|
|
batchDelete: mockBatchDelete,
|
|
} as unknown as TemplateGenerationController
|
|
|
|
;(root.get as jest.Mock).mockReturnValue(mockController)
|
|
|
|
// Act
|
|
const { result } = renderHook(() => useBatchDeleteGenerations())
|
|
|
|
await act(async () => {
|
|
const response = await result.current.batchDeleteGenerations([])
|
|
|
|
// Assert
|
|
expect(response.data?.deletedCount).toBe(0)
|
|
})
|
|
|
|
expect(mockBatchDelete).toHaveBeenCalledWith({ ids: [] })
|
|
})
|
|
})
|
|
|
|
describe('边界情况', () => {
|
|
it('应该处理 ID 为空字符串的情况', async () => {
|
|
// Arrange
|
|
const mockDelete = jest.fn().mockResolvedValue({ message: '删除成功' })
|
|
const mockController = {
|
|
delete: mockDelete,
|
|
} as unknown as TemplateGenerationController
|
|
|
|
;(root.get as jest.Mock).mockReturnValue(mockController)
|
|
|
|
// Act
|
|
const { result } = renderHook(() => useDeleteGeneration())
|
|
|
|
await act(async () => {
|
|
await result.current.deleteGeneration('')
|
|
})
|
|
|
|
// Assert: 即使是空字符串,也应该调用 API
|
|
expect(mockDelete).toHaveBeenCalledWith({ id: '' })
|
|
})
|
|
|
|
it('应该处理超长 ID 的情况', async () => {
|
|
// Arrange
|
|
const longId = 'a'.repeat(1000)
|
|
const mockDelete = jest.fn().mockResolvedValue({ message: '删除成功' })
|
|
const mockController = {
|
|
delete: mockDelete,
|
|
} as unknown as TemplateGenerationController
|
|
|
|
;(root.get as jest.Mock).mockReturnValue(mockController)
|
|
|
|
// Act
|
|
const { result } = renderHook(() => useDeleteGeneration())
|
|
|
|
await act(async () => {
|
|
await result.current.deleteGeneration(longId)
|
|
})
|
|
|
|
// Assert
|
|
expect(mockDelete).toHaveBeenCalledWith({ id: longId })
|
|
})
|
|
})
|
|
})
|