Установить состояние при тестировании функционального компонента с помощью хука useState()

Когда я тестировал компонент класса с ферментом, я мог сделать wrapper.setState({}), чтобы установить состояние. Как я могу сделать то же самое сейчас, когда я тестирую функциональный компонент с хуком useState()?

Например, в моем компоненте у меня есть:

const [mode, setMode] = useState("my value");

И я хочу изменить mode внутри своего теста

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
46
0
62 530
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

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

Вы можете найти отличный пример в этом Сообщение блога, написанном Кентом С. Доддсом.

Вот выдержка из него с примером кода.

Тест, основанный на деталях реализации состояния —

test('setOpenIndex sets the open index state properly', () => {
  const wrapper = mount(<Accordion items = {[]} />)
  expect(wrapper.state('openIndex')).toBe(0)
  wrapper.instance().setOpenIndex(1)
  expect(wrapper.state('openIndex')).toBe(1)
})

Тест, который не полагается на детали реализации состояния -

test('counter increments the count', () => {
  const {container} = render(<Counter />)
  const button = container.firstChild
  expect(button.textContent).toBe('0')
  fireEvent.click(button)
  expect(button.textContent).toBe('1')
})

О.. так что мы не можем проверить состояние, когда мы используем хуки

Anna 26.03.2019 08:59

Пока не напрямую. Мне трудно представить, как это было бы возможно из-за синтаксиса хуков, основанного на порядке вызова, а не на именовании. Я смотрю на это как на тестирование классов без доступа к приватным — приятно иметь доступ, но обычно это означает, что вы могли бы написать лучше :)

Moti Azu 26.03.2019 09:13

Хм, я думаю, это правда, что тесты на самом деле не должны полагаться на изменение состояния, а должны проверять внешний вид

Anna 26.03.2019 15:20

Внешний вид сложно проверить, но если у вас есть состояние, оно обычно передается дочернему компоненту в качестве свойства, и вы можете убедиться, что оно работает так, как вы ожидаете. Или даже имитировать вызов API с состоянием.

Moti Azu 26.03.2019 15:21

Так что я могу сказать, что знаменитый Кент С. Доддс действительно ошибается. Вот что бывает, когда много полагаешься на слова программистов, которые только и умеют твитить. Я работаю в IBM, и мы были обязаны протестировать хуки. Очевидно, что мы ДОЛЖНЫ тестировать функциональность, которая идет по крючкам, мы не можем игнорировать факты, что они существуют и являются критическими. Я следовал некоторым указаниям из этого поста blog.carbonfive.com/2019/08/05/…, а также скоро опубликую и отвечу здесь, чтобы вы знали, как ДЕЙСТВИТЕЛЬНО тестировать хуки, и это не так, как сказал Кент. Он просто неправ.

Reacting 06.03.2020 03:13

Второй тест так же хорош, как тест E2E, это не тест UNIT, где потребителем является разработчик, а не браузер.

Cristian E. 09.02.2021 17:40

Это способ, который я нашел для этого, я не говорю, что это правильно или неправильно. В моем случае блок кода зависел от состояния, установленного на определенное значение. Я оставлю свое мнение о тестировании в React при себе.

В вашем тестовом файле: Настройте свой импорт для библиотеки реагирования

import * as React from 'react'

Затем в вашем тесте следите за useState и издевайтесь над его реализацией.

const stateSetter = jest.fn()
jest
.spyOn(React, 'useState')
//Simulate that mode state value was set to 'new mode value'
.mockImplementation(stateValue => [stateValue='new mode value', stateSetter])

Имейте в виду, что насмешка над useState будет применяться ко всем экземплярам, ​​где useState вызывается для вашего теста, поэтому, если у вас есть более одного значения состояния, на которое вы смотрите, все они будут установлены на «значение нового режима». Кто-то еще может помочь вам разобраться в этом. Надеюсь, поможет.

как насчет случаев с 2 useState?

kuka 04.03.2021 16:03

В случаях с 2 или более useStates мы использовали mockImplementationOnce с некоторым успехом, но я предупреждаю вас, что это было некрасиво.

Doug Moses 13.03.2021 00:37

В верхней части тестового файла можно сначала определить как:

  import { useState } from 'react';

  jest.mock('react', () => ({
    ...jest.requireActual('react'),
    useState: jest.fn()
  }));

  const useStateMock: jest.Mock<typeof useState> = useState as never;

После этого в каждом тесте можно использовать разные значения, которые нужно протестировать:

  const setValue = jest.fn();
  useStateMock
    .mockImplementation(() => ['value', setValue]);

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