claw-dashboard 2.1.1 → 2.2.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.
Files changed (89) hide show
  1. package/CHANGELOG.md +29 -1
  2. package/docs/API.md +1 -2
  3. package/index.js +31 -41
  4. package/package.json +22 -12
  5. package/src/auto-save.js +11 -5
  6. package/src/cli/export-snapshot.js +3 -1
  7. package/src/cli/import-snapshot.js +3 -1
  8. package/src/config.js +9 -15
  9. package/src/errors.js +0 -9
  10. package/src/security.js +6 -2
  11. package/src/snapshot.js +73 -26
  12. package/src/web-server.js +7 -10
  13. package/.c8rc.json +0 -38
  14. package/.dockerignore +0 -68
  15. package/.github/dependabot.yml +0 -45
  16. package/.github/pull_request_template.md +0 -39
  17. package/.github/workflows/ci.yml +0 -147
  18. package/.github/workflows/release.yml +0 -40
  19. package/.github/workflows/security.yml +0 -84
  20. package/.husky/pre-commit +0 -1
  21. package/.planning/codebase/ARCHITECTURE.md +0 -206
  22. package/.planning/codebase/INTEGRATIONS.md +0 -150
  23. package/.planning/codebase/STACK.md +0 -122
  24. package/.planning/codebase/STRUCTURE.md +0 -201
  25. package/CONTRIBUTING.md +0 -378
  26. package/Dockerfile +0 -54
  27. package/FEATURES.md +0 -307
  28. package/TODO.md +0 -28
  29. package/ai.openclaw.dashboard.plist +0 -35
  30. package/build-cjs.js +0 -127
  31. package/cjs-shim.js +0 -13
  32. package/dist/clawdash +0 -1729
  33. package/dist/clawdash.meta.json +0 -2236
  34. package/dist/widgets.cjs +0 -6511
  35. package/docker-compose.yml +0 -67
  36. package/esbuild.config.js +0 -158
  37. package/eslint.config.js +0 -56
  38. package/examples/plugins/README.md +0 -122
  39. package/examples/plugins/api-status/index.js +0 -294
  40. package/examples/plugins/api-status/plugin.json +0 -19
  41. package/examples/plugins/hello-world/index.js +0 -104
  42. package/examples/plugins/hello-world/plugin.json +0 -15
  43. package/examples/plugins/system-metrics-chart/index.js +0 -339
  44. package/examples/plugins/system-metrics-chart/plugin.json +0 -18
  45. package/examples/plugins/weather-widget/index.js +0 -136
  46. package/examples/plugins/weather-widget/plugin.json +0 -19
  47. package/index.cjs +0 -23005
  48. package/jest.config.js +0 -11
  49. package/scripts/release.js +0 -595
  50. package/src/database.js +0 -734
  51. package/tests/alerts.test.js +0 -437
  52. package/tests/auto-save.test.js +0 -529
  53. package/tests/cache.test.js +0 -317
  54. package/tests/cli.test.js +0 -351
  55. package/tests/command-palette.test.js +0 -320
  56. package/tests/config-processor.test.js +0 -452
  57. package/tests/config-validator.test.js +0 -710
  58. package/tests/config-watcher.test.js +0 -594
  59. package/tests/config.test.js +0 -755
  60. package/tests/database.test.js +0 -438
  61. package/tests/errors.test.js +0 -189
  62. package/tests/example-plugins.test.js +0 -624
  63. package/tests/integration.test.js +0 -1321
  64. package/tests/loading-states.test.js +0 -300
  65. package/tests/manifest-validation-on-load.test.js +0 -671
  66. package/tests/performance-monitor.test.js +0 -190
  67. package/tests/plugin-api-rate-limit.test.js +0 -302
  68. package/tests/plugin-errors.test.js +0 -311
  69. package/tests/plugin-lifecycle-e2e.test.js +0 -1036
  70. package/tests/plugin-reload.test.js +0 -764
  71. package/tests/rate-limiter.test.js +0 -539
  72. package/tests/removed-dependencies.test.js +0 -74
  73. package/tests/retry.test.js +0 -308
  74. package/tests/security.test.js +0 -411
  75. package/tests/settings-modal.test.js +0 -226
  76. package/tests/theme-selector.test.js +0 -57
  77. package/tests/utils.js +0 -242
  78. package/tests/utils.test.js +0 -317
  79. package/tests/validate-plugin-cli.test.js +0 -359
  80. package/tests/validation.test.js +0 -837
  81. package/tests/web-server.test.js +0 -646
  82. package/tests/widget-arrange-mode.test.js +0 -183
  83. package/tests/widget-config-hot-reload.test.js +0 -465
  84. package/tests/widget-dependency.test.js +0 -591
  85. package/tests/widget-error-boundary.test.js +0 -749
  86. package/tests/widget-error-isolation.test.js +0 -469
  87. package/tests/widget-integration.test.js +0 -1147
  88. package/tests/widget-refresh-intervals.test.js +0 -284
  89. package/tests/worker-pool.test.js +0 -522
