@yss123/cage-testkit 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -9
- package/dist/derived-diagnostics.d.ts +98 -0
- package/dist/derived-diagnostics.js +73 -0
- package/dist/derived-diagnostics.js.map +1 -0
- package/dist/derived.d.ts +19 -5
- package/dist/derived.js +174 -45
- package/dist/derived.js.map +1 -1
- package/dist/embedded-exit.d.ts +14 -0
- package/dist/embedded-exit.js +30 -0
- package/dist/embedded-exit.js.map +1 -0
- package/dist/env.d.ts +20 -1
- package/dist/env.js +51 -0
- package/dist/env.js.map +1 -1
- package/dist/fakes.d.ts +31 -2
- package/dist/fakes.js +42 -2
- package/dist/fakes.js.map +1 -1
- package/dist/global-setup.d.ts +4 -0
- package/dist/global-setup.js +9 -0
- package/dist/global-setup.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/pg.d.ts +18 -0
- package/dist/pg.js +83 -12
- package/dist/pg.js.map +1 -1
- package/dist/session.d.ts +9 -0
- package/dist/session.js +7 -0
- package/dist/session.js.map +1 -1
- package/package.json +8 -7
package/README.md
CHANGED
|
@@ -1,19 +1,87 @@
|
|
|
1
1
|
# @yss123/cage-testkit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Cage 测试工具包。提供纯 handler 的内存假依赖、真实 PostgreSQL 集成环境、测试用户/授权、手动驱动 outbox,以及声明派生的权限、状态和不变量测试。属于开发依赖,不用于生产业务写入或日常数据库管理。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## 安装
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
需要 Node.js 24+;与 kernel 等框架包保持同版本:
|
|
8
8
|
|
|
9
9
|
```powershell
|
|
10
|
-
pnpm add -D @yss123/cage-testkit
|
|
10
|
+
pnpm add -D @yss123/cage-testkit vitest
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
domain 应已安装 Cage 内核,并从根入口导出组织模型 `@yss123/cage-admin/domain`。
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
- [框架源码与范例](https://github.com/shunshunyue/cage)
|
|
17
|
-
- [问题反馈](https://github.com/shunshunyue/cage/issues)
|
|
15
|
+
## 配置真实数据库测试
|
|
18
16
|
|
|
19
|
-
|
|
17
|
+
在执行测试的包中创建 `vitest.config.ts`:
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
/** 测试集群由 globalSetup 管理;每个 createTestEnv 仍创建独立临时库。 */
|
|
21
|
+
import { defineConfig } from 'vitest/config';
|
|
22
|
+
|
|
23
|
+
export default defineConfig({
|
|
24
|
+
test: {
|
|
25
|
+
globalSetup: ['@yss123/cage-testkit/global-setup'],
|
|
26
|
+
testTimeout: 60_000,
|
|
27
|
+
hookTimeout: 120_000,
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
可通过 `CAGE_TEST_DATABASE_URL` 提供专用测试集群的管理员连接,需具备创建数据库与角色权限;否则 globalSetup 尝试启动内嵌 PostgreSQL。测试会创建角色、临时数据库和夹具,必须使用可丢弃的测试集群,不能指向生产环境。不要在输出或源码中保存连接凭据。
|
|
33
|
+
|
|
34
|
+
下面是已有 `Note.create` 业务的测试,假设测试文件与 domain 根 `index.ts` 位于同一目录;若目录不同,请调整相对导入:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
/** 用完整内核流水线验证未授予能力时拒绝写入,而非只调用 handler。 */
|
|
38
|
+
import { afterAll, beforeAll, expect, test } from 'vitest';
|
|
39
|
+
import { createTestEnv, type TestEnv } from '@yss123/cage-testkit';
|
|
40
|
+
import * as domain from './index.js';
|
|
41
|
+
|
|
42
|
+
let env: TestEnv;
|
|
43
|
+
|
|
44
|
+
beforeAll(async () => {
|
|
45
|
+
env = await createTestEnv({ domain });
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
afterAll(async () => {
|
|
49
|
+
if (env) await env.close();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('没有创建便笺能力时拒绝创建', async () => {
|
|
53
|
+
const user = await env.user({ caps: [], scopes: { Note: 'all' } });
|
|
54
|
+
const result = await env.callAs(await user.ctx(), 'Note.create', {
|
|
55
|
+
title: '无权限的写入',
|
|
56
|
+
});
|
|
57
|
+
expect(result.ok).toBe(false);
|
|
58
|
+
if (!result.ok) expect(result.code).toBe('FORBIDDEN');
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
执行 `pnpm exec vitest run`。默认按当前声明建新库,不证明历史数据升级正确;验证迁移时向 `createTestEnv({ domain, migrations })` 传实际迁移文件,并另行准备升级数据。
|
|
63
|
+
|
|
64
|
+
## 选择测试层次
|
|
65
|
+
|
|
66
|
+
| 入口 | 用途与边界 |
|
|
67
|
+
| --- | --- |
|
|
68
|
+
| `fakeRepo`、`draftOf`、`handlerCtx` | 纯 handler 计算测试,跳过权限、状态、数据库、审计和事务 |
|
|
69
|
+
| `sampleRecord`、`sampleValue` | 按字段形状构造样例,不保证满足业务不变量 |
|
|
70
|
+
| `arbitraryOf`、`arbitrarySnapshot` | fast-check 候选数据,用于探索输入和不变量边界 |
|
|
71
|
+
| `createTestEnv` | 独立 PostgreSQL 数据库、真实内核、安全读侧和测试身份 |
|
|
72
|
+
| `env.user`、`env.actorWithout`、`env.callAs` | 明确能力/范围后执行完整命令流水线 |
|
|
73
|
+
| `env.insert`、`env.seedFor` | 绕过命令准备夹具,仅测试可用,不能当业务写入示例 |
|
|
74
|
+
| `env.drain`、`env.audit` | 驱动当前可领取 outbox 与检查审计;未来重试/死信不等于已完成 |
|
|
75
|
+
| `derived`、`SKIP`、`DerivedTestError` | 执行声明派生测试并区分跳过与失败 |
|
|
76
|
+
| `@yss123/cage-testkit/global-setup` | 整轮 Vitest 的测试集群启停 |
|
|
77
|
+
| `@yss123/cage-testkit/pg` | 内嵌 PostgreSQL 与测试连接辅助工具 |
|
|
78
|
+
|
|
79
|
+
`env.close()` 关闭连接并尝试删除本次临时库,必须放在 teardown。外部测试集群不会由 globalSetup 停止。fake 成功、派生测试通过和真实第三方联调是不同证据;跳过项需要单独报告,不能计为通过。
|
|
80
|
+
|
|
81
|
+
## 文档
|
|
82
|
+
|
|
83
|
+
- [业务开发与验证流程](https://github.com/shunshunyue/cage/blob/main/docs/ai/workflow.md)
|
|
84
|
+
- [采购业务测试示例](https://github.com/shunshunyue/cage/blob/main/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.test.ts)
|
|
85
|
+
- [架构与权限模型](https://github.com/shunshunyue/cage/blob/main/docs/ai/architecture.md)
|
|
86
|
+
|
|
87
|
+
源码与反馈:[GitHub](https://github.com/shunshunyue/cage)。许可证:[MIT](https://github.com/shunshunyue/cage/blob/main/LICENSE)。
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 声明派生测试的可复现随机源与失败报告协议。
|
|
3
|
+
* 固定种子用于命令选择和测试输入,失败区分夹具准备与业务执行,报告递归隐藏敏感和秘密字段。
|
|
4
|
+
* 最短失败前缀是本轮观察所得,不是对任意程序进行全局缩减后的最小反例。
|
|
5
|
+
*/
|
|
6
|
+
import type { AnyAggregate } from '@yss123/cage-kernel';
|
|
7
|
+
import type { TestEnv } from './env.js';
|
|
8
|
+
/**
|
|
9
|
+
* 夹具回调参数:env 是真实测试环境,aggregate 是当前聚合,run 为本轮序号。
|
|
10
|
+
* seed/random/uuid 用于复现候选数据,回调应返回已持久化记录,不能只返回一个未落库对象。
|
|
11
|
+
*/
|
|
12
|
+
export interface DerivedFixtureContext {
|
|
13
|
+
env: TestEnv;
|
|
14
|
+
aggregate: AnyAggregate;
|
|
15
|
+
run: number;
|
|
16
|
+
seed: number;
|
|
17
|
+
random(): number;
|
|
18
|
+
uuid(): string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 派生性质测试选项:seed 控制可复现选择,fixtures 按聚合名提供对象字段或构造函数。
|
|
22
|
+
* 夹具主要用于不变量序列,不能据此假设所有其他派生测试都已获得合法业务输入。
|
|
23
|
+
*/
|
|
24
|
+
export interface DerivedOptions {
|
|
25
|
+
/** uint32 随机种子;报告会保留实际使用的值,默认固定为 20261103。 */
|
|
26
|
+
seed?: number;
|
|
27
|
+
/** 对象作为 env.insert 的字段;函数通过命令/测试工具构造记录并返回已持久化的快照。 */
|
|
28
|
+
fixtures?: Record<string, Record<string, unknown> | ((context: DerivedFixtureContext) => Record<string, any> | Promise<Record<string, any>>)>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 一次命令尝试的证据:step 为序列位置,capability 为目标,input 应已脱敏。
|
|
32
|
+
* result 记录成功或标准/业务错误码,不把原始异常或响应正文存入轨迹。
|
|
33
|
+
*/
|
|
34
|
+
export interface DerivedCommandTrace {
|
|
35
|
+
step: number;
|
|
36
|
+
capability: string;
|
|
37
|
+
input: unknown;
|
|
38
|
+
result: {
|
|
39
|
+
ok: boolean;
|
|
40
|
+
code?: string;
|
|
41
|
+
domainCode?: string;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* 单轮不变量测试轨迹:initial 为初始快照,preparation 为准备命令,commands 为执行序列。
|
|
46
|
+
* phase 区分非法夹具与执行缺陷;failedInvariants 保存失败规则名,minimalPrefix 保存观察到失败为止的命令。
|
|
47
|
+
*/
|
|
48
|
+
export interface DerivedRunTrace {
|
|
49
|
+
aggregate: string;
|
|
50
|
+
seed: number;
|
|
51
|
+
run: number;
|
|
52
|
+
phase: 'fixture' | 'execution';
|
|
53
|
+
initial: unknown;
|
|
54
|
+
preparation: DerivedCommandTrace[];
|
|
55
|
+
commands: DerivedCommandTrace[];
|
|
56
|
+
failedInvariants: string[];
|
|
57
|
+
/** 在本轮观察到第一个失败时立即停止,保存截至该步的最短已观察失败前缀。 */
|
|
58
|
+
minimalPrefix: DerivedCommandTrace[];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* 不变量测试汇总,steps 是实际命令尝试数,violations 是发现的问题,seed/traces 供重现排查。
|
|
62
|
+
* 没有 violation 不意味着穷尽全部命令排列,需结合实际执行步数与业务定向用例。
|
|
63
|
+
*/
|
|
64
|
+
export interface DerivedInvariantResult {
|
|
65
|
+
steps: number;
|
|
66
|
+
violations: string[];
|
|
67
|
+
seed: number;
|
|
68
|
+
traces: DerivedRunTrace[];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 携带结构化失败轨迹的测试异常,统一标识为 CAGE-TEST-002。
|
|
72
|
+
* 构造前由调用方脱敏 detail,消息序列化同一轨迹,phase/aggregate/seed 提供快速定位字段。
|
|
73
|
+
*/
|
|
74
|
+
export declare class DerivedTestError extends Error {
|
|
75
|
+
readonly detail: DerivedRunTrace;
|
|
76
|
+
readonly code = "CAGE-TEST-002";
|
|
77
|
+
readonly phase: 'fixture' | 'execution';
|
|
78
|
+
readonly aggregate: string;
|
|
79
|
+
readonly seed: number;
|
|
80
|
+
constructor(detail: DerivedRunTrace);
|
|
81
|
+
}
|
|
82
|
+
/** 固定算法,避免 Math.random 的隐式全局状态使命令序列无法重放。 */
|
|
83
|
+
/**
|
|
84
|
+
* 返回独立闭包随机序列,同一 uint32 种子按固定算法产生相同 [0,1) 值。
|
|
85
|
+
* 仅用于测试可复现性,不具备密码学安全性,不能生成生产凭据。
|
|
86
|
+
*/
|
|
87
|
+
export declare function seededRandom(seed: number): () => number;
|
|
88
|
+
/**
|
|
89
|
+
* 从给定随机源构造符合版本/变体位形状的 UUID,消耗固定数量的随机值。
|
|
90
|
+
* 固定种子下可重复,不保证跨独立重放唯一;用于隔离测试数据而非生产标识分配。
|
|
91
|
+
*/
|
|
92
|
+
export declare function seededUuid(random: () => number): string;
|
|
93
|
+
/** 诊断不使用操作者的明文能力;敏感/隐藏字段在任意对象深度及数组内一律遮盖。 */
|
|
94
|
+
/**
|
|
95
|
+
* 从聚合声明递归收集敏感/隐藏字段名,并结合固定秘密字段名生成报告脱敏函数。
|
|
96
|
+
* 与操作者的 unmask 权限无关,数组与嵌套对象统一遮盖,避免失败证据泄露明文。
|
|
97
|
+
*/
|
|
98
|
+
export declare function derivedRedactor(aggregates: readonly AnyAggregate[]): (value: unknown) => unknown;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 携带结构化失败轨迹的测试异常,统一标识为 CAGE-TEST-002。
|
|
3
|
+
* 构造前由调用方脱敏 detail,消息序列化同一轨迹,phase/aggregate/seed 提供快速定位字段。
|
|
4
|
+
*/
|
|
5
|
+
export class DerivedTestError extends Error {
|
|
6
|
+
detail;
|
|
7
|
+
code = 'CAGE-TEST-002';
|
|
8
|
+
phase;
|
|
9
|
+
aggregate;
|
|
10
|
+
seed;
|
|
11
|
+
constructor(detail) {
|
|
12
|
+
super(`[CAGE-TEST-002] 派生测试${detail.phase === 'fixture' ? '初始夹具非法' : '执行失败'}:${JSON.stringify(detail)}`);
|
|
13
|
+
this.detail = detail;
|
|
14
|
+
this.name = 'DerivedTestError';
|
|
15
|
+
this.phase = detail.phase;
|
|
16
|
+
this.aggregate = detail.aggregate;
|
|
17
|
+
this.seed = detail.seed;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** 固定算法,避免 Math.random 的隐式全局状态使命令序列无法重放。 */
|
|
21
|
+
/**
|
|
22
|
+
* 返回独立闭包随机序列,同一 uint32 种子按固定算法产生相同 [0,1) 值。
|
|
23
|
+
* 仅用于测试可复现性,不具备密码学安全性,不能生成生产凭据。
|
|
24
|
+
*/
|
|
25
|
+
export function seededRandom(seed) {
|
|
26
|
+
let state = seed >>> 0;
|
|
27
|
+
return () => {
|
|
28
|
+
state += 0x6d2b79f5;
|
|
29
|
+
let value = Math.imul(state ^ (state >>> 15), 1 | state);
|
|
30
|
+
value ^= value + Math.imul(value ^ (value >>> 7), 61 | value);
|
|
31
|
+
return ((value ^ (value >>> 14)) >>> 0) / 4294967296;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 从给定随机源构造符合版本/变体位形状的 UUID,消耗固定数量的随机值。
|
|
36
|
+
* 固定种子下可重复,不保证跨独立重放唯一;用于隔离测试数据而非生产标识分配。
|
|
37
|
+
*/
|
|
38
|
+
export function seededUuid(random) {
|
|
39
|
+
const bytes = Array.from({ length: 16 }, () => Math.floor(random() * 256));
|
|
40
|
+
bytes[6] = (bytes[6] & 15) | 64;
|
|
41
|
+
bytes[8] = (bytes[8] & 63) | 128;
|
|
42
|
+
const hex = bytes.map((byte) => byte.toString(16).padStart(2, '0')).join('');
|
|
43
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
44
|
+
}
|
|
45
|
+
/** 诊断不使用操作者的明文能力;敏感/隐藏字段在任意对象深度及数组内一律遮盖。 */
|
|
46
|
+
/**
|
|
47
|
+
* 从聚合声明递归收集敏感/隐藏字段名,并结合固定秘密字段名生成报告脱敏函数。
|
|
48
|
+
* 与操作者的 unmask 权限无关,数组与嵌套对象统一遮盖,避免失败证据泄露明文。
|
|
49
|
+
*/
|
|
50
|
+
export function derivedRedactor(aggregates) {
|
|
51
|
+
const sensitive = new Set(['password', 'passwordhash', 'token', 'secret', 'authorization', 'cookie']);
|
|
52
|
+
const visitFields = (fields) => {
|
|
53
|
+
for (const [name, field] of Object.entries(fields)) {
|
|
54
|
+
if (field.sensitiveKind || field.isHidden)
|
|
55
|
+
sensitive.add(name.toLowerCase());
|
|
56
|
+
if (field.shape)
|
|
57
|
+
visitFields(field.shape);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
for (const aggregate of aggregates)
|
|
61
|
+
visitFields(aggregate.fields);
|
|
62
|
+
const redact = (value) => {
|
|
63
|
+
if (Array.isArray(value))
|
|
64
|
+
return value.map(redact);
|
|
65
|
+
if (value === null || typeof value !== 'object')
|
|
66
|
+
return typeof value === 'bigint' ? value.toString() : value;
|
|
67
|
+
if (value instanceof Date)
|
|
68
|
+
return value.toISOString();
|
|
69
|
+
return Object.fromEntries(Object.entries(value).map(([name, entry]) => [name, sensitive.has(name.toLowerCase()) ? '[REDACTED]' : redact(entry)]));
|
|
70
|
+
};
|
|
71
|
+
return redact;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=derived-diagnostics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derived-diagnostics.js","sourceRoot":"","sources":["../src/derived-diagnostics.ts"],"names":[],"mappings":"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"}
|
package/dist/derived.d.ts
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import { type CallResult, type TestEnv } from './env.js';
|
|
2
|
+
import { type DerivedInvariantResult, type DerivedOptions } from './derived-diagnostics.js';
|
|
3
|
+
export { DerivedTestError, type DerivedOptions, type DerivedFixtureContext, type DerivedCommandTrace, type DerivedRunTrace, type DerivedInvariantResult } from './derived-diagnostics.js';
|
|
4
|
+
/**
|
|
5
|
+
* 派生检查未执行到目标性质时的显式返回标识,用于由测试调用方记录跳过。
|
|
6
|
+
*/
|
|
2
7
|
export type Skip = 'skip';
|
|
8
|
+
/**
|
|
9
|
+
* 统一跳过值,与成功断言结果区分;调用方须保留跳过计数和原因上下文。
|
|
10
|
+
*/
|
|
3
11
|
export declare const SKIP: Skip;
|
|
12
|
+
/**
|
|
13
|
+
* 派生检查句柄,先 setup 再调用检查,结束时 teardown。
|
|
14
|
+
* 各方法返回可断言的观察结果或 SKIP;env 供项目定向检查复用,不能在 setup 前使用。
|
|
15
|
+
*/
|
|
4
16
|
export interface Derived {
|
|
5
17
|
env(): TestEnv;
|
|
6
18
|
setup(): Promise<void>;
|
|
@@ -26,9 +38,11 @@ export interface Derived {
|
|
|
26
38
|
plain: unknown;
|
|
27
39
|
seen: unknown;
|
|
28
40
|
}[] | Skip>;
|
|
29
|
-
invariantsHold(agg: string, runs?: number): Promise<
|
|
30
|
-
steps: number;
|
|
31
|
-
violations: string[];
|
|
32
|
-
} | Skip>;
|
|
41
|
+
invariantsHold(agg: string, runs?: number): Promise<DerivedInvariantResult | Skip>;
|
|
33
42
|
}
|
|
34
|
-
|
|
43
|
+
/**
|
|
44
|
+
* 为一个 domain 建立延迟初始化的性质测试集合,默认固定种子,非法 seed 立即拒绝。
|
|
45
|
+
* 能力/状态检查构造针对性身份,范围检查验证详情、列表和裸安全视图;成功性质无法执行时报告 SKIP。
|
|
46
|
+
* invariantsHold 先验证初始夹具再执行有限命令序列,区分准备失败和执行失败,并保留可定位轨迹。
|
|
47
|
+
*/
|
|
48
|
+
export declare function derived(domain: object, options?: DerivedOptions): Derived;
|