You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Testing测试axios post成功/失败场景报错排查

React表单单元测试失败排查与修复

问题背景

业务代码运行正常,可实现将用户在表单中输入的数据通过axios提交至json-server的功能,但使用msw搭建mock服务编写的单元测试始终执行失败,覆盖post请求成功、失败的两个场景均无法拿到对应的提示文本。

测试代码

describe("Testing Booking component post http call", () => {
  const server = setupServer(
    rest.post("http://localhost:4000/bookings", (req, res, ctx) => {
      return res(
        ctx.json({
          bookedOn: "2022-03-25",
          buffetName: "SouthIndianFestivalSpecial",
          emailId: "kavya@gmail.com",
          id: 1018,
          plateCount: "2",
        })
      );
    })
  );

  beforeAll(() => server.listen());
  afterEach(() => server.resetHandlers());
  afterAll(() => server.close());
  it("Testing axios post call success", async () => {
    render(<BookingComponent />);
    let buffetName = screen.getByTestId("buffetName");
    fireEvent.change(buffetName, {
      target: { value: "SouthIndianFestivalSpecial" },
    });
    let email = screen.getByTestId("emailId");
    fireEvent.change(email, { target: { value: "kavya@gmail.com" } });
    let plateCount = screen.getByTestId("plateCount");
    fireEvent.change(plateCount, { target: { value: 2 } });
    let bookedOnDate = screen.getByTestId("bookedOn");
    fireEvent.change(bookedOnDate, { target: { value: "2022-03-25" } });

    let form = screen.getByTestId("buffet-form");
    fireEvent.submit(form);
    let successMessage = await screen.findByTestId("success");
    expect(successMessage.innerHTML).toContain(`1018`);
  });
  it("Testing axios post call error", async () => {
    server.use(
      rest.post("http://localhost:4000/bookings", (req, res, ctx) => {
        return res(ctx.status(500));
      })
    );

    render(<BookingComponent />);
    let buffetName = screen.getByTestId("buffetName");
    fireEvent.change(buffetName, {
      target: { value: "SouthIndianFestivalSpecial" },
    });
    let email = screen.getByTestId("emailId");
    fireEvent.change(email, { target: { value: "kavya@gmail.com" } });
    let plateCount = screen.getByTestId("plateCount");
    fireEvent.change(plateCount, { target: { value: 2 } });
    let bookedOnDate = screen.getByTestId("bookedOn");
    fireEvent.change(bookedOnDate, { target: { value: "2022-03-25" } });

    let form = screen.getByTestId("buffet-form");
    fireEvent.submit(form);
    let errorMessage = await screen.findByTestId("error");
    expect(errorMessage.innerHTML).toContain("Something went wrong");
  });
});

业务提交逻辑代码

console.log("buffet button clicked");
// 1. 该方法会在用户点击'Book Buffet'按钮时触发
// 2. 提交时需要阻止页面重载
// 3. 校验所有表单字段是否已填写,若存在未填项则将mandatory状态设为true
// 4. 若所有字段均已填写,则向"http://localhost:4000/bookings/"发起axios调用,传入对应state作为请求数据
// 5. 若axios调用成功,将如下字符串赋值给successMessage状态:
//   "Booking is successfully created with bookingId: " + <id>
// 6. 若axios调用失败,将错误消息赋值为"Something went wrong"
e.preventDefault();
let allfiesds =
  formErrors.emailIdError &&
  formErrors.bookedOnError &&
  formErrors.buffetNameError &&
  formErrors.plateCountError;
setMandatory(allfiesds ? true : false);
// 功能正常但测试无法通过
if (valid) {
  axios
    .post(url, state)
    .then((res) => {
      console.log(res.data);
      setSuccessMessage(
        "Booking is successfully created with bookingId: " + res.data.id
      );
      setErrorMessage("");
      console.log(res.data.id);
    })
    .catch((error) => {
      if (error.response) {
        console.log(error.response.data.message);
      }
      setErrorMessage(messages.ERROR);
      setSuccessMessage("");
      console.log();
    });
}

报错信息

Testing Booking component post http call › Testing axios post call success

expect(received).toContain(expected) // indexOf

Expected substring: "1018"
Received string:    ""

  203 |     fireEvent.submit(form);
  204 |     let successMessage = await screen.findByTestId("success");
> 205 |     expect(successMessage.innerHTML).toContain(`1018`);
      |                                      ^
  206 |   });
  207 |   it("Testing axios post call error", async () => {
  208 |     server.use(

  at Object.<anonymous> (src/App.test.js:205:38)

● Testing Booking component post http call › Testing axios post call error

expect(received).toContain(expected) // indexOf

Expected substring: "Something went wrong"
Received string:    ""

  227 |     fireEvent.submit(form);
  228 |     let errorMessage = await screen.findByTestId("error");
> 229 |     expect(errorMessage.innerHTML).toContain("Something went wrong");
      |                                    ^
  230 |   });
  231 | });
  232 |

  at Object.<anonymous> (src/App.test.js:229:36)

故障原因

两个用例都能定位到success/error对应的DOM节点,但节点内容为空,说明提交时根本没有发起axios请求,问题出在三个地方:

  • valid变量未定义:代码中只计算了拼写错误的allfiesds变量,没有给if判断用到的valid赋值,导致valid始终为falsy值,永远进不到发请求的分支
  • 校验逻辑写反:现有判断formErrors.xxxError &&的含义是所有字段都有错时才判定为需要提示必填,和需求完全相反
  • 地址不匹配:注释里业务请求地址末尾带斜杠,msw拦截的地址不带斜杠,会导致mock拦截失效

修改方案

  • 修正表单校验逻辑,替换原有校验部分代码:
e.preventDefault();
// 所有字段无错误时判定表单校验通过
const isFormValid = 
  !formErrors.emailIdError &&
  !formErrors.bookedOnError &&
  !formErrors.buffetNameError &&
  !formErrors.plateCountError;
// 校验不通过时显示必填提示
setMandatory(!isFormValid);

if (isFormValid) {
  // 保留原有axios请求逻辑,注意统一url地址
  axios.post("http://localhost:4000/bookings", state)
    .then((res) => {
      setSuccessMessage(
        "Booking is successfully created with bookingId: " + res.data.id
      );
      setErrorMessage("");
    })
    .catch((error) => {
      setErrorMessage("Something went wrong");
      setSuccessMessage("");
    });
}
  • 检查表单onChange逻辑,确认输入合法时会将对应formErrors的错误标识置为false,避免校验一直不通过
  • 保证业务代码的请求地址和msw配置的拦截地址完全一致,不要出现末尾斜杠差异

内容的提问来源于stack exchange,提问作者Ashutosh Nagrale

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 03:33:30