Simulieren Sie einen Schaltflächenklick in Jest

83

Das Simulieren eines Schaltflächenklicks scheint eine sehr einfache / Standardoperation zu sein. In Jest.js Tests kann ich es jedoch nicht zum Laufen bringen.

Dies habe ich versucht (und auch mit jQuery), aber es schien nichts auszulösen:

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
quelle
Woher weißt du, dass es nichts getan hat? Was überprüfen Sie als nächstes, um festzustellen, ob der Klick auf die Schaltfläche aufgetreten ist?
Toby
Gute Frage. Ich erwarte, dass das Fehlerfeld angezeigt wird: const field = pageMounted.find ('# Benachrichtigung'); erwarten (Feldlänge) .toBe (1);
Foobar
Hrm. Haben Sie console.warnder Funktion, die onClick ausführt, eine hinzugefügt , um festzustellen, ob sie in der Jest-Konsole ausgelöst wird?
Toby
Könnten Sie bitte den Code für die MyCoolPage Komponente hinzufügen , sonst ist es schwierig herauszufinden, was das eigentliche Problem ist.
Andreas Köberle
1
Danke Jungs für die Tipps. Ich habe mein Problem dank Ihrer Fragen gefunden. Ich habe im Grunde einen kleinen Test mit einer einfachen Schaltfläche durchgeführt und es hat funktioniert: MyCoolPage = (<button type = "submit" id = "cool_button" onClick = {() => {console.warn ('Ich wurde angeklickt');}> Cool Button </ button>); Dann wurde mir klar, dass mein Button zum Redux-Formular gehört, also nicht onClick, sondern onSubmit, also button.simulate ('submit') hinzufügen; löste das Problem. Nochmals vielen Dank für Ihr Feedback!
Foobar

Antworten:

134

# 1 Mit Scherz

So verwende ich die Jest-Mock-Callback-Funktion, um das Klickereignis zu testen:

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

Ich benutze auch ein Modul namens Enzym . Enzyme ist ein Testdienstprogramm, mit dem Sie Ihre Reaktionskomponenten leichter bestätigen und auswählen können

# 2 Verwenden von Sinon

Sie können auch ein anderes Modul namens Sinon verwenden, das ein eigenständiger Testspion, Stubs und Mocks für JavaScript ist. So sieht es aus:

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 Verwenden Sie Ihren eigenen Spion

Schließlich können Sie Ihren eigenen naiven Spion machen (ich empfehle diesen Ansatz nur, wenn Sie einen gültigen Grund dafür haben).

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
quelle
1
Vielen Dank für eine ausführliche Antwort Saman! Dies ist sehr nützlich, wenn Sie die onClick-Methode direkt an die zu testende Komponente übergeben können, und ich werde Ihren Code als Referenz dafür verwenden :). Ich denke in meinem Beispiel, obwohl ich Click nicht wirklich weitergeben konnte und ich mich auf andere Hinweise verlassen musste, um zu wissen, dass auf die Schaltfläche geklickt wurde.
Foobar
Können Sie auf der Rückseite Ihres ersten Beispiels ein Beispiel geben, wie wir einen Test für eine onChangeFunktion schreiben können, valuedie mit dem valueAttribut des Eingabeelements übereinstimmt ? Vielen Dank!
blankface
7
Was testet das eigentlich?
Omortis
1
Ich habe eine Schaltfläche, die meine handleClickMethode aufruft , wenn ich darauf klicke. Wie teste ich das, handleClickwas tatsächlich aufgerufen wurde, als auf die Schaltfläche geklickt wurde?
Jeremy Moritz
Während die Frage nach React beantwortet wird, bezieht sich der größte Teil dieser Antwort eher auf das Verspotten als auf die Simulation eines Schaltflächenklicks.
Brady Dowling
19

Lösungen in akzeptierten Antworten werden nicht mehr unterstützt

# 4 Prop direkt anrufen

Das Enzymsimulat soll in Version 4 entfernt werden. Der Hauptbetreuer schlägt vor, Prop-Funktionen direkt aufzurufen, was das Simulieren intern tut. Eine Lösung besteht darin, direkt zu testen, ob das Aufrufen dieser Requisiten das Richtige ist. Oder Sie können Instanzmethoden verspotten, testen, ob die Prop-Funktionen sie aufrufen, und die Instanzmethoden einem Komponententest unterziehen.

Sie können zum Beispiel click aufrufen:

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

Oder

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

Informationen zur Verfall : Verfall von .simulate () # 2173

Schwarz
quelle
Welche vorherige Antwort? Oder ist es mehr als eine (welche?)?
Peter Mortensen
@ PeterMortensen Ich habe die Antwort geklärt. Akzeptierte Antwort ist die Verwendung von Enzymsimulaten, die veraltet sein werden.
Schwarzer
Möglicherweise müssen Sie wrapper.update()nach einem dieser Punkte anrufen , da das Enzym möglicherweise nicht bemerken kann, dass eine Änderung stattgefunden hat.
Hinrich
12

Mit Jest können Sie dies folgendermaßen tun:

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
quelle
7
Welchen Wert hat es, eine vollständige Schaltfläche in Ihren Tests mit einem verspotteten Rückruf zu erstellen, wenn Sie darauf klicken und dann im Test auf diese Schaltfläche klicken? Wie die meisten Testbeispiele, die ich gesehen habe, haben Sie dabei nicht einmal eine einzige Zeile Ihres tatsächlichen Codes getestet.
Jeremy Moritz
1
@JeremyMoritz, deshalb verstehe ich den Punkt oder die Logik bei Unit-Tests nicht.
user3808307
0

Sie können so etwas verwenden, um den auf Klick geschriebenen Handler aufzurufen:

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
quelle
0

Zusätzlich zu den Lösungen, die in Geschwisterkommentaren vorgeschlagen wurden, können Sie Ihren Testansatz ein wenig ändern und nicht die gesamte Seite auf einmal testen (mit einem tiefen untergeordneten Komponentenbaum), sondern einen isolierten Komponententest durchführen. Dies vereinfacht das Testen onClick()und ähnliche Ereignisse (siehe Beispiel unten).

Die Idee ist, jeweils nur eine Komponente zu testen und nicht alle zusammen. In diesem Fall werden alle untergeordneten Komponenten mit der Funktion jest.mock () verspottet .

Hier ist ein Beispiel, wie das onClick()Ereignis in einer isolierten SearchFormKomponente mit Jest und React-Test-Renderer getestet werden kann .

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
quelle
0

Ich musste mich ein wenig an einer Tastenkomponente testen. Diese Tests funktionieren bei mir ;-)

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
quelle