flnxi-Wu/lib/hooks/__tests__/useDebounce.test.ts
WuYongJie 473176997a docs: 完成API文档编写(任务26)
创建完整的API文档:
- 模板管理API(5个接口)
  * 获取模板列表
  * 获取模板详情(含使用统计)
  * 创建模板(含验证规则)
  * 更新模板(含版本控制)
  * 删除模板(含使用检查)

- 模板验证API
  * 内置模板验证逻辑
  * 自定义模板验证逻辑
  * 内置模板列表

- 字段池管理API(2个接口)
  * 获取字段池列表
  * 同步字段池

- 分类字段管理API
  * 获取分类管理字段

- 错误代码规范
  * 统一错误响应格式
  * 常见错误代码说明

- 性能指标
  * 响应时间目标
  * 数据库优化说明(20+个索引)

- 最佳实践
  * 版本控制使用方法
  * 错误处理示例
  * 字段验证示例
  * 性能优化建议

文档位置:docs/api/template-system-api.md
2025-12-13 15:42:39 +08:00

337 lines
8.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @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)
})
})
})