Skip to content

单测

🕒 Published at:

前端单测

  • render:渲染组件,返回 container 容器 dom 和其他的查询 api

  • fireEvent:触发某个元素的某个事件

  • createEvent:创建某个事件(一般不用这样创建)

  • waitFor:等待异步操作完成再断言,可以指定 timeout

  • act:包裹的代码会更接近浏览器里运行的方式

  • renderHook:执行 hook,返回一个对象,可以通过 对象.result.current 拿到 hook 返回值

jest 的 api 加上 @testing-libary/react 的这些 api,就可以写任何组件、hook 的单元测试了。

javascript
// useCount.ts
import { useState } from 'react';

type UseCounterReturnType = [
  count: number, 
  increment: (delta: number) => void, 
  decrement: (delta: number) => void
];

export default function useCounter(initialCount: number = 0): UseCounterReturnType {
  const [count, setCount] = useState(initialCount);

  const increment = (delta: number) => {
    setCount(count => count + delta);
  };

  const decrement = (delta: number) => {
    setCount(count => count - delta);
  };

  return [count, increment, decrement];
}
javascript
//App.test.tsx
import {render,screen,fireEvent, waitFor, renderHook} from '@testing-library/react'
import {act} from 'react-dom/test-utils';
import App from './index.tsx'
import useCount from './useCount'

test('测试名称',()=>{
    const {container} = render(<App />);
    //触发input元素的change事件,并传递value:'a'
    fireEvent.change(container.querySelector('input')!,target:value:'a'})
    
    //等待3秒后,测试p标签的文本是不是open
    await waitFor(() => expect(container.querySelector('p')?.textContent).toBe('open'), {
        timeout: 3000
    });
    
    const hook = renderHook(() => useCounter(0));
    const [count, increment, decrement]  = hook.result.current;
    act(() => {
      increment(2);
    });
    expect(hook.result.current[0]).toBe(2);
})

@testing-library/react 常见 API

API 名称功能描述示例/参数
render渲染 React 组件并返回查询函数和辅助函数render(<MyComponent />)
fireEvent模拟用户事件,如点击、输入等fireEvent.click(getByText('button text'))
screen提供全局查询函数,基于当前渲染的 DOM 结构screen.getByText('text')
getByText根据文本内容查询元素getByText('button text')
getByLabelText根据 label 属性查询元素getByLabelText('label text')
getByRole根据 ARIA 角色查询元素getByRole('button')
getByTestId根据 data-testid 属性查询元素getByTestId('test-id')
rerender重新渲染组件rerender(<MyComponent newProp={value} />)
unmount卸载组件unmount()
waitFor等待异步操作完成后再进行断言await waitFor(() => expect(element).toBeInTheDocument())
within允许在特定元素内部进行查询within(element).getByText('child text')
act在执行导致 React 状态更新的代码时包裹它,以便 Jest 能够正确地跟踪和等待这些更新act(() => { /* 在这里执行状态更新 */ })

react-dom/test-utils(未弃用API)

API 名称功能描述示例/参数
act@testing-library/react中的act功能相同,用于包裹导致状态更新的代码act(() => { /* 状态更新代码 */ })
createPortal创建一个 portal,用于将子节点渲染到与父组件不同的 DOM 节点中(主要用于测试 portal 组件,但较少在单元测试中直接使用)createPortal(child, container)

jest 常见 API

API 名称功能描述示例/参数
test/it定义一个测试用例test('addition works', () => { expect(1 + 1).toBe(2); })
describe对一组相关的测试用例进行分组describe('Math operations', () => { /* 测试用例 */ })
expect提供断言功能,用于验证代码的行为expect(value).toBe(expectedValue)
toBe断言两个值严格相等(使用Object.is进行比较)expect(1 + 1).toBe(2)
toEqual断言两个对象具有相同的值(递归检查所有字段的相等性)expect(obj1).toEqual(obj2)
toBeNull断言值是nullexpect(value).toBeNull()
toBeUndefined断言值是undefinedexpect(value).toBeUndefined()
toBeDefined断言值已被定义expect(value).toBeDefined()
toBeTruthy断言值在布尔上下文中为真expect(value).toBeTruthy()
toBeFalsy断言值在布尔上下文中为假expect(value).toBeFalsy()
toBeGreaterThan断言一个数大于另一个数expect(value).toBeGreaterThan(otherValue)
toBeLessThan断言一个数小于另一个数expect(value).toBeLessThan(otherValue)
toContain断言数组或可迭代对象包含某个特定项expect(array).toContain(item)
toMatch断言字符串匹配给定的正则表达式expect(string).toMatch(regex)
toThrow断言函数在调用时抛出错误expect(fn).toThrow()
toHaveBeenCalled断言函数已被调用expect(mockFn).toHaveBeenCalled()
toHaveBeenCalledTimes断言函数被调用的次数expect(mockFn).toHaveBeenCalledTimes(n)
toHaveBeenCalledWith断言函数被调用时使用了特定的参数expect(mockFn).toHaveBeenCalledWith(...args)