@archont561/bun-test-utils (英语)
通用测试展期 Bun 测试跑道它给 bun test Playwright 风格的定着: 已打入, 可注入的数值, 明确使用 test.extend(),缩放到一个会话,一个文件,或者一个单一的测试,并按严格的倒置顺序拆解. 在同一跑道上,它增加了由行为驱动的情景,基于属性的测试,快照测试,HTTP记录/重播磁带,以及DOM和浏览器测试.
- 联合国 https://archont561.github.io/bun-test-utils/ (中文(简体) )
- 资料来源和问题: https://github.com/Archont561/bun-test-utils (中文(简体) )
- 更改日志和发布 : https://github.com/Archont561/bun-test-utils/releases (中文(简体) )
安装
bun add -d @archont561/bun-test-utils
bunx test-utils init
init 将软件包的预装添加到 bunfig.toml (单位:千美元)[test].preload) (中文(简体) ). 预装只安装了跑道宽的被拆卸的钩子. 它不装入固定装置。 Fixtures来自您导入的模块,如下所述.
需要1号机舱或稍后.
快开始
将您的工程需要的固定装置编成一个模块,然后导入所组成的 test 输入每个测试文件.
// tests/test.ts
import { test as base } from "@archont561/bun-test-utils";
export const test = base.extend({
database: {
scope: "file",
setup: async (use) => {
const database = await createDatabase();
await use(database);
await database.close(); // runs after the last test in the file
},
},
user: {
setup: async (use, { database }) => {
await use(await database.insertUser({ name: "Ada" }));
},
},
});
// tests/user.test.ts
import { expect } from "@archont561/bun-test-utils";
import { test } from "./test";
test("finds the user", async ({ database, user }) => {
expect(await database.find(user.id)).toMatchObject({ name: "Ada" });
});
运行套房与 bun test。 。 。 .
固定器通过在 setup引擎首先建立依赖关系,最后将其撕裂。 之后的一切 await use(value) 是固定的撕裂, 它运行 即使测试失败.
固定模型
| 概念 | 这是什么意思 |
|---|---|
| 组成 | test.extend({ ... }) 返回一个新的 test 包括你的固定装置。 只有被导入的链条才提供固定装置。 文件树上没有发现任何东西. |
| 范围 | "session" (每跑一次), "file" (每个测试文件), "test" (默认,每测试一次). |
| 寿命 | 固定装置可能只取决于寿命相等或更长的固定装置。 在任何断言进行之前,一旦宣布测试,就会报告违反情况. |
| 减员 | 严格LIFO:一个固定的被撕毁的状态在它所依赖的被撕毁的东西开始之前完成. |
| 覆盖 | Fixtures共享一个命名空间. 后用同名定义取代了更早的定义,包括内置. |
内建能力
内置能力是根部的固定装置 test 上下文,所以你以同样的方式要求它们:
import { expect, test } from "@archont561/bun-test-utils";
test("reads the environment", async ({ env, tmpdir }) => {
env.set("APP_MODE", "test");
tmpdir.write("mode.txt", env.get("APP_MODE")!);
expect(tmpdir.read("mode.txt")).toBe("test");
});
| 区域 | 固定设备 | 页:1 |
|---|---|---|
| 标准 | tmpdir, (中文(简体) ), env, (中文(简体) ), stdio, (中文(简体) ), clock, (中文(简体) ), seed, (中文(简体) ), networkGuard | 孤立的临时目录,沙箱环境变量,捕获输出,控制时间和随机性,被屏蔽出行 fetch 除非允许. |
| 管理部 | window, (中文(简体) ), document, (中文(简体) ), page | 记忆中的DOM 通过快乐的地盘。 要求数 happy-dom。 。 。 . |
| Web( 无论是后端) | webPage | 默认的幸福生活 设定 BUN_TEST_UTILS_WEB_ENV=browser 在真实的 Playwright 页面上运行相同的测试. |
| 浏览器 | browser, (中文(简体) ), browserContext, (中文(简体) ), browserPage, (中文(简体) ), browserHttpMock | 剧作家克罗米姆,无头. 要求数 playwright 和已安装的浏览器。 实验. |
| 服务器和 HTTP | testServer, (中文(简体) ), serverUrl, (中文(简体) ), httpMock | 麻风 Bun.serve 服务器,以及类似MSW的获取处理器. |
| 磁盘 | cassette | 获取或记录回调结果 cassette(fn),使用明确的记录/回放控制,并记录和回放HTTP流量. |
| 抓图 | snapshot | 比较存储快照的值和文件 . |
基于财产的测试
test.prop 以 fast-check每个样本都有自己的试验镜固定装置,在隔离中被建造和拆除.
import { expect, test } from "@archont561/bun-test-utils";
test.prop(
"addition is commutative",
(fc) => ({ a: fc.integer(), b: fc.integer() }),
async (_fixtures, { a, b }) => {
expect(a + b).toBe(b + a);
},
{ numRuns: 100 },
);
要求数 bun add -d fast-check。 。 。 .
假设
test.scenario 从流利处构建一个测试 given, (中文(简体) ), when,以及 then 步骤。 返回值从 given 财务报告和审定财务报表 when 并配有固定装置.
import { test } from "@archont561/bun-test-utils";
test
.scenario("creates a user")
.given("a name", () => ({ name: "Ada" }))
.when("the user is created", ({ name }) => ({ user: { id: 1, name } }))
.then("the id is assigned", ({ user, expect }) => {
expect(user.id).toBeDefined();
});
要求数 bun add -d @aboviq/bun-test-cucumber假设是实验性的.
抓图
import { expect, test } from "@archont561/bun-test-utils";
test("renders the widget", async ({ snapshot }) => {
const widget = await snapshot(
async () => render({ name: "widget", count: 3 }),
"widget",
);
expect(widget.count).toBe(3);
});
可调用 snapshot(fn, name) 运行和等待 fn 每一次,按规定明确的名称匹配结果,并返回同样的结果。 它是一个断言包,而不是缓存:它从不按在函数正文上. 若为 fn 扔出或拒绝,其错误被传播,没有写快照。 使用 snapshot.match(value, name?) 财务报告和审定财务报表 snapshot.matchFile(path, name?) 直接值和文件不变.
第一次运行写 __snapshots__/ 在测试文件旁边。 提交目录,所以在审查中显示对快照的更改 .
HTTP 模拟和磁带
import { expect, test } from "@archont561/bun-test-utils";
test("loads the user", async ({ httpMock }) => {
httpMock.get("/api/user", () => Response.json({ name: "Ada" }));
const user = await fetch("https://app.test/api/user").then((r) => r.json());
expect(user).toEqual({ name: "Ada" });
});
cassette(fn) 是获取或记录回调表; 明确 cassette.record 财务报告和审定财务报表 cassette.replay 保持准确的控制。 本地默认 auto 模式,缺少带有可见警告的回调源记录并替换其已过时的侧车条目; CI,明确重放,和序列器-版本不匹配仍然严格. 使用 cassette.addSerializer(...) 用于测试特定召回值类型,或一次通过 /vcr 子路径。 一个测试的HTTP流量记录在下面 __cassettes__/ 第一次运行,然后在没有网络访问的情况下重播.
可选同伴
只有当您使用需要的能力时, 才会安装对等点 。 核心固定引擎在没有任何固定引擎的情况下起作用.
| 能力 | 端点 |
|---|---|
test.prop, (中文(简体) ), test.scenario.prop | fast-check |
test.scenario | @aboviq/bun-test-cucumber |
window, (中文(简体) ), document, (中文(简体) ), page, (中文(简体) ), webPage (DOM后门) | happy-dom |
browser*, (中文(简体) ), webPage (浏览器后端) | playwright,加上浏览器二进制: bunx playwright install chromium |
fast-check 已公布的申报类型也提供了参考。 与 skipLibCheck: false,TypeScript即使只使用非财产性API,也需要安装. 与 skipLibCheck: true,普通的输入类型检查没有它.
共享帮助
被打的帮助者生活在四个子路径上. 它们只输出定义和类型,从不输出跑道或固定装置.
import { defineArbitraries } from "@archont561/bun-test-utils/pbt";
import { givenStep, whenStep, thenStep } from "@archont561/bun-test-utils/bdd";
import { createSnapshotSerializer } from "@archont561/bun-test-utils/snap";
import {
defineCallbackSerializer,
registerCallbackSerializer,
unregisterCallbackSerializer,
} from "@archont561/bun-test-utils/vcr";
/pbt数字 :defineArbitraries可重复使用的快速检查任意记录./bdd数字 :givenStep, (中文(简体) ),whenStep, (中文(简体) ),thenStep可重复使用的情景步骤./snap:注册并取消注册全局快照序列器,通常来自预装./vcr数字 :defineCallbackSerializer可逆磁带价值序列器,加registerCallbackSerializer和基于身份的unregisterCallbackSerializer用于全过程共享的序列器(通常来自预装)。 当地固定cassette.addSerializer现仍保留,并优先于全球登记.
全球登记一直到未登记为止. registerCallbackSerializer 返回所提供的序列器; unregisterCallbackSerializer(serializer) 删除该具体对象的每个登记,并返回是否删除一个或多个.
例如,一个Bun测试预装可以让每个软件都使用一个可逆类型
磁带固定不重复 cassette.addSerializer(...)数字 :
// test-serializers.ts, listed in bunfig.toml [test].preload
import {
defineCallbackSerializer,
registerCallbackSerializer,
} from "@archont561/bun-test-utils/vcr";
class Token {
constructor(readonly value: string) {}
}
registerCallbackSerializer(
defineCallbackSerializer<Token>({
name: "token",
version: 1,
test: (value) => value instanceof Token,
serialize: (token) => ({ value: token.value }),
deserialize: (data) => new Token((data as { value: string }).value),
}),
);
Fixture - 本地序列器仍然能战胜这个全项目的默认. 见 记录 HTTP 磁带 用于版本和清理规则.
稳定和平台
- 平稳, 以下语义版本 : 固定引擎、标准、DOM、快照和财产测试能力以及最低磁带合同(可调用)
cassette(fn),明确record编号 :replay,固定-局部addSerializer, (中文(简体) ),/vcr全局序列器注册,以及用大写法加全URL精确的HTTP匹配. - 实验,小版本可能改变: 浏览器能力和 BDD 方案.
- 尚未冻结 : 磁盘上的磁带和快照文件格式,以及页眉-红外线帮助器.
- 不在此发布 : a 相匹配的磁带DSL、可配置的编辑、磁带迁移工具、数据库和文件系统-散装箱固定装置以及工人范围固定装置.
- 平台: Linux 和 macOS (英语). 视窗支持计划.
完全稳定性和相容性合同载于 API 参考。 。 。 .
许可证
许可证根据 MIT 许可证 或 Apache 许可证 2.0随便你.