I'm new into testing code with react and jest; and jest is having a strange behavior towards hooks.
This is my component. It has 2 useState hooks, linked to 2 functions.
Just a simple component that works as it should.
import React, {useState} from 'react';
export const Test = () => {
const [cardNumber, setCardNumber] = useState('');
const [cardType, setCardType] = useState('');
const handleOnChange = (event) => {
setCardNumber(event.target.value);
};
const handleOnBlur = () => {
setCardType(cardNumber);
};
return (
<>
<input type="text" value={cardNumber} onChange={handleOnChange} onBlur={handleOnBlur} />
<p id="cn">{`CardNumber: ${cardNumber}`}</p>
<p id="ct">{`CardType: ${cardType}`}</p>
</>
);
};
This is the test:
import React from 'react';
import {shallow} from 'enzyme';
import {Test} from '.';
import {act} from 'react-dom/test-utils';
describe('Sandbox Test', () => {
it('should set cardNumber when doing onChange', async () => {
const component = shallow(<Test />);
const inputComponent = component.find('input');
const value = {target: {value: '123456'}};
await act(async () => {
inputComponent.props().onChange(value);
await component.update();
});
const cardNumberComponent = component.find('#cn');
const cardTypeComponent = component.find('#ct');
expect(cardNumberComponent.text()).toEqual(`CardNumber: 123456`);
expect(cardTypeComponent.text()).toEqual(`CardType: `);
});
it('should set cardType when doing onBlur', async () => {
const component = shallow(<Test />);
const inputComponent = component.find('input');
const value = {target: {value: '123456'}};
await act(async () => {
inputComponent.props().onChange(value);
inputComponent.props().onBlur();
await component.update();
});
const cardNumberComponent = component.find('#cn');
const cardTypeComponent = component.find('#ct');
expect(cardNumberComponent.text()).toEqual(`CardNumber: 123456`);
expect(cardTypeComponent.text()).toEqual(`CardType: 123456`);
});
});
I dunno what's happening when the onBlur action is triggered (I know it's been triggered), but somehow, it doesn't trigger setCardType(); and thus, this is the error I get when running the tests:
What am I doing wrong? Been trying to debug this for the past couple of hours, and I'm sincerely clueless about what to do.
I think the call to .udpate()
recreates the node tree with all the updated data but doesn't automatically update references to nodes you get with find()
. So, the inputComponent
you have the moment you simulate the onBlur
event is the instance of the first render with an old version of the onBlur
handler with an empty value in cardNumber
state. You need to grab the input node again to get an updated instance before firing the onBlur
event.
...
let inputComponent = component.find("input");
const value = { target: { value: "123456" } };
await act(async () => {
inputComponent.props().onChange(value);
await component.update();
inputComponent = component.find("input");
inputComponent.props().onBlur();
await component.update();
});
...
https://codesandbox.io/s/input-onchange-onblur-enzyme-kdg0u?file=/src/MyComponent.test.tsx
I think this happens because you are calling .onChange()
and .onBlur()
in the same block of act()
. So both onChange
and onBlur
run with the closure on the same cardType
variable and only after that component re-renders with updated cardType
.
Try with splitting:
it('should set cardType when doing onBlur', async () => {
const component = shallow(<Test />);
const inputComponent = component.find('input');
const value = {target: {value: '123456'}};
await act(async () => {
inputComponent.props().onChange(value);
await component.update();
});
await act(async () => {
inputComponent.props().onBlur();
await component.update();
});
const cardNumberComponent = component.find('#cn');
const cardTypeComponent = component.find('#ct');
expect(cardNumberComponent.text()).toEqual(`CardNumber: 123456`);
expect(cardTypeComponent.text()).toEqual(`CardType: 123456`);
});
Also I'm not sure you really need await
for act()
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.