在 useEffect 中使用 react-testing-library 测试 api 调用



我想测试api调用和返回的数据,这些数据应该显示在我的功能组件中。我创建了执行 api 调用的列表组件。我希望返回的数据显示在组件中,并为此使用 useState 钩子。组件如下所示:

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>
)
}

我写了一个测试,其中我嘲笑了获取方法。我检查是否已调用 fetch 方法并且它确实发生了。不幸的是,我不知道如何测试响应返回的值。当我尝试控制台时.log我只是得到空值,我想得到"示例文本"。我的猜测是,我必须等待从 Promise 返回的这个值。不幸的是,尽管尝试了方法行动和等待,但我不知道如何实现它。这是我的测试:

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);
})

我真的很感激任何建议。

第二次尝试

还尝试使用data-testid="test"waitForElement,但仍然收到空值。

更新的组件增量:

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>
)
}

和更新的测试:

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);
})

下面是一个工作单元测试示例:

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);
});
});

单元测试结果:

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
waitForElement

不再可从'@testing-library/react'获得。文档

另一种方法是:

import { act, render } from '@testing-library/react';
it('is a test definition', async () => { // notice the async
await act(async () => { // this is kind of ugly, but it works.
render(<TheComponent />
})
// this section will run after the effects within TheComponent were triggered
})

对我有用的是两个答案的组合

it("should fetch data", async ()=>{
const fakeResponse = {title : "Test"}
const mRes = { json: jest.fn().mockResolvedValueOnce(fakeResponse) };
const mockedFetch = jest.fn().mockResolvedValueOnce(mRes);
global.fetch = mockedFetch;
render(<Component/>);
await act(async ()=>{
await waitFor(() => expect(mockedFetch).toHaveBeenCalledTimes(1))
})
})

NB:上面的代码是JavaScript的,但我认为js和ts之间没有太大区别

相关内容

  • 没有找到相关文章

最新更新