Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React test; how to mock componentDidMount or overwrite it?

I'm trying to test a react component.

var Component = React.createClass({

  componentDidMount: function () {

    return this.setState({
      name: 'blabla'
    });
  },

  render: function () {

    return (
      <h1>{this.state.name}</h1>
    );
  }
});

Is there a way, during testing, to mock what componentDidMount returns or does? That would leave me to test it on it's own and just test the component render behaviour.

Thanks!

like image 709
Besart Hoxhaj Avatar asked Aug 10 '15 16:08

Besart Hoxhaj


People also ask

Which comes first componentDidMount or render?

The componentDidMount() method is called after the component is rendered. This is where you run statements that requires that the component is already placed in the DOM.

How do I update my componentDidMount state?

componentDidMount() invokes immediately after a component mounts. You can call setState() immediately in componentDidMount() and triggers an extra rendering, but this happens before the browser updates the screen, calling render() twice.

When should I use componentDidMount and componentDidUpdate?

The componentDidUpdate()is called after componentDidMount() and can be useful to perform some action when the state of the component changes. Parameters: Following are the parameter used in this function: prevProps: Previous props passed to the component. prevState: Previous state of the component.

How do you avoid React componentDidMount being called multiple times?

React components call componentDidMount only once by default. You can run the component multiple times if you delete the component or change the props or state.


2 Answers

I prefer the following approach, but requires using ES6 classes.

// component.jsx
class Component extends React.Component {
    componentDidMount() { return this.setState({name: 'blabla'}); }
    render() { return (<h1>{this.state.name}</h1>); }
}

//component-spec.jsx
describe('Component', () => {
    it('does stuff', () => {
        let ComponentTest = class extends Component {
            componentDidMount() { 
                // your override here
            }
        };
        let component = TestUtils.renderIntoDocument(<ComponentTest />);
        //expect(component...).toEqual(...)
    });
});

The point is to create an on demand ChildClass inheriting the OriginalClass, do whatever overrides and then TestUtils.renderIntoDocument(<ChildClass />)

like image 147
Catalin Enache Avatar answered Oct 05 '22 23:10

Catalin Enache


The idea here, if I understand correctly, is that you're trying to stub out a function before a component is rendered in your test. In your case, componentWillMount is only called once in a component's lifecycle, immediately before the component is rendered. So you can't just render the component and then stub out the function, it must be done before the render occurs.

Let's take these components for example:

parent.js

var Child = require('./child.js');
var Parent = React.createClass({
    render : function () {
        return (
            <div className="parent">
                <Child/>
            </div>
        );
    }
});
module.exports = Parent;

child.js

var Child = React.createClass({
    test : function () {
        return true;
    },
    render : function () {
        if (this.test) {
            throw('boom');
        }
        return (
            <div className="child">
                Child
            </div>
        );
    }
});
module.exports = Child;

Here, we would want to stub out the test function before our Child component is rendered, otherwise, it will blow up.

I have been able to do this using jasmine-react. These helper functions provide some useful functionality when running tests, almost to the point where TestUtils can be ditched completely.

jasmineReact.render(component, [container]) will render an instance of component into the DOM node specified in [container]. This is like TestUtils.renderIntoDocument(), except it renders the component into an attached DOM node instead of a detached DOM node. It will also perform the necessary cleaning operations when the test is finished.

jasmineReact.spyOnClass(componentClass, functionName) will stub out a particular function belonging to a component class. This behavior is maintained until the end of the test, which means that you can call this function before a component is rendered. This, if I understand correctly, is what you're looking for.

So, using these two helper functions, I can write a test for the code shown above that looks something like this:

var React = require('react/addons'),
    Parent = require('./parent.js'),
    Child = require('./child.js'),
    jasmineReact = require('jasmine-react-helpers');

describe('Parent', function () {
    it('does not blow up when rendering', function () {
        jasmineReact.spyOnClass(Child, 'test').and.returnValue(false);
        var parentInstance = jasmineReact.render(<Parent/>, document.body); //does not blow up
        expect(parentInstance).toBeTruthy(); //passes
    });
});

Let me know if you have any questions.

like image 25
Michael Parker Avatar answered Oct 06 '22 01:10

Michael Parker