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

React MSW 模拟失效:实际API被调用,测试失败求助

问题:MSW未成功模拟API请求,测试调用了真实接口

组件代码(App.js)

import React, { useState, useEffect } from "react";

const App = () => {
  const [users, setUsers] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchAllUsers = async () => {
      try {
        const response = await fetch(
          "https://jsonplaceholder.typicode.com/users"
        );
        const data = await response.json();
        setUsers(data);
      } catch (err) {
        setError("Something went wrong!");
      }
    };
    fetchAllUsers();
  }, []);

  return (
    <>
      <h1>List of Users</h1>
      {error && <div>{error}</div>}
      {users ? (
        <ul>
          {users.map((user) => (
            <li key={user.id}>{user.name}</li>
          ))}
        </ul>
      ) : (
        <p>No users found</p>
      )}
    </>
  );
};

export default App;

测试代码(App.test.js)

import { render, screen } from "@testing-library/react";
import { rest } from "msw";
import { setupServer } from "msw/node";
import App from "./App";

const server = setupServer(
  rest.get("https://jsonplaceholder.typicode.com/users", (req, res, ctx) => {
    res(ctx.json(["Hello World"]));
  })
);

beforeAll(() => {
  server.listen();
});

afterAll(() => {
  server.close();
});

test("empty", async () => {
  render(<App />);
  expect(screen.getByText("List of Users")).toBeInTheDocument();
  await screen.findByText("Hello world");
});

测试失败信息

Unable to find an element with the text: Hello world. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

Ignored nodes: comments, script, style
<body>
  <div>
    <h1>
      List of Users
    </h1>
    <ul>
      <li>
        Leanne Graham
      </li>
      /*skipping a few lines of HTML*/          
      <li>
        Clementina DuBuque
      </li>
    </ul>
  </div>
</body>

排查与解决方法

1. 修正模拟数据结构与文本匹配

组件渲染的是用户对象的name字段,但当前测试模拟返回的是字符串数组["Hello World"],即使拦截成功,user.name会是undefined,页面不会显示期望文本。同时测试中查找的Hello world与模拟返回的Hello World大小写不一致,也会导致查找失败。

修改MSW的响应数据为符合组件期望的结构:

rest.get("https://jsonplaceholder.typicode.com/users", (req, res, ctx) => {
  res(ctx.json([{ id: 1, name: "Hello World" }]));
});

同时将测试中的查找文本改为Hello World(保持大小写一致)。

2. 确保MSW正确拦截请求

  • 检查msw依赖是否安装完整,执行npm install msw --save-dev确认安装。
  • 添加afterEach钩子重置MSW的请求处理器,避免测试间状态污染:
afterEach(() => {
  server.resetHandlers();
});
  • 可在beforeAll和afterAll中添加日志,确认MSW服务是否正常启动/关闭,排查初始化失败的可能。

3. 排除其他请求拦截库冲突

如果项目中使用了nock等其他请求拦截工具,可能会与MSW冲突,暂时禁用这类工具后重新测试。

修正后的完整测试代码

import { render, screen } from "@testing-library/react";
import { rest } from "msw";
import { setupServer } from "msw/node";
import App from "./App";

const server = setupServer(
  rest.get("https://jsonplaceholder.typicode.com/users", (req, res, ctx) => {
    res(ctx.json([{ id: 1, name: "Hello World" }]));
  })
);

beforeAll(() => {
  server.listen();
});

afterEach(() => {
  server.resetHandlers();
});

afterAll(() => {
  server.close();
});

test("displays mock user data", async () => {
  render(<App />);
  expect(screen.getByText("List of Users")).toBeInTheDocument();
  const mockUser = await screen.findByText("Hello World");
  expect(mockUser).toBeInTheDocument();
});

内容的提问来源于stack exchange,提问作者Gautham Muralidharan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 02:59:55