在React中测试API调用-状态未更新 [英] Testing API Call in React - State not updating
问题描述
我想测试组件中的API调用后状态是否已更新。我有一个方法可以说 method1()
,在该方法中,它调用 fetch
并将状态设置为结果。
这是方法:
I want to test if my state is updated after an API call in my component. I have a method lets say method1()
and in that method, it calls fetch
and sets the state to the results.
Here is the method:
method1 = () => {
if (this.state.state1 !== "") {
fetch('api')
.then((resp) => resp.json())
.then((data) => {
this.setState({ state2: data });
})
.catch((error) => {
console.log(error);
});
}
}
在我的测试文件中,我已经使用 fetch-mock
模拟了API,下面是尝试测试此API的测试:
In my test file I already mocked the API with fetch-mock
and here is the test trying to test this:
it('updates the state after the api call', () => {
const instance = component.instance();
instance.method1();
expect(component.state('state2')).toBe(MOCK_DATA);
});
我的 MOCK_DATA
与模拟一起定义在 beforeEach()
My MOCK_DATA
is defined along with the mock fetches and component (shallow) in beforeEach()
中获取内容和组件(浅)时,运行 state2
仍处于初始状态( []
),但我希望它是一个填充数组。
When I run this, state2
is still in its initial state ([]
), but I'm expecting it to be a populated array.
我也尝试使测试异步并使用 await
,但得到的结果相同。
I also tried making the test async and using await
but I am getting the same results.
任何帮助将不胜感激!谢谢!
Any help would be appreciated! Thanks!
推荐答案
这是不使用 fetch-mock
的解决方案。您可以自己手动模拟获取
。
Here is a solution without using fetch-mock
. You can mock fetch
manually by yourself.
index.tsx
:
import React, { Component } from 'react';
import fetch from 'node-fetch';
interface ISomeComponentState {
state1: string;
state2: string;
}
export class SomeComponent extends Component<any, ISomeComponentState> {
constructor(props) {
super(props);
this.state = {
state1: 'jest',
state2: ''
};
}
public async method1() {
if (this.state.state1 !== '') {
await fetch('api')
.then(resp => resp.json())
.then(data => {
this.setState({ state2: data });
})
.catch(error => {
console.log(error);
});
}
}
public render() {
return <div>test</div>;
}
}
单元测试, index.spec.tsx
:
import React from 'react';
import { SomeComponent } from './';
import { shallow, ShallowWrapper } from 'enzyme';
import fetch from 'node-fetch';
const { Response } = jest.requireActual('node-fetch');
jest.mock('node-fetch');
describe('SomeComponent', () => {
let component: ShallowWrapper;
beforeEach(() => {
component = shallow(<SomeComponent></SomeComponent>);
});
it('snapshot', () => {
expect(component).toMatchSnapshot();
});
it('should not fetch api', async () => {
const mockedState = { state1: '', state2: '' };
component.setState(mockedState);
expect(component.state()).toEqual(mockedState);
await (component.instance() as SomeComponent).method1();
expect(fetch).not.toBeCalled();
expect(component.state()).toEqual(mockedState);
});
it('should fetch api correctly', async () => {
(fetch as jest.MockedFunction<typeof fetch>).mockResolvedValueOnce(new Response(JSON.stringify('mocked data')));
expect(component.state()).toEqual({ state1: 'jest', state2: '' });
await (component.instance() as SomeComponent).method1();
expect(fetch).toBeCalledWith('api');
expect(component.state()).toEqual({ state1: 'jest', state2: 'mocked data' });
});
it('will fetch error', async () => {
const mockedError = new Error('some error');
const consoleLogSpyOn = jest.spyOn(console, 'log');
(fetch as jest.MockedFunction<typeof fetch>).mockRejectedValueOnce(mockedError);
await (component.instance() as SomeComponent).method1();
expect(fetch).toBeCalledWith('api');
expect(consoleLogSpyOn).toBeCalledWith(mockedError);
expect(component.state()).toEqual({ state1: 'jest', state2: '' });
});
});
具有100%覆盖率的单元测试结果:
Unit test result with 100% coverage:
PASS src/stackoverflow/52899150/index.spec.tsx
SomeComponent
✓ snapshot (20ms)
✓ should not fetch api (5ms)
✓ should fetch api correctly (6ms)
✓ will fetch error (11ms)
console.log node_modules/jest-mock/build/index.js:860
Error: some error
at Object.<anonymous> (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/52899150/index.spec.tsx:38:25)
at step (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/52899150/index.spec.tsx:32:23)
at Object.next (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/52899150/index.spec.tsx:13:53)
at /Users/ldu020/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/52899150/index.spec.tsx:7:71
at new Promise (<anonymous>)
at Object.<anonymous>.__awaiter (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/52899150/index.spec.tsx:3:12)
at Object.<anonymous> (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/52899150/index.spec.tsx:37:26)
at Object.asyncJestTest (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:102:37)
at resolve (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/node_modules/jest-jasmine2/build/queueRunner.js:43:12)
at new Promise (<anonymous>)
at mapper (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/node_modules/jest-jasmine2/build/queueRunner.js:26:19)
at promise.then (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/node_modules/jest-jasmine2/build/queueRunner.js:73:41)
at process._tickCallback (internal/process/next_tick.js:68:7)
-----------|----------|----------|----------|----------|-------------------|
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: 4 passed, 4 total
Snapshots: 1 passed, 1 total
Time: 4.697s
以下是完整的演示: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/52899150
这篇关于在React中测试API调用-状态未更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!