prevState не определен в тесте фермента, но определен в компоненте - PullRequest
0 голосов
/ 15 января 2019

Наблюдается странная проблема, когда prevState не определено в componentDidUpdate, но определяется, когда компонент запускается в браузере.

Я устанавливаю состояние в конструкторе, и в componentDidUpdate происходит проверка значения на 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 - как это происходит, когда компонент фактически работает в браузере.

Каковы схемы обращения с этим?

Ответы [ 2 ]

0 голосов
/ 16 января 2019

Я предпочитаю полностью избавиться от метода экземпляра. С предложением Some Edit в RYANS, чтобы вы могли сравнить

it("should call focus on input if form was shown, and now form is open", () => {
    component = mount(<Component {...props} />);
    // Since you want your prevState.formOpen to be true, first get it in that state
    // This will trigger a re-render and componentDidUpdate, 
    // but you don't care about this execution of componentDidUpdate 
    // (though you could verify that "focus" does NOT get called in this case)
    component.setState({formOpen: true});
    // Then set up your spy

    expect(wrapper.find('input:focus').exists()).to.false;
    // You do this by changing the state and letting React do its thing
    // which will include React calling componentDidUpdate -- you should not
    // call it yourself.
    component.setState({formOpen: false});
    expect(wrapper.find('input:focus').exists()).to.true;
});
0 голосов
/ 15 января 2019

Ваш тест не должен вызывать 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, где вы можете выполнить этот тест:

Edit xvpo9y47pp

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...