API
React 测试库
重新导出了 DOM 测试库
中的所有内容,以及以下方法
render
function render(
ui: React.ReactElement<any>,
options?: {
/* You won't often use this, expand below for docs on options */
},
): RenderResult
渲染到附加到 document.body
的容器中。
import {render} from '@testing-library/react'
render(<div />)
import {render} from '@testing-library/react'
import '@testing-library/jest-dom'
test('renders a message', () => {
const {asFragment, getByText} = render(<Greeting />)
expect(getByText('Hello, world!')).toBeInTheDocument()
expect(asFragment()).toMatchInlineSnapshot(`
<h1>Hello, World!</h1>
`)
})
render
选项
你通常不需要指定选项,但如果你需要,这里有一些你可以作为第二个参数提供给 render
的可用选项。
container
默认情况下,React 测试库
将创建一个 div
并将其附加到 document.body
,你的 React 组件将渲染在此处。如果你通过此选项提供自己的 HTMLElement container
,它不会自动附加到 document.body
。
例如:如果你正在对 tablebody
元素进行单元测试,它不能是 div
的子元素。在这种情况下,你可以指定 table
作为渲染 container
。
const table = document.createElement('table')
const {container} = render(<TableBody {...props} />, {
container: document.body.appendChild(table),
})
baseElement
如果指定了 container
,则它默认为该值,否则默认为 document.body
。它用作查询的基础元素,以及当你使用 debug()
时打印的内容。
hydrate
如果将 hydrate 设置为 true,则它将使用 ReactDOM.hydrate 进行渲染。如果你正在使用服务器端渲染并使用 ReactDOM.hydrate 来挂载你的组件,这可能很有用。
legacyRoot
此选项仅在测试使用 React 18 及更早版本运行时可用。
默认情况下,我们将使用对并发功能的支持进行渲染(即 ReactDOMClient.createRoot
)。但是,如果你正在处理需要像 React 17 中那样进行渲染的遗留应用程序(即 ReactDOM.render
),那么你应该通过设置 legacyRoot: true
来启用此选项。
wrapper
将 React 组件作为 wrapper
选项传递,使其渲染在内部元素周围。这对于为常见数据提供者创建可重用的自定义渲染函数最为有用。有关示例,请参阅 设置。
queries
要绑定的查询。覆盖来自 DOM 测试库
的默认集,除非合并。
// Example, a function to traverse table contents
import * as tableQueries from 'my-table-query-library'
import {queries} from '@testing-library/react'
const {getByRowColumn, getByText} = render(<MyTable />, {
queries: {...queries, ...tableQueries},
})
有关使用实用函数创建自定义查询的指南,请参阅 辅助函数。
还可以通过遵循 自定义渲染指南 在全局范围内添加自定义查询。
render
结果
render
方法返回一个具有几个属性的对象
...queries
render
的最重要的功能是,来自 DOM 测试库 的查询会自动返回,它们的首个参数绑定到 baseElement,它默认是 document.body
。
有关完整的列表,请参阅 查询。
示例
const {getByLabelText, queryAllByTestId} = render(<Component />)
container
渲染的 React 元素的包含 DOM 节点(使用 ReactDOM.render
渲染)。它是一个 div
。这是一个普通的 DOM 节点,因此你可以调用 container.querySelector
等来检查其子元素。
提示:要获取渲染元素的根元素,请使用
container.firstChild
。注意:当该根元素是一个 React 片段 时,
container.firstChild
仅获取该片段的第一个子元素,而不是片段本身。
🚨 如果你发现自己使用
container
来查询渲染的元素,那么你应该重新考虑!其他查询旨在更能抵御对要测试的组件所做的更改。避免使用container
来查询元素!
baseElement
包含 React 元素在容器中渲染的 DOM 节点。如果你没有在 render
的选项中指定 baseElement
,它将默认为 document.body
。
当要测试的组件在容器 div 之外渲染某些内容时,这很有用,例如,当你想对直接在 body 中渲染其 HTML 的门户组件进行快照测试时。
注意:
render
返回的查询会查看 baseElement,因此你可以在没有 baseElement 的情况下使用查询来测试门户组件。
debug
注意:建议使用
screen.debug
代替。
此方法是 console.log(prettyDOM(baseElement))
的快捷方式。
import React from 'react'
import {render} from '@testing-library/react'
const HelloWorld = () => <h1>Hello World</h1>
const {debug} = render(<HelloWorld />)
debug()
// <div>
// <h1>Hello World</h1>
// </div>
// you can also pass an element: debug(getByTestId('messages'))
// and you can pass all the same arguments to debug as you can
// to prettyDOM:
// const maxLengthToPrint = 10000
// debug(getByTestId('messages'), maxLengthToPrint, {highlight: false})
这是一个围绕 prettyDOM
的简单包装器,prettyDOM
也是公开的,它来自 DOM 测试库
。
rerender
如果你测试正在进行道具更新的组件以确保道具被正确更新,这可能会更好(参见 指南原则部分)。也就是说,如果你更愿意在测试中更新渲染组件的道具,则可以使用此函数来更新渲染组件的道具。
import {render} from '@testing-library/react'
const {rerender} = render(<NumberDisplay number={1} />)
// re-render the same component with different props
rerender(<NumberDisplay number={2} />)
unmount
这将导致渲染的组件被卸载。这对于测试你的组件从页面中删除时会发生什么很有用(例如,测试你不留下会导致内存泄漏的事件处理程序)。
此方法是对
ReactDOM.unmountComponentAtNode
的一个非常小的抽象。
import {render} from '@testing-library/react'
const {container, unmount} = render(<Login />)
unmount()
// your component has been unmounted and now: container.innerHTML === ''
asFragment
返回渲染的组件的 DocumentFragment
。如果你需要避免实时绑定并查看你的组件对事件的反应,这可能很有用。
import React, {useState} from 'react'
import {render, fireEvent} from '@testing-library/react'
const TestComponent = () => {
const [count, setCounter] = useState(0)
return (
<button onClick={() => setCounter(count => count + 1)}>
Click to increase: {count}
</button>
)
}
const {getByText, asFragment} = render(<TestComponent />)
const firstRender = asFragment()
fireEvent.click(getByText(/Click to increase/))
// This will snapshot only the difference between the first render, and the
// state of the DOM after the click event.
// See https://github.com/jest-community/snapshot-diff
expect(firstRender).toMatchDiffSnapshot(asFragment())
cleanup
卸载使用 render 挂载的 React 树。
如果你的测试框架(例如 mocha、Jest 或 Jasmine)将全局
afterEach()
函数注入到测试环境中,则会自动调用此函数。如果没有,你需要在每次测试后调用cleanup()
。
例如,如果你正在使用 ava 测试框架,那么你需要使用 test.afterEach
钩子,如下所示
import {cleanup, render} from '@testing-library/react'
import test from 'ava'
test.afterEach(cleanup)
test('renders into document', () => {
render(<div />)
// ...
})
// ... more tests ...
如果你调用了 render
但没有调用 cleanup
,可能会导致内存泄漏和非“幂等”测试(这会导致测试中难以调试的错误)。
act
这是一个围绕 react
act
函数 的轻量级包装器。如果你的 react 版本支持 act
,它所做的就是将所有参数转发给 act 函数。出于一致性考虑,建议使用来自 @testing-library/react
的导入,而不是 react
。
renderHook
这是一个围绕 render
的便利包装器,它使用自定义测试组件。该 API 源自一种流行的测试模式,主要对发布钩子的库很有用。你应该首选 render
,因为自定义测试组件会导致更易读和更健壮的测试,因为你要测试的内容不会隐藏在抽象后面。
function renderHook<
Result,
Props,
Q extends Queries = typeof queries,
Container extends Element | DocumentFragment = HTMLElement,
BaseElement extends Element | DocumentFragment = Container
>(
render: (initialProps: Props) => Result,
options?: RenderHookOptions<Props, Q, Container, BaseElement>,
): RenderHookResult<Result, Props>
示例
import {renderHook} from '@testing-library/react'
test('returns logged in user', () => {
const {result} = renderHook(() => useLoggedInUser())
expect(result.current).toEqual({name: 'Alice'})
})
renderHook
选项
renderHook
选项 initialProps
声明在首次调用时传递给渲染回调的道具。如果你在没有道具的情况下调用 rerender
,这些道具不会传递。
import {renderHook} from '@testing-library/react'
test('returns logged in user', () => {
const {result, rerender} = renderHook((props = {}) => props, {
initialProps: {name: 'Alice'},
})
expect(result.current).toEqual({name: 'Alice'})
rerender()
expect(result.current).toEqual({name: undefined})
})
注意:当将
renderHook
与wrapper
和initialProps
选项一起使用时,initialProps
不会传递给wrapper
组件。要向wrapper
组件提供道具,请考虑以下解决方案const createWrapper = (Wrapper, props) => {
return function CreatedWrapper({ children }) {
return <Wrapper {...props}>{children}</Wrapper>;
};
};
...
{
wrapper: createWrapper(Wrapper, { value: 'foo' }),
}
renderHook
选项 wrapper
renderHook
结果
renderHook
方法返回一个包含以下属性的对象。
result
保存渲染回调最近一次 **提交** 的返回值。
import {renderHook} from '@testing-library/react'
const {result} = renderHook(() => {
const [name, setName] = useState('')
React.useEffect(() => {
setName('Alice')
}, [])
return name
})
expect(result.current).toBe('Alice')
请注意,该值保存在 result.current
中。可以将 result
视为最近一次 **提交** 值的 ref。
rerender
使用新 props 重新渲染之前渲染的渲染回调。
import {renderHook} from '@testing-library/react'
const {rerender} = renderHook(({name = 'Alice'} = {}) => name)
// re-render the same hook with different props
rerender({name: 'Bob'})
unmount
卸载测试钩子。
import {renderHook} from '@testing-library/react'
const {unmount} = renderHook(({name = 'Alice'} = {}) => name)
unmount()
configure
更改全局选项。可以在 配置选项 中看到基本用法。
React Testing Library 还提供专用的选项。
import {configure} from '@testing-library/react'
configure({reactStrictMode: true})
configure
选项
reactStrictMode
启用后,<StrictMode>
将渲染在内部元素周围。默认值为 false
。