@gjsify/console 0.0.4 → 0.1.0

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/index.spec.ts CHANGED
@@ -1,10 +1,550 @@
1
+ // Ported from refs/node-test/ and refs/node/test/parallel/test-console-*.js
2
+ // Original: MIT license, Node.js contributors
1
3
  import { describe, it, expect } from '@gjsify/unit';
2
- import console from "console"
4
+ import console, { Console, log, warn, error, info } from "node:console"
5
+ import { Writable } from "node:stream"
3
6
 
4
7
  export default async () => {
5
- await describe('Default import', async () => {
8
+ await describe('console: default import', async () => {
6
9
  await it('should be an object', async () => {
7
10
  expect(console instanceof Object).toBeTruthy();
8
11
  });
12
+
13
+ await it('should have log method', async () => {
14
+ expect(typeof console.log).toBe('function');
15
+ });
16
+
17
+ await it('should have warn method', async () => {
18
+ expect(typeof console.warn).toBe('function');
19
+ });
20
+
21
+ await it('should have error method', async () => {
22
+ expect(typeof console.error).toBe('function');
23
+ });
24
+
25
+ await it('should have info method', async () => {
26
+ expect(typeof console.info).toBe('function');
27
+ });
28
+
29
+ await it('should have debug method', async () => {
30
+ expect(typeof console.debug).toBe('function');
31
+ });
32
+
33
+ await it('should have table method', async () => {
34
+ expect(typeof console.table).toBe('function');
35
+ });
36
+
37
+ await it('should have time method', async () => {
38
+ expect(typeof console.time).toBe('function');
39
+ });
40
+
41
+ await it('should have timeEnd method', async () => {
42
+ expect(typeof console.timeEnd).toBe('function');
43
+ });
44
+
45
+ await it('should have trace method', async () => {
46
+ expect(typeof console.trace).toBe('function');
47
+ });
48
+
49
+ await it('should have assert method', async () => {
50
+ expect(typeof console.assert).toBe('function');
51
+ });
52
+
53
+ await it('should have clear method', async () => {
54
+ expect(typeof console.clear).toBe('function');
55
+ });
56
+
57
+ await it('should have count method', async () => {
58
+ expect(typeof console.count).toBe('function');
59
+ });
60
+
61
+ await it('should have countReset method', async () => {
62
+ expect(typeof console.countReset).toBe('function');
63
+ });
64
+
65
+ await it('should have group method', async () => {
66
+ expect(typeof console.group).toBe('function');
67
+ });
68
+
69
+ await it('should have groupEnd method', async () => {
70
+ expect(typeof console.groupEnd).toBe('function');
71
+ });
72
+
73
+ await it('should have timeLog method', async () => {
74
+ expect(typeof console.timeLog).toBe('function');
75
+ });
76
+
77
+ await it('should have groupCollapsed method', async () => {
78
+ expect(typeof console.groupCollapsed).toBe('function');
79
+ });
80
+
81
+ await it('should have dir method', async () => {
82
+ expect(typeof console.dir).toBe('function');
83
+ });
84
+ });
85
+
86
+ await describe('console: named exports', async () => {
87
+ await it('should export log function', async () => {
88
+ expect(typeof log).toBe('function');
89
+ });
90
+
91
+ await it('should export warn function', async () => {
92
+ expect(typeof warn).toBe('function');
93
+ });
94
+
95
+ await it('should export error function', async () => {
96
+ expect(typeof error).toBe('function');
97
+ });
98
+
99
+ await it('should export info function', async () => {
100
+ expect(typeof info).toBe('function');
101
+ });
102
+ });
103
+
104
+ await describe('console: Console class', async () => {
105
+ await it('should export Console constructor', async () => {
106
+ expect(typeof Console).toBe('function');
107
+ });
108
+
109
+ await it('should be an instance of Console when constructed', async () => {
110
+ const stdoutStream = new Writable({ write(_chunk, _enc, cb) { cb(); } });
111
+ const customConsole = new Console(stdoutStream);
112
+ expect(customConsole instanceof Console).toBeTruthy();
113
+ });
114
+
115
+ await it('should be constructable with stdout and stderr streams', async () => {
116
+ const stdoutStream = new Writable({ write(_chunk, _enc, cb) { cb(); } });
117
+ const stderrStream = new Writable({ write(_chunk, _enc, cb) { cb(); } });
118
+ const customConsole = new Console(stdoutStream, stderrStream);
119
+ expect(customConsole instanceof Console).toBeTruthy();
120
+ });
121
+
122
+ await it('should be constructable with options object', async () => {
123
+ const stdoutStream = new Writable({ write(_chunk, _enc, cb) { cb(); } });
124
+ const stderrStream = new Writable({ write(_chunk, _enc, cb) { cb(); } });
125
+ const customConsole = new Console({ stdout: stdoutStream, stderr: stderrStream });
126
+ expect(customConsole instanceof Console).toBeTruthy();
127
+ });
128
+
129
+ await it('should have all standard methods', async () => {
130
+ const stdoutStream = new Writable({ write(_chunk, _enc, cb) { cb(); } });
131
+ const customConsole = new Console(stdoutStream);
132
+ expect(typeof customConsole.log).toBe('function');
133
+ expect(typeof customConsole.warn).toBe('function');
134
+ expect(typeof customConsole.error).toBe('function');
135
+ expect(typeof customConsole.info).toBe('function');
136
+ expect(typeof customConsole.debug).toBe('function');
137
+ expect(typeof customConsole.time).toBe('function');
138
+ expect(typeof customConsole.timeEnd).toBe('function');
139
+ expect(typeof customConsole.count).toBe('function');
140
+ expect(typeof customConsole.countReset).toBe('function');
141
+ expect(typeof customConsole.group).toBe('function');
142
+ expect(typeof customConsole.groupEnd).toBe('function');
143
+ });
144
+ });
145
+
146
+ // ==================== behavioral tests ====================
147
+
148
+ await describe('console: assert behavior', async () => {
149
+ await it('should not throw on truthy assertion', async () => {
150
+ expect(() => console.assert(true)).not.toThrow();
151
+ expect(() => console.assert(1)).not.toThrow();
152
+ expect(() => console.assert('non-empty')).not.toThrow();
153
+ });
154
+
155
+ await it('should not throw on false assertion', async () => {
156
+ // console.assert with falsy value logs an error but does not throw
157
+ expect(() => console.assert(false)).not.toThrow();
158
+ });
159
+
160
+ await it('should not throw on false assertion with message args', async () => {
161
+ expect(() => console.assert(false, 'expected to be true')).not.toThrow();
162
+ expect(() => console.assert(false, 'msg', 42, { key: 'val' })).not.toThrow();
163
+ });
164
+ });
165
+
166
+ await describe('console: count/countReset behavior', async () => {
167
+ await it('count should not throw', async () => {
168
+ expect(() => console.count('test-label')).not.toThrow();
169
+ expect(() => console.count('test-label')).not.toThrow();
170
+ });
171
+
172
+ await it('countReset should not throw', async () => {
173
+ expect(() => console.countReset('test-label')).not.toThrow();
174
+ });
175
+
176
+ await it('count with default label should not throw', async () => {
177
+ expect(() => console.count()).not.toThrow();
178
+ expect(() => console.countReset()).not.toThrow();
179
+ });
180
+ });
181
+
182
+ await describe('console: time/timeEnd behavior', async () => {
183
+ await it('time and timeEnd should not throw', async () => {
184
+ expect(() => console.time('test-timer')).not.toThrow();
185
+ expect(() => console.timeEnd('test-timer')).not.toThrow();
186
+ });
187
+
188
+ await it('timeEnd without time should not throw', async () => {
189
+ expect(() => console.timeEnd('nonexistent-timer')).not.toThrow();
190
+ });
191
+
192
+ await it('timeLog should not throw after time', async () => {
193
+ console.time('timelog-timer');
194
+ expect(() => console.timeLog('timelog-timer')).not.toThrow();
195
+ console.timeEnd('timelog-timer');
196
+ });
197
+
198
+ await it('timeLog without matching time should not throw', async () => {
199
+ expect(() => console.timeLog('nonexistent-timer-log')).not.toThrow();
200
+ });
201
+
202
+ await it('timeLog with extra args should not throw', async () => {
203
+ console.time('timelog-extra');
204
+ expect(() => console.timeLog('timelog-extra', 'extra', 42)).not.toThrow();
205
+ console.timeEnd('timelog-extra');
206
+ });
207
+ });
208
+
209
+ await describe('console: group/groupEnd behavior', async () => {
210
+ await it('group and groupEnd should not throw', async () => {
211
+ expect(() => console.group('test-group')).not.toThrow();
212
+ expect(() => console.groupEnd()).not.toThrow();
213
+ });
214
+
215
+ await it('nested groups should not throw', async () => {
216
+ expect(() => {
217
+ console.group('outer');
218
+ console.group('inner');
219
+ console.groupEnd();
220
+ console.groupEnd();
221
+ }).not.toThrow();
222
+ });
223
+
224
+ await it('groupCollapsed should not throw', async () => {
225
+ expect(() => console.groupCollapsed('collapsed-group')).not.toThrow();
226
+ expect(() => console.groupEnd()).not.toThrow();
227
+ });
228
+
229
+ await it('groupEnd without group should not throw', async () => {
230
+ expect(() => console.groupEnd()).not.toThrow();
231
+ });
232
+ });
233
+
234
+ await describe('console: log/warn/error with no args', async () => {
235
+ await it('log with no args should not throw', async () => {
236
+ expect(() => console.log()).not.toThrow();
237
+ });
238
+
239
+ await it('warn with no args should not throw', async () => {
240
+ expect(() => console.warn()).not.toThrow();
241
+ });
242
+
243
+ await it('error with no args should not throw', async () => {
244
+ expect(() => console.error()).not.toThrow();
245
+ });
246
+
247
+ await it('info with no args should not throw', async () => {
248
+ expect(() => console.info()).not.toThrow();
249
+ });
250
+
251
+ await it('debug with no args should not throw', async () => {
252
+ expect(() => console.debug()).not.toThrow();
253
+ });
254
+ });
255
+
256
+ await describe('console: log/warn/error should not throw', async () => {
257
+ await it('log should handle various argument types', async () => {
258
+ expect(() => console.log('string')).not.toThrow();
259
+ expect(() => console.log(42)).not.toThrow();
260
+ expect(() => console.log({ key: 'value' })).not.toThrow();
261
+ expect(() => console.log(null)).not.toThrow();
262
+ expect(() => console.log(undefined)).not.toThrow();
263
+ expect(() => console.log([1, 2, 3])).not.toThrow();
264
+ });
265
+
266
+ await it('log should handle multiple arguments', async () => {
267
+ expect(() => console.log('a', 'b', 'c')).not.toThrow();
268
+ });
269
+
270
+ await it('warn should not throw', async () => {
271
+ expect(() => console.warn('warning')).not.toThrow();
272
+ });
273
+
274
+ await it('error should not throw', async () => {
275
+ expect(() => console.error('error')).not.toThrow();
276
+ });
277
+ });
278
+
279
+ await describe('console: format specifiers', async () => {
280
+ await it('log with %s string specifier should not throw', async () => {
281
+ expect(() => console.log('hello %s', 'world')).not.toThrow();
282
+ });
283
+
284
+ await it('log with %d number specifier should not throw', async () => {
285
+ expect(() => console.log('number: %d', 42)).not.toThrow();
286
+ });
287
+
288
+ await it('log with %i integer specifier should not throw', async () => {
289
+ expect(() => console.log('integer: %i', 3.7)).not.toThrow();
290
+ });
291
+
292
+ await it('log with %o object specifier should not throw', async () => {
293
+ expect(() => console.log('object: %o', { a: 1 })).not.toThrow();
294
+ });
295
+
296
+ await it('log with %j JSON specifier should not throw', async () => {
297
+ expect(() => console.log('json: %j', { b: 2 })).not.toThrow();
298
+ });
299
+
300
+ await it('log with multiple specifiers should not throw', async () => {
301
+ expect(() => console.log('%s has %d items', 'list', 5)).not.toThrow();
302
+ });
303
+ });
304
+
305
+ await describe('console: table behavior', async () => {
306
+ await it('table with array of objects should not throw', async () => {
307
+ expect(() => console.table([{ a: 1, b: 2 }, { a: 3, b: 4 }])).not.toThrow();
308
+ });
309
+
310
+ await it('table with plain array should not throw', async () => {
311
+ expect(() => console.table([1, 2, 3])).not.toThrow();
312
+ });
313
+
314
+ await it('table with single object should not throw', async () => {
315
+ expect(() => console.table({ key: 'value', num: 42 })).not.toThrow();
316
+ });
317
+ });
318
+
319
+ await describe('console: dir should not throw', async () => {
320
+ await it('should accept objects', async () => {
321
+ expect(() => console.dir({ key: 'value' })).not.toThrow();
322
+ });
323
+
324
+ await it('should accept options with depth', async () => {
325
+ expect(() => console.dir({ nested: { deep: { val: 1 } } }, { depth: 0 })).not.toThrow();
326
+ });
327
+
328
+ await it('should accept options with colors', async () => {
329
+ expect(() => console.dir({ key: 'value' }, { colors: false })).not.toThrow();
330
+ });
331
+
332
+ await it('should accept options with depth and colors', async () => {
333
+ expect(() => console.dir({ a: 1 }, { depth: 2, colors: true })).not.toThrow();
334
+ });
335
+ });
336
+
337
+ await describe('console: clear should not throw', async () => {
338
+ await it('should not throw', async () => {
339
+ expect(() => console.clear()).not.toThrow();
340
+ });
341
+ });
342
+
343
+ await describe('console: trace behavior', async () => {
344
+ await it('trace should not throw', async () => {
345
+ expect(() => console.trace()).not.toThrow();
346
+ });
347
+
348
+ await it('trace with message should not throw', async () => {
349
+ expect(() => console.trace('trace message')).not.toThrow();
350
+ });
351
+
352
+ await it('trace with multiple args should not throw', async () => {
353
+ expect(() => console.trace('msg', 42, { key: 'val' })).not.toThrow();
354
+ });
355
+ });
356
+
357
+ await describe('console: method aliases', async () => {
358
+ await it('warn and error should both be functions', async () => {
359
+ expect(typeof console.warn).toBe('function');
360
+ expect(typeof console.error).toBe('function');
361
+ });
362
+
363
+ await it('info and log should both be functions', async () => {
364
+ expect(typeof console.info).toBe('function');
365
+ expect(typeof console.log).toBe('function');
366
+ });
367
+
368
+ await it('debug should be a function like log', async () => {
369
+ expect(typeof console.debug).toBe('function');
370
+ });
371
+ });
372
+
373
+ await describe('console: Console class stdout/stderr writing', async () => {
374
+ await it('log should write to stdout stream', async () => {
375
+ const output: string[] = [];
376
+ const stdoutStream = new Writable({
377
+ write(chunk, _enc, cb) { output.push(chunk.toString()); cb(); }
378
+ });
379
+ const c = new Console(stdoutStream);
380
+ c.log('hello');
381
+ expect(output.length).toBeGreaterThan(0);
382
+ expect(output[0]).toContain('hello');
383
+ });
384
+
385
+ await it('error should write to stderr stream', async () => {
386
+ const stdoutOutput: string[] = [];
387
+ const stderrOutput: string[] = [];
388
+ const stdoutStream = new Writable({
389
+ write(chunk, _enc, cb) { stdoutOutput.push(chunk.toString()); cb(); }
390
+ });
391
+ const stderrStream = new Writable({
392
+ write(chunk, _enc, cb) { stderrOutput.push(chunk.toString()); cb(); }
393
+ });
394
+ const c = new Console(stdoutStream, stderrStream);
395
+ c.error('err msg');
396
+ expect(stderrOutput.length).toBeGreaterThan(0);
397
+ expect(stderrOutput[0]).toContain('err msg');
398
+ });
399
+
400
+ await it('warn should write to stderr stream', async () => {
401
+ const stdoutOutput: string[] = [];
402
+ const stderrOutput: string[] = [];
403
+ const stdoutStream = new Writable({
404
+ write(chunk, _enc, cb) { stdoutOutput.push(chunk.toString()); cb(); }
405
+ });
406
+ const stderrStream = new Writable({
407
+ write(chunk, _enc, cb) { stderrOutput.push(chunk.toString()); cb(); }
408
+ });
409
+ const c = new Console(stdoutStream, stderrStream);
410
+ c.warn('warn msg');
411
+ expect(stderrOutput.length).toBeGreaterThan(0);
412
+ expect(stderrOutput[0]).toContain('warn msg');
413
+ });
414
+
415
+ await it('info should write to stdout stream', async () => {
416
+ const output: string[] = [];
417
+ const stdoutStream = new Writable({
418
+ write(chunk, _enc, cb) { output.push(chunk.toString()); cb(); }
419
+ });
420
+ const c = new Console(stdoutStream);
421
+ c.info('info msg');
422
+ expect(output.length).toBeGreaterThan(0);
423
+ expect(output[0]).toContain('info msg');
424
+ });
425
+
426
+ await it('debug should write to stdout stream', async () => {
427
+ const output: string[] = [];
428
+ const stdoutStream = new Writable({
429
+ write(chunk, _enc, cb) { output.push(chunk.toString()); cb(); }
430
+ });
431
+ const c = new Console(stdoutStream);
432
+ c.debug('debug msg');
433
+ expect(output.length).toBeGreaterThan(0);
434
+ expect(output[0]).toContain('debug msg');
435
+ });
436
+ });
437
+
438
+ await describe('console: Console class count behavior', async () => {
439
+ await it('count should increment and write to stdout', async () => {
440
+ const output: string[] = [];
441
+ const stdoutStream = new Writable({
442
+ write(chunk, _enc, cb) { output.push(chunk.toString()); cb(); }
443
+ });
444
+ const c = new Console(stdoutStream);
445
+ c.count('myLabel');
446
+ c.count('myLabel');
447
+ expect(output.length).toBe(2);
448
+ expect(output[0]).toContain('myLabel: 1');
449
+ expect(output[1]).toContain('myLabel: 2');
450
+ });
451
+
452
+ await it('countReset should reset the counter', async () => {
453
+ const output: string[] = [];
454
+ const stdoutStream = new Writable({
455
+ write(chunk, _enc, cb) { output.push(chunk.toString()); cb(); }
456
+ });
457
+ const c = new Console(stdoutStream);
458
+ c.count('reset-test');
459
+ c.count('reset-test');
460
+ c.countReset('reset-test');
461
+ c.count('reset-test');
462
+ expect(output.length).toBe(3);
463
+ expect(output[2]).toContain('reset-test: 1');
464
+ });
465
+ });
466
+
467
+ await describe('console: Console class group indentation', async () => {
468
+ await it('group should indent subsequent log output', async () => {
469
+ const output: string[] = [];
470
+ const stdoutStream = new Writable({
471
+ write(chunk, _enc, cb) { output.push(chunk.toString()); cb(); }
472
+ });
473
+ const c = new Console(stdoutStream);
474
+ c.log('before');
475
+ c.group('g1');
476
+ c.log('indented');
477
+ c.groupEnd();
478
+ c.log('after');
479
+ // 'before' should not have leading spaces, 'indented' should
480
+ expect(output[0]).toContain('before');
481
+ // The indented line should have leading whitespace
482
+ const indentedLine = output.find(l => l.includes('indented')) || '';
483
+ expect(indentedLine.startsWith(' ')).toBeTruthy();
484
+ // 'after' should not start with spaces
485
+ const afterLine = output[output.length - 1];
486
+ expect(afterLine).toContain('after');
487
+ });
488
+ });
489
+
490
+ await describe('console: Console class assert behavior', async () => {
491
+ await it('assert with false should write to stderr without throwing', async () => {
492
+ const stderrOutput: string[] = [];
493
+ const stdoutStream = new Writable({
494
+ write(_chunk, _enc, cb) { cb(); }
495
+ });
496
+ const stderrStream = new Writable({
497
+ write(chunk, _enc, cb) { stderrOutput.push(chunk.toString()); cb(); }
498
+ });
499
+ const c = new Console(stdoutStream, stderrStream);
500
+ expect(() => c.assert(false, 'test assertion')).not.toThrow();
501
+ expect(stderrOutput.length).toBeGreaterThan(0);
502
+ expect(stderrOutput[0]).toContain('Assertion failed');
503
+ });
504
+
505
+ await it('assert with true should not write anything', async () => {
506
+ const stderrOutput: string[] = [];
507
+ const stdoutStream = new Writable({
508
+ write(_chunk, _enc, cb) { cb(); }
509
+ });
510
+ const stderrStream = new Writable({
511
+ write(chunk, _enc, cb) { stderrOutput.push(chunk.toString()); cb(); }
512
+ });
513
+ const c = new Console(stdoutStream, stderrStream);
514
+ c.assert(true, 'should not appear');
515
+ expect(stderrOutput.length).toBe(0);
516
+ });
517
+ });
518
+
519
+ await describe('console: Console class trace behavior', async () => {
520
+ await it('trace should write to stderr stream', async () => {
521
+ const stderrOutput: string[] = [];
522
+ const stdoutStream = new Writable({
523
+ write(_chunk, _enc, cb) { cb(); }
524
+ });
525
+ const stderrStream = new Writable({
526
+ write(chunk, _enc, cb) { stderrOutput.push(chunk.toString()); cb(); }
527
+ });
528
+ const c = new Console(stdoutStream, stderrStream);
529
+ c.trace('trace test');
530
+ expect(stderrOutput.length).toBeGreaterThan(0);
531
+ expect(stderrOutput[0]).toContain('Trace');
532
+ });
533
+ });
534
+
535
+ await describe('console: Console class time/timeLog behavior', async () => {
536
+ await it('timeLog should write elapsed time to stdout', async () => {
537
+ const output: string[] = [];
538
+ const stdoutStream = new Writable({
539
+ write(chunk, _enc, cb) { output.push(chunk.toString()); cb(); }
540
+ });
541
+ const c = new Console(stdoutStream);
542
+ c.time('perf');
543
+ c.timeLog('perf');
544
+ c.timeEnd('perf');
545
+ expect(output.length).toBe(2);
546
+ expect(output[0]).toContain('perf:');
547
+ expect(output[1]).toContain('perf:');
548
+ });
9
549
  });
10
550
  }