首页 > 解决方案 > prevState 在 Enzyme 测试中未定义,但在组件中定义

问题描述

看到一个奇怪的问题,其中prevState未定义componentDidUpdate,但在组件在浏览器中运行时定义。

我在构造函数中设置了状态,并且在 componentDidUpdate 中检查了 on 的值prevState

  componentDidUpdate(prevProps, prevState) {
    const { showForm } = this.state;

    if (prevState.showForm && !showForm) {
      return this.input.current.focus();
    }

  }

这是酶测试:

 it("should call focus on input if form was shown, and now form is open", () => {
    component = mount(<Component {...props} />);
    const prevProps = component.props();
    const prevState = {
      ...component.state(),
      showForm: true
    };
    const focusSpy = sinon.spy(component.instance().input.current, "focus");
    component.instance().componentDidUpdate(prevProps, prevState);
    expect(focusSpy).to.have.been.called;
  });

这种方法有效 - 但只是因为我componentDidUpdate从酶测试中调用并通过了它prevState。理想情况下,我想避免这种情况——并且只定义 prevState——因为它是组件在浏览器中实际工作的时候。

处理这个的模式是什么?

标签: javascriptreactjsenzyme

解决方案


您的测试不应componentDidUpdate显式调用。setState下面是一个组件和测试,我已经验证了它只是多次调用来触发要测试的场景。

MyComp.js

import React from "react";

class MyComp extends React.PureComponent {
  constructor(props) {
    super(props);
    this.state = { showForm: false };
    this.input = React.createRef();
  }
  toggleShowForm = () => {
    this.setState({ showForm: !this.state.showForm });
  };
  componentDidUpdate(prevProps, prevState) {
    console.log(
      "componentDidUpdate prevProps: " +
        JSON.stringify(prevProps) +
        "; prevState: " +
        JSON.stringify(prevState) +
        "; this.state: " +
        JSON.stringify(this.state)
    );
    if (prevState.showForm && !this.state.showForm) {
      console.log("setting focus");
      this.input.current.focus();
    }
  }

  render() {
    return (
      <>
        <input type="text" ref={this.input} />
        <br />
        <button onClick={this.toggleShowForm}>Toggle showForm</button>
      </>
    );
  }
}

export default MyComp;

MyComp.test.js

import React from "react";
import { mount } from "enzyme";
import MyComp from "./MyComp";
import sinon from "sinon";

it("should call focus on input if showForm goes from true to false", () => {
  const myCompWrapper = mount(<MyComp />);
  console.log("before first setState");
  const focusSpy = sinon.spy(myCompWrapper.instance().input.current, "focus");
  myCompWrapper.instance().setState({ showForm: true });
  expect(focusSpy.called).toEqual(false);
  console.log("before second setState");
  myCompWrapper.instance().setState({ showForm: false });
  expect(focusSpy.called).toEqual(true);
});

以下是此测试产生的控制台日志:

  • 在第一次 setState 之前
  • componentDidUpdate prevProps: {}; prevState: {"showForm":false}; this.state: {"showForm":true}
  • 在第二个 setState 之前
  • componentDidUpdate prevProps: {}; prevState: {"showForm":true}; this.state: {"showForm":false}
  • 设置焦点

这是一个 CodeSandbox,您可以在其中执行此测试:

编辑 xvpo9y47pp


推荐阅读