我对Jest和一般测试都比较新。我有一个带有输入元素的组件:
import * as React from "react";
export interface inputProps{
placeholder: string;
className: string;
value: string;
onSearch: (depID: string) => void;
}
onSearch(event: any){
event.preventDefault();
//the actual onclick event is in another Component
this.props.onSearch(event.target.value.trim());
}
export class InputBox extends React.Component<inputProps, searchState> {
render() {
return (
<input
onChange={this.onSearch} //need to test this
className={this.props.className}
type="text"
value={this.props.value}
placeholder={this.props.placeholder} />
);
}
}
我想要一个测试来检查输入元素的onChange
是否是一个以输入元素的value
属性作为参数的函数。到目前为止我已经走了多远:
//test to see the input element's onchange
//returns a function that takes its value as a param
it("onChange param is the same value as the input value", () => {
const mockFn = jest.fn();
const input = enzyme.shallow(<InputBox
value="TestVal"
placeholder=""
className=""
onSearch={mockFn}/>);
input.find('input').simulate('change', { preventDefault() {} });
expect(mockFn.mock.calls).toBe("TestVal");
});
我将在这里找到第一个解决方案Simulate a button click in Jest 并且:https://facebook.github.io/jest/docs/en/mock-functions.html
编辑:运行上述操作会引发以下错误:
TypeError: Cannot read property 'value' of undefined
答案 0 :(得分:16)
我认为代码片段上的语法应该是:
preventDefault
测试失败,因为同样在事件对象上定义onSearch
函数,您还必须定义it('should call onChange prop', () => {
const onSearchMock = jest.fn();
const event = {
preventDefault() {},
target: { value: 'the-value' }
};
const component = enzyme.shallow(<InputBox onSearch={onSearchMock} />);
component.find('input').simulate('change', event);
expect(onSearchMock).toBeCalledWith('the-value');
});
函数上使用的其他属性。
onSearch
以前的测试代码需要定义事件形状,因为您使用的是浅层渲染。如果您想要测试enzyme.mount
函数上使用的实际输入值,则需要尝试使用it('should call onChange prop with input value', () => {
const onSearchMock = jest.fn();
const component = enzyme.mount(<InputBox onSearch={onSearchMock} value="custom value" />);
component.find('input').simulate('change');
expect(onSearchMock).toBeCalledWith('custom value');
});
进行完整渲染:
footer { margin: 0 0 -50px 0;}
答案 1 :(得分:4)
对于使用TypeScript(并从以上答案中借用)的测试,您需要执行类型强制(as React.ChangeEvent<HTMLInputElement>
),以确保短绒可以将签名视为兼容:
反应文件
export class InputBox extends React.Component<inputProps, searchState> {
onSearch(event: React.ChangeEvent<HTMLInputElement>){
event.preventDefault();
//the actual onclick event is in another Component
this.props.onSearch(event.target.value.trim());
}
render() {
return (
<input
onChange={this.onSearch} //need to test this
className={this.props.className}
type="text"
value={this.props.value}
placeholder={this.props.placeholder} />
);
}
}
测试文件
it('should call onChange prop', () => {
const onSearchMock = jest.fn();
const event = {
target: { value: 'the-value' }
} as React.ChangeEvent<HTMLInputElement>;
const component = enzyme.shallow(<InputBox onSearch={onSearchMock} />);
component.find('input').simulate('change', event);
expect(onSearchMock).toBeCalledWith('the-value');
});
或者
it('should call onChange prop', () => {
const onSearchMock = jest.fn();
const event = {
target: { value: 'the-value' }
} as React.ChangeEvent<HTMLInputElement>;
const component = enzyme.mount<InputBox>(<InputBox onSearch={onSearchMock} />);
const instance = component.instance();
instance.onSearch(event);
expect(onSearchMock).toBeCalledWith('the-value');
});
答案 2 :(得分:2)
我找到了解决方案。
因此,我们不得不传递InputBox
内的值,而是将其传递到simulate
的第二个参数中,如下所示。然后我们只是检查第一次调用mockFn
的第一个arg是否相等。此外,我们可以摆脱event.preventDefault()
;
it("onChange param is the same value as the input element's value property", () => {
const mockFn = jest.fn();
const input = enzyme.shallow(<InputBox
value=""
placeholder=""
className=""
onSearch={mockFn}/>);
input.find('input').simulate('change', {target: {value: 'matched'} });
expect(mockFn.mock.calls[0][0]).toBe('matched');
});
答案 3 :(得分:0)
这个怎么样?我使用酶模拟变化事件并执行快照测试。 组件
import React, { FunctionComponent, useState } from 'react';
const Index: FunctionComponent = () => {
const [val, setVal] = useState('');
const onInputChange = e => {
e.preventDefault();
setVal(e.target.value);
};
return (
<input type='text' onChange={onInputChange} value={val} />
);
};
export default Index;
单元测试
describe('Index with enzyme', () => {
it('Should set value to state when input is changed', () => {
const container = shallow(<Index />);
const input = container.find('input');
input.simulate('change', { preventDefault: jest.fn, target: { value: "foo" } });
expect(container).toMatchSnapshot();
});
});
快照
exports[`Index with enzyme Should set value to state when input is changed 1`] = `
<input
onChange={[Function]}
type="text"
value="foo"
/>
`;
答案 4 :(得分:0)
我为此挣扎了几个小时。另外,因为我在一页上有多个选择字段。我发现 Textfield 解决方案的工作方式与文档中给出的 Select.test 不同。
在代码中,我用 id 定义了 SelectProps。 (你也可以用data-testid)
我只能通过单击此字段来触发下拉菜单。
<TextField
select
variant = "outlined"
value = { input.value || Number(0) }
onChange = { value => input.onChange(value) }
error = { Boolean(meta.touched && meta.error) }
open = { open }
SelectProps = {
{
id: `${input.name}-select`,
MenuProps: {
anchorOrigin: {
vertical: "bottom",
horizontal: "left"
},
transformOrigin: {
vertical: "top",
horizontal: "left"
},
getContentAnchorEl: null
}
}
}
{ ...props} >
//yourOptions Goes here
</TextField>
在我的测试中。
const pickUpAddress = document.getElementById("address-select");
UserEvent.click(pickUpAddress);
UserEvent.click(screen.getByTestId("address-select-option-0"));
之后的工作就像一个魅力。希望这会有所帮助。