Simular un clic de botón en Jest

83

Simular el clic de un botón parece una operación muy fácil / estándar. Sin embargo, no puedo hacer que funcione en las pruebas de Jest.js.

Esto es lo que intenté (y también lo hice usando jQuery), pero no pareció desencadenar nada:

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
foobar
fuente
¿Cómo sabes que no hizo nada? ¿Qué está comprobando a continuación para ver si se produjo el clic del botón?
Toby
Buena pregunta. Espero que aparezca el campo de error: const field = pageMounted.find ('# notificación'); esperar (longitud de campo) .toBe (1);
foobar
Hrm. ¿Ha agregado console.warna la función que se ejecuta onClick para ver si se activa en la consola de Jest?
Toby
¿Podría agregar el código para el MyCoolPage componente? De lo contrario, es difícil averiguar cuál es el problema real.
Andreas Köberle
1
Gracias chicos por los consejos. Encontré mi problema gracias a tus preguntas. Básicamente hice una pequeña prueba con un botón simple y funcionó: MyCoolPage = (<button type = "submit" id = "cool_button" onClick = {() => {console.warn ('Me hicieron clic');}> Botón Cool </button>); Luego me di cuenta de que mi botón pertenecía al redux-form, por lo que no tenía onClick, sino onSubmit en su lugar, así que agregué button.simulate ('submit'); resuelto el problema. Gracias nuevamente por tus comentarios.
foobar

Respuestas:

134

# 1 Usando Jest

Así es como uso la función de devolución de llamada simulada de Jest para probar el evento 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);
  });
});

También estoy usando un módulo llamado enzima . Enzyme es una utilidad de prueba que facilita la afirmación y selección de sus componentes React

# 2 Usando Sinon

Además, puede usar otro módulo llamado Sinon, que es un espía de prueba independiente, stubs y simulacros para JavaScript. Así es como se ve:

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 Usando tu propio espía

Finalmente, puede crear su propio espía ingenuo (no recomiendo este enfoque a menos que tenga una razón válida para ello).

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);
});
Saman Shafigh
fuente
1
¡Gracias por una respuesta detallada Saman! Esto es muy útil cuando puede pasar el método onClick directamente al componente que está probando, y usaré su código como referencia para eso :). Creo que en mi ejemplo, aunque realmente no pude pasar onClick y tuve que confiar en otras pistas para saber que se hizo clic en el botón.
foobar
En la parte posterior de su primer ejemplo, ¿puede dar un ejemplo de cómo podemos escribir una prueba para una onChangefunción que valuecoincida con el valueatributo del elemento de entrada ? ¡Gracias!
blankface
7
Sin embargo, ¿qué prueba esto realmente?
Omortis
1
Tengo un botón que llama a mi handleClickmétodo cuando se hace clic en él. ¿Cómo pruebo que handleClickrealmente se llamó cuando se hace clic en el botón?
Jeremy Moritz
Si bien responde la pregunta de React, la mayor parte de esta respuesta está más relacionada con la burla que con la simulación de un clic en un botón.
Brady Dowling
19

Las soluciones en respuesta aceptada están siendo obsoletas

# 4 Llamar a prop directamente

Enzyme simulate se supone que se eliminará en la versión 4. El responsable principal sugiere que se invoquen directamente las funciones prop, que es lo que simulate hace internamente. Una solución es probar directamente que invocar esos accesorios hace lo correcto; o puede simular métodos de instancia, probar que las funciones prop los llaman y probar unitariamente los métodos de instancia.

Puede llamar a hacer clic, por ejemplo:

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

O

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

Información sobre la desactivación : desactivación de .simulate () # 2173

Negro
fuente
¿Qué respuesta anterior? ¿O es más de uno (¿cuáles?)
Peter Mortensen
@PeterMortensen He aclarado la respuesta. La respuesta aceptada es el uso de simulación de enzimas, que quedará obsoleto.
Negro
es posible que deba llamar wrapper.update()después de uno de estos, ya que es posible que la enzima no pueda notar que ocurrió un cambio.
Hinrich
12

Usando Jest, puede hacerlo así:

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();
});
Jackgisel
fuente
7
¿Cuál es el valor de crear un botón completo dentro de sus pruebas con una devolución de llamada simulada cuando se hace clic y luego se hace clic en ese botón en la prueba? Como la mayoría de los ejemplos de prueba que he visto, ni siquiera ha probado una sola línea de su código real cuando hace esto.
Jeremy Moritz
1
@JeremyMoritz es por eso que no entiendo el punto o la lógica en las pruebas unitarias.
user3808307
0

Puede usar algo como esto para llamar al controlador escrito al hacer clic:

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

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

// The below line will execute your click function
pageMounted.instance().yourOnClickFunction();
utkarsh
fuente
0

Además de las soluciones que se sugirieron en los comentarios de los hermanos, puede cambiar un poco su enfoque de prueba y probar no toda la página a la vez (con un árbol de componentes secundarios profundo), sino realizar una prueba de componentes aislada . Esto simplificará las pruebas deonClick() eventos similares (vea el ejemplo a continuación).

La idea es probar solo un componente a la vez y no todos juntos. En este caso, todos los componentes secundarios serán simulados usando la función jest.mock () .

A continuación se muestra un ejemplo de cómo onClick()se puede probar el evento en un SearchFormcomponente aislado usando 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);
  });
});
Oleksii Trekhleb
fuente
0

Necesitaba probar un poco el componente de un botón. Estas pruebas funcionan para mí ;-)

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);
    });
});
Hannibal B. Moulvad
fuente