[英]React testing-library - Testing a promise that set states in the first useEffect hook
I have a useEffect hook that loads when the component is mounted, as so:我有一个在安装组件时加载的 useEffect 钩子,如下所示:
useEffect(() => {
listFiles().then(keys => {
setKeys(keys)
console.log(keys)
}).catch(err => {
showFail(err.message)
})
}, [])
I'm trying to test the function with react testing-library, simply using the render function:我正在尝试使用反应测试库测试 function,只需使用渲染 function:
beforeEach(() => {
render(<Dashboard />)
})
However, when I run any test that resolves the promise and sets the state:但是,当我运行任何解决 promise 并设置 state 的测试时:
jest.mock('../utils/storage', () => ({
listFiles: jest.fn(() => Promise.resolve([])),
}))
I end up with a weird warning message about using act
to to wrap the event:我最终收到一条关于使用
act
来包装事件的奇怪警告消息:
Warning: An update to Dashboard inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):
act(() => {
/* fire events that update state */
});
/* assert on the output */
This ensures that you're testing the behavior the user would see in the browser. Learn more at ..
in Dashboard
18 | useEffect(() => {
19 | listFiles().then(keys => {
> 20 | setKeys(keys)
| ^
21 | console.log(keys)
22 | }).catch(err => {
23 | showFail(err.message)
I have tried wrapping the render in an act
, but it doesn't seem to change anything.我曾尝试将渲染包装在一个
act
中,但它似乎并没有改变任何东西。
Any suggestions as to what I'm doing wrong here?关于我在这里做错了什么有什么建议吗? Should I be rendering in some other way?
我应该以其他方式渲染吗?
Thanks in advance!提前致谢!
This error usually happens when you try to assert before the component has finished updating all state.当您在组件完成更新所有 state 之前尝试断言时,通常会发生此错误。
Note that inside listFiles
you are calling setKeys(keys)
and that updates the state.请注意,在
listFiles
中,您正在调用setKeys(keys)
并更新 state。
You should await
for the new keys(or files) to show up in the document:您应该
await
新密钥(或文件)出现在文档中:
expect(await findByText('some file name or key')).toBeInTheDocument();
// more asserts here
Alternatively, you can waitFor the mock to have been called (although I think the option above is better).或者,您可以等待模拟已被调用(尽管我认为上面的选项更好)。
await waitFor(() => expect(listFilesMock).toHaveBeenCalled());
// more asserts here
The methods above should already be wrapped in act
for you by the React Testing Library, so you don't need to do it上面的方法
act
已经被 React 测试库为你包装好了,所以你不需要这样做
act()
from the React docs : act()
是什么:When writing UI tests, tasks like rendering, user events, or data fetching can be considered as “units” of interaction with a user interface.
在编写 UI 测试时,渲染、用户事件或数据获取等任务可以被视为与用户界面交互的“单元”。 React provides a helper called act() that makes sure all updates related to these “units” have been processed and applied to the DOM before you make any assertions.
React 提供了一个名为 act() 的帮助器,它确保在您做出任何断言之前,与这些“单元”相关的所有更新都已被处理并应用于 DOM。
The name act comes from the Arrange-Act-Assert pattern.
名称 act 来自 Arrange-Act-Assert 模式。
In my case I wasn't mocking the useEffect async function.在我的情况下,我不是 mocking useEffect async function。
component.test.tsx:组件.test.tsx:
test('Working useEffect hook', () => {
const dbCallMock = jest.fn(() => Promise.resolve())
render(<Tracks dbCallMock ={dbCallMock} />)
}
component.tsx:组件.tsx:
export const myComponent = (props: {
dbCallMock: Function
}) => {
const [state, setState] = useState<string[]>([])
const getDbState= () =>
db.state.toArray().then(gotState => setState(gotState))
useEffect(
() => (props.dbCallMock ? props.dbCallMock() : getDbState()),
[]
)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.