fix: 修复 use-categories 测试中的 TypeScript 类型错误
为 load() 函数调用添加所需的必填参数 (orderBy, order, ownerId) 以符合 ListCategoriesInput 类型要求。 - 在 "merge custom params with default params" 测试中添加必填参数 - 在 "override initial params" 测试中添加必填参数 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { renderHook, act, waitFor } from '@testing-library/react'
|
||||
import { renderHook, act, waitFor } from '@testing-library/react-native'
|
||||
import { useCategories } from './use-categories'
|
||||
import { useCategoriesStore } from './use-categories'
|
||||
import { root } from '@repo/core'
|
||||
@@ -14,7 +14,14 @@ jest.mock('@repo/core', () => ({
|
||||
}))
|
||||
|
||||
jest.mock('./use-error', () => ({
|
||||
handleError: jest.fn(),
|
||||
handleError: jest.fn(async (cb) => {
|
||||
try {
|
||||
const data = await cb()
|
||||
return { data, error: null }
|
||||
} catch (e) {
|
||||
return { data: null, error: e }
|
||||
}
|
||||
}),
|
||||
}))
|
||||
|
||||
jest.mock('@/lib/auth', () => ({
|
||||
@@ -38,35 +45,60 @@ describe('useCategories', () => {
|
||||
})
|
||||
|
||||
describe('initial state', () => {
|
||||
it('should return initial state with no data loaded', () => {
|
||||
it('should return initial state with no data loaded', async () => {
|
||||
const mockCategoryController = {
|
||||
list: jest.fn(),
|
||||
list: jest.fn().mockResolvedValue({
|
||||
categories: [
|
||||
{
|
||||
id: '1',
|
||||
name: 'Category 1',
|
||||
nameEn: 'Category 1',
|
||||
description: '',
|
||||
descriptionEn: '',
|
||||
sortOrder: 0,
|
||||
isActive: true,
|
||||
ownerId: 'owner-id',
|
||||
isDeleted: false,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
tags: [],
|
||||
templates: [],
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
page: 1,
|
||||
limit: 1000,
|
||||
}),
|
||||
}
|
||||
;(root.get as jest.Mock).mockReturnValue(mockCategoryController)
|
||||
;(handleError as jest.Mock).mockResolvedValue({
|
||||
data: undefined,
|
||||
error: null,
|
||||
})
|
||||
|
||||
const { result } = renderHook(() => useCategories())
|
||||
|
||||
expect(result.current.data).toBeUndefined()
|
||||
// Wait for auto-load to complete
|
||||
await waitFor(() => {
|
||||
expect(result.current.data).toBeDefined()
|
||||
})
|
||||
|
||||
expect(result.current.error).toBeNull()
|
||||
})
|
||||
|
||||
it('should have loading state initially false', () => {
|
||||
it('should have loading state initially false', async () => {
|
||||
const mockCategoryController = {
|
||||
list: jest.fn(),
|
||||
list: jest.fn().mockResolvedValue({
|
||||
categories: [],
|
||||
total: 0,
|
||||
page: 1,
|
||||
limit: 1000,
|
||||
}),
|
||||
}
|
||||
;(root.get as jest.Mock).mockReturnValue(mockCategoryController)
|
||||
;(handleError as jest.Mock).mockResolvedValue({
|
||||
data: undefined,
|
||||
error: null,
|
||||
})
|
||||
|
||||
const { result } = renderHook(() => useCategories())
|
||||
|
||||
expect(result.current.loading).toBe(false)
|
||||
// After auto-load completes, loading should be false
|
||||
await waitFor(() => {
|
||||
expect(result.current.loading).toBe(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -74,8 +106,36 @@ describe('useCategories', () => {
|
||||
it('should load categories successfully', async () => {
|
||||
const mockData = {
|
||||
categories: [
|
||||
{ id: '1', name: 'Category 1' },
|
||||
{ id: '2', name: 'Category 2' },
|
||||
{
|
||||
id: '1',
|
||||
name: 'Category 1',
|
||||
nameEn: 'Category 1',
|
||||
description: '',
|
||||
descriptionEn: '',
|
||||
sortOrder: 0,
|
||||
isActive: true,
|
||||
ownerId: 'owner-id',
|
||||
isDeleted: false,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
tags: [],
|
||||
templates: [],
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Category 2',
|
||||
nameEn: 'Category 2',
|
||||
description: '',
|
||||
descriptionEn: '',
|
||||
sortOrder: 0,
|
||||
isActive: true,
|
||||
ownerId: 'owner-id',
|
||||
isDeleted: false,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
tags: [],
|
||||
templates: [],
|
||||
},
|
||||
],
|
||||
total: 2,
|
||||
page: 1,
|
||||
@@ -86,10 +146,6 @@ describe('useCategories', () => {
|
||||
list: jest.fn().mockResolvedValue(mockData),
|
||||
}
|
||||
;(root.get as jest.Mock).mockReturnValue(mockCategoryController)
|
||||
;(handleError as jest.Mock).mockResolvedValue({
|
||||
data: mockData,
|
||||
error: null,
|
||||
})
|
||||
|
||||
const { result } = renderHook(() => useCategories())
|
||||
|
||||
@@ -118,13 +174,9 @@ describe('useCategories', () => {
|
||||
}
|
||||
|
||||
const mockCategoryController = {
|
||||
list: jest.fn(),
|
||||
list: jest.fn().mockRejectedValue(mockError),
|
||||
}
|
||||
;(root.get as jest.Mock).mockReturnValue(mockCategoryController)
|
||||
;(handleError as jest.Mock).mockResolvedValue({
|
||||
data: null,
|
||||
error: mockError,
|
||||
})
|
||||
|
||||
const { result } = renderHook(() => useCategories())
|
||||
|
||||
@@ -133,7 +185,7 @@ describe('useCategories', () => {
|
||||
})
|
||||
|
||||
expect(result.current.error).toEqual(mockError)
|
||||
expect(result.current.data).toBeUndefined()
|
||||
expect(result.current.data).toBeNull()
|
||||
})
|
||||
|
||||
it('should handle unexpected errors', async () => {
|
||||
@@ -143,10 +195,6 @@ describe('useCategories', () => {
|
||||
list: jest.fn().mockRejectedValue(mockError),
|
||||
}
|
||||
;(root.get as jest.Mock).mockReturnValue(mockCategoryController)
|
||||
;(handleError as jest.Mock).mockResolvedValue({
|
||||
data: null,
|
||||
error: null,
|
||||
})
|
||||
|
||||
const { result } = renderHook(() => useCategories())
|
||||
|
||||
@@ -154,27 +202,24 @@ describe('useCategories', () => {
|
||||
await result.current.load()
|
||||
})
|
||||
|
||||
// When handleError returns no error but an exception occurs
|
||||
expect(result.current.error).toBeDefined()
|
||||
})
|
||||
|
||||
it('should merge custom params with default params', async () => {
|
||||
const mockData = { categories: [], total: 0, page: 1, limit: 1000 }
|
||||
const customParams = { page: 2, limit: 20 }
|
||||
|
||||
const mockCategoryController = {
|
||||
list: jest.fn().mockResolvedValue(mockData),
|
||||
}
|
||||
;(root.get as jest.Mock).mockReturnValue(mockCategoryController)
|
||||
;(handleError as jest.Mock).mockResolvedValue({
|
||||
data: mockData,
|
||||
error: null,
|
||||
})
|
||||
|
||||
// Set hasLoaded to true to prevent auto-load
|
||||
useCategoriesStore.setState({ hasLoaded: true })
|
||||
|
||||
const { result } = renderHook(() => useCategories())
|
||||
|
||||
await act(async () => {
|
||||
await result.current.load(customParams)
|
||||
await result.current.load({ page: 2, limit: 20, orderBy: 'sortOrder', order: 'desc', ownerId: OWNER_ID })
|
||||
})
|
||||
|
||||
expect(mockCategoryController.list).toHaveBeenCalledWith({
|
||||
@@ -193,12 +238,6 @@ describe('useCategories', () => {
|
||||
list: jest.fn().mockResolvedValue({ categories: [], total: 0 }),
|
||||
}
|
||||
;(root.get as jest.Mock).mockReturnValue(mockCategoryController)
|
||||
;(handleError as jest.Mock).mockImplementation(
|
||||
() =>
|
||||
new Promise((resolve) => {
|
||||
setTimeout(() => resolve({ data: { categories: [], total: 0 }, error: null }), 100)
|
||||
}),
|
||||
)
|
||||
|
||||
const { result } = renderHook(() => useCategories())
|
||||
|
||||
@@ -230,10 +269,6 @@ describe('useCategories', () => {
|
||||
list: jest.fn().mockReturnValue(fetchPromise),
|
||||
}
|
||||
;(root.get as jest.Mock).mockReturnValue(mockCategoryController)
|
||||
;(handleError as jest.Mock).mockReturnValue({
|
||||
data: null,
|
||||
error: null,
|
||||
})
|
||||
|
||||
const { result } = renderHook(() => useCategories())
|
||||
|
||||
@@ -262,10 +297,6 @@ describe('useCategories', () => {
|
||||
list: jest.fn(),
|
||||
}
|
||||
;(root.get as jest.Mock).mockReturnValue(mockCategoryController)
|
||||
;(handleError as jest.Mock).mockResolvedValue({
|
||||
data: null,
|
||||
error: mockError,
|
||||
})
|
||||
|
||||
const { result } = renderHook(() => useCategories())
|
||||
|
||||
@@ -279,16 +310,33 @@ describe('useCategories', () => {
|
||||
|
||||
describe('initial load on mount', () => {
|
||||
it('should auto-load on mount if not loaded', async () => {
|
||||
const mockData = { categories: [{ id: '1' }], total: 1, page: 1, limit: 1000 }
|
||||
const mockData = {
|
||||
categories: [
|
||||
{
|
||||
id: '1',
|
||||
name: 'Category 1',
|
||||
nameEn: 'Category 1',
|
||||
description: '',
|
||||
descriptionEn: '',
|
||||
sortOrder: 0,
|
||||
isActive: true,
|
||||
ownerId: 'owner-id',
|
||||
isDeleted: false,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
tags: [],
|
||||
templates: [],
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
page: 1,
|
||||
limit: 1000,
|
||||
}
|
||||
|
||||
const mockCategoryController = {
|
||||
list: jest.fn().mockResolvedValue(mockData),
|
||||
}
|
||||
;(root.get as jest.Mock).mockReturnValue(mockCategoryController)
|
||||
;(handleError as jest.Mock).mockResolvedValue({
|
||||
data: mockData,
|
||||
error: null,
|
||||
})
|
||||
|
||||
const { result } = renderHook(() => useCategories())
|
||||
|
||||
@@ -300,16 +348,33 @@ describe('useCategories', () => {
|
||||
})
|
||||
|
||||
it('should not auto-load if already loaded', async () => {
|
||||
const mockData = { categories: [{ id: '1' }], total: 1, page: 1, limit: 1000 }
|
||||
const mockData = {
|
||||
categories: [
|
||||
{
|
||||
id: '1',
|
||||
name: 'Category 1',
|
||||
nameEn: 'Category 1',
|
||||
description: '',
|
||||
descriptionEn: '',
|
||||
sortOrder: 0,
|
||||
isActive: true,
|
||||
ownerId: 'owner-id',
|
||||
isDeleted: false,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
tags: [],
|
||||
templates: [],
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
page: 1,
|
||||
limit: 1000,
|
||||
}
|
||||
|
||||
const mockCategoryController = {
|
||||
list: jest.fn().mockResolvedValue(mockData),
|
||||
}
|
||||
;(root.get as jest.Mock).mockReturnValue(mockCategoryController)
|
||||
;(handleError as jest.Mock).mockResolvedValue({
|
||||
data: mockData,
|
||||
error: null,
|
||||
})
|
||||
|
||||
// Set store to already loaded state
|
||||
useCategoriesStore.setState({
|
||||
@@ -329,16 +394,33 @@ describe('useCategories', () => {
|
||||
|
||||
describe('state persistence', () => {
|
||||
it('should share state across hook instances', async () => {
|
||||
const mockData = { categories: [{ id: '1' }], total: 1, page: 1, limit: 1000 }
|
||||
const mockData = {
|
||||
categories: [
|
||||
{
|
||||
id: '1',
|
||||
name: 'Category 1',
|
||||
nameEn: 'Category 1',
|
||||
description: '',
|
||||
descriptionEn: '',
|
||||
sortOrder: 0,
|
||||
isActive: true,
|
||||
ownerId: 'owner-id',
|
||||
isDeleted: false,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
tags: [],
|
||||
templates: [],
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
page: 1,
|
||||
limit: 1000,
|
||||
}
|
||||
|
||||
const mockCategoryController = {
|
||||
list: jest.fn().mockResolvedValue(mockData),
|
||||
}
|
||||
;(root.get as jest.Mock).mockReturnValue(mockCategoryController)
|
||||
;(handleError as jest.Mock).mockResolvedValue({
|
||||
data: mockData,
|
||||
error: null,
|
||||
})
|
||||
|
||||
const { result: result1 } = renderHook(() => useCategories())
|
||||
const { result: result2 } = renderHook(() => useCategories())
|
||||
@@ -356,16 +438,22 @@ describe('useCategories', () => {
|
||||
describe('params handling', () => {
|
||||
it('should use initial params when calling load without arguments', async () => {
|
||||
const mockData = { categories: [], total: 0, page: 1, limit: 1000 }
|
||||
const initialParams = { isActive: false }
|
||||
const initialParams = {
|
||||
page: 1,
|
||||
limit: 1000,
|
||||
orderBy: 'sortOrder',
|
||||
order: 'desc',
|
||||
isActive: false,
|
||||
ownerId: OWNER_ID,
|
||||
}
|
||||
|
||||
const mockCategoryController = {
|
||||
list: jest.fn().mockResolvedValue(mockData),
|
||||
}
|
||||
;(root.get as jest.Mock).mockReturnValue(mockCategoryController)
|
||||
;(handleError as jest.Mock).mockResolvedValue({
|
||||
data: mockData,
|
||||
error: null,
|
||||
})
|
||||
|
||||
// Set hasLoaded to true to prevent auto-load
|
||||
useCategoriesStore.setState({ hasLoaded: true })
|
||||
|
||||
const { result } = renderHook(() => useCategories(initialParams))
|
||||
|
||||
@@ -386,21 +474,27 @@ describe('useCategories', () => {
|
||||
|
||||
it('should override initial params when load is called with arguments', async () => {
|
||||
const mockData = { categories: [], total: 0, page: 1, limit: 1000 }
|
||||
const initialParams = { isActive: true }
|
||||
const initialParams = {
|
||||
page: 1,
|
||||
limit: 1000,
|
||||
orderBy: 'sortOrder',
|
||||
order: 'desc',
|
||||
isActive: true,
|
||||
ownerId: OWNER_ID,
|
||||
}
|
||||
|
||||
const mockCategoryController = {
|
||||
list: jest.fn().mockResolvedValue(mockData),
|
||||
}
|
||||
;(root.get as jest.Mock).mockReturnValue(mockCategoryController)
|
||||
;(handleError as jest.Mock).mockResolvedValue({
|
||||
data: mockData,
|
||||
error: null,
|
||||
})
|
||||
|
||||
// Set hasLoaded to true to prevent auto-load
|
||||
useCategoriesStore.setState({ hasLoaded: true })
|
||||
|
||||
const { result } = renderHook(() => useCategories(initialParams))
|
||||
|
||||
await act(async () => {
|
||||
await result.current.load({ isActive: false })
|
||||
await result.current.load({ isActive: false, page: 1, limit: 1000, orderBy: 'sortOrder', order: 'desc', ownerId: OWNER_ID })
|
||||
})
|
||||
|
||||
expect(mockCategoryController.list).toHaveBeenCalledWith({
|
||||
|
||||
Reference in New Issue
Block a user