[英]How do I mock a async function in a component when testing reactjs with enzyme and jest?
I have a TextField (named EmailTextField) of which is used to enter e-mail address. 我有一个TextField(名为EmailTextField),用于输入电子邮件地址。 When user enters email address and 'onBlur' event is occur, I have a async function named 'verifyUserNameAvailable' to make api call to server and check if email address is already taken or not.
当用户输入电子邮件地址并且发生“ onBlur”事件时,我有一个名为“ verifyUserNameAvailable”的异步函数可以对服务器进行api调用,并检查电子邮件地址是否已被占用。
Now, I want to create a unit test for this TextField. 现在,我想为此TextField创建一个单元测试。 I do not want to test the 'verifyUserNameAvailable' as I already have a test for that in different test suite.
我不想测试“ verifyUserNameAvailable”,因为我已经在其他测试套件中对此进行了测试。 Is there a way to mock
有没有办法嘲笑
const response = await verifyUserNameAvailable(emailAddress);
call in handleOnBlur function? 调用handleOnBlur函数?
ex. 恩。 I want to unit test EmailTextField when response is 'true' and response is 'false'.
我想在响应为“ true”且响应为“ false”时对EmailTextField进行单元测试。
EmailTextField component EmailTextField组件
import React, {useRef, useState} from 'react';
import TextField from "@material-ui/core/TextField";
import Grid from "@material-ui/core/Grid";
import {verifyUserNameAvailable} from "../../../../api/auth/authApiConsumer";
export const EmailTextField = props => {
const {onStateChange} = props;
const [state, setState] = useState({
errors: [],
onChange: false,
pristine: false,
touched: false,
inProgress: false,
value: {
email: '',
},
});
const [currentReq, setCurrentReq] = useState(0);
const latestReq = useRef(currentReq);
const helperText = 'Email address will be used as your account id';
const helperTextPristine = "'" + state.value.email + "' is available.";
const handleOnBlur = async (event) => {
const emailAddress = String(event.target.value).toLowerCase();
// If true, verify username is available
const updatedState = {
...state,
touched: true,
pristine: false,
value: {
email: emailAddress,
},
inProgress: true
};
setState(updatedState);
onStateChange(updatedState);
const response = await verifyUserNameAvailable(emailAddress);
if (response === true) {
const updatedState = {
...state,
touched: true,
pristine: true,
value: {
email: emailAddress,
},
inProgress: false,
errors: [],
};
setState(updatedState);
onStateChange(updatedState);
} else {
const updatedState = {
...state,
touched: true,
pristine: false,
value: {
email: emailAddress,
},
inProgress: false,
errors: ["'" + emailAddress + "' is already used."],
};
setState(updatedState);
onStateChange(updatedState);
}
};
return (
<Grid container spacing={1}>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
id="email"
label="email address"
error={state.errors.length > 0}
helperText={state.errors.length > 0 ? state.errors[0]
: state.pristine === true ? helperTextPristine : helperText}
name="email"
autoComplete="email"
margin='dense'
onBlur={handleOnBlur}
/>
</Grid>
</Grid>
)
};
export default EmailTextField;
Below is a unit test that I want to create. 下面是我要创建的单元测试。
import React from 'react';
import {configure} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import EmailTextField from './EmailTextField';
import TextField from '@material-ui/core/TextField';
import {createShallow} from '@material-ui/core/test-utils';
import {act} from 'react-dom/test-utils';
configure({adapter: new Adapter()});
describe('<EmailTextField />', () => {
let shallow;
beforeAll(() => {
shallow = createShallow();
});
let wrapper;
beforeEach(() => {
wrapper = shallow(<EmailTextField onStateChange={handleStateChange}/>);
});
const handleStateChange = jest.fn()
it('should show error when already registered account is entered', () => {
// MOCK - Not a working code here.. but I want to do something like...
when(verifyUserNameAvailable).isCalledReturn(false);
////////////////////////
act(() => {
wrapper.find(TextField).at(0).simulate('blur', {target: {value: 'test@abc.net'}});
});
wrapper.update();
expect(wrapper.find(TextField).at(0).props().error).toBe(
true);
expect(wrapper.find(TextField).at(0).props().helperText).toBe(
"test@abc.net is already used.");
expect(handleStateChange).toHaveBeenCalledWith({
"errors": ["test@abc.net is already used."],
"inProgress": false,
"onChange": false,
"pristine": false,
"touched": true,
"value": {"email": "test@abc.net"}
});
});
it('should not show error when account is not previously registered', () => {
// MOCK - Not a working code here.. but I want to do something like...
when(verifyUserNameAvailable).isCalledReturn(true);
////////////////////////
act(() => {
wrapper.find(TextField).at(0).simulate('blur', {target: {value: 'test@abc.net'}});
});
wrapper.update();
expect(wrapper.find(TextField).at(0).props().error).toBe(
true);
expect(wrapper.find(TextField).at(0).props().helperText).toBe(
"test@abc.net is available.");
expect(handleStateChange).toHaveBeenCalledWith({
"errors": ["test@abc.net is available."],
"inProgress": false,
"onChange": false,
"pristine": true,
"touched": true,
"value": {"email": "test@abc.net"}
});
});
});
Is there a way to do something like this in above? 上面有没有办法做这样的事情?
// MOCK - Not a working code here.. but I want to do something like...
when(verifyUserNameAvailable).isCalledReturn(true);
////////////////////////
update 更新
I tried to create a mock under ../../../../api/auth/__mocks__/authApiConsumer
我试图在
../../../../api/auth/__mocks__/authApiConsumer
下创建一个模拟
export const verifyUserNameAvailable = (email) => new Promise(
function (resolve, reject) {
resolve(true);
});
and updated the unit test to look like 并更新了单元测试,使其看起来像
import React from 'react';
import {configure} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import EmailTextField from './EmailTextField';
import TextField from '@material-ui/core/TextField';
import {createShallow} from '@material-ui/core/test-utils';
import {act} from 'react-dom/test-utils';
jest.mock("../../../../api/auth/authApiConsumer");
configure({adapter: new Adapter()});
describe('<EmailTextField />', () => {
let shallow;
beforeAll(() => {
shallow = createShallow();
});
let wrapper;
beforeEach(() => {
wrapper = shallow(<EmailTextField onStateChange={handleStateChange}/>);
});
const handleStateChange = jest.fn()
it('should not show error when account is not previously registered', () => {
act(() => {
wrapper.find(TextField).at(0).simulate('blur', {target: {value: 'test@abc.net'}});
});
wrapper.update();
expect(wrapper.find(TextField).at(0).props().error).toBe(
true);
expect(wrapper.find(TextField).at(0).props().helperText).toBe(
"test@abc.net is available.");
expect(handleStateChange).toHaveBeenCalledWith({
"errors": ["test@abc.net is available."],
"inProgress": false,
"onChange": false,
"pristine": true,
"touched": true,
"value": {"email": "test@abc.net"}
});
});
});
But this does not work... 但这行不通...
Looks like the mock function I created is being ignored or something.. 看起来我创建的模拟函数被忽略了。
You need to run the test in the next tick. 您需要在下一个刻度中运行测试。 Try this code.
试试这个代码。 It works fine.
工作正常。
import React from 'react';
import { configure } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
import EmailTextField from "./EmailTextField";
import TextField from "@material-ui/core/TextField";
import { createShallow } from "@material-ui/core/test-utils";
import { act } from "react-dom/test-utils";
jest.mock('./api/authApiConsumer');
const MOCK_MAIL = "test@abc.net";
configure({ adapter: new Adapter() });
describe("<EmailTextField />", () => {
const handleStateChange = jest.fn();
let shallow;
beforeAll(() => {
shallow = createShallow();
});
let wrapper;
it("should work", () => {
wrapper = shallow(
<EmailTextField onStateChange={handleStateChange} />
);
});
it("should not show error when account is not previously registered", (done) => {
act(() => {
wrapper.find(TextField).at(0).simulate('blur', { target: { value: 'test@abc.net' } });
});
process.nextTick(() => {
wrapper.update();
expect(
wrapper
.find(TextField)
.at(0)
.props().error
).toBe(false);
expect(
wrapper
.find(TextField)
.at(0)
.props().helperText
).toBe(`'${MOCK_MAIL}' is available.`);
expect(handleStateChange).toHaveBeenCalledWith({
errors: [],
inProgress: false,
onChange: false,
pristine: true,
touched: true,
value: { email: MOCK_MAIL }
});
done();
})
});
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.