@tkeron/tools 0.3.0 โ†’ 0.4.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/changelog.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.4.0] - 2026-02-15
4
+
5
+ ### Added
6
+
7
+ - **Logger system**: Generic logging abstraction for standardized logging across the ecosystem
8
+ - `Logger` interface: Standard interface with `log`, `error`, `warn`, `info` methods
9
+ - `logger`: Default implementation using console methods
10
+ - `silentLogger`: No-op logger for silent operation (useful in production or tests)
11
+ - `createTestLogger()`: Captures logs in arrays for testing and verification
12
+ - Full TypeScript support with exported types
13
+ - Comprehensive test coverage (45 tests across 3 test files)
14
+
15
+ ### Documentation
16
+
17
+ - Logger system fully tested with edge cases (null, undefined, Error objects, mixed types)
18
+ - Test logger supports independent instances and manual array manipulation
19
+
3
20
  ## [0.3.0] - 2026-02-15
4
21
 
5
22
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tkeron/tools",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Useful JavaScript utilities for Bun runtime",
5
5
  "main": "src/index.ts",
6
6
  "module": "src/index.ts",
package/readme.md CHANGED
@@ -27,9 +27,88 @@ import * as tools from "@tkeron/tools";
27
27
  import { rng, getLIFO, getPaths } from "@tkeron/tools";
