supertest
supertest 是一款专为 Node.js 开发者设计的 HTTP 服务器测试工具。它基于强大的 superagent 库构建,旨在通过流畅的链式 API 让后端接口测试变得简单直观。
在开发 Node.js 应用时,验证 API 响应状态、头部信息及数据格式往往需要繁琐的配置。supertest 完美解决了这一痛点:它允许开发者直接传入 Express 等框架的应用实例或 HTTP 服务函数,无需手动启动服务器或管理临时端口,即可自动完成请求发送与断言验证。无论是检查 JSON 内容类型、验证状态码,还是处理 HTTP/2 协议及身份认证场景,supertest 都能轻松应对。
该工具特别适合后端工程师、全栈开发者以及需要进行自动化接口测试的技术人员。其独特亮点在于高度的灵活性:既提供了高层级的抽象方法以简化常见测试用例,又保留了底层 superagent 的全部能力,方便用户在需要时进行深度定制。此外,supertest 能与 Mocha、Jest 等主流测试框架无缝集成,支持异步回调处理,帮助团队高效构建稳定的持续集成流程,是保障 Node.js 服务端代码质量的得力助手。
使用场景
某电商团队正在开发基于 Node.js 的订单微服务,需要在每次代码提交后快速验证 API 接口的正确性与稳定性。
没有 supertest 时
- 环境搭建繁琐:测试前必须手动启动服务器并占用特定端口,测试结束后还需清理进程,容易因端口冲突导致测试失败。
- 断言逻辑分散:需要分别编写代码检查 HTTP 状态码、响应头格式及 JSON 数据内容,代码冗长且难以维护。
- 异步处理复杂:在处理异步请求回调时,缺乏统一的错误捕获机制,一旦断言失败往往导致测试进程静默退出或报错信息模糊。
- 认证模拟困难:模拟带 Token 或 Basic Auth 的请求时,需手动构造复杂的 Header 对象,增加了测试用例的编写成本。
使用 supertest 后
- 自动端口管理:supertest 可直接接收 Express 应用实例,自动绑定临时端口进行测试,彻底消除了手动启停服务和端口占用的烦恼。
- 链式流畅断言:通过
.expect()方法链式调用,能在一条语句中同时验证状态码、响应头类型及数据长度,代码简洁直观。 - 智能错误反馈:内置的断言失败机制会自动将错误传递给测试框架(如 Mocha),确保任何接口异常都能立即中断测试并输出清晰堆栈。
- 便捷身份模拟:提供专用的
.auth()方法,仅需一行代码即可模拟用户登录态,大幅简化了受保护接口的测试流程。
supertest 通过将底层 HTTP 细节封装为高层抽象,让 Node.js 接口测试从繁琐的配置工作中解放出来,实现了高效、可靠的质量保障。
运行环境要求
- 未说明
不需要
未说明

