Как выполнить модульное тестирование метода doStuff
, описанного ниже, без необходимости создания полноценного объекта React.ChangeEvent
?
// my-form.tsx
export const doStuff = (changeHandler: ChangeHandler, e: React.ChangeEvent<HTMLInputElement>) => {
// A call to another function takes place here, but for brevity, I'm using console.log
console.log(e);
changeHandler(e);
}
interface ChangeHandler {
(e: React.ChangeEvent<HTMLInputElement>): void;
}
interface MyFormProps {
changeHandler: ChangeHandler,
username: string;
password: string;
}
const MyForm: React.SFC<MyFormProps> = ({changeHandler, username, password}) => (
<form>
<div>
<label htmlFor="username">Username</label>
<input
type="text"
name="username"
value={username}
onChange={doStuff.bind(null, changeHandler)} />
</div>
<div>
<label htmlFor="password">Password</label>
<input
type="text"
name="password"
value={password}
onChange={doStuff.bind(null, changeHandler)} />
</div>
<button>Submit</button>
</form>
);
export default MyForm;
Ниже мой тестовый файл. Первый тест - это то, что я хотел бы сделать, чтобы проверить doStuff
. Я полагаю, что второй тест - это то, как я могу также протестировать doStuff
.
// my-form.test.tsx
import MyForm, { doStuff } from './my-form.tsx';
describe('MyForm' => {
it('should call the changeHandler', () => {
// Arrange
const changeHandlerMock = jest.fn();
// Act
// How can I pass a mock for the 2nd parameter?
// doStuff(changeHandlerMock, {});
// Assert
expect(changeHandlerMock.called.length).toEqual(1);
});
it('should call the changeHandler too', () => {
// Arrange
const changeHandlerMock = jest.fn();
// Act
const wrapper = shallow(
<MyForm
changeHandler={changeHandlerMock}
username={username}
password={password} />
);
wrapper.find(`input[name='username']`).simulate('change');
// Assert
expect(changeHandlerMock.called.length).toEqual(1);
})
});
Кроме того, я могу избавиться от doStuff
и изменить разметку для каждого элемента ввода на:
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
console.log(e);
changeHandler(e);
}} />
Недостатком является то, что если мне нужно внести изменения в eventHandler, мне придется делать это в каждом объявленном месте, отсюда и метод doStuff
.
Для полноты, вот мой контейнерный компонент:
interface MyFormContainerState {
username: string;
password: string;
}
// my-form-container.tsx
class MyFormContainer extends React.Component<{}, MyFormContainerState> {
constructor(props: {}) {
super(props);
this.state = {
username: '',
password: ''
};
}
public render() {
const { username, password } = this.state;
return (
<MyForm
changeHandler={this.changeHandler}
username={username}
password={password} />
);
}
public changeHandler = (e: React.ChangeEvent<HTMLInputElement>): void => {
this.setState({
...this.state,
[e.currentTarget.name]: e.currentTarget.value
});
}
}