创建完整的API文档: - 模板管理API(5个接口) * 获取模板列表 * 获取模板详情(含使用统计) * 创建模板(含验证规则) * 更新模板(含版本控制) * 删除模板(含使用检查) - 模板验证API * 内置模板验证逻辑 * 自定义模板验证逻辑 * 内置模板列表 - 字段池管理API(2个接口) * 获取字段池列表 * 同步字段池 - 分类字段管理API * 获取分类管理字段 - 错误代码规范 * 统一错误响应格式 * 常见错误代码说明 - 性能指标 * 响应时间目标 * 数据库优化说明(20+个索引) - 最佳实践 * 版本控制使用方法 * 错误处理示例 * 字段验证示例 * 性能优化建议 文档位置:docs/api/template-system-api.md
337 lines
8.2 KiB
TypeScript
337 lines
8.2 KiB
TypeScript
/**
|
||
* @jest-environment jsdom
|
||
*/
|
||
import { renderHook, act } from '@testing-library/react'
|
||
import { useDebounce, useDebouncedCallback } from '../useDebounce'
|
||
|
||
describe('useDebounce', () => {
|
||
beforeEach(() => {
|
||
jest.useFakeTimers()
|
||
})
|
||
|
||
afterEach(() => {
|
||
jest.runOnlyPendingTimers()
|
||
jest.useRealTimers()
|
||
})
|
||
|
||
describe('基本功能', () => {
|
||
it('应该返回初始值', () => {
|
||
const { result } = renderHook(() => useDebounce('initial', 300))
|
||
expect(result.current).toBe('initial')
|
||
})
|
||
|
||
it('应该在延迟后更新值', () => {
|
||
const { result, rerender } = renderHook(
|
||
({ value, delay }) => useDebounce(value, delay),
|
||
{ initialProps: { value: 'initial', delay: 300 } }
|
||
)
|
||
|
||
expect(result.current).toBe('initial')
|
||
|
||
// 更新值
|
||
rerender({ value: 'updated', delay: 300 })
|
||
expect(result.current).toBe('initial') // 还未更新
|
||
|
||
// 快进时间
|
||
act(() => {
|
||
jest.advanceTimersByTime(300)
|
||
})
|
||
|
||
expect(result.current).toBe('updated') // 已更新
|
||
})
|
||
|
||
it('应该在值快速变化时只更新最后一个值', () => {
|
||
const { result, rerender } = renderHook(
|
||
({ value }) => useDebounce(value, 300),
|
||
{ initialProps: { value: 'initial' } }
|
||
)
|
||
|
||
// 快速更新多次
|
||
rerender({ value: 'update1' })
|
||
rerender({ value: 'update2' })
|
||
rerender({ value: 'update3' })
|
||
|
||
expect(result.current).toBe('initial')
|
||
|
||
// 快进时间
|
||
act(() => {
|
||
jest.advanceTimersByTime(300)
|
||
})
|
||
|
||
expect(result.current).toBe('update3') // 只更新到最后一个值
|
||
})
|
||
})
|
||
|
||
describe('延迟时间配置', () => {
|
||
it('应该支持自定义延迟时间', () => {
|
||
const { result, rerender } = renderHook(
|
||
({ value }) => useDebounce(value, 500),
|
||
{ initialProps: { value: 'initial' } }
|
||
)
|
||
|
||
rerender({ value: 'updated' })
|
||
|
||
// 300ms后还未更新
|
||
act(() => {
|
||
jest.advanceTimersByTime(300)
|
||
})
|
||
expect(result.current).toBe('initial')
|
||
|
||
// 再过200ms(总共500ms)后更新
|
||
act(() => {
|
||
jest.advanceTimersByTime(200)
|
||
})
|
||
expect(result.current).toBe('updated')
|
||
})
|
||
|
||
it('应该支持0延迟(立即更新)', () => {
|
||
const { result, rerender } = renderHook(
|
||
({ value }) => useDebounce(value, 0),
|
||
{ initialProps: { value: 'initial' } }
|
||
)
|
||
|
||
rerender({ value: 'updated' })
|
||
|
||
act(() => {
|
||
jest.advanceTimersByTime(0)
|
||
})
|
||
|
||
expect(result.current).toBe('updated')
|
||
})
|
||
})
|
||
|
||
describe('不同数据类型', () => {
|
||
it('应该支持字符串类型', () => {
|
||
const { result, rerender } = renderHook(
|
||
({ value }) => useDebounce(value, 300),
|
||
{ initialProps: { value: 'test' } }
|
||
)
|
||
|
||
rerender({ value: 'updated' })
|
||
act(() => {
|
||
jest.advanceTimersByTime(300)
|
||
})
|
||
|
||
expect(result.current).toBe('updated')
|
||
})
|
||
|
||
it('应该支持数字类型', () => {
|
||
const { result, rerender } = renderHook(
|
||
({ value }) => useDebounce(value, 300),
|
||
{ initialProps: { value: 0 } }
|
||
)
|
||
|
||
rerender({ value: 42 })
|
||
act(() => {
|
||
jest.advanceTimersByTime(300)
|
||
})
|
||
|
||
expect(result.current).toBe(42)
|
||
})
|
||
|
||
it('应该支持对象类型', () => {
|
||
const { result, rerender } = renderHook(
|
||
({ value }) => useDebounce(value, 300),
|
||
{ initialProps: { value: { name: 'initial' } } }
|
||
)
|
||
|
||
const newValue = { name: 'updated' }
|
||
rerender({ value: newValue })
|
||
act(() => {
|
||
jest.advanceTimersByTime(300)
|
||
})
|
||
|
||
expect(result.current).toEqual(newValue)
|
||
})
|
||
|
||
it('应该支持数组类型', () => {
|
||
const { result, rerender } = renderHook(
|
||
({ value }) => useDebounce(value, 300),
|
||
{ initialProps: { value: [1, 2, 3] } }
|
||
)
|
||
|
||
const newValue = [4, 5, 6]
|
||
rerender({ value: newValue })
|
||
act(() => {
|
||
jest.advanceTimersByTime(300)
|
||
})
|
||
|
||
expect(result.current).toEqual(newValue)
|
||
})
|
||
})
|
||
})
|
||
|
||
describe('useDebouncedCallback', () => {
|
||
beforeEach(() => {
|
||
jest.useFakeTimers()
|
||
})
|
||
|
||
afterEach(() => {
|
||
jest.runOnlyPendingTimers()
|
||
jest.useRealTimers()
|
||
})
|
||
|
||
describe('基本功能', () => {
|
||
it('应该返回一个函数', () => {
|
||
const callback = jest.fn()
|
||
const { result } = renderHook(() => useDebouncedCallback(callback, 300))
|
||
|
||
expect(typeof result.current).toBe('function')
|
||
})
|
||
|
||
it('应该在延迟后调用回调函数', () => {
|
||
const callback = jest.fn()
|
||
const { result } = renderHook(() => useDebouncedCallback(callback, 300))
|
||
|
||
act(() => {
|
||
result.current('test')
|
||
})
|
||
|
||
expect(callback).not.toHaveBeenCalled()
|
||
|
||
act(() => {
|
||
jest.advanceTimersByTime(300)
|
||
})
|
||
|
||
expect(callback).toHaveBeenCalledWith('test')
|
||
expect(callback).toHaveBeenCalledTimes(1)
|
||
})
|
||
|
||
it('应该在快速调用时只执行最后一次', () => {
|
||
const callback = jest.fn()
|
||
const { result } = renderHook(() => useDebouncedCallback(callback, 300))
|
||
|
||
// 分别调用,每次调用都会重置定时器
|
||
act(() => {
|
||
result.current('call1')
|
||
})
|
||
|
||
act(() => {
|
||
result.current('call2')
|
||
})
|
||
|
||
act(() => {
|
||
result.current('call3')
|
||
})
|
||
|
||
expect(callback).not.toHaveBeenCalled()
|
||
|
||
act(() => {
|
||
jest.advanceTimersByTime(300)
|
||
})
|
||
|
||
expect(callback).toHaveBeenCalledWith('call3')
|
||
expect(callback).toHaveBeenCalledTimes(1)
|
||
})
|
||
})
|
||
|
||
describe('参数传递', () => {
|
||
it('应该正确传递单个参数', () => {
|
||
const callback = jest.fn()
|
||
const { result } = renderHook(() => useDebouncedCallback(callback, 300))
|
||
|
||
act(() => {
|
||
result.current('test')
|
||
})
|
||
|
||
act(() => {
|
||
jest.advanceTimersByTime(300)
|
||
})
|
||
|
||
expect(callback).toHaveBeenCalledWith('test')
|
||
})
|
||
|
||
it('应该正确传递多个参数', () => {
|
||
const callback = jest.fn()
|
||
const { result } = renderHook(() => useDebouncedCallback(callback, 300))
|
||
|
||
act(() => {
|
||
result.current('arg1', 'arg2', 'arg3')
|
||
})
|
||
|
||
act(() => {
|
||
jest.advanceTimersByTime(300)
|
||
})
|
||
|
||
expect(callback).toHaveBeenCalledWith('arg1', 'arg2', 'arg3')
|
||
})
|
||
|
||
it('应该正确传递对象参数', () => {
|
||
const callback = jest.fn()
|
||
const { result } = renderHook(() => useDebouncedCallback(callback, 300))
|
||
|
||
const obj = { name: 'test', value: 42 }
|
||
act(() => {
|
||
result.current(obj)
|
||
})
|
||
|
||
act(() => {
|
||
jest.advanceTimersByTime(300)
|
||
})
|
||
|
||
expect(callback).toHaveBeenCalledWith(obj)
|
||
})
|
||
})
|
||
|
||
describe('延迟时间配置', () => {
|
||
it('应该支持自定义延迟时间', () => {
|
||
const callback = jest.fn()
|
||
const { result } = renderHook(() => useDebouncedCallback(callback, 500))
|
||
|
||
act(() => {
|
||
result.current('test')
|
||
})
|
||
|
||
// 300ms后还未调用
|
||
act(() => {
|
||
jest.advanceTimersByTime(300)
|
||
})
|
||
expect(callback).not.toHaveBeenCalled()
|
||
|
||
// 再过200ms(总共500ms)后调用
|
||
act(() => {
|
||
jest.advanceTimersByTime(200)
|
||
})
|
||
expect(callback).toHaveBeenCalledWith('test')
|
||
})
|
||
})
|
||
|
||
describe('定时器清理', () => {
|
||
it('应该在新调用时清除之前的定时器', () => {
|
||
const callback = jest.fn()
|
||
const { result } = renderHook(() => useDebouncedCallback(callback, 300))
|
||
|
||
act(() => {
|
||
result.current('call1')
|
||
})
|
||
|
||
// 快进150ms
|
||
act(() => {
|
||
jest.advanceTimersByTime(150)
|
||
})
|
||
|
||
// 再次调用,应该清除之前的定时器
|
||
act(() => {
|
||
result.current('call2')
|
||
})
|
||
|
||
// 再快进150ms(距离第一次调用已经300ms,但距离第二次调用只有150ms)
|
||
act(() => {
|
||
jest.advanceTimersByTime(150)
|
||
})
|
||
|
||
// 此时callback还不应该被调用
|
||
expect(callback).not.toHaveBeenCalled()
|
||
|
||
// 再快进150ms(距离第二次调用已经300ms)
|
||
act(() => {
|
||
jest.advanceTimersByTime(150)
|
||
})
|
||
|
||
// 现在应该只调用一次,参数是call2
|
||
expect(callback).toHaveBeenCalledWith('call2')
|
||
expect(callback).toHaveBeenCalledTimes(1)
|
||
})
|
||
})
|
||
})
|