@elizaos/core 1.5.1 → 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/index.browser.js +120 -120
- package/dist/browser/index.browser.js.map +5 -21
- package/dist/browser/index.d.ts +3 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.js +1 -5
- package/dist/node/index.d.ts +3 -1
- package/package.json +10 -4
- package/src/__tests__/action-chaining-simple.test.ts +203 -0
- package/src/__tests__/actions.test.ts +218 -0
- package/src/__tests__/buffer.test.ts +337 -0
- package/src/__tests__/character-validation.test.ts +309 -0
- package/src/__tests__/database.test.ts +750 -0
- package/src/__tests__/entities.test.ts +727 -0
- package/src/__tests__/env.test.ts +23 -0
- package/src/__tests__/environment.test.ts +285 -0
- package/src/__tests__/logger-browser-node.test.ts +716 -0
- package/src/__tests__/logger.test.ts +403 -0
- package/src/__tests__/messages.test.ts +196 -0
- package/src/__tests__/mockCharacter.ts +544 -0
- package/src/__tests__/parsing.test.ts +58 -0
- package/src/__tests__/prompts.test.ts +159 -0
- package/src/__tests__/roles.test.ts +331 -0
- package/src/__tests__/runtime-embedding.test.ts +343 -0
- package/src/__tests__/runtime.test.ts +978 -0
- package/src/__tests__/search.test.ts +15 -0
- package/src/__tests__/services-by-type.test.ts +204 -0
- package/src/__tests__/services.test.ts +136 -0
- package/src/__tests__/settings.test.ts +810 -0
- package/src/__tests__/utils.test.ts +1105 -0
- package/src/__tests__/uuid.test.ts +94 -0
- package/src/actions.ts +122 -0
- package/src/database.ts +579 -0
- package/src/entities.ts +406 -0
- package/src/index.browser.ts +48 -0
- package/src/index.node.ts +39 -0
- package/src/index.ts +50 -0
- package/src/logger.ts +527 -0
- package/src/prompts.ts +243 -0
- package/src/roles.ts +85 -0
- package/src/runtime.ts +2514 -0
- package/src/schemas/character.ts +149 -0
- package/src/search.ts +1543 -0
- package/src/sentry/instrument.browser.ts +65 -0
- package/src/sentry/instrument.node.ts +57 -0
- package/src/sentry/instrument.ts +82 -0
- package/src/services.ts +105 -0
- package/src/settings.ts +409 -0
- package/src/test_resources/constants.ts +12 -0
- package/src/test_resources/testSetup.ts +21 -0
- package/src/test_resources/types.ts +22 -0
- package/src/types/agent.ts +112 -0
- package/src/types/browser.ts +145 -0
- package/src/types/components.ts +184 -0
- package/src/types/database.ts +348 -0
- package/src/types/email.ts +162 -0
- package/src/types/environment.ts +129 -0
- package/src/types/events.ts +249 -0
- package/src/types/index.ts +29 -0
- package/src/types/knowledge.ts +65 -0
- package/src/types/lp.ts +124 -0
- package/src/types/memory.ts +228 -0
- package/src/types/message.ts +233 -0
- package/src/types/messaging.ts +57 -0
- package/src/types/model.ts +359 -0
- package/src/types/pdf.ts +77 -0
- package/src/types/plugin.ts +78 -0
- package/src/types/post.ts +271 -0
- package/src/types/primitives.ts +97 -0
- package/src/types/runtime.ts +190 -0
- package/src/types/service.ts +198 -0
- package/src/types/settings.ts +30 -0
- package/src/types/state.ts +60 -0
- package/src/types/task.ts +72 -0
- package/src/types/tee.ts +107 -0
- package/src/types/testing.ts +30 -0
- package/src/types/token.ts +96 -0
- package/src/types/transcription.ts +133 -0
- package/src/types/video.ts +108 -0
- package/src/types/wallet.ts +56 -0
- package/src/types/web-search.ts +146 -0
- package/src/utils/__tests__/buffer.test.ts +80 -0
- package/src/utils/__tests__/environment.test.ts +58 -0
- package/src/utils/__tests__/stringToUuid.test.ts +88 -0
- package/src/utils/buffer.ts +312 -0
- package/src/utils/environment.ts +316 -0
- package/src/utils/server-health.ts +117 -0
- package/src/utils.ts +1076 -0
- package/dist/tsconfig.build.tsbuildinfo +0 -1
|
@@ -0,0 +1,716 @@
|
|
|
1
|
+
import { describe, expect, it, beforeEach, afterEach, mock } from 'bun:test';
|
|
2
|
+
import { createLogger } from '../logger';
|
|
3
|
+
import { getEnvironment } from '../utils/environment';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Test type definitions
|
|
7
|
+
*/
|
|
8
|
+
interface MockProcess {
|
|
9
|
+
versions?: {
|
|
10
|
+
node?: string;
|
|
11
|
+
};
|
|
12
|
+
env?: Record<string, string | undefined>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface MockWindow {
|
|
16
|
+
document?: object;
|
|
17
|
+
console?: Partial<Console>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type MockDocument = Record<string, unknown>;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Comprehensive tests for both Node.js and Browser logger implementations
|
|
24
|
+
* This test suite ensures the logger works correctly in both environments
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
describe('Logger - Cross-Environment Tests', () => {
|
|
28
|
+
let originalProcess: typeof process | undefined;
|
|
29
|
+
let originalWindow: MockWindow | undefined;
|
|
30
|
+
let originalDocument: MockDocument | undefined;
|
|
31
|
+
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
// Save original globals
|
|
34
|
+
originalProcess = globalThis.process;
|
|
35
|
+
originalWindow = globalThis.window;
|
|
36
|
+
originalDocument = globalThis.document;
|
|
37
|
+
mock.restore();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
afterEach(() => {
|
|
41
|
+
// Restore original globals
|
|
42
|
+
globalThis.process = originalProcess as typeof process;
|
|
43
|
+
globalThis.window = originalWindow as unknown as typeof globalThis.window;
|
|
44
|
+
globalThis.document = originalDocument as unknown as typeof globalThis.document;
|
|
45
|
+
mock.restore();
|
|
46
|
+
// Clear environment cache for next test
|
|
47
|
+
getEnvironment().clearCache();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe('Environment Detection', () => {
|
|
51
|
+
it('should detect Node.js environment correctly', () => {
|
|
52
|
+
// Ensure we're in Node.js environment
|
|
53
|
+
globalThis.process = {
|
|
54
|
+
versions: { node: '20.0.0' },
|
|
55
|
+
env: { LOG_LEVEL: 'info' },
|
|
56
|
+
} as MockProcess as typeof process;
|
|
57
|
+
delete globalThis.window;
|
|
58
|
+
delete globalThis.document;
|
|
59
|
+
|
|
60
|
+
const isNode =
|
|
61
|
+
typeof process !== 'undefined' &&
|
|
62
|
+
typeof process.versions !== 'undefined' &&
|
|
63
|
+
typeof process.versions.node !== 'undefined';
|
|
64
|
+
const isBrowser =
|
|
65
|
+
typeof globalThis !== 'undefined' &&
|
|
66
|
+
typeof globalThis.window !== 'undefined' &&
|
|
67
|
+
typeof globalThis.document !== 'undefined';
|
|
68
|
+
|
|
69
|
+
expect(isNode).toBe(true);
|
|
70
|
+
expect(isBrowser).toBe(false);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should detect browser environment correctly', () => {
|
|
74
|
+
// Simulate browser environment
|
|
75
|
+
globalThis.window = {
|
|
76
|
+
document: {},
|
|
77
|
+
console: {
|
|
78
|
+
log: mock(),
|
|
79
|
+
info: mock(),
|
|
80
|
+
warn: mock(),
|
|
81
|
+
error: mock(),
|
|
82
|
+
debug: mock(),
|
|
83
|
+
trace: mock(),
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
globalThis.document = {};
|
|
87
|
+
delete globalThis.process;
|
|
88
|
+
|
|
89
|
+
const isNode =
|
|
90
|
+
typeof process !== 'undefined' &&
|
|
91
|
+
typeof process.versions !== 'undefined' &&
|
|
92
|
+
typeof process.versions.node !== 'undefined';
|
|
93
|
+
const isBrowser =
|
|
94
|
+
typeof globalThis !== 'undefined' &&
|
|
95
|
+
typeof globalThis.window !== 'undefined' &&
|
|
96
|
+
typeof globalThis.document !== 'undefined';
|
|
97
|
+
|
|
98
|
+
expect(isNode).toBe(false);
|
|
99
|
+
expect(isBrowser).toBe(true);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('BrowserLogger Class', () => {
|
|
104
|
+
beforeEach(() => {
|
|
105
|
+
// Clear environment cache to ensure proper detection
|
|
106
|
+
getEnvironment().clearCache();
|
|
107
|
+
|
|
108
|
+
// Mock browser environment
|
|
109
|
+
globalThis.window = {
|
|
110
|
+
document: {},
|
|
111
|
+
console: {
|
|
112
|
+
log: mock(),
|
|
113
|
+
info: mock(),
|
|
114
|
+
warn: mock(),
|
|
115
|
+
error: mock(),
|
|
116
|
+
debug: mock(),
|
|
117
|
+
trace: mock(),
|
|
118
|
+
clear: mock(),
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
globalThis.document = {};
|
|
122
|
+
globalThis.console = globalThis.window.console as Console;
|
|
123
|
+
|
|
124
|
+
// Clear cache again after setting up environment
|
|
125
|
+
getEnvironment().clearCache();
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('should create BrowserLogger instance with all required methods', async () => {
|
|
129
|
+
// Dynamically import to trigger browser detection
|
|
130
|
+
const module = await import('../logger');
|
|
131
|
+
|
|
132
|
+
// Create a browser logger instance, force browser type for testing
|
|
133
|
+
const browserLogger = module.createLogger({ test: 'browser', __forceType: 'browser' });
|
|
134
|
+
|
|
135
|
+
// Verify all required methods exist
|
|
136
|
+
expect(typeof browserLogger.trace).toBe('function');
|
|
137
|
+
expect(typeof browserLogger.debug).toBe('function');
|
|
138
|
+
expect(typeof browserLogger.info).toBe('function');
|
|
139
|
+
expect(typeof browserLogger.warn).toBe('function');
|
|
140
|
+
expect(typeof browserLogger.error).toBe('function');
|
|
141
|
+
expect(typeof browserLogger.fatal).toBe('function');
|
|
142
|
+
|
|
143
|
+
// Verify custom ElizaOS methods exist
|
|
144
|
+
expect(typeof browserLogger.success).toBe('function');
|
|
145
|
+
expect(typeof browserLogger.progress).toBe('function');
|
|
146
|
+
expect(typeof browserLogger.log).toBe('function');
|
|
147
|
+
expect(typeof browserLogger.clear).toBe('function');
|
|
148
|
+
expect(typeof browserLogger.child).toBe('function');
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('should log messages to console in browser environment', () => {
|
|
152
|
+
// Ensure we're in browser environment
|
|
153
|
+
delete globalThis.process;
|
|
154
|
+
globalThis.window = { document: {} };
|
|
155
|
+
globalThis.document = {};
|
|
156
|
+
|
|
157
|
+
// Mock console methods
|
|
158
|
+
const mockConsole = {
|
|
159
|
+
log: mock(),
|
|
160
|
+
info: mock(),
|
|
161
|
+
warn: mock(),
|
|
162
|
+
error: mock(),
|
|
163
|
+
debug: mock(),
|
|
164
|
+
trace: mock(),
|
|
165
|
+
clear: mock(),
|
|
166
|
+
};
|
|
167
|
+
globalThis.console = mockConsole as unknown as Console;
|
|
168
|
+
|
|
169
|
+
// Create browser logger with debug level to ensure all levels are logged
|
|
170
|
+
const browserLogger = createLogger({ level: 'debug', __forceType: 'browser' });
|
|
171
|
+
|
|
172
|
+
// Test various log levels
|
|
173
|
+
browserLogger.info('Info message');
|
|
174
|
+
browserLogger.warn('Warning message');
|
|
175
|
+
browserLogger.error('Error message');
|
|
176
|
+
browserLogger.debug('Debug message');
|
|
177
|
+
|
|
178
|
+
// Verify console methods were called
|
|
179
|
+
expect(mockConsole.info).toHaveBeenCalled();
|
|
180
|
+
expect(mockConsole.warn).toHaveBeenCalled();
|
|
181
|
+
expect(mockConsole.error).toHaveBeenCalled();
|
|
182
|
+
expect(mockConsole.debug).toHaveBeenCalled();
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('should format messages with objects correctly in browser', () => {
|
|
186
|
+
// Ensure we're in browser environment
|
|
187
|
+
delete globalThis.process;
|
|
188
|
+
globalThis.window = { document: {} };
|
|
189
|
+
globalThis.document = {};
|
|
190
|
+
|
|
191
|
+
const mockConsole = {
|
|
192
|
+
info: mock(),
|
|
193
|
+
log: mock(),
|
|
194
|
+
warn: mock(),
|
|
195
|
+
error: mock(),
|
|
196
|
+
debug: mock(),
|
|
197
|
+
trace: mock(),
|
|
198
|
+
};
|
|
199
|
+
globalThis.console = mockConsole as unknown as Console;
|
|
200
|
+
|
|
201
|
+
// Create logger with debug level to ensure all levels are logged
|
|
202
|
+
const browserLogger = createLogger({ level: 'debug', __forceType: 'browser' });
|
|
203
|
+
|
|
204
|
+
// Test with object
|
|
205
|
+
browserLogger.info({ user: 'john', action: 'login' }, 'User logged in');
|
|
206
|
+
expect(mockConsole.info).toHaveBeenCalled();
|
|
207
|
+
|
|
208
|
+
// Test with error
|
|
209
|
+
const error = new Error('Test error');
|
|
210
|
+
browserLogger.error(error);
|
|
211
|
+
expect(mockConsole.error).toHaveBeenCalled();
|
|
212
|
+
|
|
213
|
+
// Test custom levels (success and progress map to info)
|
|
214
|
+
browserLogger.success('Operation successful');
|
|
215
|
+
browserLogger.progress('50% complete');
|
|
216
|
+
expect(mockConsole.info).toHaveBeenCalled();
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('should respect log levels in browser environment', () => {
|
|
220
|
+
// Ensure we're in browser environment
|
|
221
|
+
delete globalThis.process;
|
|
222
|
+
globalThis.window = { document: {} };
|
|
223
|
+
globalThis.document = {};
|
|
224
|
+
|
|
225
|
+
const mockConsole = {
|
|
226
|
+
trace: mock(),
|
|
227
|
+
debug: mock(),
|
|
228
|
+
info: mock(),
|
|
229
|
+
warn: mock(),
|
|
230
|
+
error: mock(),
|
|
231
|
+
log: mock(),
|
|
232
|
+
};
|
|
233
|
+
globalThis.console = mockConsole as unknown as Console;
|
|
234
|
+
|
|
235
|
+
// Clear cache to detect browser environment
|
|
236
|
+
getEnvironment().clearCache();
|
|
237
|
+
|
|
238
|
+
// Create logger with warn level, force browser type for testing
|
|
239
|
+
const browserLogger = createLogger({ level: 'warn', __forceType: 'browser' });
|
|
240
|
+
|
|
241
|
+
// These should not log (below warn level)
|
|
242
|
+
browserLogger.trace('Trace message');
|
|
243
|
+
browserLogger.debug('Debug message');
|
|
244
|
+
browserLogger.info('Info message');
|
|
245
|
+
|
|
246
|
+
// These should log (warn level and above)
|
|
247
|
+
browserLogger.warn('Warning message');
|
|
248
|
+
browserLogger.error('Error message');
|
|
249
|
+
browserLogger.fatal('Fatal message');
|
|
250
|
+
|
|
251
|
+
// Verify only warn and above were called
|
|
252
|
+
expect(mockConsole.trace).not.toHaveBeenCalled();
|
|
253
|
+
expect(mockConsole.debug).not.toHaveBeenCalled();
|
|
254
|
+
expect(mockConsole.info).not.toHaveBeenCalled();
|
|
255
|
+
expect(mockConsole.warn).toHaveBeenCalled();
|
|
256
|
+
expect(mockConsole.error).toHaveBeenCalled();
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it('should maintain in-memory log storage in browser', () => {
|
|
260
|
+
const browserLogger = createLogger({ __forceType: 'browser' });
|
|
261
|
+
|
|
262
|
+
// Log multiple messages
|
|
263
|
+
browserLogger.info('Message 1');
|
|
264
|
+
browserLogger.warn('Message 2');
|
|
265
|
+
browserLogger.error('Message 3');
|
|
266
|
+
|
|
267
|
+
// Verify messages are stored (would be accessible via inMemoryDestination)
|
|
268
|
+
// The actual storage is internal, but we can verify the logger doesn't crash
|
|
269
|
+
expect(() => browserLogger.clear()).not.toThrow();
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it('should handle child loggers in browser', () => {
|
|
273
|
+
// Ensure we're in browser environment
|
|
274
|
+
delete globalThis.process;
|
|
275
|
+
globalThis.window = { document: {} };
|
|
276
|
+
globalThis.document = {};
|
|
277
|
+
|
|
278
|
+
const mockConsole = {
|
|
279
|
+
info: mock(),
|
|
280
|
+
log: mock(),
|
|
281
|
+
};
|
|
282
|
+
globalThis.console = mockConsole as unknown as Console;
|
|
283
|
+
|
|
284
|
+
// Clear cache to detect browser environment
|
|
285
|
+
getEnvironment().clearCache();
|
|
286
|
+
|
|
287
|
+
// Force browser type for testing
|
|
288
|
+
const parentLogger = createLogger({ parent: 'main', __forceType: 'browser' });
|
|
289
|
+
const childLogger = parentLogger.child({ child: 'sub' });
|
|
290
|
+
|
|
291
|
+
childLogger.info('Child message');
|
|
292
|
+
expect(mockConsole.info).toHaveBeenCalled();
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
describe('Node.js Logger (Adze backend in Node)', () => {
|
|
297
|
+
beforeEach(() => {
|
|
298
|
+
// Clear environment cache
|
|
299
|
+
getEnvironment().clearCache();
|
|
300
|
+
|
|
301
|
+
// Restore Node.js environment
|
|
302
|
+
globalThis.process =
|
|
303
|
+
originalProcess ||
|
|
304
|
+
({
|
|
305
|
+
versions: { node: '20.0.0' },
|
|
306
|
+
env: {},
|
|
307
|
+
} as unknown as typeof process);
|
|
308
|
+
delete globalThis.window;
|
|
309
|
+
delete globalThis.document;
|
|
310
|
+
|
|
311
|
+
// No need to mock transports; logger uses Adze in both environments
|
|
312
|
+
|
|
313
|
+
// Clear cache again after environment setup
|
|
314
|
+
getEnvironment().clearCache();
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it('should provide logger API in Node.js environment', () => {
|
|
318
|
+
const nodeLogger = createLogger();
|
|
319
|
+
|
|
320
|
+
// Verify core methods exist
|
|
321
|
+
expect(typeof nodeLogger.trace).toBe('function');
|
|
322
|
+
expect(typeof nodeLogger.debug).toBe('function');
|
|
323
|
+
expect(typeof nodeLogger.info).toBe('function');
|
|
324
|
+
expect(typeof nodeLogger.warn).toBe('function');
|
|
325
|
+
expect(typeof nodeLogger.error).toBe('function');
|
|
326
|
+
expect(typeof nodeLogger.fatal).toBe('function');
|
|
327
|
+
|
|
328
|
+
// Verify custom methods are added
|
|
329
|
+
expect(typeof nodeLogger.success).toBe('function');
|
|
330
|
+
expect(typeof nodeLogger.progress).toBe('function');
|
|
331
|
+
expect(typeof nodeLogger.log).toBe('function');
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
it('should handle child loggers correctly', () => {
|
|
335
|
+
const parentLogger = createLogger({ service: 'api' });
|
|
336
|
+
const childLogger = parentLogger.child({ request: '123' });
|
|
337
|
+
|
|
338
|
+
expect(childLogger).toBeDefined();
|
|
339
|
+
expect(typeof childLogger.info).toBe('function');
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
it('should support log level configuration options', () => {
|
|
343
|
+
process.env.LOG_LEVEL = 'debug';
|
|
344
|
+
process.env.LOG_JSON_FORMAT = 'true';
|
|
345
|
+
|
|
346
|
+
const nodeLogger = createLogger();
|
|
347
|
+
expect(nodeLogger.level).toBeDefined();
|
|
348
|
+
|
|
349
|
+
process.env.LOG_LEVEL = '';
|
|
350
|
+
process.env.LOG_JSON_FORMAT = '';
|
|
351
|
+
});
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
describe('Cross-Environment Compatibility', () => {
|
|
355
|
+
it('should maintain consistent API across environments', async () => {
|
|
356
|
+
// Test Node.js logger
|
|
357
|
+
globalThis.process =
|
|
358
|
+
originalProcess || ({ versions: { node: '20.0.0' }, env: {} } as unknown as typeof process);
|
|
359
|
+
delete globalThis.window;
|
|
360
|
+
const nodeLogger = createLogger();
|
|
361
|
+
|
|
362
|
+
// Test browser logger
|
|
363
|
+
globalThis.window = { document: {}, console: globalThis.console };
|
|
364
|
+
globalThis.document = {};
|
|
365
|
+
delete globalThis.process;
|
|
366
|
+
const browserLogger = createLogger();
|
|
367
|
+
|
|
368
|
+
// Both should have the same methods
|
|
369
|
+
const methods = [
|
|
370
|
+
'trace',
|
|
371
|
+
'debug',
|
|
372
|
+
'info',
|
|
373
|
+
'warn',
|
|
374
|
+
'error',
|
|
375
|
+
'fatal',
|
|
376
|
+
'success',
|
|
377
|
+
'progress',
|
|
378
|
+
'log',
|
|
379
|
+
'clear',
|
|
380
|
+
'child',
|
|
381
|
+
];
|
|
382
|
+
|
|
383
|
+
for (const method of methods) {
|
|
384
|
+
expect(typeof nodeLogger[method]).toBe('function');
|
|
385
|
+
expect(typeof browserLogger[method]).toBe('function');
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
it('should handle complex log objects in both environments', () => {
|
|
390
|
+
const testData = {
|
|
391
|
+
user: { id: 123, name: 'John' },
|
|
392
|
+
metadata: { timestamp: Date.now(), version: '1.0' },
|
|
393
|
+
nested: { deep: { value: 'test' } },
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
// Test in Node.js
|
|
397
|
+
globalThis.process =
|
|
398
|
+
originalProcess || ({ versions: { node: '20.0.0' }, env: {} } as unknown as typeof process);
|
|
399
|
+
const nodeLogger = createLogger();
|
|
400
|
+
expect(() => nodeLogger.info(testData, 'Complex object')).not.toThrow();
|
|
401
|
+
|
|
402
|
+
// Test in browser
|
|
403
|
+
globalThis.window = { document: {}, console: { info: mock() } };
|
|
404
|
+
globalThis.document = {};
|
|
405
|
+
delete globalThis.process;
|
|
406
|
+
const browserLogger = createLogger({ __forceType: 'browser' });
|
|
407
|
+
expect(() => browserLogger.info(testData, 'Complex object')).not.toThrow();
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
it('should handle errors consistently across environments', () => {
|
|
411
|
+
const error = new Error('Test error');
|
|
412
|
+
error.stack = 'Error: Test error\n at test.js:1:1';
|
|
413
|
+
|
|
414
|
+
// Node.js
|
|
415
|
+
globalThis.process =
|
|
416
|
+
originalProcess || ({ versions: { node: '20.0.0' }, env: {} } as unknown as typeof process);
|
|
417
|
+
const nodeLogger = createLogger();
|
|
418
|
+
expect(() => nodeLogger.error(error)).not.toThrow();
|
|
419
|
+
expect(() => nodeLogger.error({ error }, 'Error occurred')).not.toThrow();
|
|
420
|
+
|
|
421
|
+
// Browser
|
|
422
|
+
globalThis.window = { document: {}, console: { error: mock() } };
|
|
423
|
+
globalThis.document = {};
|
|
424
|
+
delete globalThis.process;
|
|
425
|
+
const browserLogger = createLogger({ __forceType: 'browser' });
|
|
426
|
+
expect(() => browserLogger.error(error)).not.toThrow();
|
|
427
|
+
expect(() => browserLogger.error({ error }, 'Error occurred')).not.toThrow();
|
|
428
|
+
});
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
describe('Edge Cases and Error Handling', () => {
|
|
432
|
+
it('should handle undefined console methods in browser', () => {
|
|
433
|
+
globalThis.window = { document: {} };
|
|
434
|
+
globalThis.document = {};
|
|
435
|
+
globalThis.console = {
|
|
436
|
+
log: mock(),
|
|
437
|
+
// Missing other methods
|
|
438
|
+
} as unknown as Console;
|
|
439
|
+
|
|
440
|
+
const browserLogger = createLogger({ __forceType: 'browser' });
|
|
441
|
+
|
|
442
|
+
// Should fallback to console.log for missing methods
|
|
443
|
+
expect(() => browserLogger.info('Test')).not.toThrow();
|
|
444
|
+
expect(() => browserLogger.warn('Test')).not.toThrow();
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
it('should handle circular references in objects', () => {
|
|
448
|
+
type CircularObject = Record<string, unknown> & {
|
|
449
|
+
name: string;
|
|
450
|
+
circular?: CircularObject;
|
|
451
|
+
};
|
|
452
|
+
const obj: CircularObject = { name: 'test' };
|
|
453
|
+
obj.circular = obj;
|
|
454
|
+
|
|
455
|
+
const browserLogger = createLogger({ __forceType: 'browser' });
|
|
456
|
+
expect(() => browserLogger.info(obj, 'Circular reference')).not.toThrow();
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
it('should handle very long messages', () => {
|
|
460
|
+
const longMessage = 'x'.repeat(10000);
|
|
461
|
+
const browserLogger = createLogger({ __forceType: 'browser' });
|
|
462
|
+
expect(() => browserLogger.info(longMessage)).not.toThrow();
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
it('should handle null and undefined values', () => {
|
|
466
|
+
const browserLogger = createLogger({ __forceType: 'browser' });
|
|
467
|
+
expect(() => browserLogger.info(null, 'Null value')).not.toThrow();
|
|
468
|
+
expect(() => browserLogger.info(undefined, 'Undefined value')).not.toThrow();
|
|
469
|
+
expect(() => browserLogger.info({ value: null })).not.toThrow();
|
|
470
|
+
expect(() => browserLogger.info({ value: undefined })).not.toThrow();
|
|
471
|
+
});
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
describe('Memory Management', () => {
|
|
475
|
+
it('should limit in-memory log storage', () => {
|
|
476
|
+
// Setup browser environment first
|
|
477
|
+
globalThis.window = { document: {}, console: globalThis.console };
|
|
478
|
+
globalThis.document = {};
|
|
479
|
+
delete globalThis.process;
|
|
480
|
+
|
|
481
|
+
const browserLogger = createLogger({ __forceType: 'browser' });
|
|
482
|
+
|
|
483
|
+
// Log more than the max limit (1000 by default)
|
|
484
|
+
for (let i = 0; i < 1100; i++) {
|
|
485
|
+
browserLogger.info(`Message ${i}`);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// Should not crash and should maintain limit
|
|
489
|
+
expect(() => browserLogger.clear()).not.toThrow();
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
it('should respect custom maxMemoryLogs option', () => {
|
|
493
|
+
// Setup browser environment
|
|
494
|
+
globalThis.window = { document: {}, console: globalThis.console };
|
|
495
|
+
globalThis.document = {};
|
|
496
|
+
delete globalThis.process;
|
|
497
|
+
|
|
498
|
+
// Create logger with custom maxMemoryLogs
|
|
499
|
+
const customLimit = 50;
|
|
500
|
+
const browserLogger = createLogger({
|
|
501
|
+
__forceType: 'browser',
|
|
502
|
+
maxMemoryLogs: customLimit,
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
// Log more than the custom limit
|
|
506
|
+
for (let i = 0; i < customLimit + 10; i++) {
|
|
507
|
+
browserLogger.info(`Message ${i}`);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// Should not crash and should maintain custom limit
|
|
511
|
+
expect(() => browserLogger.clear()).not.toThrow();
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
it('should clear logs properly in both environments', () => {
|
|
515
|
+
// Browser
|
|
516
|
+
const mockClear = mock();
|
|
517
|
+
globalThis.window = { document: {}, console: { clear: mockClear } };
|
|
518
|
+
globalThis.document = {};
|
|
519
|
+
globalThis.console = { ...globalThis.console, clear: mockClear };
|
|
520
|
+
delete globalThis.process;
|
|
521
|
+
|
|
522
|
+
const browserLogger = createLogger({ __forceType: 'browser' });
|
|
523
|
+
browserLogger.clear();
|
|
524
|
+
expect(mockClear).toHaveBeenCalled();
|
|
525
|
+
|
|
526
|
+
// Node.js
|
|
527
|
+
globalThis.process =
|
|
528
|
+
originalProcess || ({ versions: { node: '20.0.0' }, env: {} } as unknown as typeof process);
|
|
529
|
+
delete globalThis.window;
|
|
530
|
+
const nodeLogger = createLogger();
|
|
531
|
+
expect(() => nodeLogger.clear()).not.toThrow();
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
it('should not throw when using __forceType binding in Node', () => {
|
|
535
|
+
globalThis.process =
|
|
536
|
+
originalProcess || ({ versions: { node: '20.0.0' }, env: {} } as unknown as typeof process);
|
|
537
|
+
delete globalThis.window;
|
|
538
|
+
delete globalThis.document;
|
|
539
|
+
|
|
540
|
+
expect(() =>
|
|
541
|
+
createLogger({
|
|
542
|
+
__forceType: 'node',
|
|
543
|
+
appName: 'test-app',
|
|
544
|
+
userId: '123',
|
|
545
|
+
})
|
|
546
|
+
).not.toThrow();
|
|
547
|
+
});
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
describe('Circular Reference Handling - Advanced Edge Cases', () => {
|
|
551
|
+
it('should handle multiple circular references in different arguments', () => {
|
|
552
|
+
const browserLogger = createLogger({ __forceType: 'browser' });
|
|
553
|
+
|
|
554
|
+
// Create multiple objects with different circular patterns
|
|
555
|
+
const obj1: any = { name: 'obj1', data: { value: 1 } };
|
|
556
|
+
const obj2: any = { name: 'obj2', data: { value: 2 } };
|
|
557
|
+
const obj3: any = { name: 'obj3', data: { value: 3 } };
|
|
558
|
+
|
|
559
|
+
// Create circular references
|
|
560
|
+
obj1.self = obj1; // Self reference
|
|
561
|
+
obj2.ref = obj3; // Cross reference
|
|
562
|
+
obj3.ref = obj2; // Cross reference back
|
|
563
|
+
obj1.others = [obj2, obj3]; // Array with circular refs
|
|
564
|
+
|
|
565
|
+
// Should handle all without throwing
|
|
566
|
+
expect(() => browserLogger.info('Multiple circulars:', obj1, obj2, obj3)).not.toThrow();
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
it('should handle deeply nested circular references with arrays', () => {
|
|
570
|
+
const browserLogger = createLogger({ __forceType: 'browser' });
|
|
571
|
+
|
|
572
|
+
const deepObj: any = {
|
|
573
|
+
level1: {
|
|
574
|
+
level2: {
|
|
575
|
+
level3: {
|
|
576
|
+
level4: {
|
|
577
|
+
level5: {
|
|
578
|
+
items: [],
|
|
579
|
+
},
|
|
580
|
+
},
|
|
581
|
+
},
|
|
582
|
+
},
|
|
583
|
+
},
|
|
584
|
+
};
|
|
585
|
+
|
|
586
|
+
// Create complex circular structure
|
|
587
|
+
deepObj.level1.level2.level3.level4.level5.items.push(deepObj);
|
|
588
|
+
deepObj.level1.level2.level3.level4.level5.backToLevel2 = deepObj.level1.level2;
|
|
589
|
+
deepObj.level1.array = [deepObj, deepObj.level1, deepObj.level1.level2];
|
|
590
|
+
|
|
591
|
+
expect(() => browserLogger.info('Deep circular:', deepObj)).not.toThrow();
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
it('should handle circular references in error objects with nested arguments', () => {
|
|
595
|
+
const browserLogger = createLogger({ __forceType: 'browser' });
|
|
596
|
+
|
|
597
|
+
const error: any = new Error('Test error');
|
|
598
|
+
const context: any = { errorRef: error, data: {} };
|
|
599
|
+
const metadata: any = { context, timestamp: Date.now() };
|
|
600
|
+
|
|
601
|
+
// Create circular references
|
|
602
|
+
error.context = context;
|
|
603
|
+
context.data.metadata = metadata;
|
|
604
|
+
metadata.error = error;
|
|
605
|
+
|
|
606
|
+
// Multiple arguments with circular references
|
|
607
|
+
expect(() => browserLogger.error('Complex error:', error, context, metadata)).not.toThrow();
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
it('should handle circular references with symbols and special properties', () => {
|
|
611
|
+
const browserLogger = createLogger({ __forceType: 'browser' });
|
|
612
|
+
|
|
613
|
+
const sym = Symbol('test');
|
|
614
|
+
const obj: any = {
|
|
615
|
+
[sym]: 'symbol value',
|
|
616
|
+
normalProp: 'normal',
|
|
617
|
+
nested: {},
|
|
618
|
+
};
|
|
619
|
+
|
|
620
|
+
// Add various types of circular references
|
|
621
|
+
obj.nested.parent = obj;
|
|
622
|
+
obj[Symbol.for('circular')] = obj;
|
|
623
|
+
Object.defineProperty(obj, 'hiddenCircular', {
|
|
624
|
+
value: obj,
|
|
625
|
+
enumerable: false,
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
expect(() => browserLogger.info('Symbol circular:', obj)).not.toThrow();
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
it('should handle circular references in mixed argument types', () => {
|
|
632
|
+
const browserLogger = createLogger({ __forceType: 'browser' });
|
|
633
|
+
|
|
634
|
+
const arr: any[] = [1, 2, 3];
|
|
635
|
+
const obj: any = { arr, name: 'test' };
|
|
636
|
+
const map = new Map();
|
|
637
|
+
const set = new Set();
|
|
638
|
+
|
|
639
|
+
// Create complex circular structure
|
|
640
|
+
arr.push(obj);
|
|
641
|
+
obj.self = obj;
|
|
642
|
+
map.set('obj', obj);
|
|
643
|
+
map.set('arr', arr);
|
|
644
|
+
set.add(obj);
|
|
645
|
+
set.add(arr);
|
|
646
|
+
obj.map = map;
|
|
647
|
+
obj.set = set;
|
|
648
|
+
|
|
649
|
+
// Test with multiple mixed-type arguments
|
|
650
|
+
expect(() =>
|
|
651
|
+
browserLogger.info('Mixed types:', obj, arr, 'string', 123, map, set)
|
|
652
|
+
).not.toThrow();
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
it('should handle circular references in function properties', () => {
|
|
656
|
+
const browserLogger = createLogger({ __forceType: 'browser' });
|
|
657
|
+
|
|
658
|
+
const obj: any = {
|
|
659
|
+
name: 'function container',
|
|
660
|
+
callback: function () {
|
|
661
|
+
return obj;
|
|
662
|
+
},
|
|
663
|
+
};
|
|
664
|
+
|
|
665
|
+
// Add circular reference through function
|
|
666
|
+
obj.callback.parent = obj;
|
|
667
|
+
obj.methods = {
|
|
668
|
+
get: () => obj,
|
|
669
|
+
set: (value: any) => {
|
|
670
|
+
obj.value = value;
|
|
671
|
+
return obj;
|
|
672
|
+
},
|
|
673
|
+
};
|
|
674
|
+
obj.methods.container = obj;
|
|
675
|
+
|
|
676
|
+
expect(() => browserLogger.info('Function circular:', obj)).not.toThrow();
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
it('should handle circular references with prototype chain manipulation', () => {
|
|
680
|
+
const browserLogger = createLogger({ __forceType: 'browser' });
|
|
681
|
+
|
|
682
|
+
class CustomClass {
|
|
683
|
+
constructor(public name: string) {}
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
const instance: any = new CustomClass('test');
|
|
687
|
+
const proto: any = Object.getPrototypeOf(instance);
|
|
688
|
+
|
|
689
|
+
// Create circular through prototype
|
|
690
|
+
instance.proto = proto;
|
|
691
|
+
proto.instance = instance;
|
|
692
|
+
instance.self = instance;
|
|
693
|
+
|
|
694
|
+
expect(() => browserLogger.info('Prototype circular:', instance)).not.toThrow();
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
it('should handle maximum recursion depth with circular references', () => {
|
|
698
|
+
const browserLogger = createLogger({ __forceType: 'browser' });
|
|
699
|
+
|
|
700
|
+
// Create a chain of objects with circular reference at the end
|
|
701
|
+
let current: any = { level: 0 };
|
|
702
|
+
const root = current;
|
|
703
|
+
|
|
704
|
+
for (let i = 1; i < 100; i++) {
|
|
705
|
+
current.next = { level: i, prev: current };
|
|
706
|
+
current = current.next;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// Add circular reference at the end
|
|
710
|
+
current.next = root;
|
|
711
|
+
root.tail = current;
|
|
712
|
+
|
|
713
|
+
expect(() => browserLogger.info('Deep chain circular:', root)).not.toThrow();
|
|
714
|
+
});
|
|
715
|
+
});
|
|
716
|
+
});
|