Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enzyme/Mocha: How to test a react component function by firing an onChange event from a child component

I'm using enzyme/mocha to test my react component.

I have a parent component which I am testing.

let wrapper = mount(<Parent />);

and this parent has a child component in it's render function

render: function() {
    <Child onChange={this.foo} />
},
foo: function() {
    console.log("I was called");
}

I would like the child's onChange function to fire so that I can test my parents foo function.

So far, I have found no way to do this - I've read about sinon and stubbing but that's mostly about intercepting functions and not firing them.

The following test

shallow(<Parent />).instance().foo();

is a weak test because it doesn't test the line of code connecting my child and parent, and in case I haven't written a unit test for my child, it doesn't test the child's onChange functionality either. IMHO - If breaking up my components to parents/children means less testability - then something is wrong with this framework

Any help will be appreciated, thanks

like image 583
NiRR Avatar asked Oct 25 '25 12:10

NiRR


1 Answers

This is something that I do in a lot of my tests. The method that I've found that works best for me is to manually invoke the child component's onChange handler, and make your assertions based on the behavior you expect to happen as a result.

So let's say you have a Parent component that looks like this:

import React from 'react';
import Child from './child';

export default class extends React.Component {
    render() {
        return (
            <div>
                <Child onChange={this.foo} />
            </div>
        );
    }

    foo() {
        console.log('bar');
    }
}

The onChange prop passed to child will log the string 'bar' when invoked. This is the behavior we want to test. To do this, we'll need to take the following steps:

  1. Stub console.log using your mocking library of choice (I'll be using Sinon for this example)

  2. Create a shallow instance of the Parent component, and obtain a reference to its Child.

  3. Manually invoke the Child's onChange prop.

  4. Assert that console.log was called once, and with a single argument: 'bar'

And here is how I would do that (using mocha and chai):

import Foo from './foo';

import React from 'react';
import {shallow} from 'enzyme';

import sinon from 'sinon';
import sinonChai from 'sinon-chai';
import chai, {expect} from 'chai';

describe('Foo', () => {
    let renderedElement;

    function renderComponent() {
        const componentElement = React.createElement(Foo);

        renderedElement = shallow(componentElement);
    }

    before(() => {
        chai.use(sinonChai);
    });

    it('should log the string "bar" when the child component is changed', () => {
        //step 1
        sinon.stub(console, 'log');

        //step 2
        renderComponent();
        const childComponent = renderedElement.props().children;

        //step 3
        childComponent.props.onChange();

        //step 4
        expect(console.log).to.have.callCount(1);
        expect(console.log).to.be.calledWith('bar');

        //clean up
        console.log.restore();
    });
});

The reason I like this approach is because it's testing component behavior as opposed to simply testing that it was passed a function as a prop that happens to be equal to another function.

like image 111
Michael Parker Avatar answered Oct 28 '25 04:10

Michael Parker



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!