Testing OnClick Event On React Component Using Jasmine
I have a React component that has buttons for which the onClick events are bound to functions passed as properties from the parent component, e.g. <Counter counter=0 incrementCounter={incrementFunction} decrementCounter={decrementFunction} />
.
I'm new to unit testing React components so I'm trying to check that the function gets called when clicking on the increment/decrement buttons. For this I'm using Jasmine's spyOn method, but it never seems to catch the function being called.
If I output a console.log in the function I'm using (e.g. let incrementCounter = () => { console.log("increment!"); };
) then I can tell the function is being called when I do TestUtils.Simulate.click(incrementButton);
, however the test still won't pass. What am I missing?
Counter.js
import React, { Component, PropTypes } from "react";
class Counter extends Component {
constructor(props) {
super(props);
}
render() {
const { incrementCounter, decrementCounter, counter } = this.props;
return (
<div>
<h1>Counter</h1>
<p>
<b>Counter: {counter} times</b>
{" "}
<button onClick={incrementCounter}>+</button>
{" "}
<button onClick={decrementCounter}>-</button>
</p>
</div>
);
}
}
Counter.propTypes = {
incrementCounter: PropTypes.func.isRequired,
decrementCounter: PropTypes.func.isRequired,
counter: PropTypes.number.isRequired
};
export default Counter;
Counter.test.js
import React from "react";
import TestUtils from "react/lib/ReactTestUtils";
import Counter from "./Counter"
describe("Counter", function () {
let renderedComponent = {};
let heading = {};
let decrementButton = {};
let incrementButton = {};
let incrementCounter = () => {};
let decrementCounter = () => {};
let counter = 0;
beforeEach(function(){
renderedComponent = TestUtils.renderIntoDocument(
<Counter incrementCounter={incrementCounter} decrementCounter={decrementCounter} counter={counter} />
);
heading = TestUtils.findRenderedDOMComponentWithTag(renderedComponent, "h1");
let buttons = TestUtils.scryRenderedDOMComponentsWithTag(renderedComponent, "button");
decrementButton = buttons[1];
incrementButton = buttons[0];
this.incrementCounter = incrementCounter;
});
it("renders without problems", function () {
expect(TestUtils.isDOMComponent(heading)).toBe(true);
expect(heading.innerText).toMatch(/Counter/g);
expect(TestUtils.isDOMComponent(decrementButton)).toBe(true);
expect(decrementButton.innerText).toMatch(/-/g);
expect(TestUtils.isDOMComponent(incrementButton)).toBe(true);
expect(incrementButton.innerText).toMatch(/\+/g);
});
it("fires the increment function", function() {
spyOn(this, "incrementCounter");
TestUtils.Simulate.click(incrementButton);
expect(this.incrementCounter).toHaveBeenCalled(); // Error: fuction doesn't get called
});
});
Answer
I'm not quite sure how Jasmine actually wraps functions with spyOn
, but try setting this.incrementCounter = incrementCounter
at the top of beforeEach
and use that directly in the component:
beforeEach(function(){
let that = this;
this.incrementCounter = incrementCounter;
renderedComponent = TestUtils.renderIntoDocument(
<Counter incrementCounter={that.incrementCounter} decrementCounter={decrementCounter} counter={counter} />
);
If that still doesn't work, because of a glitch with that
/this
, just declare incrementCounter
as a spy from the beginning:
let incrementCounter = jasmine.createSpy('incrementCounter')
and use that in <Counter />
and the rest of the test.
Related Questions
- → Can't test submit handler in React component
- → React components not works in RequireJS+Jasmine unit tests
- → How to unit test forms with Sinon and Chai
- → Laravel running tests as different users
- → Unexpected HTTP GET calls from within a custom Service unit test
- → What is the purpose of Redux Async Action Testing?
- → How do we mock fetch for Redux Async Actions?
- → How to mock Cache::remember in Laravel
- → How to solve Unable to locate factory with name [default] [AppModelsDomain]?
- → How to execute unit tests for octobercms/library
- → Mocha test suite errorring out when attempting to connect to API
- → How to spy on a method that receives function arguments?
- → Laravel5 Unit Testing a Login Form