Когда я тестировал компонент класса с ферментом, я мог сделать wrapper.setState({}), чтобы установить состояние. Как я могу сделать то же самое сейчас, когда я тестирую функциональный компонент с хуком useState()?
Например, в моем компоненте у меня есть:
const [mode, setMode] = useState("my value");
И я хочу изменить mode внутри своего теста





При использовании состояния из хуков ваш тест должен игнорировать детали реализации, такие как состояние, чтобы правильно протестировать его. Вы по-прежнему можете убедиться, что компонент передает правильное состояние своим дочерним элементам.
Вы можете найти отличный пример в этом Сообщение блога, написанном Кентом С. Доддсом.
Вот выдержка из него с примером кода.
Тест, основанный на деталях реализации состояния —
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')
})
Пока не напрямую. Мне трудно представить, как это было бы возможно из-за синтаксиса хуков, основанного на порядке вызова, а не на именовании. Я смотрю на это как на тестирование классов без доступа к приватным — приятно иметь доступ, но обычно это означает, что вы могли бы написать лучше :)
Хм, я думаю, это правда, что тесты на самом деле не должны полагаться на изменение состояния, а должны проверять внешний вид
Внешний вид сложно проверить, но если у вас есть состояние, оно обычно передается дочернему компоненту в качестве свойства, и вы можете убедиться, что оно работает так, как вы ожидаете. Или даже имитировать вызов API с состоянием.
Так что я могу сказать, что знаменитый Кент С. Доддс действительно ошибается. Вот что бывает, когда много полагаешься на слова программистов, которые только и умеют твитить. Я работаю в IBM, и мы были обязаны протестировать хуки. Очевидно, что мы ДОЛЖНЫ тестировать функциональность, которая идет по крючкам, мы не можем игнорировать факты, что они существуют и являются критическими. Я следовал некоторым указаниям из этого поста blog.carbonfive.com/2019/08/05/…, а также скоро опубликую и отвечу здесь, чтобы вы знали, как ДЕЙСТВИТЕЛЬНО тестировать хуки, и это не так, как сказал Кент. Он просто неправ.
Второй тест так же хорош, как тест E2E, это не тест UNIT, где потребителем является разработчик, а не браузер.
Это способ, который я нашел для этого, я не говорю, что это правильно или неправильно. В моем случае блок кода зависел от состояния, установленного на определенное значение. Я оставлю свое мнение о тестировании в 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?
В случаях с 2 или более useStates мы использовали mockImplementationOnce с некоторым успехом, но я предупреждаю вас, что это было некрасиво.
В верхней части тестового файла можно сначала определить как:
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]);
О.. так что мы не можем проверить состояние, когда мы используем хуки