I have a TextField (named EmailTextField) of which is used to enter e-mail address. 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.
Now, I want to create a unit test for this TextField. I do not want to test the 'verifyUserNameAvailable' as I already have a test for that in different test suite. Is there a way to mock
const response = await verifyUserNameAvailable(emailAddress);
call in handleOnBlur function?
ex. I want to unit test EmailTextField when response is 'true' and response is 'false'.
EmailTextField component
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: '[email protected]'}});
});
wrapper.update();
expect(wrapper.find(TextField).at(0).props().error).toBe(
true);
expect(wrapper.find(TextField).at(0).props().helperText).toBe(
"[email protected] is already used.");
expect(handleStateChange).toHaveBeenCalledWith({
"errors": ["[email protected] is already used."],
"inProgress": false,
"onChange": false,
"pristine": false,
"touched": true,
"value": {"email": "[email protected]"}
});
});
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: '[email protected]'}});
});
wrapper.update();
expect(wrapper.find(TextField).at(0).props().error).toBe(
true);
expect(wrapper.find(TextField).at(0).props().helperText).toBe(
"[email protected] is available.");
expect(handleStateChange).toHaveBeenCalledWith({
"errors": ["[email protected] is available."],
"inProgress": false,
"onChange": false,
"pristine": true,
"touched": true,
"value": {"email": "[email protected]"}
});
});
});
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
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: '[email protected]'}});
});
wrapper.update();
expect(wrapper.find(TextField).at(0).props().error).toBe(
true);
expect(wrapper.find(TextField).at(0).props().helperText).toBe(
"[email protected] is available.");
expect(handleStateChange).toHaveBeenCalledWith({
"errors": ["[email protected] is available."],
"inProgress": false,
"onChange": false,
"pristine": true,
"touched": true,
"value": {"email": "[email protected]"}
});
});
});
But this does not work...
Looks like the mock function I created is being ignored or something..