Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock functions, and test that they're called, when passed as props in react components?

I'm following the example from this stackoverflow answer - Test a React Component function with Jest. I have an example component and test set up. The component works correctly when loaded into App.js.

Component -

import React, { PropTypes, Component } from 'react';

export default class ExampleModule extends Component {
  static propTypes = {
    onAction: PropTypes.func,
  }

  static defaultProps = {
  onAction: () => { console.log("In onAction"); }
}

doAction = () => {
  // do something else
  console.log('In do action');
  this.props.onAction();
}

render() {
  return(
    <div>
      <button className='action-btn' onClick=  {this.doAction.bind(this)}>Do action</button>
    </div>
  )
}
}

And here's the test -

import React from 'react';
import ReactDOM from 'react-dom';
import TestUtils from 'react-addons-test-utils';
import ExampleComponent from './ExampleModule.js';

let Example;

describe('Example component', function() {
  beforeEach(function() {
    Example = TestUtils.renderIntoDocument(<ExampleComponent />);
  })

  it('calls props functions', function() {
    Example.doAction = jest.genMockFunction();
    let actionBtn = TestUtils.findRenderedDOMComponentWithClass(Example, 'action-btn');
    TestUtils.Simulate.click(actionBtn);
    expect(Example.doAction).toBeCalled();
  })

  it('doAction calls onAction', function() {
    expect(Example.props.onAction).not.toBeCalled();
    Example.doAction();
    expect(Example.props.onAction).toBeCalled();
  })
})

However, I get the following error -

FAIL  src/App/components/Example/ExampleModule.test.js
  Console

    console.log src/App/components/Example/ExampleModule.js:14
      In do action
    console.log src/App/components/Example/ExampleModule.js:24
      In onAction

  Example component › calls props functions

    Expected the mock function to be called.

      at Object.<anonymous> (src/App/components/Example/ExampleModule.test.js:17:30)
      at process._tickCallback (node.js:369:9)

  Example component › doAction calls onAction

    toBeCalled matcher can only be used on a spy or mock function.

      at Object.<anonymous> (src/App/components/Example/ExampleModule.test.js:21:40)
      at process._tickCallback (node.js:369:9)

I can see the console.logs in the doAction and onAction are being called even when I want to mock out doAction. Also, I'm unable to mock out onAction. I get this error -

TypeError: Cannot assign to read only property 'onAction' of #<Object>

I've tried jest.fn() but got the same errors.

How do I mock these functions and test them?

EDIT:

I was able to mock doAction by using jest.fn() in the following way -

let mockFn = jest.fn();
Example.doAction = mockFn()

However, I'm still unable to mock Example.props.onAction.

like image 366
Madhu Avatar asked Sep 05 '16 01:09

Madhu


1 Answers

In your test when you render document, you need to pass a mock function which you can later watch if it was being called, something like this -

let onActionMock = jest.fn();

beforeAll(function() {
  Example = TestUtils.renderIntoDocument(<ExampleComponent onAction={onActionMock}/>);
});

beforeEach(function() {
  onActionMock.mockClear();
});

it('doAction calls onAction', () => {
  Example.doAction();
  expect(onActionMock).toBeCalled();
});

You can further test the function with what it has been called with -

expect(onActionMock).toBeCalledWith('Some argument');

Hope this helps.

like image 105
grgmo Avatar answered Oct 15 '22 04:10

grgmo