我正在尝试嘲笑我的axios进入Jest。我是反应测试的新手,请保持友善
我遵循了this教程和this的答案,我认为我已经掌握了该做什么。基本上是在组件安装上,我在UseEffect
上调用了2次数据获取。
这是不起作用的测试:
jest.mock("axios");
describe("User form async tests", () => {
it("Renders widget", async (done) => {
const promiseRole = new Promise((resolve, reject) =>
┊ setTimeout(
┊ ┊ () =>
┊ ┊ ┊ resolve({
┊ ┊ ┊ ┊ data: [
┊ ┊ ┊ ┊ ┊ { id: 0, name: "Admin" },
┊ ┊ ┊ ┊ ┊ { id: 1, name: "Editor" },
┊ ┊ ┊ ┊ ],
┊ ┊ ┊ }),
┊ ┊ 100
┊ )
);
const promiseLocs = new Promise((resolve, reject) =>
┊ setTimeout(
┊ ┊ () =>
┊ ┊ ┊ resolve({
┊ ┊ ┊ ┊ data: [
┊ ┊ ┊ ┊ ┊ { id: 0, name: "Loc1" },
┊ ┊ ┊ ┊ ┊ { id: 1, name: "Loc2" },
┊ ┊ ┊ ┊ ],
┊ ┊ ┊ }),
┊ ┊ 100
┊ )
);
┊ axios.get.mockImplementationOnce(() => promiseRole);
┊ axios.get.mockImplementationOnce(() => promiseLocs);
┊ const wrapper = mount(<UserForm />);
┊ await promiseRole;
┊ await promiseLocs;
┊ setImmediate(() => {
┊ ┊ wrapper.update();
┊ ┊ expect(wrapper.contains(Widget)).toEqual(true);
┊ ┊ done();
┊ });
});
});
以某种方式,它始终为小部件返回false。提取数据后,我所做的就是将状态设置为ready,因此它将呈现Widget组件。有趣的是,如果我直接将代码更改为嘲笑解析值,那么它将起作用。我不明白的是为什么上面的代码不起作用?基本上,它也能解决相同的价值……有人可以帮忙吗?我真的很困惑,无法解决这个问题,这真的困扰着我
如果axios返回正确的数据,则有一个代码会调用
setReady(true)
,因此它在之后返回<Widget ... />
谢谢
工作测试,因为我嘲笑了每个获取请求:
jest.mock("axios");
describe("User form async tests", () => {
it("Renders widget", async (done) => {
┊ const location = [{ id: 0, name: "hurstville" }];
┊ const resp = { data: location };
┊ axios.get.mockResolvedValue(resp);
┊ const wrapper = mount(<UserForm />);
┊ setImmediate(() => {
┊ ┊ wrapper.update();
┊ ┊ expect(wrapper.contains(Widget)).toEqual(true);
┊ ┊ done();
┊ });
});
});
在UserForm
组件中,我正在使用formik
和material-ui
。因此,问题出在getData()
中的useEffect
函数处,它期望数据类型为
[{id: PropTypes.number, name: PropTypes.string}]
将在<FormikSelect />
组件中提供以供选择。
因此第二项工作测试有效
UserForm:
import React, { useEffect, useState } from "react";
import {
FormikTextField,
FormikArray,
FormikSelect,
} from "app/components/forms/Utils";
import { FormikTransferList, Widget, Alert } from "app/components";
import { Formik, Form, ErrorMessage } from "formik";
import {
getUserById,
getUserRole,
addUser,
getLocationList,
updateUser,
} from "app/crud/user.crud";
import {
formValues,
validationUser,
} from "app/components/forms/users/UserConst";
import { useLocation, useHistory } from "react-router-dom";
import FuseSplashScreen from "@fuse/core/FuseSplashScreen";
import { Snackbar, Button } from "@material-ui/core";
const processedLocs = (data) =>
data.map((item) => {
return {
...item,
key: item.id,
title: item.name,
};
});
function UserForm() {
const [initial, setFormValues] = useState(formValues);
const location = useLocation();
const history = useHistory();
const [roles, setRoles] = useState([]);
const [locationList, setLocationList] = useState([]);
const [ready, setReady] = useState(false);
const [open, setOpen] = useState(false);
useEffect(() => {
async function getData() {
try {
const response = await getUserRole();
const locresult = await getLocationList();
if (response) {
setRoles(response.data);
setLocationList(processedLocs(locresult.data));
setReady(true);
}
} catch (err) {
console.log(err.message);
}
}
getData();
}, [getUserRole]);
useEffect(() => {
async function getUserDetails(id) {
const response = await getUserById(id);
if (response) {
const newVal = {
...response.data,
roles: response.data.roles.map((item) => ({
...item,
locations: item.locations.map((loc) => loc.id),
})),
};
setFormValues(newVal);
} else {
setFormValues(formValues);
}
}
if (location.state && location.state.id) {
getUserDetails(location.state.id);
}
}, [location.state]);
const handleCloseAlert = (event, reason) => {
if (reason === "clickaway") {
return;
}
setOpen(false);
};
const handleSuccess = () => {
setOpen(true);
};
return ready ? (
<>
<Formik
enableReinitialize
initialValues={initial}
validationSchema={validationUser}
onSubmit={async (
values,
{ setSubmitting, setErrors, setStatus, resetForm }
) => {
setTimeout(async () => {
try {
let response;
if (location.state && location.state.id) {
response = await updateUser(values.id, values);
} else {
response = await addUser(values);
if (response) {
handleSuccess();
}
}
resetForm(formValues);
history.goBack();
setStatus({ success: true });
} catch (err) {
setSubmitting(false);
setErrors({ submit: err.message });
}
}, 200);
}}
>
<Form>
<div className="container grid grid-cols-1 gap-4 p-8">
<Widget title="User Details" containerClass="p-8">
<div className="grid grid grid-cols-1 gap-4">
<FormikTextField
id="name"
variant="outlined"
name="name"
label="Full Name"
/>
<FormikTextField
id="email"
variant="outlined"
name="email"
label="Email Address"
/>
<FormikTextField
id="phone"
variant="outlined"
name="phone"
label="Phone number"
/>
</div>
</Widget>
<Widget title="User Roles" containerClass="p-8">
<div className="flex flex-col p-8">
<ErrorMessage
name="roles"
render={(msg) => (
<div className="text-lg text-red-600 p-8 ml-8">{msg}</div>
)}
/>
<FormikArray name="roles" defaultValue={initial.roles[0]}>
{({ index }) => (
<div className="flex flex-col p-8 mb-8">
<div>
<p className="text-lg font-semibold text-blue-400">
Assign locations to the role of the user. Each user
can has multiple locations based on the role that they
have
</p>
</div>
<div>
<p className="text-lg font-medium">Role {index + 1} </p>
</div>
<FormikSelect
labelId={`rolesSelectLabel${index}`}
options={roles}
label="Select Roles"
selectId={`rolesSelect${index}`}
name={`roles.${index}.id`}
/>
<div>
<p className="text-lg font-medium">Put Location:</p>
</div>
<div className="w-full">
<FormikTransferList
options={locationList}
name={`roles.${index}.locations`}
/>
</div>
</div>
)}
</FormikArray>
</div>
<div className="w-1/2 p-8">
<Button variant="contained" color="primary" type="submit">
{location.state && location.state.id ? "Update" : "Submit"}
</Button>
</div>
</Widget>
</div>
</Form>
</Formik>
<Snackbar open={open} autoHideDuration={4000} onClose={handleCloseAlert}>
<Alert onClose={handleCloseAlert} severity="success">
User Created
</Alert>
</Snackbar>
</>
) : (
<FuseSplashScreen />
);
}
UserForm.propTypes = {};
export default UserForm;