使用 react-testing-library 进行测试时,我可以手动触发状态更改吗?
Posted
技术标签:
【中文标题】使用 react-testing-library 进行测试时,我可以手动触发状态更改吗?【英文标题】:Can I manually trigger a state change when testing using react-testing-library? 【发布时间】:2019-07-17 03:55:19 【问题描述】:我仍在将我的 Enzyme 测试转移到 react-testing-library 的过程中,并且我有一个相当常见的场景,当组件安装时,它会启动 Ajax 请求以获取一些数据。就在 fetch 开始之前,它设置了一些状态值来指示它正在加载,这反过来又呈现了一个微调器。完成后,状态将同时更新数据,并且“loadingState”在适当的情况下设置为“Completed”或“Failed”。
import React, useEffect, useState from "react";
import SwapSpinner from "react-spinners-kit";
import styled from "styled-components";
import * as R from "ramda";
import getPeople from "./getPeople";
const FlexCenter = styled.div`
height: 250px;
display: flex;
justify-content: center;
align-items: center;
`;
const loadingStates =
notStarted: "notStarted",
isLoading: "isLoading",
success: "success",
failure: "failure"
;
function App()
const [people, setPeople] = useState([]);
const [isLoading, setLoading] = useState(loadingStates.notStarted);
useEffect(() =>
setLoading(loadingStates.isLoading);
getPeople()
.then(( results ) =>
setPeople(results);
setLoading(loadingStates.success);
)
.catch(error =>
setLoading(loadingStates.failure);
);
, []);
return (
<div>
R.cond([
[
R.equals(loadingStates.isLoading),
() => (
<FlexCenter data-testid="spinner">
<SwapSpinner />
</FlexCenter>
)
],
[
R.equals(loadingStates.success),
() => (
<ul data-testid="people-list">
people.map(( name ) => (
<li key=name>name</li>
))
</ul>
)
],
[R.equals(loadingStates.failure), <div>An error occured</div>]
])(isLoading)
</div>
);
export default App;
使用 Enzyme,我可以手动将状态设置为任一 loadingStates
键,并断言渲染条件会渲染适当的更改。
有没有办法在 RTL 中做到这一点?
【问题讨论】:
【参考方案1】:你不能用 RTL 做到这一点。您不应该与组件的内部交互。
这大概是我测试你的组件的方式:
import getPeople from "./getPeople";
jest.mock('./getPeople')
test('skeleton of a test', async () =>
const people = [/* Put some mock people in here */]
getPeople.mockResolvedValueOnce( results: people )
render(<App />)
expect(/* Somehow get the loading spinner */).toBeInTheDocument()
await wait(() => expect(/* Here you check that the people is on the page */).toBeInTheDocument())
// We also check that the API gets called
expect(getPeople).toHaveBeenCalledOnce()
expect(getPeople).toHaveBeenCalledWith()
)
如您所见,我没有检查App
的内部状态。相反,我正在检查是否显示了加载微调器,然后人们会出现在屏幕上并且 API 是否被调用。
此测试更可靠,因为您测试的是用户将看到的内容,而不是实现细节。
【讨论】:
以上是关于使用 react-testing-library 进行测试时,我可以手动触发状态更改吗?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 React-Testing-Library 测试 mapDispatchToProps?
如何使用 Jest 和 react-testing-library 测试 useRef?
react-testing-library - 屏幕与渲染查询
如何使用 react-testing-library 测试由其他组件组成的组件?