简体   繁体   English

带有 useState 钩子的 onBlur 在 Jest 中不起作用?

[英]onBlur with useState hook not working in Jest?

I'm new into testing code with react and jest;我是用 react 和 jest 测试代码的新手; and jest is having a strange behavior towards hooks.和 jest 对钩子有一种奇怪的行为。

This is my component.这是我的组件。 It has 2 useState hooks, linked to 2 functions.它有 2 个 useState 钩子,链接到 2 个函数。

  • HandleChange will be triggered with onChange, and set the cardNumber with setCardNumber(). HandleChange 将通过 onChange 触发,并使用 setCardNumber() 设置 cardNumber。
  • HandleBlur will be triggered with onBlur, and set the cardType with setCardType(). HandleBlur 将使用 onBlur 触发,并使用 setCardType() 设置 cardType。

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();我不知道触发 onBlur 操作时发生了什么(我知道它已被触发),但不知何故,它不会触发 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() .我认为对.udpate()的调用使用所有更新的数据重新创建节点树,但不会自动更新对使用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.因此,当您模拟onBlur事件时,您拥有的inputComponent是第一次渲染的实例,使用旧版本的onBlur处理程序,并且cardNumber状态为空值。 You need to grab the input node again to get an updated instance before firing the onBlur event.在触发onBlur事件之前,您需要再次抓取输入节点以获取更新的实例。

    ...
    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 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() .我认为这是因为您在同一块act()中调用.onChange().onBlur() 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 .所以onChangeonBlur都在同一个cardType变量上使用闭包运行,并且只有在该组件使用更新的cardType重新渲染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() .另外,我不确定您是否真的需要await act()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM