@frontend-testing/server-stubs

中文文档
0.0.1-alpha.4发布于 2026/01/02MITTypeScriptESM + CJS零依赖近 30 天下载 3685

解除MSW 服务器管理和 JSON 响应断接测试

中文使用文档
文档目录19 节
  1. 特征
  2. 安装
  3. 快速启动
  4. 1. 配置MSW 服务器
  5. 2. 测试中的使用
  6. API 密码
  7. stubJsonResponse(options)
  8. 请求间谍
  9. 图像分析
  10. 动态反应
  11. 顺序答复
  12. serverManager
  13. 高级示例
  14. 文件上传
  15. 抓好所有处理器
  16. 多个终点
  17. 类型脚本
  18. 如何运作
  19. 许可证

@ 前端测试/ server- stubs

解开MSW为Vitest所打的钩. 单线JSON反应 与内置请求间谍相嘲弄.

特征

  • 🎯 零沸腾 - 任何端口都用自动请求捕获
  • 🔍 内建间谍 - 用解析后的身体、标题和参数跟踪所有请求
  • 🔄 顺序答复 - 模拟重试、授标或状态变化
  • 🎭 动态反应 - 根据请求数据计算答复
  • 📦 类型脚本 - 全类型支持

安装

npm install -D @frontend-testing/server-stubs

同伴依赖关系 : msw >= 2.0.0, (中文(简体) ), vitest >= 3.0.0

快速启动

1. 配置MSW 服务器

// src/test/setup.ts
import { setupWorker } from "msw/browser"; // or setupServer from "msw/node"
import { serverManager } from "@frontend-testing/server-stubs";
import { beforeAll, afterEach, afterAll } from "vitest";

const server = setupWorker();

serverManager.setDefaultServerLoader(() => server);

beforeAll(() => server.start({ onUnhandledRequest: "warn" }));
afterEach(() => server.resetHandlers());
afterAll(() => server.stop());

2. 测试中的使用

import { stubJsonResponse } from "@frontend-testing/server-stubs";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";

describe("LoginForm", () => {
  it("sends credentials and handles success", async () => {
    const { spy } = stubJsonResponse({
      path: "*/api/auth/login",
      method: "POST",
      response: { token: "jwt-token", user: { id: 1, name: "John" } },
    });

    render(<LoginForm />);

    await userEvent.type(screen.getByLabelText("Email"), "[email protected]");
    await userEvent.type(screen.getByLabelText("Password"), "secret123");
    await userEvent.click(screen.getByRole("button", { name: "Login" }));

    expect(spy).toHaveBeenCalledTimes(1);
    expect(spy.mock.calls[0][0].body).toEqual({
      email: "[email protected]",
      password: "secret123",
    });
  });

  it("displays error on 401", async () => {
    stubJsonResponse({
      path: "*/api/auth/login",
      method: "POST",
      response: { error: "Invalid credentials" },
      status: 401,
    });

    render(<LoginForm />);
    await userEvent.click(screen.getByRole("button", { name: "Login" }));

    await screen.findByText("Invalid credentials");
  });
});

API 密码

stubJsonResponse(options)

创建一个能截取匹配请求并返回 JSON 响应的处理器 .

const { spy } = stubJsonResponse({
  path: "*/api/users",      // URL pattern (supports MSW wildcards)
  method: "POST",            // GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD, ALL
  response: { id: 1 },       // Static value or (ctx) => value
  status: 200,               // Static number or (ctx) => number
});
选项类型默认说明
pathstring所需经费要匹配的 URL 模式
methodHttpMethod"GET"HTTP 方法
responseunknown | (ctx) => unknownundefined反应机构
statusnumber | (ctx) => number200HTTP 状态代码
responsesSequentialResponse[]- 说吧顺序答复

请求间谍

每个树枝都回了 spy 获取请求的细节 :

const { spy } = stubJsonResponse({ path: "*/api/users", response: [] });

await fetch("/api/users?page=1", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ name: "John" }),
});

const call = spy.mock.calls[0][0];
call.url;      // Full request URL
call.method;   // "POST"
call.body;     // { name: "John" } (auto-parsed)
call.headers;  // { "content-type": "application/json", ... }
call.params;   // { id: "123" } for /users/:id patterns
call.request;  // Original Request object

图像分析

请求机构根据 Content-Type数字 :

内容 - 类型解析为
application/jsonJavaScript 对象
application/x-www-form-urlencoded来自密钥值对的对象
multipart/form-data对象为 File 实例
无信头/ 未知尝试 JSON, 返回到原始文本

动态反应

使用函数根据请求数据计算响应:

stubJsonResponse({
  path: "*/api/echo",
  method: "POST",
  response: (ctx) => ({ received: ctx.body }),
  status: (ctx) => ctx.body?.valid ? 200 : 400,
});

回应背景:

interface ResponseContext {
  url: string;
  method: string;
  body?: unknown;
  headers: Record<string, string>;
  params?: Record<string, string>;
  callIndex: number; // 0-based call counter
}

顺序答复

模拟多个调用中的逻辑或状态变化 :

stubJsonResponse({
  path: "*/api/flaky",
  responses: [
    { response: { error: "Service unavailable" }, status: 503 },
    { response: { error: "Service unavailable" }, status: 503 },
    { response: { data: "Success!" }, status: 200 },
  ],
});

// 1st call → 503
// 2nd call → 503
// 3rd+ calls → 200 (repeats last response)

serverManager

Singleton)用于MSW服务器管理. 配置一次,在任何地方使用根茎.

import { serverManager } from "@frontend-testing/server-stubs";

// Set server directly
serverManager.setServer(myServer);

// Or lazy load (recommended)
serverManager.setDefaultServerLoader(() => myServer);

// Access
serverManager.getServer();
serverManager.hasServer();
serverManager.reset();

高级示例

文件上传

const { spy } = stubJsonResponse({
  path: "*/api/upload",
  method: "POST",
  response: { id: "file-123" },
});

const formData = new FormData();
formData.append("file", new File(["content"], "doc.pdf"));

await fetch("/api/upload", { method: "POST", body: formData });

const body = spy.mock.calls[0][0].body as Record<string, unknown>;
expect(body.file).toBeInstanceOf(File);

抓好所有处理器

stubJsonResponse({
  path: "*/api/flexible",
  method: "ALL",
  response: (ctx) => ({ method: ctx.method }),
});

多个终点

const usersSpy = stubJsonResponse({
  path: "*/api/users",
  response: [{ id: 1, name: "John" }],
});

const statsSpy = stubJsonResponse({
  path: "*/api/stats",
  response: { visits: 1000 },
});

类型脚本

所有类型都导出 :

import type {
  HttpMethod,
  RequestCall,
  ResponseContext,
  ResponseProvider,
  SequentialResponse,
  StubJsonResponseOptions,
  MswServer,
} from "@frontend-testing/server-stubs";

如何运作

这个库将MSW的请求处理器用更清洁的API和自动请求跟踪来包裹. 当你打电话 stubJsonResponse(),则:

  1. 为指定的路径/方法创建 MSW 处理器
  2. 根据 Content-Type
  3. 记录所有向Vitest间谍提出的请求
  4. 返回所配置的响应(静态、动态或相继)

这个 serverManager 从测试文件中去除MSW服务器设置, 因此您会在测试设置中配置一次, 在不导入服务器实例的情况下, 在任何地方使用 stubs .

许可证

麻省理工学院

版本与发布记录

@frontend-testing/server-stubs 共发布 3 个版本,首次发布于 2025/12/19;过去 12 个月发布了 3 个版本。

版本发布日期距今
0.0.1-alpha.4latest2026/01/0210 个月前
0.0.1-alpha.32026/01/0210 个月前
0.0.1-alpha.2alpha2025/12/1910 个月前

关于 @frontend-testing/server-stubs 的常见问题

@frontend-testing/server-stubs 是什么?

解除MSW 服务器管理和 JSON 响应断接测试

如何安装 @frontend-testing/server-stubs?

在项目目录运行 npm install @frontend-testing/server-stubs,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:msw(^2.0.0)、vitest(>=3.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@frontend-testing/server-stubs 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@frontend-testing/server-stubs 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@frontend-testing/server-stubs 可以商用吗?

@frontend-testing/server-stubs 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@frontend-testing/server-stubs 的下载量有多少?

根据 npm 官方下载统计,@frontend-testing/server-stubs 在 2026/10/16 – 2026/11/14 这 30 天内被下载 3,685 次,日均约 123 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@frontend-testing/server-stubs 还在维护吗?

最新版本 0.0.1-alpha.4 发布于 2026/01/02(10 个月前);至今共发布 3 个版本,其中过去 12 个月发布了 3 个;首次发布于 2025/12/19。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。