Checkbox is not `checked` after simulate `change` with enzyme

Freewind picture Freewind · Oct 6, 2016 · Viewed 16.8k times · Source

I tried to use enzyme to simulate change event on a checkbox, and use chai-enzyme to assert if it's been checked.

This is my Hello react component:

import React from 'react';

class Hello extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      checked: false
    }
  }

  render() {
    const {checked} = this.state;
    return <div>
      <input type="checkbox" defaultChecked={checked} onChange={this._toggle.bind(this)}/>
      {
        checked ? "checked" : "not checked"
      }
    </div>
  }

  _toggle() {
    const {onToggle} = this.props;
    this.setState({checked: !this.state.checked});
    onToggle();
  }
}

export default Hello;

And my test:

import React from "react";
import Hello from "../src/hello.jsx";
import chai from "chai";
import {mount} from "enzyme";
import chaiEnzyme from "chai-enzyme";
import jsdomGlobal from "jsdom-global";
import spies  from 'chai-spies';

function myAwesomeDebug(wrapper) {
  let html = wrapper.html();
  console.log(html);
  return html
}

jsdomGlobal();
chai.should();
chai.use(spies);
chai.use(chaiEnzyme(myAwesomeDebug));


describe('<Hello />', () => {

  it('checks the checkbox', () => {
    const onToggle = chai.spy();
    const wrapper = mount(<Hello onToggle={onToggle}/>);

    var checkbox = wrapper.find('input');
    checkbox.should.not.be.checked();
    checkbox.simulate('change', {target: {checked: true}});
    onToggle.should.have.been.called.once();

    console.log(checkbox.get(0).checked);
    checkbox.should.be.checked();
  });

});

When I run this test, the checkbox.get(0).checked is false, and the assertion checkbox.should.be.checked() reports error:

AssertionError: expected the node in <Hello /> to be checked <input type="checkbox" checked="checked">

You can see the message is quite strange since there is already checked="checked" in the output.

I'm not sure where is wrong, since it involves too many things.

You can also see a demo project here: https://github.com/js-demos/react-enzyme-simulate-checkbox-events-demo, notice these lines

Answer

rogeliog picture rogeliog · Dec 9, 2016

I think some of the details of my explanation might be a bit wrong, but my understanding is:

When you do

var checkbox = wrapper.find('input');

It saves a reference to that Enzyme node in checkbox, but there are times that when the Enzyme tree gets updated, but checkbox does not. I don't know if this is because the reference in the tree changes and therefore the checkbox is now a reference to a node in an old version of the tree.

Making checkbox a function seems to make it work for me, because now the value of checkbox() is always taken from the most up to date tree.

var checkbox = () => wrapper.find('input');
checkbox().should.not.be.checked();
checkbox().simulate('change', {target: {checked: true}});
///...