Simulate a button click in Jest

Simulating a button click seems like a very easy/standard operation. Yet, I can't get it to work in Jest.js tests.

This is what I tried (and also doing it using jquery), but it didn't seem to trigger anything:

import { mount } from 'enzyme';

page = <MyCoolPage />;
pageMounted = mount(page);

const button = pageMounted.find('#some_button');
expect(button.length).toBe(1); // it finds it alright
button.simulate('click'); // nothing happens

Answers


#1 Using Jest

This is how I use the jest mock callback function to test the click event

import React from 'react';
import { shallow } from 'enzyme';
import Button from './Button';

describe('Test Button component', () => {
  it('Test click event', () => {
    const mockCallBack = jest.fn();

    const button = shallow((<Button onClick={mockCallBack}>Ok!</Button>));
    button.find('button').simulate('click');
    expect(mockCallBack.mock.calls.length).toEqual(1);
  });
});

I am also using a module called enzyme Enzyme is a testing utility that makes it easier to assert and select your React Components

#2 Using Sinon

Also you can use another module called sinon which is a standalone test spies, stubs and mocks for JavaScript. This is how does it look

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

import Button from './Button';

describe('Test Button component', () => {
  it('simulates click events', () => {
    const mockCallBack = sinon.spy();
    const button = shallow((<Button onClick={mockCallBack}>Ok!</Button>));

    button.find('button').simulate('click');
    expect(mockCallBack).toHaveProperty('callCount', 1);
  });
});

#3 Using Your own Spy

Finally you can make your own naive spy

function MySpy() {
  this.calls = 0;
}
MySpy.prototype.fn = function () {
  return () => this.calls++;
}

it('Test Button component', () => {
  const mySpy = new MySpy();
  const mockCallBack = mySpy.fn();

  const button = shallow((<Button onClick={mockCallBack}>Ok!</Button>));

  button.find('button').simulate('click');
  expect(mySpy.calls).toEqual(1);
});

Using jest you can do it like this:

test('it calls start logout on button click', () => {
    const mockLogout = jest.fn();
    const wrapper = shallow(<Component startLogout={mockLogout}/>);
    wrapper.find('button').at(0).simulate('click');
    expect(mockLogout).toHaveBeenCalled();
});

Enzyme simulate is supposed to be removed in version 4. Main maintainer is suggesting directly invoking prop functions. One solution is to directly test that invoking those props does the right thing; or you can mock out instance methods, test that the prop functions call them, and unit test the instance methods.

You could call click for example

wrapper.find('Button').prop('onClick')() 

or

wrapper.find('Button').props().onClick() 

Information about deprecation: https://github.com/airbnb/enzyme/issues/2173


You may use something like this to call the handler written on click:

import { shallow } from 'enzyme'; // mount is not required

page = <MyCoolPage />;
pageMounted = shallow(page);
// below line will execute your click function
pageMounted.instance().yourOnClickFunction();

Additionally to the solutions that were suggested in sibling comments you may change your testing approach a little bit and test not the whole page all at once (with deep children components tree) but do an isolated component testing. This will simplify testing of onClick() and similar events (see example below).

The idea is to test only one component at a time and not all of them together. In this case all children components will be mocked using jest.mock() function.

Here is an example of how onClick() event may be tested in isolated SearchForm component using Jest and react-test-renderer.

import React from 'react';
import renderer from 'react-test-renderer';
import { SearchForm } from '../SearchForm';

describe('SearchForm', () => {
  it('should fire onSubmit form callback', () => {
    // Mock search form parameters.
    const searchQuery = 'kittens';
    const onSubmit = jest.fn();

    // Create test component instance.
    const testComponentInstance = renderer.create((
      <SearchForm query={searchQuery} onSearchSubmit={onSubmit} />
    )).root;

    // Try to find submit button inside the form.
    const submitButtonInstance = testComponentInstance.findByProps({
      type: 'submit',
    });
    expect(submitButtonInstance).toBeDefined();

    // Since we're not going to test the button component itself
    // we may just simulate its onClick event manually.
    const eventMock = { preventDefault: jest.fn() };
    submitButtonInstance.props.onClick(eventMock);

    expect(onSubmit).toHaveBeenCalledTimes(1);
    expect(onSubmit).toHaveBeenCalledWith(searchQuery);
  });
});

I needed to do a little bit of testing myself of a button component. These tests works for me ;-)

import { shallow } from "enzyme";
import * as React from "react";
import Button from "../button.component";

describe("Button Component Tests", () => {
    it("Renders correctly in DOM", () => {
        shallow(
            <Button text="Test" />
        );
    });
    it("Expects to find button HTML element in the DOM", () => {
        const wrapper = shallow(<Button text="test"/>)
        expect(wrapper.find('button')).toHaveLength(1);
    });

    it("Expects to find button HTML element with className test in the DOM", () => {
        const wrapper = shallow(<Button className="test" text="test"/>)
        expect(wrapper.find('button.test')).toHaveLength(1);
    });

    it("Expects to run onClick function when button is pressed in the DOM", () => {
        const mockCallBackClick = jest.fn();
        const wrapper = shallow(<Button onClick={mockCallBackClick} className="test" text="test"/>);
        wrapper.find('button').simulate('click');
        expect(mockCallBackClick.mock.calls.length).toEqual(1);
    });
});

Need Your Help

Strange errors in Apple's Reachability files

objective-c ios

I'm trying to work with reachability in my project. I added Reachability.h and Reachability.m files. But after building project xCode shows me strange errors:

Combine stored procedure and query in T-SQL

sql sql-server tsql stored-procedures dml

How do I combine executing of a stored procedure and using its result or parameters in a regular SQL query?