react-native-testing-library:如何使用 act 测试 useEffect
Posted
技术标签:
【中文标题】react-native-testing-library:如何使用 act 测试 useEffect【英文标题】:react-native-testing-library: how to test useEffect with act 【发布时间】:2020-03-26 14:31:39 【问题描述】:我正在使用 react-native-testing-library
来测试我的 react-native 组件。
我有一个组件(为了这篇文章的目的,它已经被过度简化了):
export const ComponentUnderTest = () =>
useEffect(() =>
__make_api_call_here_then_update_state__
, [])
return (
<View>
__content__goes__here
</View>
)
这是我的(简化版)component.spec.tsx
:
import render, act from 'react-native-testing-library';
import ComponentUnderTest from './componentundertest.tsx';
test('it updates content on successful call', () =>
let root;
act(() =>
root = render(<ComponentUnderTest />); // this fails with below error message
);
expect(...);
)
现在当我运行这段代码时,我得到了这个错误:
Can't access .root on unmounted test renderer
我什至现在都不知道这个错误消息是什么意思。我按照react-native-testing-library
中的文档了解如何使用act and useEffect
进行测试。
任何帮助将不胜感激。谢谢
【问题讨论】:
【参考方案1】:我找到了解决方法:
import render, waitFor from 'react-native-testing-library';
import ComponentUnderTest from './componentundertest.tsx';
test('it updates content on successful call', async () =>
const root = await waitFor(() =>
render(<ComponentUnderTest />);
);
expect(...);
)
【讨论】:
这不行,时间过去了,什么也没有发生。【参考方案2】:root = render(<ComponentUnderTest />);
应该是
root = create(<ComponentUnderTest />);
----全码sn-p。经过上述更改后它对我有用
import React, useState, useEffect from 'react'
import Text, View from 'react-native'
import render, act from 'react-native-testing-library'
import create from 'react-test-renderer'
export const ComponentUnderTest = () =>
useEffect(() => , [])
return (
<View>
<Text>Hello</Text>
</View>
)
test('it updates content on successful call', () =>
let root
act(() =>
root = create(<ComponentUnderTest />)
)
)
【讨论】:
感谢您的回答。但是您从哪个库导入create
? react-native-testing-library
好像没有这样的导出成员
react-test-renderer(它已经是 react-native-testing-library 的依赖项)
我按照你的建议使用了create
。不幸的是,我遇到了同样的错误。一些类似的错误/问题(在 react,不是 react-native,具有相应的 @testing-library/react)报告了未匹配版本的问题。 (见github.com/testing-library/react-hooks-testing-library/issues/…)我不知道什么是适合我的版本
我已经用完整的代码更新了我的答案。它在我使用 create 时有效。使用渲染我得到同样的错误
失败了不是吗?我们希望渲染使用查询:getByRole
、getByTestID
等。除非有其他方法可以找到使用 fireEvents 的元素,否则在这种情况下我看不到 create
有多大用处。我在create
上也找不到太多文档或示例。【参考方案3】:
您可以使用:@testing-library/react-native
例子:
import cleanup, fireEvent, render, debug, act from '@testing-library/react-native'
afterEach(() => cleanup());
test('given correct credentials, gets response token.', async () =>
const debug, getByPlaceholderText, getByRole = await render(<Component/>);
await act( async () =>
const emailInput = getByPlaceholderText('Email');;
const passwordInput = getByPlaceholderText('Password');
const submitBtn = getByRole('button', name: '/submitBtn/i');
fireEvent.changeText(emailInput, 'email');
fireEvent.changeText(passwordInput, 'password');
fireEvent.press(submitBtn);
);
);
也应该与 useEffect 一起使用,但我自己还没有测试过。与 useState 一起工作正常。
【讨论】:
如果你只需要在第一次渲染后等待useEffect
被触发一次,你会用什么包裹act
?【参考方案4】:
以下步骤解决了我的情况:
升级React
和react-test-renderer
版本到16.9 或更高版本,支持act
内部的async
函数(据我所知,这两个包需要是相同的版本)
按照@helloworld 的建议,将react-native-testing-library
的render
替换为react-test-renderer
的create
(谢谢您,先生,它帮助了我)
创建测试函数async
,在act
前面加上await
,并传递一个async
函数给它
最终结果如下所示:
test('it updates content on successful call', async () =>
let root
await act(async () =>
root = create(<ComponentUnderTest />)
)
)
【讨论】:
你是如何与 getTestById 等结合起来的,因为 create 没有它们,我相信它很浅。 const getByTestId = await waitFor我使用useEffect
测试异步组件并触发setState
重新渲染的方法是正常设置测试用例,但使用waitFor
or findBy
阻止断言,直到组件使用获取的重新渲染数据。
这是一个简单的可运行示例:
import React, useEffect, useState from "react";
import FlatList, Text from "react-native";
import render from "@testing-library/react-native";
const Posts = () =>
const [posts, setPosts] = useState(null);
useEffect(() =>
const url = "https://jsonplaceholder.typicode.com/posts";
fetch(url).then(res => res.json()).then(setPosts);
, []);
return !posts ? <Text>loading</Text> : <FlatList
testID="posts"
data=posts
renderItem=(item: id, title, index) =>
<Text testID="post" key=id>title</Text>
/>;
;
describe("Posts", () =>
beforeEach(() =>
global.fetch = jest.fn(url => Promise.resolve(
ok: true,
status: 200,
json: () => Promise.resolve([
id: 1, title: "foo title",
id: 2, title: "bar title",
])
));
);
it("should fetch posts", async () =>
const findAllByTestId = render(<Posts />);
const posts = await findAllByTestId("post", timeout: 500);
expect(posts).toHaveLength(2);
expect(posts[0]).toHaveTextContent("foo title");
expect(posts[1]).toHaveTextContent("bar title");
expect(fetch).toHaveBeenCalledTimes(1);
);
);
这并没有给我任何act
警告,但我已经分享了这些警告。 This open GitHub issue 似乎是规范资源。
使用的包:
"dependencies":
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-native": "^0.64.0",
"react-native-web": "^0.15.6"
,
"devDependencies":
"@babel/core": "^7.13.15",
"@testing-library/jest-native": "^4.0.1",
"@testing-library/react-native": "^7.2.0",
"babel-jest": "^26.6.3",
"jest": "^26.6.3",
"metro-react-native-babel-preset": "^0.65.2",
"react-test-renderer": "^17.0.2"
在 Jest 配置中:
setupFilesAfterEnv: ["@testing-library/jest-native/extend-expect"],
对于.toHaveTextContent
匹配器。或者您可以使用导入:
import "@testing-library/jest-native/extend-expect";
【讨论】:
以上是关于react-native-testing-library:如何使用 act 测试 useEffect的主要内容,如果未能解决你的问题,请参考以下文章