快速开始
supertest
通过 superagent 轻松实现 HTTP 断言。由 Forward Email 和 Lad 维护。
关于
本模块的初衷是为测试 HTTP 提供高层次的抽象,同时仍然允许你回退到 superagent 提供的低层次 API。
快速开始
将 supertest 作为 npm 模块安装,并将其保存为开发依赖项到你的 package.json 文件中:
npm install supertest --save-dev
安装完成后,只需调用 require('supertest'); 即可引用它。
示例
你可以将 http.Server 或 Function 传递给 request() —— 如果服务器尚未开始监听连接,它会为你绑定到一个临时端口,因此无需手动管理端口号。
supertest 可以与任何测试框架配合使用,以下是一个完全不依赖测试框架的示例:
const request = require('supertest');
const express = require('express');
const app = express();
app.get('/user', function(req, res) {
res.status(200).json({ name: 'john' });
});
request(app)
.get('/user')
.expect('Content-Type', /json/)
.expect('Content-Length', '15')
.expect(200)
.end(function(err, res) {
if (err) throw err;
});
要启用 HTTP/2 协议,只需在 request 或 request.agent 中添加一个选项即可:
const request = require('supertest');
const express = require('express');
const app = express();
app.get('/user', function(req, res) {
res.status(200).json({ name: 'john' });
});
request(app, { http2: true })
.get('/user')
.expect('Content-Type', /json/)
.expect('Content-Length', '15')
.expect(200)
.end(function(err, res) {
if (err) throw err;
});
request.agent(app, { http2: true })
.get('/user')
.expect('Content-Type', /json/)
.expect('Content-Length', '15')
.expect(200)
.end(function(err, res) {
if (err) throw err;
});
以下是使用 Mocha 的示例,请注意,你可以直接将 done 回调函数传递给任意 .expect() 调用:
describe('GET /user', function() {
it('响应 JSON 数据', function(done) {
request(app)
.get('/user')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200, done);
});
});
你可以使用 auth 方法来传递 HTTP 用户名和密码,方式与 superagent 相同:
describe('GET /user', function() {
it('响应 JSON 数据', function(done) {
request(app)
.get('/user')
.auth('username', 'password')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200, done);
});
});
需要注意的是,如果未添加状态码断言(例如 .expect(302)),superagent 现在会将所有 HTTP 错误(即非 2XX 响应码)作为第一个参数传递给回调函数。
如果你使用 .end() 方法,失败的 .expect() 断言不会抛出错误;它们会将断言结果作为错误对象返回给 .end() 回调。为了使测试用例失败,你需要重新抛出错误或将 err 传递给 done(),如下所示:
describe('POST /users', function() {
it('响应 JSON 数据', function(done) {
request(app)
.post('/users')
.send({name: 'john'})
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200)
.end(function(err, res) {
if (err) return done(err);
return done();
});
});
});
你也可以使用 Promise:
describe('GET /users', function() {
it('响应 JSON 数据', function() {
return request(app)
.get('/users')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200)
.then(response => {
expect(response.body.email).toEqual('foo@bar.com');
})
});
});
或者使用 async/await 语法:
describe('GET /users', function() {
it('响应 JSON 数据', async function() {
const response = await request(app)
.get('/users')
.set('Accept', 'application/json')
expect(response.headers["content-type"]).toMatch(/json/);
expect(response.status).toEqual(200;
expect(response.body.email).toEqual('foo@bar.com');
});
});
断言会按照定义的顺序依次执行。这一特性可用于在执行断言之前修改响应体或响应头。
describe('POST /user', function() {
it('用户名称应为不区分大小写的 "john"', function(done) {
request(app)
.post('/user')
.send('name=john') // x-www-form-urlencoded 格式上传
.set('Accept', 'application/json')
.expect(function(res) {
res.body.id = '某个固定 ID';
res.body.name = res.body.name.toLowerCase();
})
.expect(200, {
id: '某个固定 ID',
name: 'john'
}, done);
});
});
凡是 superagent 能做到的事情,supertest 也能做到——例如多部分文件上传!
request(app)
.post('/')
.field('name', '我的超赞头像')
.field('complex_object', '{"attribute": "value"}', {contentType: 'application/json'})
.attach('avatar', 'test/fixtures/avatar.jpg')
...
每次都不必重复传递应用实例或 URL;如果你测试的是同一台主机,只需将 request 变量重新赋值为初始的应用实例或 URL 即可,每次调用 request.VERB() 都会创建一个新的测试对象。
request = request('http://localhost:5555');
request.get('/').expect(200, function(err){
console.log(err);
});
request.get('/').expect('heya', function(err){
console.log(err);
});
以下是使用 Mocha 的示例,展示了如何保持请求及其 Cookie 的持久性:
const request = require('supertest');
const should = require('should');
const express = require('express');
const cookieParser = require('cookie-parser');
describe('request.agent(app)', function() {
const app = express();
app.use(cookieParser());
app.get('/', function(req, res) {
res.cookie('cookie', 'hey');
res.send();
});
app.get('/return', function(req, res) {
if (req.cookies.cookie) res.send(req.cookies.cookie);
else res.send(':(')
});
const agent = request.agent(app);
it('应该保存 Cookie', function(done) {
agent
.get('/')
.expect('set-cookie', 'cookie=hey; Path=/', done);
});
it('应该发送 Cookie', function(done) {
agent
.get('/return')
.expect('hey', done);
});
});
还有一个由文件 agency.js 引入的示例。
以下是一个在请求中设置两个 Cookie 的示例:
agent(app)
.get('/api/content')
.set('Cookie', ['nameOne=valueOne;nameTwo=valueTwo'])
.send()
.expect(200)
.end((err, res) => {
if (err) {
return done(err);
}
expect(res.text).to.be.equal('hey');
return done();
});
API
你可以使用任何 superagent 的方法,包括 .write()、.pipe() 等,并在 .end() 回调中进行低层次的断言。
.expect(status[, fn])
断言响应的状态码。
.expect(status, body[, fn])
断言响应的状态码和响应体。
.expect(body[, fn])
断言响应体文本,可以是字符串、正则表达式或解析后的对象。
.expect(field, value[, fn])
断言响应头中的字段值,可以是字符串或正则表达式。
.expect(function(res) {})
传递一个自定义断言函数。该函数会接收响应对象进行检查。如果检查失败,抛出错误。
request(app)
.get('/')
.expect(hasPreviousAndNextKeys)
.end(done);
function hasPreviousAndNextKeys(res) {
if (!('next' in res.body)) throw new Error("missing next key");
if (!('prev' in res.body)) throw new Error("missing prev key");
}
.end(fn)
执行请求并调用 fn(err, res)。
Cookies
以下是使用 set 和 not cookie 断言的示例:
// 设置 super-test
const request = require('supertest');
const express = require('express');
const cookies = request.cookies;
// 设置 express 测试服务
const app = express();
app.get('/users', function(req, res) {
res.cookie('alpha', 'one', { domain: 'domain.com', path: '/', httpOnly: true });
res.send(200, { name: 'tobi' });
});
// 向服务发送测试请求
request(app)
.get('/users')
.expect('Content-Type', /json/)
.expect('Content-Length', '15')
.expect(200)
// 断言 'alpha' cookie 已设置,并且具有 domain、path 和 httpOnly 选项
.expect(cookies.set({ name: 'alpha', options: ['domain', 'path', 'httponly'] }))
// 断言 'bravo' cookie 未被设置
.expect(cookies.not('set', { name: 'bravo' }))
.end(function(err, res) {
if (err) {
throw err;
}
});
也可以链式调用断言:
cookies.set({/* ... */}).not('set', {/* ... */})
Cookie 断言
函数和方法可以链式调用。
cookies([secret], [asserts])
获取用于 super-test .expect() 方法的断言函数。
参数
secret- 字符串或字符串数组。Cookie 签名密钥。asserts(req, res)- 函数或函数数组。自定义断言失败时应抛出错误。
.set(expects, [assert])
断言 cookie 及其选项已设置。
参数
expects- 对象或对象数组。name- Cookie 的名称(字符串)。options- 可选 的选项数组。
assert- 可选 的“断言为真”修饰符。默认值:true。
.reset(expects, [assert])
断言 cookie 已设置,并且之前已经设置过(在请求头中)。
参数
expects- 对象或对象数组。name- Cookie 的名称(字符串)。
assert- 可选 的“断言为真”修饰符。默认值:true。
.new(expects, [assert])
断言 cookie 已设置,但之前未设置过(不在请求头中)。
参数
expects- 对象或对象数组。name- Cookie 的名称(字符串)。
assert- 可选 的“断言为真”修饰符。默认值:true。
.renew(expects, [assert])
断言 cookie 的 expires 或 max-age 值严格大于给定的值。
参数
expects- 对象或对象数组。name- Cookie 的名称(字符串)。options- 选项对象。需从以下两个选项中选择其一:options.expires- 原始 cookie 的 UTC 到期时间(在请求头中)。options.max-age- 原始 cookie 的存活时间(以秒为单位,也在请求头中)。
assert- 可选 的“断言为真”修饰符。默认值:true。
.contain(expects, [assert])
断言 cookie 已设置,并且包含指定的选项。
如果 cookie 是签名的,则需要先初始化 cookies(secret)。
参数
expects- 对象或对象数组。name- Cookie 的名称(字符串)。value- 可选 的 unsigned cookie 值(字符串)。options- 可选 的选项对象。options.domain- 可选 的域名。options.path- 可选 的路径。options.expires- 可选 的 UTC 到期时间。options.max-age- 可选 的存活时间(以秒为单位)。options.secure- 可选 的安全标志。options.httponly- 可选 的 httpOnly 标志。
assert- 可选 的“断言为真”修饰符。默认值:true。
.not(method, expects)
调用任何 cookie 断言方法,并将“断言为真”修饰符设为 false。
语法糖。
参数
method- 字符串方法名。方法名对应的参数适用于expects。expects- 对象或对象数组。name- Cookie 的名称(字符串)。value- 可选 的 unsigned cookie 值(字符串)。options- 可选 的选项对象。
注释
灵感来自 api-easy,去除了与 vows 的耦合。
许可证
MIT
版本历史
v7.2.22026/01/06v7.2.12026/01/06v7.2.02026/01/06v7.1.42025/07/22v7.1.32025/07/07v7.1.22025/07/07v7.1.12025/05/12v7.1.02025/03/20v7.0.02024/04/24v6.3.42024/01/14v6.3.32022/12/07v6.3.22022/12/02v6.3.12022/10/24v6.3.02022/10/04v6.2.42022/07/01v6.2.32022/04/26v6.2.22022/01/18v6.2.12022/01/11v6.2.02022/01/10v6.1.62021/08/17常见问题
相似工具推荐
openclaw
OpenClaw 是一款专为个人打造的本地化 AI 助手,旨在让你在自己的设备上拥有完全可控的智能伙伴。它打破了传统 AI 助手局限于特定网页或应用的束缚,能够直接接入你日常使用的各类通讯渠道,包括微信、WhatsApp、Telegram、Discord、iMessage 等数十种平台。无论你在哪个聊天软件中发送消息,OpenClaw 都能即时响应,甚至支持在 macOS、iOS 和 Android 设备上进行语音交互,并提供实时的画布渲染功能供你操控。 这款工具主要解决了用户对数据隐私、响应速度以及“始终在线”体验的需求。通过将 AI 部署在本地,用户无需依赖云端服务即可享受快速、私密的智能辅助,真正实现了“你的数据,你做主”。其独特的技术亮点在于强大的网关架构,将控制平面与核心助手分离,确保跨平台通信的流畅性与扩展性。 OpenClaw 非常适合希望构建个性化工作流的技术爱好者、开发者,以及注重隐私保护且不愿被单一生态绑定的普通用户。只要具备基础的终端操作能力(支持 macOS、Linux 及 Windows WSL2),即可通过简单的命令行引导完成部署。如果你渴望拥有一个懂你
stable-diffusion-webui
stable-diffusion-webui 是一个基于 Gradio 构建的网页版操作界面,旨在让用户能够轻松地在本地运行和使用强大的 Stable Diffusion 图像生成模型。它解决了原始模型依赖命令行、操作门槛高且功能分散的痛点,将复杂的 AI 绘图流程整合进一个直观易用的图形化平台。 无论是希望快速上手的普通创作者、需要精细控制画面细节的设计师,还是想要深入探索模型潜力的开发者与研究人员,都能从中获益。其核心亮点在于极高的功能丰富度:不仅支持文生图、图生图、局部重绘(Inpainting)和外绘(Outpainting)等基础模式,还独创了注意力机制调整、提示词矩阵、负向提示词以及“高清修复”等高级功能。此外,它内置了 GFPGAN 和 CodeFormer 等人脸修复工具,支持多种神经网络放大算法,并允许用户通过插件系统无限扩展能力。即使是显存有限的设备,stable-diffusion-webui 也提供了相应的优化选项,让高质量的 AI 艺术创作变得触手可及。
everything-claude-code
everything-claude-code 是一套专为 AI 编程助手(如 Claude Code、Codex、Cursor 等)打造的高性能优化系统。它不仅仅是一组配置文件,而是一个经过长期实战打磨的完整框架,旨在解决 AI 代理在实际开发中面临的效率低下、记忆丢失、安全隐患及缺乏持续学习能力等核心痛点。 通过引入技能模块化、直觉增强、记忆持久化机制以及内置的安全扫描功能,everything-claude-code 能显著提升 AI 在复杂任务中的表现,帮助开发者构建更稳定、更智能的生产级 AI 代理。其独特的“研究优先”开发理念和针对 Token 消耗的优化策略,使得模型响应更快、成本更低,同时有效防御潜在的攻击向量。 这套工具特别适合软件开发者、AI 研究人员以及希望深度定制 AI 工作流的技术团队使用。无论您是在构建大型代码库,还是需要 AI 协助进行安全审计与自动化测试,everything-claude-code 都能提供强大的底层支持。作为一个曾荣获 Anthropic 黑客大奖的开源项目,它融合了多语言支持与丰富的实战钩子(hooks),让 AI 真正成长为懂上
ComfyUI
ComfyUI 是一款功能强大且高度模块化的视觉 AI 引擎,专为设计和执行复杂的 Stable Diffusion 图像生成流程而打造。它摒弃了传统的代码编写模式,采用直观的节点式流程图界面,让用户通过连接不同的功能模块即可构建个性化的生成管线。 这一设计巧妙解决了高级 AI 绘图工作流配置复杂、灵活性不足的痛点。用户无需具备编程背景,也能自由组合模型、调整参数并实时预览效果,轻松实现从基础文生图到多步骤高清修复等各类复杂任务。ComfyUI 拥有极佳的兼容性,不仅支持 Windows、macOS 和 Linux 全平台,还广泛适配 NVIDIA、AMD、Intel 及苹果 Silicon 等多种硬件架构,并率先支持 SDXL、Flux、SD3 等前沿模型。 无论是希望深入探索算法潜力的研究人员和开发者,还是追求极致创作自由度的设计师与资深 AI 绘画爱好者,ComfyUI 都能提供强大的支持。其独特的模块化架构允许社区不断扩展新功能,使其成为当前最灵活、生态最丰富的开源扩散模型工具之一,帮助用户将创意高效转化为现实。
markitdown
MarkItDown 是一款由微软 AutoGen 团队打造的轻量级 Python 工具,专为将各类文件高效转换为 Markdown 格式而设计。它支持 PDF、Word、Excel、PPT、图片(含 OCR)、音频(含语音转录)、HTML 乃至 YouTube 链接等多种格式的解析,能够精准提取文档中的标题、列表、表格和链接等关键结构信息。 在人工智能应用日益普及的今天,大语言模型(LLM)虽擅长处理文本,却难以直接读取复杂的二进制办公文档。MarkItDown 恰好解决了这一痛点,它将非结构化或半结构化的文件转化为模型“原生理解”且 Token 效率极高的 Markdown 格式,成为连接本地文件与 AI 分析 pipeline 的理想桥梁。此外,它还提供了 MCP(模型上下文协议)服务器,可无缝集成到 Claude Desktop 等 LLM 应用中。 这款工具特别适合开发者、数据科学家及 AI 研究人员使用,尤其是那些需要构建文档检索增强生成(RAG)系统、进行批量文本分析或希望让 AI 助手直接“阅读”本地文件的用户。虽然生成的内容也具备一定可读性,但其核心优势在于为机器
LLMs-from-scratch
LLMs-from-scratch 是一个基于 PyTorch 的开源教育项目,旨在引导用户从零开始一步步构建一个类似 ChatGPT 的大型语言模型(LLM)。它不仅是同名技术著作的官方代码库,更提供了一套完整的实践方案,涵盖模型开发、预训练及微调的全过程。 该项目主要解决了大模型领域“黑盒化”的学习痛点。许多开发者虽能调用现成模型,却难以深入理解其内部架构与训练机制。通过亲手编写每一行核心代码,用户能够透彻掌握 Transformer 架构、注意力机制等关键原理,从而真正理解大模型是如何“思考”的。此外,项目还包含了加载大型预训练权重进行微调的代码,帮助用户将理论知识延伸至实际应用。 LLMs-from-scratch 特别适合希望深入底层原理的 AI 开发者、研究人员以及计算机专业的学生。对于不满足于仅使用 API,而是渴望探究模型构建细节的技术人员而言,这是极佳的学习资源。其独特的技术亮点在于“循序渐进”的教学设计:将复杂的系统工程拆解为清晰的步骤,配合详细的图表与示例,让构建一个虽小但功能完备的大模型变得触手可及。无论你是想夯实理论基础,还是为未来研发更大规模的模型做准备