前端单测
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 | 断言值是null | expect(value).toBeNull() |
toBeUndefined | 断言值是undefined | expect(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) |