writing-dev-server-tests

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Writing HMR/Dev Server Tests

编写HMR/Dev Server测试

Dev server tests validate hot-reloading robustness and reliability.
开发服务器测试用于验证热重载的健壮性与可靠性。

File Structure

文件结构

  • test/bake/bake-harness.ts
    - shared utilities:
    devTest
    ,
    prodTest
    ,
    devAndProductionTest
    ,
    Dev
    class,
    Client
    class
  • test/bake/client-fixture.mjs
    - subprocess for
    Client
    (page loading, IPC queries)
  • test/bake/dev/*.test.ts
    - dev server and hot reload tests
  • test/bake/dev-and-prod.ts
    - tests running on both dev and production mode
  • test/bake/bake-harness.ts
    - 共享工具:
    devTest
    prodTest
    devAndProductionTest
    Dev
    类、
    Client
  • test/bake/client-fixture.mjs
    -
    Client
    的子进程(页面加载、IPC查询)
  • test/bake/dev/*.test.ts
    - 开发服务器与热重载测试
  • test/bake/dev-and-prod.ts
    - 同时在开发和生产模式下运行的测试

Test Categories

测试分类

  • bundle.test.ts
    - DevServer-specific bundling bugs
  • css.test.ts
    - CSS bundling issues
  • plugins.test.ts
    - development mode plugins
  • ecosystem.test.ts
    - library compatibility (prefer concrete bugs over full package tests)
  • esm.test.ts
    - ESM features in development
  • html.test.ts
    - HTML file handling
  • react-spa.test.ts
    - React, react-refresh transform, server components
  • sourcemap.test.ts
    - source map correctness
  • bundle.test.ts
    - 针对DevServer的特定打包问题
  • css.test.ts
    - CSS打包问题
  • plugins.test.ts
    - 开发模式插件
  • ecosystem.test.ts
    - 库兼容性测试(优先针对具体问题,而非完整包测试)
  • esm.test.ts
    - 开发模式下的ESM特性
  • html.test.ts
    - HTML文件处理
  • react-spa.test.ts
    - React、react-refresh转换、服务器组件
  • sourcemap.test.ts
    - 源映射正确性

devTest Basics

devTest基础用法

ts
import { devTest, emptyHtmlFile } from "../bake-harness";

devTest("html file is watched", {
  files: {
    "index.html": emptyHtmlFile({
      scripts: ["/script.ts"],
      body: "<h1>Hello</h1>",
    }),
    "script.ts": `console.log("hello");`,
  },
  async test(dev) {
    await dev.fetch("/").expect.toInclude("<h1>Hello</h1>");
    await dev.patch("index.html", { find: "Hello", replace: "World" });
    await dev.fetch("/").expect.toInclude("<h1>World</h1>");

    await using c = await dev.client("/");
    await c.expectMessage("hello");

    await c.expectReload(async () => {
      await dev.patch("index.html", { find: "World", replace: "Bar" });
    });
    await c.expectMessage("hello");
  },
});
ts
import { devTest, emptyHtmlFile } from "../bake-harness";

devTest("html file is watched", {
  files: {
    "index.html": emptyHtmlFile({
      scripts: ["/script.ts"],
      body: "<h1>Hello</h1>",
    }),
    "script.ts": `console.log("hello");`,
  },
  async test(dev) {
    await dev.fetch("/").expect.toInclude("<h1>Hello</h1>");
    await dev.patch("index.html", { find: "Hello", replace: "World" });
    await dev.fetch("/").expect.toInclude("<h1>World</h1>");

    await using c = await dev.client("/");
    await c.expectMessage("hello");

    await c.expectReload(async () => {
      await dev.patch("index.html", { find: "World", replace: "Bar" });
    });
    await c.expectMessage("hello");
  },
});

Key APIs

核心API

  • files
    : Initial filesystem state
  • dev.fetch()
    : HTTP requests
  • dev.client()
    : Opens browser instance
  • dev.write/patch/delete
    : Filesystem mutations (wait for hot-reload automatically)
  • c.expectMessage()
    : Assert console.log output
  • c.expectReload()
    : Wrap code that causes hard reload
Important: Use
dev.write/patch/delete
instead of
node:fs
- they wait for hot-reload.
  • files
    : 初始文件系统状态
  • dev.fetch()
    : HTTP请求
  • dev.client()
    : 打开浏览器实例
  • dev.write/patch/delete
    : 文件系统变更(自动等待热重载完成)
  • c.expectMessage()
    : 断言console.log输出
  • c.expectReload()
    : 包裹会触发硬重载的代码
重要提示:请使用
dev.write/patch/delete
而非
node:fs
- 它们会自动等待热重载完成。

Testing Errors

错误测试

ts
devTest("import then create", {
  files: {
    "index.html": `<!DOCTYPE html><html><head></head><body><script type="module" src="/script.ts"></script></body></html>`,
    "script.ts": `import data from "./data"; console.log(data);`,
  },
  async test(dev) {
    const c = await dev.client("/", {
      errors: ['script.ts:1:18: error: Could not resolve: "./data"'],
    });
    await c.expectReload(async () => {
      await dev.write("data.ts", "export default 'data';");
    });
    await c.expectMessage("data");
  },
});
Specify expected errors with the
errors
option:
ts
await dev.delete("other.ts", {
  errors: ['index.ts:1:16: error: Could not resolve: "./other"'],
});
ts
devTest("import then create", {
  files: {
    "index.html": `<!DOCTYPE html><html><head></head><body><script type="module" src="/script.ts"></script></body></html>`,
    "script.ts": `import data from "./data"; console.log(data);`,
  },
  async test(dev) {
    const c = await dev.client("/", {
      errors: ['script.ts:1:18: error: Could not resolve: "./data"'],
    });
    await c.expectReload(async () => {
      await dev.write("data.ts", "export default 'data';");
    });
    await c.expectMessage("data");
  },
});
通过
errors
选项指定预期错误:
ts
await dev.delete("other.ts", {
  errors: ['index.ts:1:16: error: Could not resolve: "./other"'],
});