Simulate a button click in Jest

前端 未结 6 500
太阳男子
太阳男子 2020-11-30 22:49

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 jQue

相关标签:
6条回答
  • 2020-11-30 23:06

    I needed to do a little bit of testing myself of a button component. These tests work 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);
        });
    });
    
    0 讨论(0)
  • 2020-11-30 23:07

    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();
    });
    
    0 讨论(0)
  • 2020-11-30 23:08

    Solutions in accepted answer are being deprecated

    #4 Calling prop directly

    Enzyme simulate is supposed to be removed in version 4. The main maintainer is suggesting directly invoking prop functions, which is what simulate does internally. 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: Deprecation of .simulate() #2173

    0 讨论(0)
  • 2020-11-30 23:18

    #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 spy, stubs and mocks for JavaScript. This is how it looks:

    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 (I don't recommend this approach unless you have a valid reason for that).

    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);
    });
    
    0 讨论(0)
  • 2020-11-30 23:19

    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 a 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 the jest.mock() function.

    Here is an example of how the onClick() event may be tested in an 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);
      });
    });
    
    0 讨论(0)
  • 2020-11-30 23:29

    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);
    
    // The below line will execute your click function
    pageMounted.instance().yourOnClickFunction();
    
    0 讨论(0)
提交回复
热议问题