首页 > 解决方案 > 使用返回承诺的玩笑模拟 axios 不起作用

问题描述

我试图嘲笑我的 axios 进入 Jest。我是反应测试的新手,所以请善待

我已经按照教程和这个答案进行了操作,我想我已经掌握了该怎么做。基本上在组件安装时,我在我的UseEffect.

这是不工作的测试

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。获取数据后,我所做的就是将状态设置为就绪,因此它将呈现 Widget 组件。有趣的是,如果我直接将代码更改为 mockResolvedValue,那么它就可以工作。我不明白为什么上面的代码不起作用?基本上它也解决了相同的值......有人可以帮忙吗?我真的很困惑,无法解决这个问题,这真的让我很困扰

如果 axios 返回正确的数据,有一个代码调用 setReady(true),因此它返回<Widget ... />

谢谢

工作测试,因为我嘲笑了每个 get 请求:


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我使用的组件中formikmaterial-ui. 所以问题在于它期望 在组件中提供数据类型以供选择的getData()功能。useEffect[{id: PropTypes.number, name: PropTypes.string}]<FormikSelect />

因此第二个工作测试有效

用户窗体:

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;

标签: javascriptreactjsjestjsaxios

解决方案


推荐阅读