@blokjs/shared 0.6.18 → 0.6.20

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.
@@ -1,77 +0,0 @@
1
- import { beforeEach, describe, expect, it } from "vitest";
2
- import { Metrics } from "../../src/Metrics";
3
-
4
- describe("Metrics", () => {
5
- let metrics: Metrics;
6
-
7
- beforeEach(() => {
8
- metrics = new Metrics();
9
- });
10
-
11
- it("should construct without errors", () => {
12
- expect(metrics).toBeDefined();
13
- });
14
-
15
- describe("start()", () => {
16
- it("should call start on all sub-metrics without error", () => {
17
- expect(() => metrics.start()).not.toThrow();
18
- });
19
- });
20
-
21
- describe("stop()", () => {
22
- it("should call stop without error after start", () => {
23
- metrics.start();
24
- expect(() => metrics.stop()).not.toThrow();
25
- });
26
- });
27
-
28
- describe("retry()", () => {
29
- it("should call start on memoryUsage only", () => {
30
- metrics.start();
31
- expect(() => metrics.retry()).not.toThrow();
32
- });
33
- });
34
-
35
- describe("clear()", () => {
36
- it("should clear memory usage values", () => {
37
- metrics.start();
38
- metrics.clear();
39
- // After clear, memory metrics should be zeroed
40
- const result = metrics.getMetrics();
41
- expect(result.memory.min).toBe(0);
42
- expect(result.memory.max).toBe(0);
43
- });
44
- });
45
-
46
- describe("getMetrics()", () => {
47
- it("should return object with cpu, memory, time", () => {
48
- metrics.start();
49
- metrics.stop();
50
-
51
- const result = metrics.getMetrics();
52
- expect(result).toHaveProperty("cpu");
53
- expect(result).toHaveProperty("memory");
54
- expect(result).toHaveProperty("time");
55
- });
56
-
57
- it("should return valid metric shapes after start/stop cycle", () => {
58
- metrics.start();
59
- metrics.stop();
60
-
61
- const result = metrics.getMetrics();
62
- // CPU
63
- expect(result.cpu).toHaveProperty("total");
64
- expect(result.cpu).toHaveProperty("average");
65
- expect(result.cpu).toHaveProperty("usage");
66
- expect(result.cpu).toHaveProperty("model");
67
- // Memory
68
- expect(result.memory).toHaveProperty("total");
69
- expect(result.memory).toHaveProperty("min");
70
- expect(result.memory).toHaveProperty("max");
71
- // Time
72
- expect(result.time).toHaveProperty("startTime");
73
- expect(result.time).toHaveProperty("endTime");
74
- expect(result.time).toHaveProperty("duration");
75
- });
76
- });
77
- });
@@ -1,290 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from "vitest";
2
- import GlobalError from "../../src/GlobalError";
3
- import NodeBase from "../../src/NodeBase";
4
- import type Context from "../../src/types/Context";
5
- import type ResponseContext from "../../src/types/ResponseContext";
6
-
7
- class TestNode extends NodeBase {
8
- public mockResponse: ResponseContext = { data: { result: "ok" }, error: null, success: true };
9
- public runCalls: Context[] = [];
10
-
11
- async run(ctx: Context): Promise<ResponseContext> {
12
- this.runCalls.push(ctx);
13
- return this.mockResponse;
14
- }
15
- }
16
-
17
- // Loose `Record<string, unknown>` overrides so tests can pass shapes that
18
- // don't strictly match `Partial<Context>` (e.g. `config: { "<node>": ... }`,
19
- // which is the runtime layout but isn't reflected in the typed `ConfigContext`).
20
- function createTestContext(overrides: Record<string, unknown> = {}): Context {
21
- return {
22
- id: "test-ctx",
23
- request: { body: {}, headers: {}, query: {}, params: {} },
24
- response: { data: null, error: null, success: true },
25
- error: { message: "" },
26
- logger: { log: vi.fn(), logLevel: vi.fn(), error: vi.fn() },
27
- config: {},
28
- func: {},
29
- vars: {},
30
- eventLogger: null,
31
- _PRIVATE_: null,
32
- ...overrides,
33
- } as unknown as Context;
34
- }
35
-
36
- describe("NodeBase", () => {
37
- let node: TestNode;
38
-
39
- beforeEach(() => {
40
- node = new TestNode();
41
- node.name = "test-node";
42
- vi.restoreAllMocks();
43
- });
44
-
45
- describe("default properties", () => {
46
- it("should have correct defaults", () => {
47
- const n = new TestNode();
48
- expect(n.flow).toBe(false);
49
- expect(n.name).toBe("");
50
- expect(n.active).toBe(true);
51
- expect(n.stop).toBe(false);
52
- expect(n.ephemeral).toBe(false);
53
- expect(n.spread).toBe(false);
54
- expect(n.contentType).toBe("");
55
- });
56
- });
57
-
58
- describe("process()", () => {
59
- it("should call run() and return response", async () => {
60
- const ctx = createTestContext({
61
- config: { "test-node": { param: "value" } },
62
- });
63
-
64
- const response = await node.process(ctx);
65
- expect(response).toEqual(node.mockResponse);
66
- expect(node.runCalls).toHaveLength(1);
67
- });
68
-
69
- it("should clone config for originalConfig", async () => {
70
- const configData = { key: "val" };
71
- const ctx = createTestContext({
72
- config: { "test-node": configData },
73
- });
74
-
75
- await node.process(ctx);
76
- expect(node.originalConfig).toEqual(configData);
77
- // Should be a deep clone, not same reference
78
- expect(node.originalConfig).not.toBe(configData);
79
- });
80
-
81
- it("should set ctx.response on success", async () => {
82
- const ctx = createTestContext({
83
- config: { "test-node": {} },
84
- });
85
-
86
- await node.process(ctx);
87
- expect(ctx.response).toEqual(node.mockResponse);
88
- });
89
-
90
- it("should throw when response has error", async () => {
91
- const error = new GlobalError("process error");
92
- node.mockResponse = { data: null, error, success: false };
93
-
94
- const ctx = createTestContext({
95
- config: { "test-node": {} },
96
- });
97
-
98
- await expect(node.process(ctx)).rejects.toBe(error);
99
- });
100
- });
101
-
102
- describe("processFlow()", () => {
103
- it("should call run() and return response", async () => {
104
- const ctx = createTestContext({
105
- config: { "test-node": {} },
106
- });
107
-
108
- const response = await node.processFlow(ctx);
109
- expect(response).toEqual(node.mockResponse);
110
- });
111
-
112
- it("should catch errors and wrap in setError", async () => {
113
- const testNode = new TestNode();
114
- testNode.name = "error-node";
115
- testNode.run = vi.fn().mockRejectedValue({ message: "oops" });
116
-
117
- const ctx = createTestContext({
118
- config: { "error-node": {} },
119
- });
120
-
121
- const response = await testNode.processFlow(ctx);
122
- expect(response.success).toBe(false);
123
- expect(response.error).toBeInstanceOf(GlobalError);
124
- });
125
-
126
- it("should set ctx.response on error", async () => {
127
- const testNode = new TestNode();
128
- testNode.name = "error-node";
129
- testNode.run = vi.fn().mockRejectedValue({ message: "fail" });
130
-
131
- const ctx = createTestContext({
132
- config: { "error-node": {} },
133
- });
134
-
135
- await testNode.processFlow(ctx);
136
- expect(ctx.response.success).toBe(false);
137
- expect(ctx.response.error).toBeInstanceOf(GlobalError);
138
- });
139
- });
140
-
141
- describe("runSteps()", () => {
142
- it('should throw "not implemented" error', () => {
143
- const ctx = createTestContext();
144
- const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {});
145
-
146
- expect(() => node.runSteps([], ctx)).toThrow("runSteps method is not implemented.");
147
- consoleSpy.mockRestore();
148
- });
149
- });
150
-
151
- describe("runJs()", () => {
152
- it("should evaluate simple expressions", () => {
153
- const ctx = createTestContext();
154
- const result = node.runJs("1 + 2", ctx);
155
- expect(result).toBe(3);
156
- });
157
-
158
- it("should access ctx parameter", () => {
159
- const ctx = createTestContext({ id: "my-id" });
160
- const result = node.runJs("ctx.id", ctx);
161
- expect(result).toBe("my-id");
162
- });
163
-
164
- it("should access data parameter", () => {
165
- const ctx = createTestContext();
166
- const result = node.runJs("data.x", ctx, { x: 42 } as unknown as Record<string, string>);
167
- expect(result).toBe(42);
168
- });
169
-
170
- it("should access vars parameter", () => {
171
- const ctx = createTestContext();
172
- const result = node.runJs("vars.count", ctx, {}, {}, { count: 10 });
173
- expect(result).toBe(10);
174
- });
175
-
176
- it("should handle string concatenation", () => {
177
- const ctx = createTestContext();
178
- const result = node.runJs('"hello" + " " + "world"', ctx);
179
- expect(result).toBe("hello world");
180
- });
181
- });
182
-
183
- describe("setVar()", () => {
184
- it("should initialize ctx.vars if undefined", () => {
185
- const ctx = createTestContext();
186
- ctx.vars = undefined;
187
- node.setVar(ctx, { key: "value" });
188
- expect(ctx.vars).toEqual({ key: "value" });
189
- });
190
-
191
- it("should merge vars into ctx.vars", () => {
192
- const ctx = createTestContext({ vars: { existing: "keep" } });
193
- node.setVar(ctx, { newKey: "newVal" });
194
- expect(ctx.vars).toEqual({ existing: "keep", newKey: "newVal" });
195
- });
196
- });
197
-
198
- describe("getVar()", () => {
199
- it("should return value by name", () => {
200
- const ctx = createTestContext({ vars: { myVar: "found" } });
201
- expect(node.getVar(ctx, "myVar")).toBe("found");
202
- });
203
-
204
- it("should return undefined for missing var", () => {
205
- const ctx = createTestContext({ vars: { a: 1 } });
206
- expect(node.getVar(ctx, "nonexistent")).toBeUndefined();
207
- });
208
-
209
- it("should handle undefined ctx.vars", () => {
210
- const ctx = createTestContext();
211
- ctx.vars = undefined;
212
- expect(node.getVar(ctx, "any")).toBeUndefined();
213
- });
214
- });
215
-
216
- describe("blueprintMapper()", () => {
217
- it("should handle string input", () => {
218
- const ctx = createTestContext();
219
- const result = node.blueprintMapper("plain text" as unknown as Record<string, string>, ctx);
220
- expect(result).toBe("plain text");
221
- });
222
-
223
- it("should handle object input without error", () => {
224
- const ctx = createTestContext();
225
- const obj = { key: "value" };
226
- const result = node.blueprintMapper(obj, ctx);
227
- expect(result).toEqual(obj);
228
- });
229
-
230
- it("should catch and log mapper errors", () => {
231
- const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => {});
232
- const ctx = createTestContext();
233
- // null will cause mapper to fail
234
- const result = node.blueprintMapper(null as unknown as Record<string, string>, ctx);
235
- // Should not throw
236
- expect(result).toBeNull();
237
- consoleSpy.mockRestore();
238
- });
239
- });
240
-
241
- describe("setError()", () => {
242
- it("should create GlobalError from string", () => {
243
- const error = node.setError("simple error" as unknown as any);
244
- expect(error).toBeInstanceOf(GlobalError);
245
- expect(error.message).toBe("simple error");
246
- });
247
-
248
- it("should create GlobalError from {message} only", () => {
249
- const error = node.setError({ message: "just a message" });
250
- expect(error).toBeInstanceOf(GlobalError);
251
- expect(error.message).toBe("just a message");
252
- });
253
-
254
- it("should create GlobalError from object with multiple keys", () => {
255
- const config = { message: "error", detail: "extra info" };
256
- const error = node.setError(config as any);
257
- expect(error).toBeInstanceOf(GlobalError);
258
- expect(error.hasJson()).toBe(true);
259
- });
260
-
261
- it("should set json when config has json field", () => {
262
- const config = { message: "err", json: { detail: "info" } };
263
- const error = node.setError(config as any);
264
- expect(error.hasJson()).toBe(true);
265
- });
266
-
267
- it("should set stack when config has stack field", () => {
268
- const config = { message: "err", stack: "Error\n at line 1" };
269
- const error = node.setError(config);
270
- expect(error.context.stack).toBe("Error\n at line 1");
271
- });
272
-
273
- it("should set numeric code from config", () => {
274
- const config = { message: "err", code: 404 };
275
- const error = node.setError(config);
276
- expect(error.context.code).toBe(404);
277
- });
278
-
279
- it("should default to 500 for non-numeric code", () => {
280
- const config = { message: "err", code: "bad" as unknown as number };
281
- const error = node.setError(config);
282
- expect(error.context.code).toBe(500);
283
- });
284
-
285
- it("should set name from this.name", () => {
286
- const error = node.setError({ message: "err" });
287
- expect(error.context.name).toBe("test-node");
288
- });
289
- });
290
- });
@@ -1,23 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import Trigger from "../../src/Trigger";
3
-
4
- class TestTrigger extends Trigger {
5
- public listenCalled = false;
6
-
7
- listen(): void {
8
- this.listenCalled = true;
9
- }
10
- }
11
-
12
- describe("Trigger", () => {
13
- it("should allow concrete subclass to implement listen()", () => {
14
- const trigger = new TestTrigger();
15
- trigger.listen();
16
- expect(trigger.listenCalled).toBe(true);
17
- });
18
-
19
- it("should be an instance of Trigger", () => {
20
- const trigger = new TestTrigger();
21
- expect(trigger).toBeInstanceOf(Trigger);
22
- });
23
- });
@@ -1,102 +0,0 @@
1
- import os from "node:os";
2
- import { beforeEach, describe, expect, it, vi } from "vitest";
3
- import CpuMetrics from "../../../src/utils/CpuUsage";
4
-
5
- const mockCpuInfo = (idle: number, user: number, sys: number) => [
6
- {
7
- model: "Test CPU Model",
8
- speed: 2400,
9
- times: { idle, user, sys, nice: 0, irq: 0 },
10
- },
11
- {
12
- model: "Test CPU Model",
13
- speed: 2400,
14
- times: { idle, user, sys, nice: 0, irq: 0 },
15
- },
16
- ];
17
-
18
- describe("CpuMetrics", () => {
19
- let cpu: CpuMetrics;
20
-
21
- beforeEach(() => {
22
- cpu = new CpuMetrics();
23
- vi.restoreAllMocks();
24
- });
25
-
26
- describe("start()", () => {
27
- it("should capture CPU info (model and count)", () => {
28
- vi.spyOn(os, "cpus").mockReturnValue(mockCpuInfo(1000, 500, 200) as os.CpuInfo[]);
29
- cpu.start();
30
- const metrics = cpu.getMetrics();
31
- expect(metrics.model).toBe("Test CPU Model");
32
- expect(metrics.total).toBe(2);
33
- });
34
- });
35
-
36
- describe("stop()", () => {
37
- it("should capture end usage without error", () => {
38
- vi.spyOn(os, "cpus").mockReturnValue(mockCpuInfo(1000, 500, 200) as os.CpuInfo[]);
39
- cpu.start();
40
- cpu.stop();
41
- // Should not throw
42
- expect(true).toBe(true);
43
- });
44
- });
45
-
46
- describe("getAverage()", () => {
47
- it("should calculate CPU percentage between start and stop", () => {
48
- const startCpus = mockCpuInfo(1000, 500, 200);
49
- const stopCpus = mockCpuInfo(1050, 550, 250);
50
-
51
- vi.spyOn(os, "cpus")
52
- .mockReturnValueOnce(startCpus as os.CpuInfo[]) // start -> constructor call
53
- .mockReturnValueOnce(startCpus as os.CpuInfo[]) // start -> measureCpu
54
- .mockReturnValueOnce(stopCpus as os.CpuInfo[]) // stop -> measureCpu
55
- .mockReturnValueOnce(stopCpus as os.CpuInfo[]); // potential extra
56
-
57
- cpu.start();
58
- cpu.stop();
59
-
60
- const metrics = cpu.getMetrics();
61
- expect(metrics.average).toBeTypeOf("number");
62
- expect(metrics.average).toBeGreaterThanOrEqual(0);
63
- expect(metrics.average).toBeLessThanOrEqual(100);
64
- });
65
- });
66
-
67
- describe("getMetrics()", () => {
68
- it("should return correct shape with total, average, usage, model", () => {
69
- vi.spyOn(os, "cpus").mockReturnValue(mockCpuInfo(1000, 500, 200) as os.CpuInfo[]);
70
- cpu.start();
71
- cpu.stop();
72
-
73
- const metrics = cpu.getMetrics();
74
- expect(metrics).toHaveProperty("total");
75
- expect(metrics).toHaveProperty("average");
76
- expect(metrics).toHaveProperty("usage");
77
- expect(metrics).toHaveProperty("model");
78
- });
79
- });
80
-
81
- describe("measureCpu()", () => {
82
- it("should return idle, total, model, cpus shape", () => {
83
- vi.spyOn(os, "cpus").mockReturnValue(mockCpuInfo(1000, 500, 200) as os.CpuInfo[]);
84
- const result = cpu.measureCpu();
85
- expect(result).toHaveProperty("idle");
86
- expect(result).toHaveProperty("total");
87
- expect(result).toHaveProperty("model");
88
- expect(result).toHaveProperty("cpus");
89
- expect(result.cpus).toBe(2);
90
- });
91
-
92
- it("should aggregate across all CPU cores", () => {
93
- vi.spyOn(os, "cpus").mockReturnValue(mockCpuInfo(1000, 500, 200) as os.CpuInfo[]);
94
- const result = cpu.measureCpu();
95
- // idle is averaged: (1000 + 1000) / 2 = 1000
96
- expect(result.idle).toBe(1000);
97
- // total per core: idle + irq + nice + sys + user = 1000 + 0 + 0 + 200 + 500 = 1700
98
- // averaged: (1700 + 1700) / 2 = 1700
99
- expect(result.total).toBe(1700);
100
- });
101
- });
102
- });