@ricsam/isolate-console 0.1.1 → 0.1.3

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/src/setup.test.ts DELETED
@@ -1,509 +0,0 @@
1
- import { test, describe, beforeEach, afterEach } from "node:test";
2
- import assert from "node:assert";
3
- import ivm from "isolated-vm";
4
- import { setupConsole, type ConsoleHandle } from "./index.ts";
5
-
6
- describe("@ricsam/isolate-console", () => {
7
- let isolate: ivm.Isolate;
8
- let context: ivm.Context;
9
-
10
- beforeEach(async () => {
11
- isolate = new ivm.Isolate();
12
- context = await isolate.createContext();
13
- });
14
-
15
- afterEach(() => {
16
- context.release();
17
- isolate.dispose();
18
- });
19
-
20
- describe("log-level methods", () => {
21
- test("console.log calls onLog with correct level", async () => {
22
- const logCalls: Array<{ level: string; args: unknown[] }> = [];
23
- await setupConsole(context, {
24
- onLog: (level, ...args) => logCalls.push({ level, args }),
25
- });
26
- context.evalSync(`console.log("hello", 123)`);
27
- assert.strictEqual(logCalls.length, 1);
28
- assert.strictEqual(logCalls[0].level, "log");
29
- assert.deepStrictEqual(logCalls[0].args, ["hello", 123]);
30
- });
31
-
32
- test("console.warn calls onLog with warn level", async () => {
33
- const logCalls: Array<{ level: string; args: unknown[] }> = [];
34
- await setupConsole(context, {
35
- onLog: (level, ...args) => logCalls.push({ level, args }),
36
- });
37
- context.evalSync(`console.warn("warning")`);
38
- assert.strictEqual(logCalls.length, 1);
39
- assert.strictEqual(logCalls[0].level, "warn");
40
- assert.deepStrictEqual(logCalls[0].args, ["warning"]);
41
- });
42
-
43
- test("console.error calls onLog with error level", async () => {
44
- const logCalls: Array<{ level: string; args: unknown[] }> = [];
45
- await setupConsole(context, {
46
- onLog: (level, ...args) => logCalls.push({ level, args }),
47
- });
48
- context.evalSync(`console.error("error message")`);
49
- assert.strictEqual(logCalls.length, 1);
50
- assert.strictEqual(logCalls[0].level, "error");
51
- assert.deepStrictEqual(logCalls[0].args, ["error message"]);
52
- });
53
-
54
- test("console.debug calls onLog with debug level", async () => {
55
- const logCalls: Array<{ level: string; args: unknown[] }> = [];
56
- await setupConsole(context, {
57
- onLog: (level, ...args) => logCalls.push({ level, args }),
58
- });
59
- context.evalSync(`console.debug("debug info")`);
60
- assert.strictEqual(logCalls.length, 1);
61
- assert.strictEqual(logCalls[0].level, "debug");
62
- });
63
-
64
- test("console.info calls onLog with info level", async () => {
65
- const logCalls: Array<{ level: string; args: unknown[] }> = [];
66
- await setupConsole(context, {
67
- onLog: (level, ...args) => logCalls.push({ level, args }),
68
- });
69
- context.evalSync(`console.info("information")`);
70
- assert.strictEqual(logCalls.length, 1);
71
- assert.strictEqual(logCalls[0].level, "info");
72
- });
73
-
74
- test("console.trace calls onLog with trace level", async () => {
75
- const logCalls: Array<{ level: string; args: unknown[] }> = [];
76
- await setupConsole(context, {
77
- onLog: (level, ...args) => logCalls.push({ level, args }),
78
- });
79
- context.evalSync(`console.trace("trace")`);
80
- assert.strictEqual(logCalls.length, 1);
81
- assert.strictEqual(logCalls[0].level, "trace");
82
- });
83
-
84
- test("console.dir calls onLog with dir level", async () => {
85
- const logCalls: Array<{ level: string; args: unknown[] }> = [];
86
- await setupConsole(context, {
87
- onLog: (level, ...args) => logCalls.push({ level, args }),
88
- });
89
- context.evalSync(`console.dir({ key: "value" })`);
90
- assert.strictEqual(logCalls.length, 1);
91
- assert.strictEqual(logCalls[0].level, "dir");
92
- assert.deepStrictEqual(logCalls[0].args, [{ key: "value" }]);
93
- });
94
-
95
- test("console.table calls onLog with table level", async () => {
96
- const logCalls: Array<{ level: string; args: unknown[] }> = [];
97
- await setupConsole(context, {
98
- onLog: (level, ...args) => logCalls.push({ level, args }),
99
- });
100
- context.evalSync(`console.table([1, 2, 3])`);
101
- assert.strictEqual(logCalls.length, 1);
102
- assert.strictEqual(logCalls[0].level, "table");
103
- assert.deepStrictEqual(logCalls[0].args, [[1, 2, 3]]);
104
- });
105
-
106
- test("console.log with no arguments", async () => {
107
- const logCalls: Array<{ level: string; args: unknown[] }> = [];
108
- await setupConsole(context, {
109
- onLog: (level, ...args) => logCalls.push({ level, args }),
110
- });
111
- context.evalSync(`console.log()`);
112
- assert.strictEqual(logCalls.length, 1);
113
- assert.deepStrictEqual(logCalls[0].args, []);
114
- });
115
-
116
- test("console.log with multiple arguments", async () => {
117
- const logCalls: Array<{ level: string; args: unknown[] }> = [];
118
- await setupConsole(context, {
119
- onLog: (level, ...args) => logCalls.push({ level, args }),
120
- });
121
- context.evalSync(`console.log("a", "b", "c", 1, 2, 3)`);
122
- assert.strictEqual(logCalls.length, 1);
123
- assert.deepStrictEqual(logCalls[0].args, ["a", "b", "c", 1, 2, 3]);
124
- });
125
- });
126
-
127
- describe("timing methods", () => {
128
- test("console.time starts a timer", async () => {
129
- const handle = await setupConsole(context);
130
- context.evalSync(`console.time("test")`);
131
- assert.strictEqual(handle.getTimers().has("test"), true);
132
- });
133
-
134
- test("console.time uses default label", async () => {
135
- const handle = await setupConsole(context);
136
- context.evalSync(`console.time()`);
137
- assert.strictEqual(handle.getTimers().has("default"), true);
138
- });
139
-
140
- test("console.timeEnd reports duration", async () => {
141
- const timeCalls: Array<{ label: string; duration: number }> = [];
142
- const handle = await setupConsole(context, {
143
- onTime: (label, duration) => timeCalls.push({ label, duration }),
144
- });
145
- context.evalSync(`console.time("test")`);
146
- await new Promise((resolve) => setTimeout(resolve, 10));
147
- context.evalSync(`console.timeEnd("test")`);
148
-
149
- assert.strictEqual(timeCalls.length, 1);
150
- assert.strictEqual(timeCalls[0].label, "test");
151
- assert.ok(timeCalls[0].duration >= 0);
152
- assert.strictEqual(handle.getTimers().has("test"), false);
153
- });
154
-
155
- test("console.timeEnd with default label", async () => {
156
- const timeCalls: Array<{ label: string; duration: number }> = [];
157
- await setupConsole(context, {
158
- onTime: (label, duration) => timeCalls.push({ label, duration }),
159
- });
160
- context.evalSync(`console.time()`);
161
- await new Promise((resolve) => setTimeout(resolve, 5));
162
- context.evalSync(`console.timeEnd()`);
163
-
164
- assert.strictEqual(timeCalls.length, 1);
165
- assert.strictEqual(timeCalls[0].label, "default");
166
- });
167
-
168
- test("console.timeEnd with non-existent timer is no-op", async () => {
169
- const timeCalls: Array<{ label: string; duration: number }> = [];
170
- await setupConsole(context, {
171
- onTime: (label, duration) => timeCalls.push({ label, duration }),
172
- });
173
- context.evalSync(`console.timeEnd("nonexistent")`);
174
- assert.strictEqual(timeCalls.length, 0);
175
- });
176
-
177
- test("console.timeLog reports duration without ending", async () => {
178
- const timeLogCalls: Array<{
179
- label: string;
180
- duration: number;
181
- args: unknown[];
182
- }> = [];
183
- const handle = await setupConsole(context, {
184
- onTimeLog: (label, duration, ...args) =>
185
- timeLogCalls.push({ label, duration, args }),
186
- });
187
- context.evalSync(`console.time("test")`);
188
- await new Promise((resolve) => setTimeout(resolve, 5));
189
- context.evalSync(`console.timeLog("test", "additional", "args")`);
190
-
191
- assert.strictEqual(timeLogCalls.length, 1);
192
- assert.strictEqual(timeLogCalls[0].label, "test");
193
- assert.deepStrictEqual(timeLogCalls[0].args, ["additional", "args"]);
194
- assert.strictEqual(handle.getTimers().has("test"), true); // Timer still running
195
- });
196
-
197
- test("console.timeLog with non-existent timer is no-op", async () => {
198
- const timeLogCalls: Array<{
199
- label: string;
200
- duration: number;
201
- args: unknown[];
202
- }> = [];
203
- await setupConsole(context, {
204
- onTimeLog: (label, duration, ...args) =>
205
- timeLogCalls.push({ label, duration, args }),
206
- });
207
- context.evalSync(`console.timeLog("nonexistent")`);
208
- assert.strictEqual(timeLogCalls.length, 0);
209
- });
210
- });
211
-
212
- describe("counting methods", () => {
213
- test("console.count increments counter", async () => {
214
- const countCalls: Array<{ label: string; count: number }> = [];
215
- await setupConsole(context, {
216
- onCount: (label, count) => countCalls.push({ label, count }),
217
- });
218
- context.evalSync(`console.count("test")`);
219
- assert.strictEqual(countCalls.length, 1);
220
- assert.deepStrictEqual(countCalls[0], { label: "test", count: 1 });
221
-
222
- context.evalSync(`console.count("test")`);
223
- assert.strictEqual(countCalls.length, 2);
224
- assert.deepStrictEqual(countCalls[1], { label: "test", count: 2 });
225
- });
226
-
227
- test("console.count uses default label", async () => {
228
- const countCalls: Array<{ label: string; count: number }> = [];
229
- await setupConsole(context, {
230
- onCount: (label, count) => countCalls.push({ label, count }),
231
- });
232
- context.evalSync(`console.count()`);
233
- assert.strictEqual(countCalls[0].label, "default");
234
- });
235
-
236
- test("console.countReset clears counter", async () => {
237
- const countCalls: Array<{ label: string; count: number }> = [];
238
- const countResetCalls: string[] = [];
239
- const handle = await setupConsole(context, {
240
- onCount: (label, count) => countCalls.push({ label, count }),
241
- onCountReset: (label) => countResetCalls.push(label),
242
- });
243
- context.evalSync(`console.count("test")`);
244
- context.evalSync(`console.count("test")`);
245
- context.evalSync(`console.countReset("test")`);
246
-
247
- assert.deepStrictEqual(countResetCalls, ["test"]);
248
- assert.strictEqual(handle.getCounters().has("test"), false);
249
-
250
- // After reset, count starts from 1 again
251
- context.evalSync(`console.count("test")`);
252
- assert.deepStrictEqual(countCalls[countCalls.length - 1], {
253
- label: "test",
254
- count: 1,
255
- });
256
- });
257
-
258
- test("console.countReset with default label", async () => {
259
- const countResetCalls: string[] = [];
260
- await setupConsole(context, {
261
- onCountReset: (label) => countResetCalls.push(label),
262
- });
263
- context.evalSync(`console.count()`);
264
- context.evalSync(`console.countReset()`);
265
- assert.deepStrictEqual(countResetCalls, ["default"]);
266
- });
267
-
268
- test("console.countReset with non-existent counter still calls handler", async () => {
269
- const countResetCalls: string[] = [];
270
- await setupConsole(context, {
271
- onCountReset: (label) => countResetCalls.push(label),
272
- });
273
- context.evalSync(`console.countReset("nonexistent")`);
274
- assert.deepStrictEqual(countResetCalls, ["nonexistent"]);
275
- });
276
-
277
- test("getCounters returns correct state", async () => {
278
- const handle = await setupConsole(context);
279
- context.evalSync(`console.count("a")`);
280
- context.evalSync(`console.count("a")`);
281
- context.evalSync(`console.count("b")`);
282
-
283
- const counters = handle.getCounters();
284
- assert.strictEqual(counters.get("a"), 2);
285
- assert.strictEqual(counters.get("b"), 1);
286
- });
287
- });
288
-
289
- describe("grouping methods", () => {
290
- test("console.group increments depth", async () => {
291
- const groupCalls: Array<{ label: string; collapsed: boolean }> = [];
292
- const handle = await setupConsole(context, {
293
- onGroup: (label, collapsed) => groupCalls.push({ label, collapsed }),
294
- });
295
- assert.strictEqual(handle.getGroupDepth(), 0);
296
- context.evalSync(`console.group("Group 1")`);
297
- assert.strictEqual(handle.getGroupDepth(), 1);
298
- assert.deepStrictEqual(groupCalls[0], {
299
- label: "Group 1",
300
- collapsed: false,
301
- });
302
- });
303
-
304
- test("console.groupCollapsed increments depth with collapsed flag", async () => {
305
- const groupCalls: Array<{ label: string; collapsed: boolean }> = [];
306
- const handle = await setupConsole(context, {
307
- onGroup: (label, collapsed) => groupCalls.push({ label, collapsed }),
308
- });
309
- context.evalSync(`console.groupCollapsed("Collapsed Group")`);
310
- assert.strictEqual(handle.getGroupDepth(), 1);
311
- assert.deepStrictEqual(groupCalls[0], {
312
- label: "Collapsed Group",
313
- collapsed: true,
314
- });
315
- });
316
-
317
- test("console.group uses default label", async () => {
318
- const groupCalls: Array<{ label: string; collapsed: boolean }> = [];
319
- await setupConsole(context, {
320
- onGroup: (label, collapsed) => groupCalls.push({ label, collapsed }),
321
- });
322
- context.evalSync(`console.group()`);
323
- assert.strictEqual(groupCalls[0].label, "default");
324
- });
325
-
326
- test("console.groupEnd decrements depth", async () => {
327
- let groupEndCalls = 0;
328
- const handle = await setupConsole(context, {
329
- onGroupEnd: () => groupEndCalls++,
330
- });
331
- context.evalSync(`console.group()`);
332
- context.evalSync(`console.group()`);
333
- assert.strictEqual(handle.getGroupDepth(), 2);
334
-
335
- context.evalSync(`console.groupEnd()`);
336
- assert.strictEqual(handle.getGroupDepth(), 1);
337
- assert.strictEqual(groupEndCalls, 1);
338
- });
339
-
340
- test("console.groupEnd at depth 0 stays at 0", async () => {
341
- let groupEndCalls = 0;
342
- const handle = await setupConsole(context, {
343
- onGroupEnd: () => groupEndCalls++,
344
- });
345
- context.evalSync(`console.groupEnd()`);
346
- assert.strictEqual(handle.getGroupDepth(), 0);
347
- assert.strictEqual(groupEndCalls, 1); // Handler still called
348
- });
349
-
350
- test("nested groups track depth correctly", async () => {
351
- const handle = await setupConsole(context);
352
- context.evalSync(`
353
- console.group("Level 1");
354
- console.group("Level 2");
355
- console.group("Level 3");
356
- `);
357
- assert.strictEqual(handle.getGroupDepth(), 3);
358
-
359
- context.evalSync(`
360
- console.groupEnd();
361
- console.groupEnd();
362
- `);
363
- assert.strictEqual(handle.getGroupDepth(), 1);
364
- });
365
- });
366
-
367
- describe("other methods", () => {
368
- test("console.clear calls onClear", async () => {
369
- let clearCalls = 0;
370
- await setupConsole(context, {
371
- onClear: () => clearCalls++,
372
- });
373
- context.evalSync(`console.clear()`);
374
- assert.strictEqual(clearCalls, 1);
375
- });
376
-
377
- test("console.assert with truthy condition does not call handler", async () => {
378
- const assertCalls: Array<{ condition: boolean; args: unknown[] }> = [];
379
- await setupConsole(context, {
380
- onAssert: (condition, ...args) =>
381
- assertCalls.push({ condition, args }),
382
- });
383
- context.evalSync(`console.assert(true, "should not appear")`);
384
- assert.strictEqual(assertCalls.length, 0);
385
- });
386
-
387
- test("console.assert with falsy condition calls handler", async () => {
388
- const assertCalls: Array<{ condition: boolean; args: unknown[] }> = [];
389
- await setupConsole(context, {
390
- onAssert: (condition, ...args) =>
391
- assertCalls.push({ condition, args }),
392
- });
393
- context.evalSync(`console.assert(false, "assertion failed", 123)`);
394
- assert.strictEqual(assertCalls.length, 1);
395
- assert.deepStrictEqual(assertCalls[0], {
396
- condition: false,
397
- args: ["assertion failed", 123],
398
- });
399
- });
400
-
401
- test("console.assert with undefined condition calls handler", async () => {
402
- const assertCalls: Array<{ condition: boolean; args: unknown[] }> = [];
403
- await setupConsole(context, {
404
- onAssert: (condition, ...args) =>
405
- assertCalls.push({ condition, args }),
406
- });
407
- context.evalSync(`console.assert(undefined)`);
408
- assert.strictEqual(assertCalls.length, 1);
409
- });
410
-
411
- test("console.assert with 0 calls handler", async () => {
412
- const assertCalls: Array<{ condition: boolean; args: unknown[] }> = [];
413
- await setupConsole(context, {
414
- onAssert: (condition, ...args) =>
415
- assertCalls.push({ condition, args }),
416
- });
417
- context.evalSync(`console.assert(0)`);
418
- assert.strictEqual(assertCalls.length, 1);
419
- });
420
-
421
- test("console.assert with empty string calls handler", async () => {
422
- const assertCalls: Array<{ condition: boolean; args: unknown[] }> = [];
423
- await setupConsole(context, {
424
- onAssert: (condition, ...args) =>
425
- assertCalls.push({ condition, args }),
426
- });
427
- context.evalSync(`console.assert("")`);
428
- assert.strictEqual(assertCalls.length, 1);
429
- });
430
-
431
- test("console.assert with null calls handler", async () => {
432
- const assertCalls: Array<{ condition: boolean; args: unknown[] }> = [];
433
- await setupConsole(context, {
434
- onAssert: (condition, ...args) =>
435
- assertCalls.push({ condition, args }),
436
- });
437
- context.evalSync(`console.assert(null)`);
438
- assert.strictEqual(assertCalls.length, 1);
439
- });
440
- });
441
-
442
- describe("handle methods", () => {
443
- test("reset() clears all state", async () => {
444
- const handle = await setupConsole(context);
445
- context.evalSync(`
446
- console.time("timer");
447
- console.count("counter");
448
- console.group("group");
449
- `);
450
-
451
- assert.strictEqual(handle.getTimers().size, 1);
452
- assert.strictEqual(handle.getCounters().size, 1);
453
- assert.strictEqual(handle.getGroupDepth(), 1);
454
-
455
- handle.reset();
456
-
457
- assert.strictEqual(handle.getTimers().size, 0);
458
- assert.strictEqual(handle.getCounters().size, 0);
459
- assert.strictEqual(handle.getGroupDepth(), 0);
460
- });
461
-
462
- test("getTimers returns a copy", async () => {
463
- const handle = await setupConsole(context);
464
- context.evalSync(`console.time("test")`);
465
- const timers1 = handle.getTimers();
466
- const timers2 = handle.getTimers();
467
- assert.notStrictEqual(timers1, timers2);
468
- assert.deepStrictEqual([...timers1.keys()], [...timers2.keys()]);
469
- });
470
-
471
- test("getCounters returns a copy", async () => {
472
- const handle = await setupConsole(context);
473
- context.evalSync(`console.count("test")`);
474
- const counters1 = handle.getCounters();
475
- const counters2 = handle.getCounters();
476
- assert.notStrictEqual(counters1, counters2);
477
- assert.deepStrictEqual(counters1, counters2);
478
- });
479
- });
480
-
481
- describe("no handlers", () => {
482
- test("works without handlers", async () => {
483
- // Create a new context without handlers
484
- const testIsolate = new ivm.Isolate();
485
- const testContext = await testIsolate.createContext();
486
-
487
- const h = await setupConsole(testContext); // No handlers
488
-
489
- const result = testContext.evalSync(`
490
- console.log("test");
491
- console.time("t");
492
- console.timeEnd("t");
493
- console.count("c");
494
- console.countReset("c");
495
- console.clear();
496
- console.assert(false);
497
- console.group("g");
498
- console.groupEnd();
499
- "done"
500
- `);
501
-
502
- assert.strictEqual(result, "done");
503
-
504
- h.dispose();
505
- testContext.release();
506
- testIsolate.dispose();
507
- });
508
- });
509
- });
package/tsconfig.json DELETED
@@ -1,8 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.base.json",
3
- "compilerOptions": {
4
- "rootDir": "./src"
5
- },
6
- "include": ["src/**/*"],
7
- "exclude": ["node_modules", "dist", "**/*.test.ts"]
8
- }