Jest에서 버튼 클릭 시뮬레이션


83

버튼 클릭을 시뮬레이션하는 것은 매우 쉽고 표준적인 작업처럼 보입니다. 그러나 Jest.js 테스트에서는 작동하지 않습니다.

이것은 내가 시도한 것입니다 (또한 jQuery를 사용하여 수행합니다).하지만 아무것도 트리거하지 않는 것 같습니다.

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

아무것도하지 않았다는 것을 어떻게 알 수 있습니까? 버튼 클릭이 발생했는지 확인하기 위해 다음에 무엇을 확인하고 있습니까?
Toby

좋은 질문. 오류 필드가 나타날 것으로 예상합니다. const field = pageMounted.find ( '# notification'); expect (field.length) .toBe (1);
foobar

흠. console.warnonClick을 실행하는 함수에 를 추가 하여 Jest 콘솔에서 실행되는지 확인 했습니까?
Toby

MyCoolPage 구성 요소 에 대한 코드를 추가해 주시겠습니까? 그렇지 않으면 실제 문제가 무엇인지 파악하기 어렵습니다.
Andreas Köberle

1
팁 주셔서 감사합니다. 귀하의 질문 덕분에 내 문제를 발견했습니다. 기본적으로 간단한 버튼으로 작은 테스트를했는데 제대로 작동했습니다. MyCoolPage = (<button type = "submit"id = "cool_button"onClick = {() => {console.warn ( 'I was clicked');}> 멋진 버튼 </ button>); 그런 다음 내 버튼이 redux-form에 속하므로 onClick이 없었고 대신 onSubmit이 있으므로 button.simulate ( 'submit'); 문제를 해결했습니다. 피드백에 다시 한번 감사드립니다!
foobar

답변:


134

# 1 Jest 사용

다음은 Jest 모의 콜백 함수를 사용하여 클릭 이벤트를 테스트하는 방법입니다.

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

나는 또한 효소 라는 모듈을 사용하고 있습니다. Enzyme은 React 컴포넌트를보다 쉽게 ​​주장하고 선택할 수있게 해주는 테스트 유틸리티입니다.

# 2 Sinon 사용

또한 독립 실행 형 테스트 스파이, JavaScript 용 스텁 및 모의 인 Sinon 이라는 다른 모듈을 사용할 수 있습니다 . 이것이 어떻게 보이는지 :

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 자신의 스파이 사용

마지막으로 자신 만의 순진한 스파이를 만들 수 있습니다 (유효한 이유가없는 한이 접근 방식을 권장하지 않습니다).

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

1
자세한 답변 감사합니다 Saman! 이것은 테스트중인 구성 요소에 onClick 메서드를 직접 전달할 수있을 때 매우 유용하며, 이에 대한 참조로 코드를 사용할 것입니다. :). 내 예제에서는 실제로 onClick을 전달할 수없고 버튼이 클릭되었음을 알기 위해 다른 단서에 의존해야한다고 생각합니다.
foobar

첫 번째 예제의 뒷면 에서 입력 요소의 속성 과 일치 하는 onChange함수에 대한 테스트를 작성하는 방법에 대한 예제를 제공 할 수 있습니까? 감사! valuevalue
blankface

7
이것은 실제로 무엇을 테스트합니까?
Omortis

1
handleClick클릭하면 내 메서드 를 호출하는 버튼이 있습니다. handleClick버튼을 클릭했을 때 실제로 호출 된 것을 어떻게 테스트 합니까?
Jeremy Moritz 19

React에 대한 질문에 대답하지만이 대답의 대부분은 버튼 클릭을 시뮬레이션하는 것보다 조롱과 더 관련이 있습니다.
Brady Dowling

19

수락 된 답변의 솔루션은 더 이상 사용되지 않습니다.

# 4 직접 prop 호출

Enzyme 시뮬레이션은 버전 4에서 제거되어야합니다. 메인 메인테이너는 시뮬레이션이 내부적으로 수행하는 prop 함수를 직접 호출하는 것을 제안합니다. 한 가지 해결책은 이러한 props를 호출하는 것이 옳은 일을하는지 직접 테스트하는 것입니다. 또는 인스턴스 메서드를 모의하고, prop 함수가 호출하는지 테스트하고, 인스턴스 메서드를 단위 테스트 할 수 있습니다.

클릭을 호출 할 수 있습니다. 예를 들면 다음과 같습니다.

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

또는

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

지원 중단에 대한 정보 : .simulate () 지원 중단 # 2173


이전 답변은 무엇입니까? 아니면 둘 이상입니까 (어떤 것입니까?)?
Peter Mortensen

@PeterMortensen 나는 대답을 명확히했습니다. 허용되는 대답은 더 이상 사용되지 않을 효소 시뮬레이션을 사용하는 것입니다.
검은 색

wrapper.update()효소가 변화가 일어난 것을 알아 차리지 못할 수 있으므로 이들 중 하나 를 호출해야 할 수도 있습니다 .
Hinrich

onClick소품 이없는 버튼 은 어떻습니까? type="submit"내 버튼과 같은 <form />? 예 onSubmit, 양식을 요청할 수 있습니다. 그러나 이것은 이상적이지 않습니다. 사용자가 버튼을 클릭하면 테스트 할 것입니다.
Oli

12

Jest를 사용하면 다음과 같이 할 수 있습니다.

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

7
클릭했을 때 모의 콜백을 사용하여 테스트 내에서 완전한 버튼을 생성 한 다음 테스트에서 해당 버튼을 클릭하면 어떤 가치가 있습니까? 내가 본 대부분의 테스트 예제와 마찬가지로이 작업을 수행 할 때 실제 코드 한 줄도 테스트하지 않았습니다.
Jeremy Moritz

1
@JeremyMoritz 그래서 단위 테스트의 요점이나 논리를 이해하지 못합니다.
user3808307

0

클릭시 작성된 핸들러를 호출하려면 다음과 같이 사용할 수 있습니다.

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

형제 의견에서 제안 된 솔루션 외에도 테스트 접근 방식 을 약간 변경 하고 전체 페이지를 한 번에 테스트하지 않고 (깊은 하위 구성 요소 트리 사용) 격리 된 구성 요소 테스트를 수행 할 수 있습니다. 이렇게하면 onClick()및 유사한 이벤트의 테스트가 간단 해집니다 (아래 예 참조).

아이디어는 한 번에 하나의 구성 요소 만 테스트 하고 모든 구성 요소를 함께 테스트하는 것이 아닙니다 . 이 경우 모든 자식 구성 요소는 jest.mock () 함수를 사용하여 모의 처리 됩니다.

다음은 Jestreact-test-renderer를 사용하여 onClick()격리 된 SearchForm구성 요소 에서 이벤트를 테스트 하는 방법의 예입니다 .

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

버튼 컴포넌트에 대해 약간의 테스트가 필요했습니다. 이 테스트는 나를 위해 작동합니다 ;-)

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);
    });
});
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.