28
28
  ```
29
29
 
30
+ ## ๐Ÿ“š Available Utilities
31
+
32
+ ### Logger System
33
+
34
+ Generic logging abstraction for standardized logging across applications:
35
+
36
+ ```typescript
37
+ import { Logger, logger, silentLogger, createTestLogger } from "@tkeron/tools";
38
+
39
+ // Default logger (uses console)
40
+ logger.log("Hello world");
41
+ logger.error("Error message");
42
+ logger.warn("Warning message");
43
+ logger.info("Info message");
44
+
45
+ // Silent logger (no output, useful for production or testing)
46
+ silentLogger.log("This won't appear");
47
+
48
+ // Test logger (captures logs in arrays for testing)
49
+ const { logger: testLog, logs, errors, warns, infos } = createTestLogger();
50
+ testLog.log("Test message");
51
+ console.log(logs); // ["Test message"]
52
+
53
+ // Inject logger in your functions
54
+ const myFunction = (data: string, log: Logger = logger) => {
55
+ log.info("Processing:", data);
56
+ // ... your logic
57
+ };
58
+ ```
59
+
60
+ ### File System Utilities
61
+
62
+ Glob pattern matching and path retrieval:
63
+
64
+ ```typescript
65
+ import { getPaths, getFilePaths, getDirectoryPaths } from "@tkeron/tools";
66
+
67
+ // Get all files and directories
68
+ const allPaths = getPaths("/path/to/dir", "**/*", "yes");
69
+
70
+ // Get only files
71
+ const files = getFilePaths("/path/to/dir", "**/*.ts");
72
+
73
+ // Get only directories
74
+ const dirs = getDirectoryPaths("/path/to/dir", "**/");
75
+ ```
76
+
77
+ ### Data Structures
78
+
79
+ Stack implementations (LIFO/FIFO):
80
+
81
+ ```typescript
82
+ import { getLIFO, getFIFO } from "@tkeron/tools";
83
+
84
+ const stack = getLIFO<string>();
85
+ stack.push("first");
86
+ stack.push("second");
87
+ console.log(stack.current); // "second"
88
+ console.log(stack.pop()); // "second"
89
+ ```
90
+
91
+ ### Random Number Generator
92
+
93
+ Seedable random number generator:
94
+
95
+ ```typescript
96
+ import { rng } from "@tkeron/tools";
97
+
98
+ // Generate infinite sequence with seed
99
+ for (const num of rng(42)) {
100
+ console.log(num);
101
+ }
102
+
103
+ // Generate limited sequence
104
+ for (const num of rng(42, 10)) {
105
+ console.log(num); // Only 10 numbers
106
+ }
107
+ ```
108
+
30
109
  ## ๐Ÿ“š Documentation
31
110
 
32
- For detailed documentation of all available utilities, please refer to the TypeScript definitions or explore the source code. Each utility is fully typed and includes JSDoc comments for better IDE support.
111
+ For detailed documentation and TypeScript definitions, refer to the source code. Each utility is fully typed with JSDoc comments for IDE support.
33
112
 
34
113
  ## ๐Ÿงช Testing
35
114
 
@@ -0,0 +1,31 @@
1
+ import type { Logger } from "./loggerObj.js";
2
+
3
+ export const createTestLogger = () => {
4
+ const logs: string[] = [];
5
+ const errors: string[] = [];
6
+ const warns: string[] = [];
7
+ const infos: string[] = [];
8
+
9
+ const format = (args: unknown[]) =>
10
+ args
11
+ .map((a) => {
12
+ if (typeof a === "string") return a;
13
+ if (a === undefined) return "undefined";
14
+ if (a instanceof Error) return a.stack || a.message || String(a);
15
+ return JSON.stringify(a);
16
+ })
17
+ .join(" ");
18
+
19
+ return {
20
+ logger: {
21
+ log: (...args: unknown[]) => logs.push(format(args)),
22
+ error: (...args: unknown[]) => errors.push(format(args)),
23
+ warn: (...args: unknown[]) => warns.push(format(args)),
24
+ info: (...args: unknown[]) => infos.push(format(args)),
25
+ } as Logger,
26
+ logs,
27
+ errors,
28
+ warns,
29
+ infos,
30
+ };
31
+ };
package/src/index.ts CHANGED
@@ -1,3 +1,6 @@
1
1
  export * from "./random";
2
2
  export * from "./stack";
3
3
  export * from "./getPaths";
4
+ export * from "./loggerObj";
5
+ export * from "./silentLogger";
6
+ export * from "./createTestLogger";
@@ -0,0 +1,13 @@
1
+ export interface Logger {
2
+ log: (...args: unknown[]) => void;
3
+ error: (...args: unknown[]) => void;
4
+ warn: (...args: unknown[]) => void;
5
+ info: (...args: unknown[]) => void;
6
+ }
7
+
8
+ export const logger: Logger = {
9
+ log: (...args: unknown[]) => console.log(...args),
10
+ error: (...args: unknown[]) => console.error(...args),
11
+ warn: (...args: unknown[]) => console.warn(...args),
12
+ info: (...args: unknown[]) => console.info(...args),
13
+ };
@@ -0,0 +1,8 @@
1
+ import type { Logger } from "./loggerObj.js";
2
+
3
+ export const silentLogger: Logger = {
4
+ log: () => {},
5
+ error: () => {},
6
+ warn: () => {},
7
+ info: () => {},
8
+ };
@@ -0,0 +1,392 @@
1
+ import { describe, it, expect, spyOn, beforeEach, afterEach } from "bun:test";
2
+ import { createTestLogger } from "../src/createTestLogger.js";
3
+ import type { Logger } from "../src/loggerObj.js";
4
+
5
+ describe("createTestLogger", () => {
6
+ it("should return an object with logger and arrays", () => {
7
+ const result = createTestLogger();
8
+ expect(result).toHaveProperty("logger");
9
+ expect(result).toHaveProperty("logs");
10
+ expect(result).toHaveProperty("errors");
11
+ expect(result).toHaveProperty("warns");
12
+ expect(result).toHaveProperty("infos");
13
+ expect(Array.isArray(result.logs)).toBe(true);
14
+ expect(Array.isArray(result.errors)).toBe(true);
15
+ expect(Array.isArray(result.warns)).toBe(true);
16
+ expect(Array.isArray(result.infos)).toBe(true);
17
+ });
18
+
19
+ it("should return empty arrays initially", () => {
20
+ const { logs, errors, warns, infos } = createTestLogger();
21
+ expect(logs).toEqual([]);
22
+ expect(errors).toEqual([]);
23
+ expect(warns).toEqual([]);
24
+ expect(infos).toEqual([]);
25
+ });
26
+
27
+ it("should return a logger compatible with Logger interface", () => {
28
+ const { logger } = createTestLogger();
29
+ const testLogger: Logger = logger;
30
+ expect(testLogger).toBeDefined();
31
+ });
32
+
33
+ it("should have all required methods", () => {
34
+ const { logger } = createTestLogger();
35
+ expect(logger).toHaveProperty("log");
36
+ expect(logger).toHaveProperty("error");
37
+ expect(logger).toHaveProperty("warn");
38
+ expect(logger).toHaveProperty("info");
39
+ expect(typeof logger.log).toBe("function");
40
+ expect(typeof logger.error).toBe("function");
41
+ expect(typeof logger.warn).toBe("function");
42
+ expect(typeof logger.info).toBe("function");
43
+ });
44
+ });
45
+
46
+ describe("createTestLogger.logger.log", () => {
47
+ let consoleSpy: any;
48
+
49
+ beforeEach(() => {
50
+ consoleSpy = spyOn(console, "log");
51
+ });
52
+
53
+ afterEach(() => {
54
+ consoleSpy.mockRestore();
55
+ });
56
+
57
+ it("should not call console.log", () => {
58
+ const { logger } = createTestLogger();
59
+ logger.log("test");
60
+ expect(consoleSpy).not.toHaveBeenCalled();
61
+ });
62
+
63
+ it("should capture single string", () => {
64
+ const { logger, logs } = createTestLogger();
65
+ logger.log("test message");
66
+ expect(logs).toEqual(["test message"]);
67
+ });
68
+
69
+ it("should capture multiple strings", () => {
70
+ const { logger, logs } = createTestLogger();
71
+ logger.log("test", "multiple", "args");
72
+ expect(logs).toEqual(["test multiple args"]);
73
+ });
74
+
75
+ it("should capture number", () => {
76
+ const { logger, logs } = createTestLogger();
77
+ logger.log(42);
78
+ expect(logs).toEqual(["42"]);
79
+ });
80
+
81
+ it("should capture object as JSON", () => {
82
+ const { logger, logs } = createTestLogger();
83
+ logger.log({ key: "value" });
84
+ expect(logs).toEqual(['{"key":"value"}']);
85
+ });
86
+
87
+ it("should capture array as JSON", () => {
88
+ const { logger, logs } = createTestLogger();
89
+ logger.log([1, 2, 3]);
90
+ expect(logs).toEqual(["[1,2,3]"]);
91
+ });
92
+
93
+ it("should capture null", () => {
94
+ const { logger, logs } = createTestLogger();
95
+ logger.log(null);
96
+ expect(logs).toEqual(["null"]);
97
+ });
98
+
99
+ it("should capture undefined", () => {
100
+ const { logger, logs } = createTestLogger();
101
+ logger.log(undefined);
102
+ expect(logs).toEqual(["undefined"]);
103
+ });
104
+
105
+ it("should capture boolean", () => {
106
+ const { logger, logs } = createTestLogger();
107
+ logger.log(true);
108
+ expect(logs).toEqual(["true"]);
109
+ });
110
+
111
+ it("should capture multiple calls", () => {
112
+ const { logger, logs } = createTestLogger();
113
+ logger.log("first");
114
+ logger.log("second");
115
+ logger.log("third");
116
+ expect(logs).toEqual(["first", "second", "third"]);
117
+ });
118
+
119
+ it("should capture mixed types", () => {
120
+ const { logger, logs } = createTestLogger();
121
+ logger.log("string", 42, { key: "val" });
122
+ expect(logs).toEqual(['string 42 {"key":"val"}']);
123
+ });
124
+
125
+ it("should capture empty string", () => {
126
+ const { logger, logs } = createTestLogger();
127
+ logger.log("");
128
+ expect(logs).toEqual([""]);
129
+ });
130
+
131
+ it("should capture zero", () => {
132
+ const { logger, logs } = createTestLogger();
133
+ logger.log(0);
134
+ expect(logs).toEqual(["0"]);
135
+ });
136
+
137
+ it("should capture negative number", () => {
138
+ const { logger, logs } = createTestLogger();
139
+ logger.log(-42);
140
+ expect(logs).toEqual(["-42"]);
141
+ });
142
+
143
+ it("should capture NaN", () => {
144
+ const { logger, logs } = createTestLogger();
145
+ logger.log(NaN);
146
+ expect(logs).toEqual(["null"]);
147
+ });
148
+
149
+ it("should capture Infinity", () => {
150
+ const { logger, logs } = createTestLogger();
151
+ logger.log(Infinity);
152
+ expect(logs).toEqual(["null"]);
153
+ });
154
+
155
+ it("should not mutate logs array reference", () => {
156
+ const testLogger = createTestLogger();
157
+ const originalLogsRef = testLogger.logs;
158
+ testLogger.logger.log("test");
159
+ expect(testLogger.logs).toBe(originalLogsRef);
160
+ });
161
+ });
162
+
163
+ describe("createTestLogger.logger.error", () => {
164
+ let consoleSpy: any;
165
+
166
+ beforeEach(() => {
167
+ consoleSpy = spyOn(console, "error");
168
+ });
169
+
170
+ afterEach(() => {
171
+ consoleSpy.mockRestore();
172
+ });
173
+
174
+ it("should not call console.error", () => {
175
+ const { logger } = createTestLogger();
176
+ logger.error("test");
177
+ expect(consoleSpy).not.toHaveBeenCalled();
178
+ });
179
+
180
+ it("should capture single string", () => {
181
+ const { logger, errors } = createTestLogger();
182
+ logger.error("error message");
183
+ expect(errors).toEqual(["error message"]);
184
+ });
185
+
186
+ it("should capture multiple strings", () => {
187
+ const { logger, errors } = createTestLogger();
188
+ logger.error("error", "multiple", "args");
189
+ expect(errors).toEqual(["error multiple args"]);
190
+ });
191
+
192
+ it("should capture Error object", () => {
193
+ const { logger, errors } = createTestLogger();
194
+ const error = new Error("test error");
195
+ logger.error(error);
196
+ expect(errors.length).toBe(1);
197
+ expect(errors[0]).toContain("test error");
198
+ });
199
+
200
+ it("should capture null", () => {
201
+ const { logger, errors } = createTestLogger();
202
+ logger.error(null);
203
+ expect(errors).toEqual(["null"]);
204
+ });
205
+
206
+ it("should capture undefined", () => {
207
+ const { logger, errors } = createTestLogger();
208
+ logger.error(undefined);
209
+ expect(errors).toEqual(["undefined"]);
210
+ });
211
+
212
+ it("should capture multiple calls", () => {
213
+ const { logger, errors } = createTestLogger();
214
+ logger.error("first");
215
+ logger.error("second");
216
+ logger.error("third");
217
+ expect(errors).toEqual(["first", "second", "third"]);
218
+ });
219
+ });
220
+
221
+ describe("createTestLogger.logger.warn", () => {
222
+ let consoleSpy: any;
223
+
224
+ beforeEach(() => {
225
+ consoleSpy = spyOn(console, "warn");
226
+ });
227
+
228
+ afterEach(() => {
229
+ consoleSpy.mockRestore();
230
+ });
231
+
232
+ it("should not call console.warn", () => {
233
+ const { logger } = createTestLogger();
234
+ logger.warn("test");
235
+ expect(consoleSpy).not.toHaveBeenCalled();
236
+ });
237
+
238
+ it("should capture single string", () => {
239
+ const { logger, warns } = createTestLogger();
240
+ logger.warn("warning message");
241
+ expect(warns).toEqual(["warning message"]);
242
+ });
243
+
244
+ it("should capture multiple strings", () => {
245
+ const { logger, warns } = createTestLogger();
246
+ logger.warn("warn", "multiple", "args");
247
+ expect(warns).toEqual(["warn multiple args"]);
248
+ });
249
+
250
+ it("should capture null", () => {
251
+ const { logger, warns } = createTestLogger();
252
+ logger.warn(null);
253
+ expect(warns).toEqual(["null"]);
254
+ });
255
+
256
+ it("should capture undefined", () => {
257
+ const { logger, warns } = createTestLogger();
258
+ logger.warn(undefined);
259
+ expect(warns).toEqual(["undefined"]);
260
+ });
261
+
262
+ it("should capture multiple calls", () => {
263
+ const { logger, warns } = createTestLogger();
264
+ logger.warn("first");
265
+ logger.warn("second");
266
+ logger.warn("third");
267
+ expect(warns).toEqual(["first", "second", "third"]);
268
+ });
269
+ });
270
+
271
+ describe("createTestLogger.logger.info", () => {
272
+ let consoleSpy: any;
273
+
274
+ beforeEach(() => {
275
+ consoleSpy = spyOn(console, "info");
276
+ });
277
+
278
+ afterEach(() => {
279
+ consoleSpy.mockRestore();
280
+ });
281
+
282
+ it("should not call console.info", () => {
283
+ const { logger } = createTestLogger();
284
+ logger.info("test");
285
+ expect(consoleSpy).not.toHaveBeenCalled();
286
+ });
287
+
288
+ it("should capture single string", () => {
289
+ const { logger, infos } = createTestLogger();
290
+ logger.info("info message");
291
+ expect(infos).toEqual(["info message"]);
292
+ });
293
+
294
+ it("should capture multiple strings", () => {
295
+ const { logger, infos } = createTestLogger();
296
+ logger.info("info", "multiple", "args");
297
+ expect(infos).toEqual(["info multiple args"]);
298
+ });
299
+
300
+ it("should capture null", () => {
301
+ const { logger, infos } = createTestLogger();
302
+ logger.info(null);
303
+ expect(infos).toEqual(["null"]);
304
+ });
305
+
306
+ it("should capture undefined", () => {
307
+ const { logger, infos } = createTestLogger();
308
+ logger.info(undefined);
309
+ expect(infos).toEqual(["undefined"]);
310
+ });
311
+
312
+ it("should capture multiple calls", () => {
313
+ const { logger, infos } = createTestLogger();
314
+ logger.info("first");
315
+ logger.info("second");
316
+ logger.info("third");
317
+ expect(infos).toEqual(["first", "second", "third"]);
318
+ });
319
+ });
320
+
321
+ describe("createTestLogger isolation", () => {
322
+ it("should create independent loggers", () => {
323
+ const logger1 = createTestLogger();
324
+ const logger2 = createTestLogger();
325
+
326
+ logger1.logger.log("logger1");
327
+ logger2.logger.log("logger2");
328
+
329
+ expect(logger1.logs).toEqual(["logger1"]);
330
+ expect(logger2.logs).toEqual(["logger2"]);
331
+ });
332
+
333
+ it("should not share state between instances", () => {
334
+ const logger1 = createTestLogger();
335
+ const logger2 = createTestLogger();
336
+
337
+ logger1.logger.log("test1");
338
+ logger1.logger.error("error1");
339
+
340
+ expect(logger2.logs).toEqual([]);
341
+ expect(logger2.errors).toEqual([]);
342
+ });
343
+
344
+ it("should allow manual array manipulation", () => {
345
+ const testLogger = createTestLogger();
346
+ testLogger.logger.log("test");
347
+ expect(testLogger.logs).toEqual(["test"]);
348
+
349
+ testLogger.logs.length = 0;
350
+ expect(testLogger.logs).toEqual([]);
351
+ });
352
+ });
353
+
354
+ describe("createTestLogger all methods", () => {
355
+ it("should capture to correct arrays", () => {
356
+ const { logger, logs, errors, warns, infos } = createTestLogger();
357
+
358
+ logger.log("log message");
359
+ logger.error("error message");
360
+ logger.warn("warn message");
361
+ logger.info("info message");
362
+
363
+ expect(logs).toEqual(["log message"]);
364
+ expect(errors).toEqual(["error message"]);
365
+ expect(warns).toEqual(["warn message"]);
366
+ expect(infos).toEqual(["info message"]);
367
+ });
368
+
369
+ it("should not cross-contaminate arrays", () => {
370
+ const { logger, logs, errors, warns, infos } = createTestLogger();
371
+
372
+ logger.log("log");
373
+ expect(errors).toEqual([]);
374
+ expect(warns).toEqual([]);
375
+ expect(infos).toEqual([]);
376
+
377
+ logger.error("error");
378
+ expect(logs).toEqual(["log"]);
379
+ expect(warns).toEqual([]);
380
+ expect(infos).toEqual([]);
381
+
382
+ logger.warn("warn");
383
+ expect(logs).toEqual(["log"]);
384
+ expect(errors).toEqual(["error"]);
385
+ expect(infos).toEqual([]);
386
+
387
+ logger.info("info");
388
+ expect(logs).toEqual(["log"]);
389
+ expect(errors).toEqual(["error"]);
390
+ expect(warns).toEqual(["warn"]);
391
+ });
392
+ });
@@ -0,0 +1,285 @@
1
+ import { describe, it, expect, spyOn, beforeEach, afterEach } from "bun:test";
2
+ import { logger } from "../src/loggerObj.js";
3
+ import type { Logger } from "../src/loggerObj.js";
4
+
5
+ describe("Logger interface", () => {
6
+ it("should have all required methods", () => {
7
+ expect(logger).toHaveProperty("log");
8
+ expect(logger).toHaveProperty("error");
9
+ expect(logger).toHaveProperty("warn");
10
+ expect(logger).toHaveProperty("info");
11
+ expect(typeof logger.log).toBe("function");
12
+ expect(typeof logger.error).toBe("function");
13
+ expect(typeof logger.warn).toBe("function");
14
+ expect(typeof logger.info).toBe("function");
15
+ });
16
+ });
17
+
18
+ describe("logger.log", () => {
19
+ let logSpy: any;
20
+
21
+ beforeEach(() => {
22
+ logSpy = spyOn(console, "log");
23
+ });
24
+
25
+ afterEach(() => {
26
+ logSpy.mockRestore();
27
+ });
28
+
29
+ it("should call console.log with single string", () => {
30
+ logger.log("test message");
31
+ expect(logSpy).toHaveBeenCalledWith("test message");
32
+ expect(logSpy).toHaveBeenCalledTimes(1);
33
+ });
34
+
35
+ it("should call console.log with multiple arguments", () => {
36
+ logger.log("test", "multiple", "args");
37
+ expect(logSpy).toHaveBeenCalledWith("test", "multiple", "args");
38
+ expect(logSpy).toHaveBeenCalledTimes(1);
39
+ });
40
+
41
+ it("should call console.log with number", () => {
42
+ logger.log(42);
43
+ expect(logSpy).toHaveBeenCalledWith(42);
44
+ expect(logSpy).toHaveBeenCalledTimes(1);
45
+ });
46
+
47
+ it("should call console.log with object", () => {
48
+ const obj = { key: "value" };
49
+ logger.log(obj);
50
+ expect(logSpy).toHaveBeenCalledWith(obj);
51
+ expect(logSpy).toHaveBeenCalledTimes(1);
52
+ });
53
+
54
+ it("should call console.log with array", () => {
55
+ const arr = [1, 2, 3];
56
+ logger.log(arr);
57
+ expect(logSpy).toHaveBeenCalledWith(arr);
58
+ expect(logSpy).toHaveBeenCalledTimes(1);
59
+ });
60
+
61
+ it("should call console.log with null", () => {
62
+ logger.log(null);
63
+ expect(logSpy).toHaveBeenCalledWith(null);
64
+ expect(logSpy).toHaveBeenCalledTimes(1);
65
+ });
66
+
67
+ it("should call console.log with undefined", () => {
68
+ logger.log(undefined);
69
+ expect(logSpy).toHaveBeenCalledWith(undefined);
70
+ expect(logSpy).toHaveBeenCalledTimes(1);
71
+ });
72
+
73
+ it("should call console.log with boolean", () => {
74
+ logger.log(true);
75
+ expect(logSpy).toHaveBeenCalledWith(true);
76
+ expect(logSpy).toHaveBeenCalledTimes(1);
77
+ });
78
+
79
+ it("should call console.log with mixed types", () => {
80
+ logger.log("string", 42, { key: "value" }, [1, 2], null, undefined, true);
81
+ expect(logSpy).toHaveBeenCalledWith(
82
+ "string",
83
+ 42,
84
+ { key: "value" },
85
+ [1, 2],
86
+ null,
87
+ undefined,
88
+ true,
89
+ );
90
+ expect(logSpy).toHaveBeenCalledTimes(1);
91
+ });
92
+
93
+ it("should call console.log with no arguments", () => {
94
+ logger.log();
95
+ expect(logSpy).toHaveBeenCalledWith();
96
+ expect(logSpy).toHaveBeenCalledTimes(1);
97
+ });
98
+
99
+ it("should call console.log multiple times independently", () => {
100
+ logger.log("first");
101
+ logger.log("second");
102
+ logger.log("third");
103
+ expect(logSpy).toHaveBeenCalledTimes(3);
104
+ });
105
+
106
+ it("should call console.log with empty string", () => {
107
+ logger.log("");
108
+ expect(logSpy).toHaveBeenCalledWith("");
109
+ expect(logSpy).toHaveBeenCalledTimes(1);
110
+ });
111
+
112
+ it("should call console.log with zero", () => {
113
+ logger.log(0);
114
+ expect(logSpy).toHaveBeenCalledWith(0);
115
+ expect(logSpy).toHaveBeenCalledTimes(1);
116
+ });
117
+
118
+ it("should call console.log with negative number", () => {
119
+ logger.log(-42);
120
+ expect(logSpy).toHaveBeenCalledWith(-42);
121
+ expect(logSpy).toHaveBeenCalledTimes(1);
122
+ });
123
+
124
+ it("should call console.log with NaN", () => {
125
+ logger.log(NaN);
126
+ expect(logSpy).toHaveBeenCalledWith(NaN);
127
+ expect(logSpy).toHaveBeenCalledTimes(1);
128
+ });
129
+
130
+ it("should call console.log with Infinity", () => {
131
+ logger.log(Infinity);
132
+ expect(logSpy).toHaveBeenCalledWith(Infinity);
133
+ expect(logSpy).toHaveBeenCalledTimes(1);
134
+ });
135
+ });
136
+
137
+ describe("logger.error", () => {
138
+ let errorSpy: any;
139
+
140
+ beforeEach(() => {
141
+ errorSpy = spyOn(console, "error");
142
+ });
143
+
144
+ afterEach(() => {
145
+ errorSpy.mockRestore();
146
+ });
147
+
148
+ it("should call console.error with single string", () => {
149
+ logger.error("error message");
150
+ expect(errorSpy).toHaveBeenCalledWith("error message");
151
+ expect(errorSpy).toHaveBeenCalledTimes(1);
152
+ });
153
+
154
+ it("should call console.error with multiple arguments", () => {
155
+ logger.error("error", "multiple", "args");
156
+ expect(errorSpy).toHaveBeenCalledWith("error", "multiple", "args");
157
+ expect(errorSpy).toHaveBeenCalledTimes(1);
158
+ });
159
+
160
+ it("should call console.error with Error object", () => {
161
+ const error = new Error("test error");
162
+ logger.error(error);
163
+ expect(errorSpy).toHaveBeenCalledWith(error);
164
+ expect(errorSpy).toHaveBeenCalledTimes(1);
165
+ });
166
+
167
+ it("should call console.error with null", () => {
168
+ logger.error(null);
169
+ expect(errorSpy).toHaveBeenCalledWith(null);
170
+ expect(errorSpy).toHaveBeenCalledTimes(1);
171
+ });
172
+
173
+ it("should call console.error with undefined", () => {
174
+ logger.error(undefined);
175
+ expect(errorSpy).toHaveBeenCalledWith(undefined);
176
+ expect(errorSpy).toHaveBeenCalledTimes(1);
177
+ });
178
+
179
+ it("should call console.error with no arguments", () => {
180
+ logger.error();
181
+ expect(errorSpy).toHaveBeenCalledWith();
182
+ expect(errorSpy).toHaveBeenCalledTimes(1);
183
+ });
184
+ });
185
+
186
+ describe("logger.warn", () => {
187
+ let warnSpy: any;
188
+
189
+ beforeEach(() => {
190
+ warnSpy = spyOn(console, "warn");
191
+ });
192
+
193
+ afterEach(() => {
194
+ warnSpy.mockRestore();
195
+ });
196
+
197
+ it("should call console.warn with single string", () => {
198
+ logger.warn("warning message");
199
+ expect(warnSpy).toHaveBeenCalledWith("warning message");
200
+ expect(warnSpy).toHaveBeenCalledTimes(1);
201
+ });
202
+
203
+ it("should call console.warn with multiple arguments", () => {
204
+ logger.warn("warn", "multiple", "args");
205
+ expect(warnSpy).toHaveBeenCalledWith("warn", "multiple", "args");
206
+ expect(warnSpy).toHaveBeenCalledTimes(1);
207
+ });
208
+
209
+ it("should call console.warn with null", () => {
210
+ logger.warn(null);
211
+ expect(warnSpy).toHaveBeenCalledWith(null);
212
+ expect(warnSpy).toHaveBeenCalledTimes(1);
213
+ });
214
+
215
+ it("should call console.warn with undefined", () => {
216
+ logger.warn(undefined);
217
+ expect(warnSpy).toHaveBeenCalledWith(undefined);
218
+ expect(warnSpy).toHaveBeenCalledTimes(1);
219
+ });
220
+
221
+ it("should call console.warn with no arguments", () => {
222
+ logger.warn();
223
+ expect(warnSpy).toHaveBeenCalledWith();
224
+ expect(warnSpy).toHaveBeenCalledTimes(1);
225
+ });
226
+ });
227
+
228
+ describe("logger.info", () => {
229
+ let infoSpy: any;
230
+
231
+ beforeEach(() => {
232
+ infoSpy = spyOn(console, "info");
233
+ });
234
+
235
+ afterEach(() => {
236
+ infoSpy.mockRestore();
237
+ });
238
+
239
+ it("should call console.info with single string", () => {
240
+ logger.info("info message");
241
+ expect(infoSpy).toHaveBeenCalledWith("info message");
242
+ expect(infoSpy).toHaveBeenCalledTimes(1);
243
+ });
244
+
245
+ it("should call console.info with multiple arguments", () => {
246
+ logger.info("info", "multiple", "args");
247
+ expect(infoSpy).toHaveBeenCalledWith("info", "multiple", "args");
248
+ expect(infoSpy).toHaveBeenCalledTimes(1);
249
+ });
250
+
251
+ it("should call console.info with null", () => {
252
+ logger.info(null);
253
+ expect(infoSpy).toHaveBeenCalledWith(null);
254
+ expect(infoSpy).toHaveBeenCalledTimes(1);
255
+ });
256
+
257
+ it("should call console.info with undefined", () => {
258
+ logger.info(undefined);
259
+ expect(infoSpy).toHaveBeenCalledWith(undefined);
260
+ expect(infoSpy).toHaveBeenCalledTimes(1);
261
+ });
262
+
263
+ it("should call console.info with no arguments", () => {
264
+ logger.info();
265
+ expect(infoSpy).toHaveBeenCalledWith();
266
+ expect(infoSpy).toHaveBeenCalledTimes(1);
267
+ });
268
+ });
269
+
270
+ describe("Logger type compatibility", () => {
271
+ it("should be compatible with Logger interface", () => {
272
+ const testLogger: Logger = logger;
273
+ expect(testLogger).toBeDefined();
274
+ });
275
+
276
+ it("should allow custom Logger implementation", () => {
277
+ const customLogger: Logger = {
278
+ log: () => {},
279
+ error: () => {},
280
+ warn: () => {},
281
+ info: () => {},
282
+ };
283
+ expect(customLogger).toBeDefined();
284
+ });
285
+ });
@@ -0,0 +1,246 @@
1
+ import { describe, it, expect, spyOn, beforeEach, afterEach } from "bun:test";
2
+ import { silentLogger } from "../src/silentLogger.js";
3
+ import type { Logger } from "../src/loggerObj.js";
4
+
5
+ describe("silentLogger interface", () => {
6
+ it("should have all required Logger methods", () => {
7
+ expect(silentLogger).toHaveProperty("log");
8
+ expect(silentLogger).toHaveProperty("error");
9
+ expect(silentLogger).toHaveProperty("warn");
10
+ expect(silentLogger).toHaveProperty("info");
11
+ expect(typeof silentLogger.log).toBe("function");
12
+ expect(typeof silentLogger.error).toBe("function");
13
+ expect(typeof silentLogger.warn).toBe("function");
14
+ expect(typeof silentLogger.info).toBe("function");
15
+ });
16
+
17
+ it("should be compatible with Logger type", () => {
18
+ const testLogger: Logger = silentLogger;
19
+ expect(testLogger).toBeDefined();
20
+ });
21
+ });
22
+
23
+ describe("silentLogger.log", () => {
24
+ let logSpy: any;
25
+
26
+ beforeEach(() => {
27
+ logSpy = spyOn(console, "log");
28
+ });
29
+
30
+ afterEach(() => {
31
+ logSpy.mockRestore();
32
+ });
33
+
34
+ it("should not call console.log with single string", () => {
35
+ silentLogger.log("test message");
36
+ expect(logSpy).not.toHaveBeenCalled();
37
+ });
38
+
39
+ it("should not call console.log with multiple arguments", () => {
40
+ silentLogger.log("test", "multiple", "args");
41
+ expect(logSpy).not.toHaveBeenCalled();
42
+ });
43
+
44
+ it("should not call console.log with object", () => {
45
+ silentLogger.log({ key: "value" });
46
+ expect(logSpy).not.toHaveBeenCalled();
47
+ });
48
+
49
+ it("should not call console.log with null", () => {
50
+ silentLogger.log(null);
51
+ expect(logSpy).not.toHaveBeenCalled();
52
+ });
53
+
54
+ it("should not call console.log with undefined", () => {
55
+ silentLogger.log(undefined);
56
+ expect(logSpy).not.toHaveBeenCalled();
57
+ });
58
+
59
+ it("should not call console.log with no arguments", () => {
60
+ silentLogger.log();
61
+ expect(logSpy).not.toHaveBeenCalled();
62
+ });
63
+
64
+ it("should not call console.log when called multiple times", () => {
65
+ silentLogger.log("first");
66
+ silentLogger.log("second");
67
+ silentLogger.log("third");
68
+ expect(logSpy).not.toHaveBeenCalled();
69
+ });
70
+
71
+ it("should not throw when called", () => {
72
+ expect(() => silentLogger.log("test")).not.toThrow();
73
+ });
74
+
75
+ it("should return undefined", () => {
76
+ const result = silentLogger.log("test");
77
+ expect(result).toBeUndefined();
78
+ });
79
+ });
80
+
81
+ describe("silentLogger.error", () => {
82
+ let errorSpy: any;
83
+
84
+ beforeEach(() => {
85
+ errorSpy = spyOn(console, "error");
86
+ });
87
+
88
+ afterEach(() => {
89
+ errorSpy.mockRestore();
90
+ });
91
+
92
+ it("should not call console.error with single string", () => {
93
+ silentLogger.error("error message");
94
+ expect(errorSpy).not.toHaveBeenCalled();
95
+ });
96
+
97
+ it("should not call console.error with multiple arguments", () => {
98
+ silentLogger.error("error", "multiple", "args");
99
+ expect(errorSpy).not.toHaveBeenCalled();
100
+ });
101
+
102
+ it("should not call console.error with Error object", () => {
103
+ silentLogger.error(new Error("test error"));
104
+ expect(errorSpy).not.toHaveBeenCalled();
105
+ });
106
+
107
+ it("should not call console.error with null", () => {
108
+ silentLogger.error(null);
109
+ expect(errorSpy).not.toHaveBeenCalled();
110
+ });
111
+
112
+ it("should not call console.error with undefined", () => {
113
+ silentLogger.error(undefined);
114
+ expect(errorSpy).not.toHaveBeenCalled();
115
+ });
116
+
117
+ it("should not call console.error with no arguments", () => {
118
+ silentLogger.error();
119
+ expect(errorSpy).not.toHaveBeenCalled();
120
+ });
121
+
122
+ it("should not throw when called", () => {
123
+ expect(() => silentLogger.error("test")).not.toThrow();
124
+ });
125
+
126
+ it("should return undefined", () => {
127
+ const result = silentLogger.error("test");
128
+ expect(result).toBeUndefined();
129
+ });
130
+ });
131
+
132
+ describe("silentLogger.warn", () => {
133
+ let warnSpy: any;
134
+
135
+ beforeEach(() => {
136
+ warnSpy = spyOn(console, "warn");
137
+ });
138
+
139
+ afterEach(() => {
140
+ warnSpy.mockRestore();
141
+ });
142
+
143
+ it("should not call console.warn with single string", () => {
144
+ silentLogger.warn("warning message");
145
+ expect(warnSpy).not.toHaveBeenCalled();
146
+ });
147
+
148
+ it("should not call console.warn with multiple arguments", () => {
149
+ silentLogger.warn("warn", "multiple", "args");
150
+ expect(warnSpy).not.toHaveBeenCalled();
151
+ });
152
+
153
+ it("should not call console.warn with null", () => {
154
+ silentLogger.warn(null);
155
+ expect(warnSpy).not.toHaveBeenCalled();
156
+ });
157
+
158
+ it("should not call console.warn with undefined", () => {
159
+ silentLogger.warn(undefined);
160
+ expect(warnSpy).not.toHaveBeenCalled();
161
+ });
162
+
163
+ it("should not call console.warn with no arguments", () => {
164
+ silentLogger.warn();
165
+ expect(warnSpy).not.toHaveBeenCalled();
166
+ });
167
+
168
+ it("should not throw when called", () => {
169
+ expect(() => silentLogger.warn("test")).not.toThrow();
170
+ });
171
+
172
+ it("should return undefined", () => {
173
+ const result = silentLogger.warn("test");
174
+ expect(result).toBeUndefined();
175
+ });
176
+ });
177
+
178
+ describe("silentLogger.info", () => {
179
+ let infoSpy: any;
180
+
181
+ beforeEach(() => {
182
+ infoSpy = spyOn(console, "info");
183
+ });
184
+
185
+ afterEach(() => {
186
+ infoSpy.mockRestore();
187
+ });
188
+
189
+ it("should not call console.info with single string", () => {
190
+ silentLogger.info("info message");
191
+ expect(infoSpy).not.toHaveBeenCalled();
192
+ });
193
+
194
+ it("should not call console.info with multiple arguments", () => {
195
+ silentLogger.info("info", "multiple", "args");
196
+ expect(infoSpy).not.toHaveBeenCalled();
197
+ });
198
+
199
+ it("should not call console.info with null", () => {
200
+ silentLogger.info(null);
201
+ expect(infoSpy).not.toHaveBeenCalled();
202
+ });
203
+
204
+ it("should not call console.info with undefined", () => {
205
+ silentLogger.info(undefined);
206
+ expect(infoSpy).not.toHaveBeenCalled();
207
+ });
208
+
209
+ it("should not call console.info with no arguments", () => {
210
+ silentLogger.info();
211
+ expect(infoSpy).not.toHaveBeenCalled();
212
+ });
213
+
214
+ it("should not throw when called", () => {
215
+ expect(() => silentLogger.info("test")).not.toThrow();
216
+ });
217
+
218
+ it("should return undefined", () => {
219
+ const result = silentLogger.info("test");
220
+ expect(result).toBeUndefined();
221
+ });
222
+ });
223
+
224
+ describe("silentLogger behavior", () => {
225
+ it("should not produce any console output when all methods are called", () => {
226
+ const logSpy = spyOn(console, "log");
227
+ const errorSpy = spyOn(console, "error");
228
+ const warnSpy = spyOn(console, "warn");
229
+ const infoSpy = spyOn(console, "info");
230
+
231
+ silentLogger.log("test");
232
+ silentLogger.error("test");
233
+ silentLogger.warn("test");
234
+ silentLogger.info("test");
235
+
236
+ expect(logSpy).not.toHaveBeenCalled();
237
+ expect(errorSpy).not.toHaveBeenCalled();
238
+ expect(warnSpy).not.toHaveBeenCalled();
239
+ expect(infoSpy).not.toHaveBeenCalled();
240
+
241
+ logSpy.mockRestore();
242
+ errorSpy.mockRestore();
243
+ warnSpy.mockRestore();
244
+ infoSpy.mockRestore();
245
+ });
246
+ });