@telorun/assert 0.1.3 → 0.1.4
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/dist/events.d.ts +3 -1
- package/dist/events.js +17 -12
- package/dist/module-context.d.ts +15 -0
- package/dist/module-context.js +94 -0
- package/package.json +4 -3
- package/dist/value.js +0 -3
package/dist/events.d.ts
CHANGED
|
@@ -13,5 +13,7 @@ export declare const schema: import("@sinclair/typebox").TObject<{
|
|
|
13
13
|
}>>;
|
|
14
14
|
}>;
|
|
15
15
|
type AssertManifest = Static<typeof schema>;
|
|
16
|
-
export declare function create(manifest: AssertManifest, ctx: ResourceContext): Promise<{
|
|
16
|
+
export declare function create(manifest: AssertManifest, ctx: ResourceContext): Promise<{
|
|
17
|
+
run: () => Promise<void>;
|
|
18
|
+
}>;
|
|
17
19
|
export {};
|
package/dist/events.js
CHANGED
|
@@ -102,22 +102,27 @@ function buildReport(name, captured, expect) {
|
|
|
102
102
|
export async function create(manifest, ctx) {
|
|
103
103
|
const captured = [];
|
|
104
104
|
const filters = manifest.filter ?? [{ type: "*" }];
|
|
105
|
+
let appStarted = false;
|
|
106
|
+
ctx.on("Kernel.Started", () => {
|
|
107
|
+
appStarted = true;
|
|
108
|
+
});
|
|
105
109
|
ctx.on("*", (event) => {
|
|
106
110
|
if (filters.some((f) => matchesPattern(f.type, event.name))) {
|
|
107
111
|
captured.push({ name: event.name, payload: event.payload });
|
|
108
112
|
}
|
|
109
113
|
});
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if (report
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
return {
|
|
115
|
+
run: async () => {
|
|
116
|
+
const report = buildReport(manifest.metadata.name, captured, manifest.expect);
|
|
117
|
+
if (report) {
|
|
118
|
+
if (report.passed) {
|
|
119
|
+
process.stdout.write(report.report);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
process.stderr.write(report.report);
|
|
123
|
+
ctx.requestExit(1);
|
|
124
|
+
}
|
|
119
125
|
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
return {};
|
|
126
|
+
},
|
|
127
|
+
};
|
|
123
128
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Static } from "@sinclair/typebox";
|
|
2
|
+
import { ResourceContext, Runnable } from "@telorun/sdk";
|
|
3
|
+
export declare const schema: import("@sinclair/typebox").TObject<{
|
|
4
|
+
metadata: import("@sinclair/typebox").TObject<{
|
|
5
|
+
name: import("@sinclair/typebox").TString;
|
|
6
|
+
module: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
7
|
+
}>;
|
|
8
|
+
imports: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TObject<{
|
|
9
|
+
variables: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TAny>>;
|
|
10
|
+
secrets: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TAny>>;
|
|
11
|
+
}>>>;
|
|
12
|
+
}>;
|
|
13
|
+
type ModuleContextManifest = Static<typeof schema>;
|
|
14
|
+
export declare function create(manifest: ModuleContextManifest, ctx: ResourceContext): Promise<Runnable>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
2
|
+
const ImportEntry = Type.Object({
|
|
3
|
+
variables: Type.Optional(Type.Record(Type.String(), Type.Any())),
|
|
4
|
+
secrets: Type.Optional(Type.Record(Type.String(), Type.Any())),
|
|
5
|
+
});
|
|
6
|
+
export const schema = Type.Object({
|
|
7
|
+
metadata: Type.Object({
|
|
8
|
+
name: Type.String(),
|
|
9
|
+
module: Type.Optional(Type.String()),
|
|
10
|
+
}),
|
|
11
|
+
imports: Type.Optional(Type.Record(Type.String(), ImportEntry)),
|
|
12
|
+
});
|
|
13
|
+
const useColor = process.stderr.isTTY;
|
|
14
|
+
const c = (code, text) => (useColor ? `\x1b[${code}m${text}\x1b[0m` : text);
|
|
15
|
+
const bold = (t) => c("1", t);
|
|
16
|
+
const red = (t) => c("31", t);
|
|
17
|
+
const green = (t) => c("32", t);
|
|
18
|
+
const yellow = (t) => c("33", t);
|
|
19
|
+
const dim = (t) => c("2", t);
|
|
20
|
+
function deepEqual(a, b) {
|
|
21
|
+
if (a === b)
|
|
22
|
+
return true;
|
|
23
|
+
if (a === null || b === null)
|
|
24
|
+
return false;
|
|
25
|
+
if (typeof a !== "object" || typeof b !== "object")
|
|
26
|
+
return false;
|
|
27
|
+
const aKeys = Object.keys(a);
|
|
28
|
+
const bKeys = Object.keys(b);
|
|
29
|
+
if (aKeys.length !== bKeys.length)
|
|
30
|
+
return false;
|
|
31
|
+
for (const key of aKeys) {
|
|
32
|
+
if (!deepEqual(a[key], b[key]))
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
export async function create(manifest, ctx) {
|
|
38
|
+
return {
|
|
39
|
+
run: async () => {
|
|
40
|
+
const declaringModule = manifest.metadata.module ?? "default";
|
|
41
|
+
const importsToCheck = manifest.imports ?? {};
|
|
42
|
+
const failures = [];
|
|
43
|
+
const passed = [];
|
|
44
|
+
for (const [alias, expected] of Object.entries(importsToCheck)) {
|
|
45
|
+
const realModule = ctx.resolveModuleAlias(declaringModule, alias);
|
|
46
|
+
if (!realModule) {
|
|
47
|
+
failures.push(`Import alias '${alias}' not found in module '${declaringModule}'`);
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
const moduleCtx = ctx.moduleContext;
|
|
51
|
+
const importSnap = moduleCtx.resources[alias] ?? {};
|
|
52
|
+
const expectedVariables = expected.variables ?? {};
|
|
53
|
+
const expectedSecrets = expected.secrets ?? {};
|
|
54
|
+
for (const [key, expectedValue] of Object.entries(expectedVariables)) {
|
|
55
|
+
const actualValue = importSnap?.variables?.[key];
|
|
56
|
+
if (!deepEqual(actualValue, expectedValue)) {
|
|
57
|
+
failures.push(`imports.${alias}.variables.${key}: expected ${yellow(JSON.stringify(expectedValue))}, got ${red(JSON.stringify(actualValue))}`);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
passed.push(`imports.${alias}.variables.${key}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
for (const [key] of Object.entries(expectedSecrets)) {
|
|
64
|
+
const actualSecret = importSnap?.secrets?.[key];
|
|
65
|
+
if (!deepEqual(actualSecret, expectedSecrets[key])) {
|
|
66
|
+
failures.push(`imports.${alias}.secrets.${key}: ${dim("value mismatch")}`);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
passed.push(`imports.${alias}.secrets.${key}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const name = manifest.metadata.name;
|
|
74
|
+
if (failures.length > 0) {
|
|
75
|
+
let report = bold(red(`Assert.ModuleContext.${name}: assertion failed`)) + "\n";
|
|
76
|
+
for (const p of passed) {
|
|
77
|
+
report += ` ${green("✓")} ${dim(p)}\n`;
|
|
78
|
+
}
|
|
79
|
+
for (const f of failures) {
|
|
80
|
+
report += ` ${red("✗")} ${f}\n`;
|
|
81
|
+
}
|
|
82
|
+
process.stderr.write(report);
|
|
83
|
+
ctx.requestExit(1);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
let report = bold(green(`Assert.ModuleContext.${name}: assertion passed`)) + "\n";
|
|
87
|
+
for (const p of passed) {
|
|
88
|
+
report += ` ${green("✓")} ${dim(p)}\n`;
|
|
89
|
+
}
|
|
90
|
+
process.stdout.write(report);
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
package/package.json
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@telorun/assert",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./schema": "./src/schema.ts",
|
|
7
|
-
"./events": "./src/events.ts"
|
|
7
|
+
"./events": "./src/events.ts",
|
|
8
|
+
"./module-context": "./src/module-context.ts"
|
|
8
9
|
},
|
|
9
10
|
"files": [
|
|
10
11
|
"dist/**"
|
|
11
12
|
],
|
|
12
13
|
"dependencies": {
|
|
13
14
|
"@sinclair/typebox": "^0.34.48",
|
|
14
|
-
"@telorun/sdk": "0.2.
|
|
15
|
+
"@telorun/sdk": "0.2.5"
|
|
15
16
|
},
|
|
16
17
|
"devDependencies": {
|
|
17
18
|
"@types/node": "^20.0.0",
|
package/dist/value.js
DELETED