Проверьте, что метод React prop был вызван с помощью Jest

У меня есть компонент ввода, который принимает метод prop и вызывает его, когда пользователь что-то вводит. Сам код работает так, как ожидалось, но по некоторым причинам тест не проходит. Он думает, что метод prop не был вызван. Почему это происходит? Для тестирования я использую Jest и react-testing-library.

И второй вопрос. В реальном приложении моя идея состоит в том, чтобы проверить параметры, которые были переданы этому методу prop. Считается ли это тестированием реализации (я знаю, что должен это проверить)?

Input.js

export default function Input({ onChange }) {
  return <input onChange={onChange} />;
}

Тестовое задание

import React from "react";
import { render, act, cleanup, fireEvent } from "react-testing-library";
import Input from "./input";

describe("Input tests", () => {
  afterEach(cleanup);

  it("Should call prop function", () => {
    const onChange = jest.fn();
    const { getByTestId } = render(<Input onChange={onChange} />);
    const input = getByTestId("input");

    act(() => {
      fireEvent.change(input, { target: { value: "Q" } });
    });

    expect(onChange).toHaveBeenCalled();
  });
});

https://codesandbox.io/s/y229669nvx


person th1rt3nth    schedule 02.03.2019    source источник
comment
Поскольку изменение означает, что состояние изменилось, если вы хотите инициировать изменение, как насчет прямого присвоения значения, например input.value = xxx?   -  person Nana Sun    schedule 02.03.2019


Ответы (2)


Прочитав это, похоже, что намеренно не возражает обработчики событий. Хотя кажется, что работает в React 16.5, однако использование 16.8.x не работает. Я бы посоветовал перейти на фермент, если вы хотите протестировать такие возможности.

Тестирование с react-testing-library завершается неудачно (однако, как вы заметите, при запуске теста входное значение фактически изменится): https://codesandbox.io/s/n3rvy891n4

Тестирование с enzyme успешно: https://codesandbox.io/s/lx34ny41nl

person Matt Carlotta    schedule 02.03.2019
comment
Большое спасибо за ответ! Я тоже начал думать о переходе на Enzyme, теперь думаю, что сделаю это :) - person th1rt3nth; 04.03.2019
comment
Если честно, это, наверное, лучший ход. react-testing-library, похоже, усложняет тестирование, заставляя вас искать по data attributes или text в element. В то время как enzyme предлагает поиск по id, className, text, prop, element, component ... и т. Д. - person Matt Carlotta; 04.03.2019
comment
Чтобы уточнить, data-testid считается последним средством, когда дело доходит до RTL. Предпочтительный способ найти элемент - это поиск текста, меток или других вещей, которые увидит пользователь. - person Giorgio Polvara - Gpx; 04.03.2019

Причина, по которой ваш тест не работает, заключается в том, что вы используете getByTestId, чтобы найти свой элемент. getByTestId ищет узел DOM с атрибутом data-testid.

Чтобы пройти тест, у вас есть несколько вариантов.

Вы можете добавить data-testid к вашему input: <input data-testid="input" onChange={onChange} />. Это сработает, однако лучше по возможности избегать тестовых идентификаторов.

В реальном приложении ваш ввод будет отображаться с label, мы можем воспользоваться этим:

const { getByLabelText } = render(
  <label>
    My input
    <Input onChange={onChange} />
  </label>
)
const input = getByLabelText('My input')

Другое решение - использовать container, которое является одним из значений, возвращаемых render. Это узел DOM, как и все остальное в RTL, поэтому вы можете использовать обычные API DOM:

const { container } = render(<Input onChange={onChange} />)
// Any of these would work
const input = container.firstChild
const input = container.querySelector('input')

В качестве примечания я согласен с тем, что тесты RTL кажутся более сложными по сравнению с Enzyme. Для этого есть веская причина. RTL подталкивает вас к тестированию вашего приложения, как если бы это был черный ящик. Вначале это немного сложнее, но в конечном итоге приводит к лучшим тестам.

Enzyme, с другой стороны, по умолчанию имитирует большинство вещей и позволяет вам взаимодействовать с реализацией ваших компонентов. По моему опыту, вначале это выглядит проще, но приведет к хрупким испытаниям.

Я призываю вас присоединиться к каналу спектра, если вам понадобится помощь в начале работы.

person Giorgio Polvara - Gpx    schedule 04.03.2019
comment
Спасибо за ответ! Как я уже писал в своем вопросе, есть проблема с утверждением expect(onChange).toHaveBeenCalled(). Я легко могу найти элемент ввода, могу редактировать его значение и видеть изменения в DOM. Но метод prop никогда не вызывается, согласно RTL. - person th1rt3nth; 04.03.2019
comment
Если я запустил ваш код и ящик, я вижу ошибку Unable to find an element by: [data-testid="input"]. Если я применю одно из предложенных мной изменений, оно будет работать нормально. - person Giorgio Polvara - Gpx; 04.03.2019
comment
Чтобы убедиться, мы говорим об этой песочнице: codeandbox.io/s/y229669nvx? Я только что открыл его снова и вижу эту ошибку: expect (jest.fn ()). ToHaveBeenCalled () Ожидаемая фиктивная функция должна быть вызвана. - person th1rt3nth; 04.03.2019
comment
Да, это песочница. Вы, вероятно, видите некоторые локальные изменения, которые вы еще не внесли. Я вижу ошибку Unable to find an element by: [data-testid="input"], что имеет смысл, если вы посмотрите на опубликованный вами код. - person Giorgio Polvara - Gpx; 04.03.2019
comment
@Gpx - я уже включил это в свой тест (в первой песочнице). Это все еще не удается. Как уже упоминалось, создатель заявляет, что не следует утверждать против обработчиков событий. - person Matt Carlotta; 04.03.2019
comment
Здесь что-то странное, я вижу другую ошибку, и изменение логики, чтобы найти ввод, исправляет тест для меня. Я запускаю песочницу в Chrome в приватном окне - person Giorgio Polvara - Gpx; 04.03.2019