Klaha
Klaha

Reputation: 67

onBlur with useState hook not working in Jest?

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:

Console Error while Testing

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.

Upvotes: 1

Views: 712

Answers (1)

diedu
diedu

Reputation: 20785

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

Upvotes: 1

Related Questions