Rory
Rory

Reputation: 1492

Enzyme / React Unit test

I have this React functional UI only component, which has two props passed in, the second being a function that is passed from its parent component. The onClick calls 'delegates' to a function in the parent container component, this parent method is then responsible for dispatching to a redux store.

import React, {Component} from 'react';
import PropTypes from 'prop-types';

const BotShowUI = ({ bot,  onClick  }) => {
    return(
        <div id={bot.id}  onClick={onClick}>
            {bot.id} : {bot.text}
        </div>
    )
}

BotShowUI.propTypes = {
   bot: PropTypes.object.isRequired,
   onClick: PropTypes.func.isRequired
};

export default BotShowUI;

My test spec is, which uses Jasmine

import React, {Component} from 'react';
import { mount } from 'enzyme';

import BotShowUI from '../botShowUI';

function onClickFunction(){};

describe('botShowUI', () =>  {

    const bot = {id: 1, isDone: false, text: 'bot 123'};
    const expectedDivText = '1 : bot 123';

    const wrapper = mount(<BotShowUI bot={bot} onClick={onClickFunction} />);

    it(' div has been rendered ', () => {
        expect(wrapper.find('div').first()).not.toBe(null);
    });

    it(' div displays the correct bot text ', () => {
        expect(wrapper.find('div').first().text()).toEqual(expectedDivText)
    });

    it(' div click event fired ', () => {
        wrapper.simulate('click');
        expect(wrapper.state('onClick')).toBe(true);
    });
});

This last assertion fails with

Chrome 57.0.2987 (Windows 10 0.0.0) botShowUI  div click event fired  FAILED
        TypeError: Cannot read property 'onClick' of null
            at ReactWrapper.state (webpack:///~/enzyme/build/ReactWrapper.js:825:24 <- tests.webpack.js:26303:25)
            at Object.<anonymous> (webpack:///app/react/components/bots/_tests/botShowUI.spec.js:25:23 <- tests.webpack.js:25415:25)

wrapper.simulate('click'); works, but the next line fails What is the correct way to assert that the click was fired ? Do I have to drop into wrapper's props/children instead of using state ?

I'm not trying to test the parent container in any way, the two are isolated. This test is only concerned with this UI component.

Upvotes: 0

Views: 493

Answers (2)

Rory
Rory

Reputation: 1492

Based on Abhishek's answer here's my solution for Jasmine

it(' div click event fired ', () => {

    let onClickFunction_spy = jasmine.createSpy('onClickFunction');
    const wrapper = mount(<BotShowUI bot={bot} onClick={onClickFunction_spy} />); 
    wrapper.simulate('click');
    expect(onClickFunction_spy).toHaveBeenCalled();
});

Hope this helps anyone.

Upvotes: 0

Abhishek Jain
Abhishek Jain

Reputation: 2977

First thing is that onClick isn't on state, but on props, so you will have to access it by doing wrapper.props('onClick').

Secondly, to test whether onClick has been handled or not is to use a spy, rather than an empty function. If you do not want to use spy, you can still do that, but not the way you have done. If you are interested, I can post some pseudo-code for that too. But coming back to using spies, you can use a spy as the onClick prop. Below is the code for that. I have hand-written it, so please check for any syntax error, but you should get the idea on what needs to be done.

it('should call the onClick handler on click', () => {
  const onClickFunction = sinon.spy()
  wrapper = mount(<BotShowUI bot={bot} onClick={onClickFunction} />)
  wrapper.simulate('click');
  expect(onClickFunction).toHaveBeenCalled();
})

Upvotes: 1

Related Questions