使用 react-testing-library 测试 useEffect 内部的 api 调用 [英] Testing api call inside useEffect using react-testing-library
问题描述
我想测试 api 调用和返回的数据,这些数据应该显示在我的功能组件中.我创建了执行 api 调用的 List 组件.我希望返回的数据显示在组件中,为此我使用了 useState 钩子.组件如下所示:
const 列表:FC<{}>= () =>{const [data, setData] = useState();const getData = (): Promise=>{return fetch('https://jsonplaceholder.typicode.com/todos/1');};React.useEffect(() => {const func = async() =>{const 数据 = 等待 getData();const value = await data.json();设置数据(值.标题);}功能();}, [])返回 (<div><div id="test">{data}</div>
)}
我写了一个测试,其中我模拟了 fetch 方法.我检查 fetch 方法是否已被调用并且它确实发生了.不幸的是,我不知道如何测试响应返回的值.当我尝试 console.log 时,我只是得到 null,我想得到示例文本".我的猜测是我必须等待从 Promise 返回的这个值.不幸的是,尽管尝试使用行为和等待方法,但我不知道如何实现它.这是我的测试:
it('test', async() => {让组件;const fakeResponse = '示例文本';const mockFetch = Promise.resolve({json: () => Promise.resolve(fakeResponse)});const mockedFetch = jest.spyOn(window, 'fetch').mockImplementationOnce(() => mockFetch as any )等待等待(异步()=> {组件 = 渲染(<列表/>);})const 值:Element = component.container.querySelector('#test');console.log(value.textContent);期望(mockedFetch).toHaveBeenCalledTimes(1);})
如果您有任何建议,我将不胜感激.
第二次尝试
也尝试使用 data-testid="test"
和 waitForElement
,但仍然收到空值.
更新的组件增量:
const 列表:FC<{}>= () =>{- const [data, setData] = useState();+ const [data, setData] = useState('test');const getData = (): Promise=>{return fetch('https://jsonplaceholder.typicode.com/todos/1');};React.useEffect(() => {const func = async() =>{const 数据 = 等待 getData();const value = await data.json();setData(value.title);}功能();}, [])返回 (<div>- <div id="test">{data}</div>+ )}
和更新的测试:
it('test', async() => {const fakeResponse = '示例文本';const mockFetch = Promise.resolve({json: () => Promise.resolve(fakeResponse)});const mockedFetch = jest.spyOn(window, 'fetch').mockImplementationOnce(() => mockFetch as any )const { getByTestId } = render(<List/>);expect(getByTestId("test")).toHaveTextContent("test");const resolveValue = await waitForElement(() => getByTestId('test'));expect(resolvedValue).toHaveTextContent(示例文本");期望(mockedFetch).toHaveBeenCalledTimes(1);})
解决方案 这是一个工作单元测试示例:
index.tsx
:
import React, { useState, FC } from 'react';导出常量列表:FC<{}>= () =>{const [data, setData] = useState();const getData = (): Promise=>{return fetch('https://jsonplaceholder.typicode.com/todos/1');};React.useEffect(() => {const func = async() =>{const 数据 = 等待 getData();const value = await data.json();设置数据(值.标题);};功能();}, []);返回 (<div><div data-testid="test">{data}</div>
);};
index.test.tsx
:
import { List } from './';从反应"导入反应;导入'@testing-library/jest-dom/extend-expect';从'@testing-library/react'导入{渲染,waitForElement};描述('59892259',()=> {让 originFetch;beforeEach(() => {originFetch = (全局为任何).fetch;});afterEach(() => {(全局为任何).fetch = originFetch;});it('应该通过', async() => {const fakeResponse = { title: '示例文本' };const mRes = { json: jest.fn().mockResolvedValueOnce(fakeResponse) };const mockedFetch = jest.fn().mockResolvedValueOnce(mRes as any);(全局为任何).fetch = mockedFetch;const { getByTestId } = render(<List></List>);const div = await waitForElement(() => getByTestId('test'));期望(div).toHaveTextContent('示例文本');期望(mockedFetch).toBeCalledTimes(1);期望(mRes.json).toBeCalledTimes(1);});});
单元测试结果:
PASS src/stackoverflow/59892259/index.test.tsx (9.816s)59892259✓ 应该通过 (63ms)-----------|----------|----------|----------|----------|--------------------|档案 |% stmts |% 分支 |% 函数 |% 行 |未覆盖的行#s |-----------|----------|----------|----------|----------|--------------------|所有文件 |100 |100 |100 |100 ||index.tsx |100 |100 |100 |100 ||-----------|----------|----------|----------|----------|--------------------|测试套件:1 次通过,总共 1 次测试:1 次通过,共 1 次快照:共 0 个时间:11.73s,估计13s
I want to test api call and data returned which should be displayed inside my functional component. I created List component which performs api call. I would like the returned data to be displayed in the component and I use the useState hook for this. Component looks like this:
const List: FC<{}> = () => {
const [data, setData] = useState<number>();
const getData = (): Promise<any> => {
return fetch('https://jsonplaceholder.typicode.com/todos/1');
};
React.useEffect(() => {
const func = async () => {
const data = await getData();
const value = await data.json();
setData(value.title);
}
func();
}, [])
return (
<div>
<div id="test">{data}</div>
</div>
)
}
I wrote one test in which I mocked the fetch method. I check if the fetch method has been called and it actually happens. Unfortunately, I don't know how I could test the value returned from response. When I try console.log I just get null and I'd like to get 'example text'. My guess is that I have to wait for this value returned from Promise. Unfortunately, despite trying with methods act and wait, I don't know how to achieve it. Here is my test:
it('test', async () => {
let component;
const fakeResponse = 'example text';
const mockFetch = Promise.resolve({json: () => Promise.resolve(fakeResponse)});
const mockedFetch = jest.spyOn(window, 'fetch').mockImplementationOnce(() => mockFetch as any )
await wait( async () => {
component = render(<List />);
})
const value: Element = component.container.querySelector('#test');
console.log(value.textContent);
expect(mockedFetch).toHaveBeenCalledTimes(1);
})
I would be really thankful for any suggestions.
Second Attempt
Also tried using data-testid="test"
and waitForElement
, but still receiving null value.
updated component deltas:
const List: FC<{}> = () => {
- const [data, setData] = useState<number>();
+ const [data, setData] = useState<string>('test');
const getData = (): Promise<any> => {
return fetch('https://jsonplaceholder.typicode.com/todos/1');
};
React.useEffect(() => {
const func = async () => {
const data = await getData();
const value = await data.json();
setData(value.title);
}
func();
}, [])
return (
<div>
- <div id="test">{data}</div>
+ <div data-testid="test" id="test">{data}</div>
</div>
)
}
and updated test:
it('test', async () => {
const fakeResponse = 'example text';
const mockFetch = Promise.resolve({json: () => Promise.resolve(fakeResponse)});
const mockedFetch = jest.spyOn(window, 'fetch').mockImplementationOnce(() => mockFetch as any )
const { getByTestId } = render(<List />);
expect(getByTestId("test")).toHaveTextContent("test");
const resolvedValue = await waitForElement(() => getByTestId('test'));
expect(resolvedValue).toHaveTextContent("example text");
expect(mockedFetch).toHaveBeenCalledTimes(1);
})
Here is a working unit testing example:
index.tsx
:
import React, { useState, FC } from 'react';
export const List: FC<{}> = () => {
const [data, setData] = useState<number>();
const getData = (): Promise<any> => {
return fetch('https://jsonplaceholder.typicode.com/todos/1');
};
React.useEffect(() => {
const func = async () => {
const data = await getData();
const value = await data.json();
setData(value.title);
};
func();
}, []);
return (
<div>
<div data-testid="test">{data}</div>
</div>
);
};
index.test.tsx
:
import { List } from './';
import React from 'react';
import '@testing-library/jest-dom/extend-expect';
import { render, waitForElement } from '@testing-library/react';
describe('59892259', () => {
let originFetch;
beforeEach(() => {
originFetch = (global as any).fetch;
});
afterEach(() => {
(global as any).fetch = originFetch;
});
it('should pass', async () => {
const fakeResponse = { title: 'example text' };
const mRes = { json: jest.fn().mockResolvedValueOnce(fakeResponse) };
const mockedFetch = jest.fn().mockResolvedValueOnce(mRes as any);
(global as any).fetch = mockedFetch;
const { getByTestId } = render(<List></List>);
const div = await waitForElement(() => getByTestId('test'));
expect(div).toHaveTextContent('example text');
expect(mockedFetch).toBeCalledTimes(1);
expect(mRes.json).toBeCalledTimes(1);
});
});
unit test result:
PASS src/stackoverflow/59892259/index.test.tsx (9.816s)
59892259
✓ should pass (63ms)
-----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.tsx | 100 | 100 | 100 | 100 | |
-----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 11.73s, estimated 13s
这篇关于使用 react-testing-library 测试 useEffect 内部的 api 调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!