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

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

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

Input.js

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

Test

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

Поскольку изменение означает, что его состояние изменилось, если вы хотите инициировать изменение, как насчет прямого присвоения значения, такого как input.value = "xxx"?

Nana Sun 02.03.2019 18:09
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
2
1
8 148
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

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

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

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

Большое спасибо за ответ! Начал подумывать перейти и на Enzyme, теперь думаю так и сделаю :)

th1rt3nth 03.03.2019 22:13

Честно говоря, это, вероятно, лучший ход. react-testing-library, кажется, усложняет тестирование, заставляя вас искать по data attributes или по text внутри element. В то время как enzyme предлагает поиск по id, className, text, prop, element, component и т. д.

Matt Carlotta 03.03.2019 23:57

Просто чтобы уточнить, data-testid считается последним средством, когда дело доходит до RTL. Предпочтительный способ найти элемент — искать текст, метки или другие вещи, которые увидит пользователь.

Giorgio Polvara - Gpx 04.03.2019 10:29

Причина, по которой ваш тест не работает, заключается в том, что вы используете 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, с другой стороны, имитирует большинство вещей по умолчанию и позволяет вам взаимодействовать с реализацией ваших компонентов. По моему опыту, поначалу это выглядит проще, но может привести к хрупким испытаниям.

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

Спасибо за ответ! Как я уже писал в своем вопросе, есть проблема с утверждением expect(onChange).toHaveBeenCalled(). Я могу легко найти элемент ввода, я могу отредактировать его значение и увидеть изменения в DOM. Но, согласно RTL, метод prop никогда не вызывается.

th1rt3nth 04.03.2019 10:30

Если я запускаю ваши коды и коробку, я вижу ошибку Unable to find an element by: [data-testid = "input"]. Если я применю одно из предложенных мной изменений, оно будет работать нормально.

Giorgio Polvara - Gpx 04.03.2019 11:28

Просто чтобы убедиться, мы говорим об этой песочнице: codeandbox.io/s/y229669nvx? Я только что снова открыл его и вижу эту ошибку: expect(jest.fn()).toHaveBeenCalled() Ожидается, что будет вызвана фиктивная функция.

th1rt3nth 04.03.2019 12:46

Да, это песочница. Вероятно, вы видите какие-то локальные изменения, которые вы еще не запустили. Ошибка, которую я вижу, это Unable to find an element by: [data-testid = "input"], что имеет смысл, если вы посмотрите на код, который вы разместили.

Giorgio Polvara - Gpx 04.03.2019 16:18

@Gpx - я уже включил это в свой тест (в первую песочницу). Это все еще терпит неудачу. Как уже упоминалось, создатель заявляет, что не следует возражать против обработчиков событий.

Matt Carlotta 04.03.2019 16:28

Здесь что-то странное, я вижу другую ошибку, и изменение логики для поиска ввода исправляет тест для меня. Я запускаю песочницу в Chrome в приватном окне

Giorgio Polvara - Gpx 04.03.2019 17:19

Другие вопросы по теме