@chamvi/test-kit

中文文档
0.8.0发布于 2026/11/09Apache-2.0TypeScriptES Module零依赖构建来源已验证近 30 天下载 3083

Test helpers for chamvi: a controllable clock, the store and workspace contract suites, a git fixture and a fake GitHub.

原始使用文档
文档目录9 节
  1. Installation
  2. Usage
  3. Scripted models
  4. Repository contract
  5. Controllable clock
  6. Workspace contract
  7. Fake GitHub
  8. API
  9. License

@chamvi/test-kit

@chamvi/test-kit

Test helpers for chamvi: a controllable clock, the repository and workspace contract suites, a git fixture and an in-process fake GitHub.

npm version CI License


Installation

npm install --save-dev @chamvi/test-kit @chamvi/core ai vitest

@chamvi/core, ai (v7) and vitest are peer dependencies. The workspace contract takes any IWorkspace of @chamvi/sandbox (typed structurally as ContractWorkspace, so the kit does not depend on @chamvi/sandbox).

Usage

Scripted models

mockModel(responses) provides one scripted AI SDK model for generation and streaming. Each MockResponse contains text or tool-call parts and optional token usage. textModel(text), approvalModel(toolName, input) and failingModel() cover common test flows.

import { textModel } from '@chamvi/test-kit';

const model = textModel('done');

Repository contract

Every IStore implementation proves itself with the shared Vitest suite. The factory gets a fresh ControllableClock per test and must use it for every expiry decision:

import { createMemoryStore } from '@chamvi/core';
import { describeRepositoryContract } from '@chamvi/test-kit';

describeRepositoryContract((clock) => createMemoryStore({ clock }));

Controllable clock

ControllableClock implements IClock and only moves when told to, so engine timeouts, claim leases and approval expiry are tested without real timers:

import { createMemoryStore, Engine } from '@chamvi/core';
import { ControllableClock } from '@chamvi/test-kit';

const clock = new ControllableClock();
const store = createMemoryStore({ clock });
const engine = new Engine({ store, agents: [], clock });

clock.advance(60_000); // fires every timer due within the next minute, in order

Workspace contract

Every sandbox provider proves its workspaces with the shared Vitest suite: argv exec and exit codes, stdin, cwd and path escapes, the 64 KiB output caps under a flood, process-group kills on timeout (a backgrounded grandchild included), abort, UTF-8 files and their size cap, and dispose during an exec. It runs real processes with short real timeouts, so the factory returns a fresh, repo-less workspace per test (the suite disposes it). With find (a second provider instance's, like a restarted process) it also drops a workspace's handle and expects find to return it with its files:

import { createLocalSandbox } from '@chamvi/sandbox-local';
import { describeWorkspaceContract } from '@chamvi/test-kit';

const provider = createLocalSandbox();
describeWorkspaceContract('local', (input) => provider.create({ runId: input?.runId ?? 'contract' }), {
    find: (runId) => createLocalSandbox().find(runId),
});

createGitFixture(files) creates a temporary git repository with one commit of files on branch main, tagged v1, and returns { path, url, commit, cleanup }; url is a file:// URL for a manager with allowFileRepos: true.

Fake GitHub

createFakeGithub({ appId, slug?, clock }) is an in-process GitHub for createGithubApp({ fetch }) from @chamvi/github: it generates an RSA key pair, checks App JWTs and installation tokens on clock, serves issues, comments, labels, pull requests, contents and releases from mutable maps, and never touches the network:

import { createGithubApp } from '@chamvi/github';
import { ControllableClock, createFakeGithub } from '@chamvi/test-kit';

const clock = new ControllableClock(new Date('2026-10-21T09:00:00Z'));
const fake = createFakeGithub({ appId: '123', slug: 'my-app', clock });
const gh = createGithubApp({
    appId: '123',
    privateKey: fake.privateKey,
    webhookSecret: 'webhook-secret',
    slug: 'my-app',
    clock,
    fetch: fake.fetch,
});

fake.issues.set('octo/demo#7', { number: 7, title: 'Bug', state: 'open' });
fake.failNext('POST', '/repos/octo/demo/issues/7/comments', 502); // one injected failure

route(method, path, handler) adds or overrides a route (:name is one segment, *name the rest), requests records every request, tokenInstallations the installation of every issued token. A request whose signal aborts, also while a route handler is pending, rejects with the signal's reason, as Node's fetch does.

API

ExportKindPurpose
ControllableClockclassIClock that advances only via advance(ms); starts at new Date(0) unless given a date
describeRepositoryContractfunctionVitest suite every IStore implementation must pass
describeWorkspaceContractfunctionVitest suite every sandbox provider's IWorkspace must pass
createGitFixturefunctionA temporary git repository with one commit (branch main, tag v1)
createFakeGithubfunctionAn in-process GitHub (App JWTs, installation tokens, repository routes) for createGithubApp({ fetch })

Types: ContractWorkspace, WorkspaceContractFactory, GitFixture, FakeGithub, FakeGithubOptions, FakeRequest, FakeRouteInput, FakeRouteResult, FakeRouteHandler, JwtClaims.

License

Made with 💚

Published under Apache License 2.0.

版本与发布记录

@chamvi/test-kit 共发布 15 个版本,首次发布于 2026/10/25;过去 12 个月发布了 15 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.8.0latest2026/11/09今天
0.7.32026/11/063 天前
0.7.22026/11/053 天前
0.7.12026/11/054 天前
0.7.02026/11/045 天前
0.6.12026/11/045 天前

关于 @chamvi/test-kit 的常见问题

@chamvi/test-kit 是什么?

Test helpers for chamvi: a controllable clock, the store and workspace contract suites, a git fixture and a fake GitHub.

如何安装 @chamvi/test-kit?

在项目目录运行 npm install @chamvi/test-kit,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:ai(^7)、vitest(^5)、@chamvi/core(^0.8.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@chamvi/test-kit 支持 TypeScript 吗?

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

@chamvi/test-kit 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@chamvi/test-kit 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=26.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@chamvi/test-kit 可以商用吗?

@chamvi/test-kit 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@chamvi/test-kit 的下载量有多少?

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

@chamvi/test-kit 还在维护吗?

最新版本 0.8.0 发布于 2026/11/09(今天);至今共发布 15 个版本,其中过去 12 个月发布了 15 个;首次发布于 2026/10/25。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。