拓展 - 03 - jest 测试

jest

1. 安装依赖

bash 复制代码
npm install -D jest @types/jest ts-jest supertest @types/supertest cross-env
作用
jest 测试框架:跑测试、组织用例、断言、mock
@types/jest 让 TS 识别 describeitexpect 等全局 API
ts-jest 让 Jest 直接运行 .ts 文件,无需先编译成 JS
supertest 对 Express 发 HTTP 请求并检查响应,无需浏览器/Postman
@types/supertest supertest 的 TS 类型
cross-env 跨平台设置环境变量(Windows 也能写 NODE_ENV=test

缺了会怎样:

  • 无 jest → 没有测试框架
  • 无 ts-jest → Jest 跑不了 .ts
  • 无 @types/* → 写测试时 TS 报类型错误
  • 无 supertest → 不方便测 HTTP 接口
  • 无 cross-env → Windows 上环境变量写法可能失效

2. 运行 npm test 时发生了什么

复制代码
npm test
  → cross-env 设置 NODE_ENV=test
  → node 启动 Jest(ESM 需 --experimental-vm-modules)
  → 读取 jest.config.cjs
  → 先执行 tests/setup.ts
  → 找到 tests/*.test.ts
  → ts-jest 编译 TypeScript
  → supertest 向 Express 发请求
  → expect 断言 → 输出 PASS / FAIL

3. 各文件职责

文件 职责
package.jsontest 一键启动测试的命令
jest.config.cjs 告诉 Jest 跑哪些文件、怎么编译 TS、路径怎么映射
tests/setup.ts 每个测试运行前的公共初始化
tests/*.test.ts 具体测试用例
tsconfig.json TS 编译规则 + Jest 类型支持
index.ts 被测的 Express 应用;测试时不 listen,只 export

4. package.json --- test 命令

json 复制代码
"test": "cross-env NODE_ENV=test node --experimental-vm-modules node_modules/jest/bin/jest.js"
片段 含义
cross-env NODE_ENV=test 设为测试模式,index.ts 里据此跳过 app.listen()
node --experimental-vm-modules 项目 "type": "module"(ESM),Jest 需要此开关
jest/bin/jest.js Jest 入口

index.ts 相关逻辑:

ts 复制代码
if (process.env.NODE_ENV !== "test") {
  app.listen(PORT, ...);  // 正常启动才监听端口
}
export default app;       // 测试时导出 app 给 supertest 用

5. jest.config.cjs --- Jest 配置

.cjs 是因为项目是 ESM,避免和 "type": "module" 冲突。

配置 含义
preset: "ts-jest/presets/default-esm" ts-jest 的 ESM 预设
testEnvironment: "node" 在 Node 环境跑(测后端 API)
extensionsToTreatAsEsm: [".ts"] .ts 当 ESM 模块
moduleNameMapper 路径映射:../index.ts@/xxx 能被正确解析
transform + useESM: true 用 ts-jest 编译 TS,按 ESM 处理
setupFiles: ["tests/setup.ts"] 每个测试前先跑 setup
testMatch: ["**/tests/**/*.test.ts"] 只跑 tests 目录下 .test.ts 文件

6. tests/setup.ts --- 测试前准备

ts 复制代码
import "dotenv/config";        // 加载 .env(数据库地址等)
process.env.NODE_ENV = "test"; // 确保测试模式

7. tests/health.test.ts --- 示例用例

ts 复制代码
import request from "supertest";
import app from "../index.ts";

describe("Get /health", () => {           // 一组相关测试
  it("returns 200 and status ok", async () => {  // 一个具体场景
    const res = await request(app).get("/health");
    expect(res.status).toBe(200);
    expect(res.body).toEqual({ status: "ok", message: "API is running" });
  });
});
API 作用
describe 分组,把相关测试包在一起
it 一个测试用例
request(app).get(...) supertest 模拟 HTTP 请求
expect(...).toBe(...) 断言:不符合预期则 FAIL

8. tsconfig.json --- 测试相关项

json 复制代码
"types": ["node", "jest"]           // 加载 Jest 全局类型,否则 describe/expect 报错
"baseUrl" + "paths"                 // 路径别名 @/* → src/*
"ignoreDeprecations": "6.0"          // TS6 中 baseUrl 已弃用,加此项消除编译报错

IDE 若报 ignoreDeprecations 值无效:Cursor 内置 TS5 不认识 "6.0"

Ctrl+Shift+P → TypeScript: Select TypeScript Version → Use Workspace Version 即可。

.vscode/settings.json 已配置 "typescript.tsdk": "node_modules/typescript/lib" 指向项目 TS 版本。


9. 依赖协作关系

复制代码
npm test
  ├── cross-env      → NODE_ENV=test
  ├── jest           → 找测试、跑测试、输出结果
  ├── ts-jest        → 编译 .ts(读 tsconfig.json)
  ├── @types/jest    → describe/it/expect 类型
  ├── supertest      → 对 app 发 HTTP 请求
  └── @types/supertest → request() 类型