Как протестировать onChange в React?

У меня есть компонент <Input />, и мне нужно протестировать метод обработчика onChange, но метод имитации не работает, и когда я проверяю свойство изменения, его состояние не меняется.

Ниже показано, как я использую компонент <Input />:

...
let formFields = formElementsArray.map(formElement => (
        <Input
            key = {formElement.id}
            elementType = {formElement.config.elementType}
            elementConfig = {formElement.config.elementConfig}
            value = {formElement.config.value}
            invalid = {!formElement.config.valid}
            shouldValidate = {formElement.config.validation}
            touched = {formElement.config.touched}
            changed = {(event) => inputChangeHandler(event, formElement.id)} />
    ))
...

Ниже мой компонент <Input />:

import React from 'react';

import styles from './Input.module.css';

const input = (props) => {
    let inputElement = null;
    const inputClasses = [styles.InputElement];

    if (props.invalid && props.shouldValidate && props.touched) {
        inputClasses.push(styles.Invalid);
    }

    switch (props.elementType) {
        case ('input'):
            inputElement = <input
                className = {inputClasses.join(' ')}
                {...props.elementConfig}
                value = {props.value}
                onChange = {props.changed} />;
            break;
        case ('textarea'):
            inputElement = <textarea
                className = {inputClasses.join(' ')}
                {...props.elementConfig}
                value = {props.value}
                onChange = {props.changed} />;
            break;
        case ('select'):
            inputElement = <select
                className = {inputClasses.join(' ')}
                {...props.elementConfig}
                value = {props.value}
                onChange = {props.changed}>
                {props.elementConfig.options.map(option => (
                    <option
                        key = {option.value}
                        value = {option.value}>{option.displayValue}</option>
                ))}
            </select>;
            break;
        default:
            inputElement = <input
                className = {inputClasses.join(' ')}
                {...props.elementConfig}
                value = {props.value}
                onChange = {props.changed} />;
    }

    return (
        <div className = {styles.Input}>
            {props.label && <label className = {styles.Label}>{props.label}</label>}
            {inputElement}
        </div>
    )
};

export default input;

Ниже показано, как я тестирую onChange:

import React from 'react';
import { Redirect } from 'react-router-dom';
import thunk from 'redux-thunk';

import { configure, shallow } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import configureStore from 'redux-mock-store';

import { Auth } from './Auth';
import Spinner from '../../components/UI/Spinner/Spinner';
import Button from '../../components/UI/Button/Button';
import Input from '../../components/UI/Input/Input';

configure({ adapter: new Adapter() });

const setup = () => {
    const props = {
        onAuth: jest.fn()
    }

    const enzymeWrapper = shallow(<Auth {...props} />);

    return {
        enzymeWrapper,
        props
    }
}

describe('<Auth />', () => {

    it('should create user when form is submitted', () => {
        const { enzymeWrapper: wrapper, props: reduxProps } = setup();
        const form = wrapper.find('form');
        const inputs = form.find(Input);
        const emailInput = inputs.at(0);
        const passwordInput = inputs.at(1);
        const email = "[email protected]";
        const password = "senha";

        // below the onChange doesn't works
        emailInput.simulate('change', {
            target: {
                value: email
            }
        });
        passwordInput.simulate('change', {
            target: {
                value: password
            }
        });
        // below the onChange doesn't works
        emailInput.find('input').simulate('change', {
            target: {
                value: email
            }
        });
        passwordInput.find('input').simulate('change', {
            target: {
                value: password
            }
        });
        // below the onChange works, but state doesn't change
        emailInput.props().changed({
            target: {
                value: email
            }
        }, 0);
        passwordInput.props().changed({
            target: {
                value: password
            }
        }, 1);

        expect(emailInput.props().value).toEqual(email);
        expect(passwordInput.props().value).toEqual(password);
    });
});

Мои рассуждения верны? Как проверить onChange?

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

Ответы 1

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

Вы в правильном направлении, просто упускаете пару вещей.

Во-первых, React Hooks может быть сложно протестировать, но на самом деле вы не используете хуки (по крайней мере, не в опубликованном вами коде), так что не беспокойтесь об этом :)

Во-вторых, в вашем тесте отсутствует оператор expect. Когда вы тестируете, вы хотите проверить, работает ли что-то, и вы используете для этого expect.

Итак, после этого фрагмента кода:

emailInput.simulate('change', {
    target: {
        value: email
    }
});

У вас может быть что-то вроде:

expect(emailInput.value).toEqual(email);

Вы можете следовать примеру из документации Enzyme здесь.

Также вы можете ознакомиться с документацией expectздесь.

Это не работает. Пожалуйста, прочитайте с большим вниманием мой тестовый код, я упомянул, что этот фрагмент кода не имитирует onChange. Я не знаю, почему мой компонент не имеет onChange, но это входные дочерние элементы, потому что, если я заменю свойство changed = {} на onChange в <Input />, это сработает, но это неправильно. У меня есть знания о документации, спасибо за предложение. Отсутствие ожидания является преднамеренной моей целью, оно имитирует изменение.

Allan Duarte 21.05.2019 00:27

Думаю, я немного запутался. Во-первых, как проверить, что onChange не сработал без ожидания? Во-вторых, почему у вас модульный тест без expect? Извините, просто пытаюсь понять вашу ситуацию...

Bruno Monteiro 21.05.2019 00:36

Да, я согласен, что это запутанно, я закончил тем, что добавил ожидание в проблему. Но пока не работает с вашим предложением.

Allan Duarte 21.05.2019 00:50

Если вы попробуете expect(emailInput.value).toEqual(email); вместо expect(emailInput.props().value).toEqual(email); (удалить props()), сработает ли это? Что говорит ошибка? У него должно быть что-то вроде «Ожидается… Получено…», когда вы запускаете Jest.

Bruno Monteiro 21.05.2019 00:55

Я уже тестирую предложенный код, но не работает. Во-первых, симуляция не запускает метод onChange. Я знаю это, потому что я добавил console.info в метод, и состояние не изменилось. Я когда-либо проводил другие подобные тесты с этим, и он работает, но не в этой ситуации, когда компонент не имеет onChange, но является свойством, а onChange находится во входном HTML-элементе внутри компонента.

Allan Duarte 21.05.2019 01:02

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

Bruno Monteiro 21.05.2019 01:33

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