@@ -1,438 +0,0 @@
1
- /**
2
- * Unit tests for database.js
3
- * Tests history persistence and metrics storage
4
- */
5
-
6
- import {
7
- initDatabase,
8
- closeDatabase,
9
- storeSessionSnapshot,
10
- storeCpuMetrics,
11
- storeMemoryMetrics,
12
- storeNetworkMetrics,
13
- storeMetricsSnapshot,
14
- getSessionsLast24Hours,
15
- getSessionsLast7Days,
16
- getSessionsByHours,
17
- getSessionsByDays,
18
- getCpuMetricsHistory,
19
- getMemoryMetricsHistory,
20
- getNetworkMetricsHistory,
21
- getMetricsSummary,
22
- cleanupOldData,
23
- } from '../src/database.js';
24
-
25
- describe('Database', () => {
26
- // Clean up after each test
27
- afterEach(async () => {
28
- await closeDatabase();
29
- });
30
-
31
- describe('initDatabase', () => {
32
- test('should initialize database successfully', async () => {
33
- const result = await initDatabase();
34
- expect(result).toBe(true);
35
- });
36
-
37
- test('should handle errors gracefully', async () => {
38
- // Second initialization should still work
39
- await initDatabase();
40
- const result = await initDatabase();
41
- expect(result).toBe(true);
42
- });
43
- });
44
-
45
- describe('storeSessionSnapshot', () => {
46
- test('should store session with all fields', async () => {
47
- await initDatabase();
48
-
49
- const session = {
50
- sessionId: 'test-session-1',
51
- key: 'agent:main:main',
52
- agent: 'test-agent',
53
- deliveryContext: { channel: 'test-channel' },
54
- model: 'gpt-4',
55
- totalTokens: 1500,
56
- status: 'running',
57
- };
58
-
59
- // Should not throw
60
- expect(() => storeSessionSnapshot(session)).not.toThrow();
61
- });
62
-
63
- test('should handle null session gracefully', () => {
64
- // Should not throw even without database
65
- expect(() => storeSessionSnapshot(null)).not.toThrow();
66
- });
67
-
68
- test('should handle session with minimal fields', async () => {
69
- await initDatabase();
70
-
71
- const session = {
72
- sessionId: 'minimal-session',
73
- key: 'agent:test',
74
- };
75
-
76
- expect(() => storeSessionSnapshot(session)).not.toThrow();
77
- });
78
-
79
- test('should extract agent from session key', async () => {
80
- await initDatabase();
81
-
82
- const session = {
83
- key: 'agent:my-agent:instance',
84
- sessionId: 'test',
85
- };
86
-
87
- expect(() => storeSessionSnapshot(session)).not.toThrow();
88
- });
89
-
90
- test('should handle alternative field names', async () => {
91
- await initDatabase();
92
-
93
- const session = {
94
- key: 'test-key',
95
- llmModel: 'claude',
96
- tokens: 500,
97
- systemRunning: true,
98
- };
99
-
100
- expect(() => storeSessionSnapshot(session)).not.toThrow();
101
- });
102
- });
103
-
104
- describe('storeCpuMetrics', () => {
105
- test('should store CPU metrics', async () => {
106
- await initDatabase();
107
-
108
- const cpuData = {
109
- cpus: [
110
- {
111
- load: 50,
112
- loadAvg1: 0.5,
113
- loadAvg5: 0.6,
114
- loadAvg15: 0.7,
115
- cpuUsageUser: 20,
116
- cpuUsageSystem: 10,
117
- cpuUsageIdle: 70,
118
- },
119
- ],
120
- };
121
-
122
- expect(() => storeCpuMetrics(cpuData)).not.toThrow();
123
- });
124
-
125
- test('should handle null data', () => {
126
- // Should not throw
127
- expect(() => storeCpuMetrics(null)).not.toThrow();
128
- });
129
-
130
- test('should handle empty data', () => {
131
- // Should not throw
132
- expect(() => storeCpuMetrics({})).not.toThrow();
133
- });
134
-
135
- test('should handle object format (non-array)', async () => {
136
- await initDatabase();
137
-
138
- const cpuData = {
139
- loadAvg1: 1.0,
140
- loadAvg5: 2.0,
141
- loadAvg15: 3.0,
142
- cpuUsageUser: 25,
143
- cpuUsageSystem: 15,
144
- cpuUsageIdle: 60,
145
- };
146
-
147
- expect(() => storeCpuMetrics(cpuData)).not.toThrow();
148
- });
149
-
150
- test('should handle alternative field names', async () => {
151
- await initDatabase();
152
-
153
- const cpuData = {
154
- cpu_count: 8,
155
- load_avg_1: 1.5,
156
- loadavg: [1.0, 2.0, 3.0],
157
- cpuUsage: [20, 10, 70, 0, 0, 0],
158
- };
159
-
160
- expect(() => storeCpuMetrics(cpuData)).not.toThrow();
161
- });
162
- });
163
-
164
- describe('storeMemoryMetrics', () => {
165
- test('should store memory metrics', async () => {
166
- await initDatabase();
167
-
168
- const memoryData = {
169
- totalBytes: 16000000000,
170
- usedBytes: 8000000000,
171
- freeBytes: 7000000000,
172
- availableBytes: 7500000000,
173
- usedPercent: 50,
174
- swapTotalBytes: 2000000000,
175
- swapUsedBytes: 500000000,
176
- swapFreeBytes: 1500000000,
177
- swapUsedPercent: 25,
178
- };
179
-
180
- expect(() => storeMemoryMetrics(memoryData)).not.toThrow();
181
- });
182
-
183
- test('should handle null data', () => {
184
- expect(() => storeMemoryMetrics(null)).not.toThrow();
185
- });
186
-
187
- test('should handle alternative field names', async () => {
188
- await initDatabase();
189
-
190
- const memoryData = {
191
- total_bytes: 16000000000,
192
- used_bytes: 8000000000,
193
- free_bytes: 7000000000,
194
- available_bytes: 7500000000,
195
- used_percent: 50,
196
- };
197
-
198
- expect(() => storeMemoryMetrics(memoryData)).not.toThrow();
199
- });
200
- });
201
-
202
- describe('storeNetworkMetrics', () => {
203
- test('should store network metrics', async () => {
204
- await initDatabase();
205
-
206
- const networkData = {
207
- interfaceName: 'eth0',
208
- rxBytes: 1000000,
209
- txBytes: 500000,
210
- rxSec: 1000,
211
- txSec: 500,
212
- };
213
-
214
- expect(() => storeNetworkMetrics(networkData)).not.toThrow();
215
- });
216
-
217
- test('should handle array of interfaces', async () => {
218
- await initDatabase();
219
-
220
- const interfaces = [
221
- { interfaceName: 'eth0', rxBytes: 100 },
222
- { interfaceName: 'eth1', rxBytes: 200 },
223
- ];
224
-
225
- expect(() => storeNetworkMetrics(interfaces)).not.toThrow();
226
- });
227
-
228
- test('should handle null data', () => {
229
- expect(() => storeNetworkMetrics(null)).not.toThrow();
230
- });
231
-
232
- test('should handle alternative field names', async () => {
233
- await initDatabase();
234
-
235
- const networkData = {
236
- interface_name: 'wlan0',
237
- rx_bytes: 1000000,
238
- tx_bytes: 500000,
239
- rx_sec: 1000,
240
- tx_sec: 500,
241
- };
242
-
243
- expect(() => storeNetworkMetrics(networkData)).not.toThrow();
244
- });
245
- });
246
-
247
- describe('storeMetricsSnapshot', () => {
248
- test('should store all metrics from data object', async () => {
249
- await initDatabase();
250
-
251
- const data = {
252
- cpu: { cpus: [{ load: 50 }] },
253
- memory: { totalBytes: 16000000000, usedBytes: 8000000000 },
254
- network: { interfaceName: 'eth0', rxBytes: 100 },
255
- sessions: [
256
- { sessionId: 's1', tokens: 100 },
257
- { sessionId: 's2', tokens: 200 },
258
- ],
259
- };
260
-
261
- expect(() => storeMetricsSnapshot(data)).not.toThrow();
262
- });
263
-
264
- test('should handle empty data', () => {
265
- expect(() => storeMetricsSnapshot({})).not.toThrow();
266
- });
267
-
268
- test('should handle null data', () => {
269
- expect(() => storeMetricsSnapshot(null)).not.toThrow();
270
- });
271
-
272
- test('should handle partial data', async () => {
273
- await initDatabase();
274
-
275
- // Only CPU data
276
- expect(() => storeMetricsSnapshot({ cpu: { cpus: [] } })).not.toThrow();
277
-
278
- // Only memory data
279
- expect(() => storeMetricsSnapshot({ memory: {} })).not.toThrow();
280
-
281
- // Only network data
282
- expect(() => storeMetricsSnapshot({ network: {} })).not.toThrow();
283
-
284
- // Only sessions
285
- expect(() => storeMetricsSnapshot({ sessions: [] })).not.toThrow();
286
- });
287
- });
288
-
289
- describe('getSessionsLast24Hours', () => {
290
- test('should return array even when not initialized', () => {
291
- const sessions = getSessionsLast24Hours();
292
- expect(Array.isArray(sessions)).toBe(true);
293
- });
294
-
295
- test('should return array when initialized', async () => {
296
- await initDatabase();
297
- const sessions = getSessionsLast24Hours();
298
- expect(Array.isArray(sessions)).toBe(true);
299
- });
300
- });
301
-
302
- describe('getSessionsByHours', () => {
303
- test('should return array even when not initialized', () => {
304
- const sessions = getSessionsByHours(12);
305
- expect(Array.isArray(sessions)).toBe(true);
306
- });
307
-
308
- test('should return array when initialized', async () => {
309
- await initDatabase();
310
- const sessions = getSessionsByHours(12);
311
- expect(Array.isArray(sessions)).toBe(true);
312
- });
313
-
314
- test('should handle default hours parameter', async () => {
315
- await initDatabase();
316
- const sessions = getSessionsByHours();
317
- expect(Array.isArray(sessions)).toBe(true);
318
- });
319
- });
320
-
321
- describe('getSessionsByDays', () => {
322
- test('should return array', async () => {
323
- await initDatabase();
324
- const sessions = getSessionsByDays(7);
325
- expect(Array.isArray(sessions)).toBe(true);
326
- });
327
-
328
- test('should handle default days parameter', async () => {
329
- await initDatabase();
330
- const sessions = getSessionsByDays();
331
- expect(Array.isArray(sessions)).toBe(true);
332
- });
333
- });
334
-
335
- describe('getCpuMetricsHistory', () => {
336
- test('should return empty array when not initialized', () => {
337
- const metrics = getCpuMetricsHistory(24);
338
- expect(metrics).toEqual([]);
339
- });
340
-
341
- test('should return array when initialized', async () => {
342
- await initDatabase();
343
- const metrics = getCpuMetricsHistory(24);
344
- expect(Array.isArray(metrics)).toBe(true);
345
- });
346
-
347
- test('should handle default hours parameter', async () => {
348
- await initDatabase();
349
- const metrics = getCpuMetricsHistory();
350
- expect(Array.isArray(metrics)).toBe(true);
351
- });
352
- });
353
-
354
- describe('getMemoryMetricsHistory', () => {
355
- test('should return empty array when not initialized', () => {
356
- const metrics = getMemoryMetricsHistory(24);
357
- expect(metrics).toEqual([]);
358
- });
359
-
360
- test('should return array when initialized', async () => {
361
- await initDatabase();
362
- const metrics = getMemoryMetricsHistory(24);
363
- expect(Array.isArray(metrics)).toBe(true);
364
- });
365
- });
366
-
367
- describe('getNetworkMetricsHistory', () => {
368
- test('should return empty array when not initialized', () => {
369
- const metrics = getNetworkMetricsHistory(24);
370
- expect(metrics).toEqual([]);
371
- });
372
-
373
- test('should return array when initialized', async () => {
374
- await initDatabase();
375
- const metrics = getNetworkMetricsHistory(24);
376
- expect(Array.isArray(metrics)).toBe(true);
377
- });
378
- });
379
-
380
- describe('getMetricsSummary', () => {
381
- test('should return null when not initialized', () => {
382
- const summary = getMetricsSummary(24);
383
- expect(summary).toBeNull();
384
- });
385
-
386
- test('should return summary when initialized', async () => {
387
- await initDatabase();
388
- const summary = getMetricsSummary(24);
389
- expect(summary).toHaveProperty('cpu');
390
- expect(summary).toHaveProperty('memory');
391
- expect(summary).toHaveProperty('sessions');
392
- expect(summary).toHaveProperty('tokens');
393
- });
394
-
395
- test('should handle default hours parameter', async () => {
396
- await initDatabase();
397
- const summary = getMetricsSummary();
398
- expect(summary).toHaveProperty('cpu');
399
- expect(summary).toHaveProperty('memory');
400
- });
401
- });
402
-
403
- describe('cleanupOldData', () => {
404
- test('should run without errors when initialized', async () => {
405
- await initDatabase();
406
- // Should not throw
407
- expect(() => cleanupOldData(30)).not.toThrow();
408
- });
409
-
410
- test('should run without errors when not initialized', () => {
411
- // Should not throw
412
- expect(() => cleanupOldData(30)).not.toThrow();
413
- });
414
-
415
- test('should handle default days parameter', async () => {
416
- await initDatabase();
417
- expect(() => cleanupOldData()).not.toThrow();
418
- });
419
- });
420
-
421
- describe('closeDatabase', () => {
422
- test('should close database gracefully', async () => {
423
- await initDatabase();
424
- expect(() => closeDatabase()).not.toThrow();
425
- });
426
-
427
- test('should handle closing when not initialized', async () => {
428
- expect(() => closeDatabase()).not.toThrow();
429
- });
430
-
431
- test('should allow re-initialization after close', async () => {
432
- await initDatabase();
433
- await closeDatabase();
434
- const result = await initDatabase();
435
- expect(result).toBe(true);
436
- });
437
- });
438
- });
@@ -1,189 +0,0 @@
1
- import {
2
- DashboardError,
3
- ConfigError,
4
- SettingsError,
5
- GatewayError,
6
- SessionError,
7
- DataFetchError,
8
- AuthError,
9
- NetworkError,
10
- UIError,
11
- DatabaseError,
12
- ValidationError,
13
- TimeoutError,
14
- ERROR_CODES,
15
- isDashboardError,
16
- getErrorCode
17
- } from '../src/errors.js';
18
-
19
- describe('Custom Error Classes', () => {
20
- describe('DashboardError', () => {
21
- test('creates error with message, code, and details', () => {
22
- const error = new DashboardError('Test error', 'TEST_CODE', { foo: 'bar' });
23
- expect(error.message).toBe('Test error');
24
- expect(error.code).toBe('TEST_CODE');
25
- expect(error.details).toEqual({ foo: 'bar' });
26
- expect(error.name).toBe('DashboardError');
27
- expect(error.timestamp).toBeDefined();
28
- });
29
-
30
- test('provides default values for missing params', () => {
31
- const error = new DashboardError('Test error');
32
- expect(error.code).toBe('DASHBOARD_ERROR');
33
- expect(error.details).toEqual({});
34
- });
35
-
36
- test('toJSON includes all properties', () => {
37
- const error = new DashboardError('Test error', 'CODE', { key: 'value' });
38
- const json = error.toJSON();
39
- expect(json.message).toBe('Test error');
40
- expect(json.code).toBe('CODE');
41
- expect(json.details).toEqual({ key: 'value' });
42
- expect(json.timestamp).toBeDefined();
43
- expect(json.stack).toBeDefined();
44
- });
45
- });
46
-
47
- describe('ConfigError', () => {
48
- test('creates config error with correct code', () => {
49
- const error = new ConfigError('Invalid config', { key: 'theme' });
50
- expect(error.name).toBe('ConfigError');
51
- expect(error.code).toBe('CONFIG_ERROR');
52
- });
53
- });
54
-
55
- describe('SettingsError', () => {
56
- test('creates settings error with correct code', () => {
57
- const error = new SettingsError('Settings invalid', { path: '/path' });
58
- expect(error.name).toBe('SettingsError');
59
- expect(error.code).toBe('SETTINGS_ERROR');
60
- });
61
- });
62
-
63
- describe('GatewayError', () => {
64
- test('creates gateway error with correct code', () => {
65
- const error = new GatewayError('Connection failed', { port: 18789 });
66
- expect(error.name).toBe('GatewayError');
67
- expect(error.code).toBe('GATEWAY_ERROR');
68
- });
69
- });
70
-
71
- describe('SessionError', () => {
72
- test('creates session error with correct code', () => {
73
- const error = new SessionError('Session not found', { sessionId: 'abc' });
74
- expect(error.name).toBe('SessionError');
75
- expect(error.code).toBe('SESSION_ERROR');
76
- });
77
- });
78
-
79
- describe('DataFetchError', () => {
80
- test('creates data fetch error with correct code', () => {
81
- const error = new DataFetchError('Failed to fetch CPU', { type: 'cpu' });
82
- expect(error.name).toBe('DataFetchError');
83
- expect(error.code).toBe('DATA_FETCH_ERROR');
84
- });
85
- });
86
-
87
- describe('AuthError', () => {
88
- test('creates auth error with correct code', () => {
89
- const error = new AuthError('Unauthorized');
90
- expect(error.name).toBe('AuthError');
91
- expect(error.code).toBe('AUTH_ERROR');
92
- });
93
- });
94
-
95
- describe('NetworkError', () => {
96
- test('creates network error with correct code', () => {
97
- const error = new NetworkError('Connection refused', { host: 'localhost' });
98
- expect(error.name).toBe('NetworkError');
99
- expect(error.code).toBe('NETWORK_ERROR');
100
- });
101
- });
102
-
103
- describe('UIError', () => {
104
- test('creates UI error with correct code', () => {
105
- const error = new UIError('Render failed', { widget: 'cpu' });
106
- expect(error.name).toBe('UIError');
107
- expect(error.code).toBe('UI_ERROR');
108
- });
109
- });
110
-
111
- describe('DatabaseError', () => {
112
- test('creates database error with correct code', () => {
113
- const error = new DatabaseError('Query failed', { operation: 'SELECT' });
114
- expect(error.name).toBe('DatabaseError');
115
- expect(error.code).toBe('DATABASE_ERROR');
116
- });
117
- });
118
-
119
- describe('ValidationError', () => {
120
- test('creates validation error with correct code', () => {
121
- const error = new ValidationError('Invalid input', { field: 'refreshInterval' });
122
- expect(error.name).toBe('ValidationError');
123
- expect(error.code).toBe('VALIDATION_ERROR');
124
- });
125
- });
126
-
127
- describe('TimeoutError', () => {
128
- test('creates timeout error with correct code', () => {
129
- const error = new TimeoutError('Operation timed out', { timeout: 5000 });
130
- expect(error.name).toBe('TimeoutError');
131
- expect(error.code).toBe('TIMEOUT_ERROR');
132
- });
133
- });
134
-
135
- describe('ERROR_CODES constant', () => {
136
- test('exports all expected error codes', () => {
137
- expect(ERROR_CODES.CONFIG_ERROR).toBe('CONFIG_ERROR');
138
- expect(ERROR_CODES.SETTINGS_ERROR).toBe('SETTINGS_ERROR');
139
- expect(ERROR_CODES.GATEWAY_ERROR).toBe('GATEWAY_ERROR');
140
- expect(ERROR_CODES.SESSION_ERROR).toBe('SESSION_ERROR');
141
- expect(ERROR_CODES.DATA_FETCH_ERROR).toBe('DATA_FETCH_ERROR');
142
- expect(ERROR_CODES.AUTH_ERROR).toBe('AUTH_ERROR');
143
- expect(ERROR_CODES.NETWORK_ERROR).toBe('NETWORK_ERROR');
144
- expect(ERROR_CODES.UI_ERROR).toBe('UI_ERROR');
145
- expect(ERROR_CODES.DATABASE_ERROR).toBe('DATABASE_ERROR');
146
- expect(ERROR_CODES.VALIDATION_ERROR).toBe('VALIDATION_ERROR');
147
- expect(ERROR_CODES.TIMEOUT_ERROR).toBe('TIMEOUT_ERROR');
148
- });
149
- });
150
-
151
- describe('isDashboardError', () => {
152
- test('returns true for DashboardError instances', () => {
153
- const error = new DashboardError('test');
154
- expect(isDashboardError(error)).toBe(true);
155
- });
156
-
157
- test('returns true for subclass instances', () => {
158
- const error = new ConfigError('test');
159
- expect(isDashboardError(error)).toBe(true);
160
- });
161
-
162
- test('returns false for regular Error', () => {
163
- const error = new Error('test');
164
- expect(isDashboardError(error)).toBe(false);
165
- });
166
-
167
- test('returns false for null/undefined', () => {
168
- expect(isDashboardError(null)).toBe(false);
169
- expect(isDashboardError(undefined)).toBe(false);
170
- });
171
- });
172
-
173
- describe('getErrorCode', () => {
174
- test('returns code for DashboardError', () => {
175
- const error = new GatewayError('test');
176
- expect(getErrorCode(error)).toBe('GATEWAY_ERROR');
177
- });
178
-
179
- test('returns UNKNOWN_ERROR for regular Error', () => {
180
- const error = new Error('test');
181
- expect(getErrorCode(error)).toBe('UNKNOWN_ERROR');
182
- });
183
-
184
- test('returns UNKNOWN_ERROR for non-error values', () => {
185
- expect(getErrorCode('string')).toBe('UNKNOWN_ERROR');
186
- expect(getErrorCode({})).toBe('UNKNOWN_ERROR');
187
- });
188
- });
189
- });