May*_*ate 11 typescript reactjs jestjs material-ui react-testing-library
我正在尝试使用打字稿中的react-testing-library创建带有样式的Material-UI组件的测试。我发现很难访问组件的内部功能以进行模拟和断言。
Form.tsx
export const styles = ({ palette, spacing }: Theme) => createStyles({
root: {
flexGrow: 1,
},
paper: {
padding: spacing.unit * 2,
margin: spacing.unit * 2,
textAlign: 'center',
color: palette.text.secondary,
},
button: {
margin: spacing.unit * 2,
}
});
interface Props extends WithStyles<typeof styles> { };
export class ExampleForm extends Component<Props, State> {
async handleSubmit(event: React.FormEvent<HTMLFormElement>) {
// Handle form Submit
...
if (errors) {
window.alert('Some Error occurred');
return;
}
}
// render the form
}
export default withStyles(styles)(ExampleForm);
Run Code Online (Sandbox Code Playgroud)
测试文件
import FormWithStyles from './Form';
it('alerts on submit click', async () => {
jest.spyOn(window,'alert').mockImplementation(()=>{});
const spy = jest.spyOn(ActivityCreateStyles,'handleSubmit');
const { getByText, getByTestId } = render(<FormWithStyles />)
fireEvent.click(getByText('Submit'));
expect(spy).toHaveBeenCalledTimes(1);
expect(window.alert).toHaveBeenCalledTimes(1);
})
Run Code Online (Sandbox Code Playgroud)
jest.spyOn引发以下错误,Argument of type '"handleSubmit"' is not assignable to parameter of type 'never'.ts(2345)可能是因为ExampleForm封装在withStyles中。
我也尝试直接导入ExampleForm组件并手动分配样式,但无法这样做:
import {ExampleForm, styles} from './Form';
it('alerts on submit click', async () => {
...
const { getByText, getByTestId } = render(<ActivityCreateForm classes={styles({palette,spacing})} />)
...
}
Run Code Online (Sandbox Code Playgroud)
出现以下错误: Type '{ palette: any; spacing: any; }' is missing the following properties from type 'Theme': shape, breakpoints, direction, mixins, and 4 more.ts(2345)
由于强大的类型和包装的组件,我发现很难用Typescript为Material-UI具有react-testing-library&的组件编写基本测试Jest。请指导。
首先,当您使用react-testing-library 的render方法时,您无需担心使用或任何包装器,因为最后它会呈现组件,因为它可能在真实的 dom 中,因此您可以正常编写测试。withStyles
然后,据我所知,您正在做与我开始测试时所做的相同的事情(这意味着您将变得擅长;)。您正在尝试模拟内部方法,这不是最好的方法,因为您需要做的是测试真正的方法。
所以让我们想象一下我们有一个Register用户组件。
源代码/注册.tsx
import ... more cool things
import * as api from './api';
const Register = () => {
const [name, setName] = useState('');
const handleNameChange = (event) => {
setName(event.target.value);
};
const handleSubmit = (event) => {
event.preventDefault();
if (name) {
api.registerUser({ name });
}
};
return (
<form onSubmit={handleSubmit}>
<TextField
id='name'
name='name'
label='Name'
fullWidth
value={name}
onChange={handleNameChange}
/>
<Button data-testid='button' fullWidth type='submit' variant='contained'>
Save
</Button>
</form>
);
}
Run Code Online (Sandbox Code Playgroud)
该组件非常简单,它是一个带有输入和按钮的表单。我们react hooks用于更改输入值,并基于在触发事件api.registerUser时调用与否handleSubmit。
要测试组件,我们需要做的第一件事就是模拟 api.registerUser方法。
src/__tests__/Register.tsx
import * as api from '../api'
jest.mock('../api')
api.registerUser = jest.fn()
Run Code Online (Sandbox Code Playgroud)
这将允许我们查看该方法是否被调用。
接下来要做的是......编写测试,在这种情况下,我们可以测试两件事,看看是否handleSubmit正常工作。
api.registerUser如果名称为空,则不调用。it('should not call api registerUser method', () => {
const { getByTestId } = render(<Register />)
fireEvent.click(getByTestId('button'))
expect(api.registerUser).toHaveBeenCalledTimes(0)
})
Run Code Online (Sandbox Code Playgroud)
api.registerUser如果名称不为空,则调用。it('should call api registerUser method', () => {
const { getByLabelText, getByTestId } = render(<Register />)
fireEvent.change(getByLabelText('Name'), { target: { value: 'Steve Jobs' }})
fireEvent.click(getByTestId('button'))
expect(api.registerUser).toHaveBeenCalledTimes(1)
})
Run Code Online (Sandbox Code Playgroud)
在最后一个测试中,我们也隐含地进行了测试,handleNameChange因为我们正在更改名称 :) 所以name不会为空,registerUser而是会被调用。
用这个例子withStyles和打字稿在这个回购。
演示在这里。
小智 1
为什么不使用enzymeFull DOM Rendering呢?您可以使用simulate方法来模拟已安装组件上的事件。
class Foo extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
render() {
const { count } = this.state;
return (
<div>
<div className={`clicks-${count}`}>
{count} clicks
</div>
<a href="url" onClick={() => { this.setState({ count: count + 1 }); }}>
Increment
</a>
</div>
);
}
}
const wrapper = mount(<Foo />);
expect(wrapper.find('.clicks-0').length).to.equal(1);
wrapper.find('a').simulate('click');
expect(wrapper.find('.clicks-1').length).to.equal(1);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
741 次 |
| 最近记录: |