129 votes

Simuler un clic sur un bouton en Jest

Simuler un clic sur un bouton semble être une opération très facile/standard. Pourtant, je n'arrive pas à la faire fonctionner dans les tests Jest.js.

C'est ce que j'ai essayé (et je l'ai également fait en utilisant jquery), mais cela ne semble pas déclencher quoi que ce soit :

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

0 votes

Comment savez-vous que ça n'a rien fait ? Que vérifiez-vous ensuite pour savoir si le bouton a été cliqué ?

1 votes

Bonne question. Je m'attends à ce que le champ d'erreur apparaisse : const field = pageMounted.find('#notification') ; expect(field.length).toBe(1) ;

0 votes

Hrm. Avez-vous ajouté un console.warn à la fonction qui exécute onClick pour voir si elle se déclenche dans la console Jest ?

175voto

Saman Shafigh Points 1573

#1 Utilisation de Jest

Voici comment j'utilise la fonction de rappel de jest mock pour tester l'événement de clic.

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);
  });
});

J'utilise également un module appelé enzyme Enzyme est un utilitaire de test qui facilite l'évaluation et la sélection de vos composants React.

#2 Utilisation de Sinon

Vous pouvez également utiliser un autre module appelé sinon qui est un test autonome de spies, stubs et mocks pour JavaScript. Voici à quoi il ressemble

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 Utiliser votre propre espion

Vous pouvez enfin faire votre propre espion naïf

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);
});

2 votes

Merci pour cette réponse détaillée, Saman ! C'est très utile lorsque vous pouvez passer la méthode onClick directement dans le composant que vous testez, et je vais utiliser votre code comme référence pour cela :). Je pense que dans mon exemple, je ne pouvais pas vraiment passer la méthode onClick et je devais me fier à d'autres indices pour savoir que le bouton avait été cliqué.

0 votes

Sur la base de votre premier exemple, pouvez-vous donner un exemple de la manière dont nous pouvons écrire un test pour une onChange dont la fonction value correspond à l'élément d'entrée value attribut ? Merci !

14 votes

Mais qu'est-ce que cela teste réellement ?

13voto

Jackgisel Points 57

En utilisant jest, vous pouvez le faire comme ceci :

test('should call 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();
});

17 votes

Quel est l'intérêt de créer un bouton complet dans vos tests avec un callback simulé lorsqu'il est cliqué, puis de cliquer sur ce bouton dans le test ? Comme la plupart des exemples de tests que j'ai vus, vous n'avez même pas testé une seule ligne de votre code réel lorsque vous faites cela.

5 votes

@JeremyMoritz c'est pourquoi je ne comprends pas l'intérêt ou la logique des tests unitaires.

1voto

utkarsh Points 53

Vous pouvez utiliser quelque chose comme ceci pour appeler le gestionnaire écrit sur le clic :

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

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

1voto

Oleksii Trekhleb Points 385

En plus des solutions suggérées dans les commentaires des frères et sœurs, vous pouvez changer votre approche de l'évaluation un peu et ne pas tester toute la page en une seule fois (avec l'arbre des composants des enfants profonds) mais faire une isolé le test des composants. Cela simplifiera les tests de onClick() et autres événements similaires (voir exemple ci-dessous).

L'idée est de tester uniquement un à la fois et pas tous d'eux ensemble. Dans ce cas, tous les composants enfants seront simulés à l'aide des éléments suivants jest.mock() fonction.

Voici un exemple de la façon dont onClick() peut être testé dans des cas isolés SearchForm en utilisant Jest y 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);
  });
});

1voto

J'avais besoin de tester un peu moi-même un composant de bouton. Ces tests fonctionnent pour moi ;-)

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);
    });
});

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X