Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 343
Freewind Avatar asked Oct 06 '16 09:10

Freewind


2 Answers

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}});
///...
like image 152
rogeliog Avatar answered Oct 23 '22 12:10

rogeliog


It is not bug, but "it works as designed".

Enzyme underlying uses the react test utils to interact with react, especially with the simulate api.

Simulate doesn't actually update the dom, it merely triggers react event handlers attached to the component, possibly with the additional parameters you pass in.

According to the answer I got here (https://github.com/facebook/react/issues/4950 ) this is because updating the dom would require React to reimplement a lot of the browsers functionality, probably still resulting in unforeseen behaviours, so they decided to simply rely on the browser to do the update.

The only way to actually test this is to manually update the dom yourself and then call the simulate api.

like image 9
mastrolindus Avatar answered Oct 23 '22 13:10

mastrolindus