如何在不创建完整的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
});
}
}