我正在尝试这些状态方法,当把状态从父组件传递到子组件时。
const [bio, setBio] = useState("");
const [gravatar, setGravatar] = useState("");
但我得到这个错误
✓应该检查EditProfile是否渲染子组件(2ms) ✕应该测试生物状态(4ms)。
应该呈现'应该测试生物状态
TypeError: Cannot read property 'target' of undefined
当这个测试被调用时,我做错了什么? 谢谢。
it("should test bio state", () => {
wrapper
.find("EditProfileForm")
.props()
.handleBio();
expect(setState).toHaveBeenCalledWith("set bio");
});
editProfile.test.tsx
import React from "react";
import EditProfile from "./editProfile";
import { shallow, mount, render } from "enzyme";
import EditProfileForm from "../forms/editProfile/editForm";
import { createShallow } from "@material-ui/core/test-utils";
import { Provider } from "react-redux";
import { store } from "../../store";
describe("Should render <EditProfile/>", () => {
let wrapper;
const setState = jest.fn();
const useStateSpy = jest.spyOn(React, "useState");
useStateSpy.mockImplementation((init) => [init, setState]);
beforeAll(() => {
wrapper = mount(
<Provider store={store}>
<EditProfile />
</Provider>,
);
});
it("Should render <EditProfile/>", () => {
expect(wrapper).toHaveLength(1);
});
it("Should check if EditProfile renders child component", () => {
expect(wrapper.find("EditProfileForm")).toHaveLength(1);
});
it("should test bio state", () => {
wrapper
.find("EditProfileForm")
.props()
.handleBio();
expect(setState).toHaveBeenCalledWith("set bio");
});
});
editProfile.tsx
import React, { useEffect, Component, useRef, useState } from "react";
import Typography from "@material-ui/core/Typography";
import EditProfileForm from "../forms/editProfile/editForm";
import GridHoc from "../hoc/grid";
import { Grid } from "@material-ui/core";
import storeMethods from "../../common/storeHooks";
function EditProfile(props: any) {
const [bio, setBio] = useState("");
const [gravatar, setGravatar] = useState("");
const mounted = useRef<Object>();
const { getProfile, profileData, userErr, message, updateProfile } = storeMethods();
useEffect(() => {
if (!mounted.current) {
getProfile();
mounted.current = true;
} else {
setBio(bio ? bio : profileData.bio);
setGravatar(gravatar ? gravatar : profileData.gravatar);
}
});
const handleSubmit = (e: any) => {
e.preventDefault();
const formData = {
bio,
gravatar,
};
updateProfile(formData);
};
return (
<Grid container={true} justify="center">
<Grid item={true} xs={12} sm={12} md={8} lg={8}>
{userErr && <Typography style={{ color: "red" }}>{message || userErr}</Typography>}
{message && <Typography style={{ color: "green" }}>{message || userErr}</Typography>}
<EditProfileForm handleBio={(e) => setBio(e.target.value)} handleGravatar={(e) => setGravatar(e.target.value)} onSubmit={handleSubmit} bio={bio} gravatar={gravatar} />
</Grid>
</Grid>
);
}
export default GridHoc(EditProfile);
editProfileForm
import Button from "@material-ui/core/Button";
import FormGroup from "@material-ui/core/FormGroup";
import FormLabel from "@material-ui/core/FormLabel";
import TextField from "@material-ui/core/TextField";
import Typography from "@material-ui/core/Typography";
import React from "react";
const EditProfileForm = (props: any) => (
<form onSubmit={props.onSubmit}>
<Typography variant="h5">Edit Profile</Typography>
<FormGroup style={{ padding: "30px 0px" }}>
<FormLabel style={{ display: "block" }}>Bio</FormLabel>
<TextField
id="outlined-name"
style={{
width: "100%",
}}
name="bio"
multiline={true}
rows="3"
defaultValue={props.bio}
onChange={props.handleBio}
margin="normal"
variant="outlined"
/>
<FormLabel style={{ display: "block" }}>Gravatar</FormLabel>
<TextField
id="outlined-name"
style={{
width: "100%",
}}
name="gravatar"
multiline={true}
rows="3"
onChange={props.handleGravatar}
defaultValue={props.gravatar}
margin="normal"
variant="outlined"
/>
</FormGroup>
<Button className="subBtn" variant="outlined" color="primary" type="submit">
Submit
</Button>
</form>
);
export default EditProfileForm;
你的测试方式有问题吗?handleBio
已被调用。测试应该是模仿用户的交互,但在这里,你以编程方式调用了 handleBio
相反,你应该想象用户可能会用你的组件做什么,以及哪些操作必须被执行。setBio
时被正确调用。handleBio
的调用,这只是测试React是否正确绑定了道具(你不需要不应该这样做)。handleBio
受访 TextField
变化,这应该发生在 EditProfileForm
测试。
要做到这一点,您需要在 TextField
(如果用户修改了 TextField
值),只有在这之后,才会期待 handleBio
已被调用,且参数正确。
我建议你用 @testing-libraryreact 这将使你的测试更容易编写。
你可以添加一个 label
的属性。TextField
:
<TextField name="bio" label="bio" />
<TextField name="gravatar" label="gravatar" />
然后写下下面的测试。
// existing imports
import { render as testRender, fireEvent, screen } from '@testing-library/react';
const props = {
onSubmit: jest.fn(),
handleBio: jest.fn(),
handleGravatar: jest.fn(),
}
const render = () => testRender(<EditProfileForm {...props} />;
describe('EditProfile', () => {
...
it('calls handleBio on bio TextField change', () => {
render();
const input = screen.getByLabelText('bio');
fireEvent.change(input, { target: { value: 'new value' } });
expect(props.handleBio).toHaveBeenCalledTimes(1);
}
});