У меня есть компонент <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?





Вы в правильном направлении, просто упускаете пару вещей.
Во-первых, React Hooks может быть сложно протестировать, но на самом деле вы не используете хуки (по крайней мере, не в опубликованном вами коде), так что не беспокойтесь об этом :)
Во-вторых, в вашем тесте отсутствует оператор expect. Когда вы тестируете, вы хотите проверить, работает ли что-то, и вы используете для этого expect.
Итак, после этого фрагмента кода:
emailInput.simulate('change', {
target: {
value: email
}
});
У вас может быть что-то вроде:
expect(emailInput.value).toEqual(email);
Вы можете следовать примеру из документации Enzyme здесь.
Также вы можете ознакомиться с документацией expectздесь.
Думаю, я немного запутался. Во-первых, как проверить, что onChange не сработал без ожидания? Во-вторых, почему у вас модульный тест без expect? Извините, просто пытаюсь понять вашу ситуацию...
Да, я согласен, что это запутанно, я закончил тем, что добавил ожидание в проблему. Но пока не работает с вашим предложением.
Если вы попробуете expect(emailInput.value).toEqual(email); вместо expect(emailInput.props().value).toEqual(email); (удалить props()), сработает ли это? Что говорит ошибка? У него должно быть что-то вроде «Ожидается… Получено…», когда вы запускаете Jest.
Я уже тестирую предложенный код, но не работает. Во-первых, симуляция не запускает метод onChange. Я знаю это, потому что я добавил console.info в метод, и состояние не изменилось. Я когда-либо проводил другие подобные тесты с этим, и он работает, но не в этой ситуации, когда компонент не имеет onChange, но является свойством, а onChange находится во входном HTML-элементе внутри компонента.
Это становится длинным для обсуждения SO. Я напишу вам в Твиттере, чтобы мы могли поговорить и вернуться сюда, когда у нас будет лучший ответ.
Это не работает. Пожалуйста, прочитайте с большим вниманием мой тестовый код, я упомянул, что этот фрагмент кода не имитирует onChange. Я не знаю, почему мой компонент не имеет onChange, но это входные дочерние элементы, потому что, если я заменю свойство
changed = {}на onChange в<Input />, это сработает, но это неправильно. У меня есть знания о документации, спасибо за предложение. Отсутствие ожидания является преднамеренной моей целью, оно имитирует изменение.