@sc4rfurryx/proteusjs 1.0.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/API.md +438 -0
- package/FEATURES.md +286 -0
- package/LICENSE +21 -0
- package/README.md +645 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/proteus.cjs.js +16014 -0
- package/dist/proteus.cjs.js.map +1 -0
- package/dist/proteus.d.ts +3018 -0
- package/dist/proteus.esm.js +16005 -0
- package/dist/proteus.esm.js.map +1 -0
- package/dist/proteus.esm.min.js +8 -0
- package/dist/proteus.esm.min.js.map +1 -0
- package/dist/proteus.js +16020 -0
- package/dist/proteus.js.map +1 -0
- package/dist/proteus.min.js +8 -0
- package/dist/proteus.min.js.map +1 -0
- package/package.json +98 -0
- package/src/__tests__/mvp-integration.test.ts +518 -0
- package/src/accessibility/AccessibilityEngine.ts +2106 -0
- package/src/accessibility/ScreenReaderSupport.ts +444 -0
- package/src/accessibility/__tests__/ScreenReaderSupport.test.ts +435 -0
- package/src/animations/FLIPAnimationSystem.ts +491 -0
- package/src/compatibility/BrowserCompatibility.ts +1076 -0
- package/src/containers/BreakpointSystem.ts +347 -0
- package/src/containers/ContainerBreakpoints.ts +726 -0
- package/src/containers/ContainerManager.ts +370 -0
- package/src/containers/ContainerUnits.ts +336 -0
- package/src/containers/ContextIsolation.ts +394 -0
- package/src/containers/ElementQueries.ts +411 -0
- package/src/containers/SmartContainer.ts +536 -0
- package/src/containers/SmartContainers.ts +376 -0
- package/src/containers/__tests__/ContainerBreakpoints.test.ts +411 -0
- package/src/containers/__tests__/SmartContainers.test.ts +281 -0
- package/src/content/ResponsiveImages.ts +570 -0
- package/src/core/EventSystem.ts +147 -0
- package/src/core/MemoryManager.ts +321 -0
- package/src/core/PerformanceMonitor.ts +238 -0
- package/src/core/PluginSystem.ts +275 -0
- package/src/core/ProteusJS.test.ts +164 -0
- package/src/core/ProteusJS.ts +962 -0
- package/src/developer/PerformanceProfiler.ts +567 -0
- package/src/developer/VisualDebuggingTools.ts +656 -0
- package/src/developer/ZeroConfigSystem.ts +593 -0
- package/src/index.ts +35 -0
- package/src/integration.test.ts +227 -0
- package/src/layout/AdaptiveGrid.ts +429 -0
- package/src/layout/ContentReordering.ts +532 -0
- package/src/layout/FlexboxEnhancer.ts +406 -0
- package/src/layout/FlowLayout.ts +545 -0
- package/src/layout/SpacingSystem.ts +512 -0
- package/src/observers/IntersectionObserverPolyfill.ts +289 -0
- package/src/observers/ObserverManager.ts +299 -0
- package/src/observers/ResizeObserverPolyfill.ts +179 -0
- package/src/performance/BatchDOMOperations.ts +519 -0
- package/src/performance/CSSOptimizationEngine.ts +646 -0
- package/src/performance/CacheOptimizationSystem.ts +601 -0
- package/src/performance/EfficientEventHandler.ts +740 -0
- package/src/performance/LazyEvaluationSystem.ts +532 -0
- package/src/performance/MemoryManagementSystem.ts +497 -0
- package/src/performance/PerformanceMonitor.ts +931 -0
- package/src/performance/__tests__/BatchDOMOperations.test.ts +309 -0
- package/src/performance/__tests__/EfficientEventHandler.test.ts +268 -0
- package/src/performance/__tests__/PerformanceMonitor.test.ts +422 -0
- package/src/polyfills/BrowserPolyfills.ts +586 -0
- package/src/polyfills/__tests__/BrowserPolyfills.test.ts +328 -0
- package/src/test/setup.ts +115 -0
- package/src/theming/SmartThemeSystem.ts +591 -0
- package/src/types/index.ts +134 -0
- package/src/typography/ClampScaling.ts +356 -0
- package/src/typography/FluidTypography.ts +759 -0
- package/src/typography/LineHeightOptimization.ts +430 -0
- package/src/typography/LineHeightOptimizer.ts +326 -0
- package/src/typography/TextFitting.ts +355 -0
- package/src/typography/TypographicScale.ts +428 -0
- package/src/typography/VerticalRhythm.ts +369 -0
- package/src/typography/__tests__/FluidTypography.test.ts +432 -0
- package/src/typography/__tests__/LineHeightOptimization.test.ts +436 -0
- package/src/utils/Logger.ts +173 -0
- package/src/utils/debounce.ts +259 -0
- package/src/utils/performance.ts +371 -0
- package/src/utils/support.ts +106 -0
- package/src/utils/version.ts +24 -0
@@ -0,0 +1,422 @@
|
|
1
|
+
/**
|
2
|
+
* PerformanceMonitor Test Suite
|
3
|
+
* Comprehensive tests for performance monitoring system
|
4
|
+
*/
|
5
|
+
|
6
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
7
|
+
import { PerformanceMonitor, PerformanceThresholds } from '../PerformanceMonitor';
|
8
|
+
|
9
|
+
// Mock performance.memory
|
10
|
+
Object.defineProperty(performance, 'memory', {
|
11
|
+
value: {
|
12
|
+
usedJSHeapSize: 50 * 1024 * 1024, // 50MB
|
13
|
+
totalJSHeapSize: 100 * 1024 * 1024, // 100MB
|
14
|
+
jsHeapSizeLimit: 200 * 1024 * 1024 // 200MB
|
15
|
+
},
|
16
|
+
configurable: true
|
17
|
+
});
|
18
|
+
|
19
|
+
// Mock requestAnimationFrame
|
20
|
+
global.requestAnimationFrame = vi.fn((callback) => {
|
21
|
+
return setTimeout(() => callback(performance.now()), 16);
|
22
|
+
});
|
23
|
+
|
24
|
+
global.cancelAnimationFrame = vi.fn((id) => {
|
25
|
+
clearTimeout(id);
|
26
|
+
});
|
27
|
+
|
28
|
+
describe('PerformanceMonitor', () => {
|
29
|
+
let performanceMonitor: PerformanceMonitor;
|
30
|
+
|
31
|
+
beforeEach(() => {
|
32
|
+
// Clean up DOM
|
33
|
+
document.body.innerHTML = '';
|
34
|
+
|
35
|
+
performanceMonitor = new PerformanceMonitor();
|
36
|
+
|
37
|
+
// Mock performance.now to return predictable values
|
38
|
+
let mockTime = 0;
|
39
|
+
vi.spyOn(performance, 'now').mockImplementation(() => {
|
40
|
+
mockTime += 16.67; // Simulate 60fps
|
41
|
+
return mockTime;
|
42
|
+
});
|
43
|
+
});
|
44
|
+
|
45
|
+
afterEach(() => {
|
46
|
+
performanceMonitor.stop();
|
47
|
+
vi.restoreAllMocks();
|
48
|
+
});
|
49
|
+
|
50
|
+
describe('Initialization', () => {
|
51
|
+
it('should initialize with default thresholds', () => {
|
52
|
+
const metrics = performanceMonitor.getMetrics();
|
53
|
+
|
54
|
+
expect(metrics).toBeDefined();
|
55
|
+
expect(metrics.frameRate).toBe(60);
|
56
|
+
expect(metrics.averageFrameTime).toBe(16.67);
|
57
|
+
expect(metrics.memoryUsage).toBeDefined();
|
58
|
+
});
|
59
|
+
|
60
|
+
it('should accept custom thresholds', () => {
|
61
|
+
const customThresholds: Partial<PerformanceThresholds> = {
|
62
|
+
minFrameRate: 30,
|
63
|
+
maxMemoryUsage: 200 * 1024 * 1024
|
64
|
+
};
|
65
|
+
|
66
|
+
const monitor = new PerformanceMonitor(customThresholds);
|
67
|
+
|
68
|
+
expect(monitor).toBeDefined();
|
69
|
+
});
|
70
|
+
});
|
71
|
+
|
72
|
+
describe('Monitoring Control', () => {
|
73
|
+
it('should start monitoring', () => {
|
74
|
+
expect(() => {
|
75
|
+
performanceMonitor.start();
|
76
|
+
}).not.toThrow();
|
77
|
+
});
|
78
|
+
|
79
|
+
it('should stop monitoring', () => {
|
80
|
+
performanceMonitor.start();
|
81
|
+
|
82
|
+
expect(() => {
|
83
|
+
performanceMonitor.stop();
|
84
|
+
}).not.toThrow();
|
85
|
+
});
|
86
|
+
|
87
|
+
it('should handle multiple start calls gracefully', () => {
|
88
|
+
performanceMonitor.start();
|
89
|
+
performanceMonitor.start(); // Should not cause issues
|
90
|
+
|
91
|
+
expect(() => {
|
92
|
+
performanceMonitor.stop();
|
93
|
+
}).not.toThrow();
|
94
|
+
});
|
95
|
+
|
96
|
+
it('should handle stop without start gracefully', () => {
|
97
|
+
expect(() => {
|
98
|
+
performanceMonitor.stop();
|
99
|
+
}).not.toThrow();
|
100
|
+
});
|
101
|
+
});
|
102
|
+
|
103
|
+
describe('Metrics Collection', () => {
|
104
|
+
it('should collect frame rate metrics', async () => {
|
105
|
+
performanceMonitor.start();
|
106
|
+
|
107
|
+
// Wait for a few frames
|
108
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
109
|
+
|
110
|
+
const metrics = performanceMonitor.getMetrics();
|
111
|
+
|
112
|
+
expect(metrics.frameRate).toBeGreaterThan(0);
|
113
|
+
expect(metrics.averageFrameTime).toBeGreaterThan(0);
|
114
|
+
});
|
115
|
+
|
116
|
+
it('should collect memory metrics', () => {
|
117
|
+
performanceMonitor.updateMetrics();
|
118
|
+
|
119
|
+
const metrics = performanceMonitor.getMetrics();
|
120
|
+
|
121
|
+
expect(metrics.memoryUsage.used).toBeGreaterThan(0);
|
122
|
+
expect(metrics.memoryUsage.total).toBeGreaterThan(0);
|
123
|
+
expect(metrics.memoryUsage.percentage).toBeGreaterThan(0);
|
124
|
+
});
|
125
|
+
|
126
|
+
it('should collect DOM metrics', () => {
|
127
|
+
// Add some DOM elements
|
128
|
+
for (let i = 0; i < 10; i++) {
|
129
|
+
const div = document.createElement('div');
|
130
|
+
document.body.appendChild(div);
|
131
|
+
}
|
132
|
+
|
133
|
+
performanceMonitor.updateMetrics();
|
134
|
+
|
135
|
+
const metrics = performanceMonitor.getMetrics();
|
136
|
+
|
137
|
+
expect(metrics.domNodes).toBeGreaterThan(0);
|
138
|
+
});
|
139
|
+
|
140
|
+
it('should track operations per second', () => {
|
141
|
+
performanceMonitor.start();
|
142
|
+
|
143
|
+
// Record some operations
|
144
|
+
for (let i = 0; i < 10; i++) {
|
145
|
+
performanceMonitor.recordOperation();
|
146
|
+
}
|
147
|
+
|
148
|
+
performanceMonitor.updateMetrics();
|
149
|
+
|
150
|
+
const metrics = performanceMonitor.getMetrics();
|
151
|
+
|
152
|
+
expect(metrics.operationsPerSecond).toBeGreaterThanOrEqual(0);
|
153
|
+
});
|
154
|
+
|
155
|
+
it('should update cache hit rate', () => {
|
156
|
+
performanceMonitor.updateCacheHitRate(80, 100);
|
157
|
+
|
158
|
+
const metrics = performanceMonitor.getMetrics();
|
159
|
+
|
160
|
+
expect(metrics.cacheHitRate).toBe(80);
|
161
|
+
});
|
162
|
+
});
|
163
|
+
|
164
|
+
describe('Performance Alerts', () => {
|
165
|
+
it('should generate frame rate alerts', () => {
|
166
|
+
// Mock low frame rate
|
167
|
+
vi.spyOn(performance, 'now').mockImplementation(() => {
|
168
|
+
return Date.now(); // This will result in inconsistent frame times
|
169
|
+
});
|
170
|
+
|
171
|
+
const monitor = new PerformanceMonitor({ minFrameRate: 55 });
|
172
|
+
monitor.start();
|
173
|
+
|
174
|
+
// Force metrics update with poor performance
|
175
|
+
monitor['metrics'].frameRate = 30; // Below threshold
|
176
|
+
monitor['checkThresholds']();
|
177
|
+
|
178
|
+
const alerts = monitor.getAlerts();
|
179
|
+
|
180
|
+
expect(alerts.length).toBeGreaterThan(0);
|
181
|
+
expect(alerts[0].metric).toBe('frameRate');
|
182
|
+
expect(alerts[0].type).toBe('warning');
|
183
|
+
});
|
184
|
+
|
185
|
+
it('should generate memory alerts', () => {
|
186
|
+
const monitor = new PerformanceMonitor({ maxMemoryUsage: 10 * 1024 * 1024 }); // 10MB threshold
|
187
|
+
|
188
|
+
// Force high memory usage
|
189
|
+
monitor['metrics'].memoryUsage.used = 20 * 1024 * 1024; // 20MB
|
190
|
+
monitor['checkThresholds']();
|
191
|
+
|
192
|
+
const alerts = monitor.getAlerts();
|
193
|
+
|
194
|
+
expect(alerts.length).toBeGreaterThan(0);
|
195
|
+
expect(alerts[0].metric).toBe('memoryUsage');
|
196
|
+
expect(alerts[0].type).toBe('critical');
|
197
|
+
});
|
198
|
+
|
199
|
+
it('should generate DOM node alerts', () => {
|
200
|
+
const monitor = new PerformanceMonitor({ maxDOMNodes: 100 });
|
201
|
+
|
202
|
+
// Force high DOM node count
|
203
|
+
monitor['metrics'].domNodes = 200;
|
204
|
+
monitor['checkThresholds']();
|
205
|
+
|
206
|
+
const alerts = monitor.getAlerts();
|
207
|
+
|
208
|
+
expect(alerts.length).toBeGreaterThan(0);
|
209
|
+
expect(alerts[0].metric).toBe('domNodes');
|
210
|
+
});
|
211
|
+
|
212
|
+
it('should clear alerts', () => {
|
213
|
+
const monitor = new PerformanceMonitor({ minFrameRate: 55 });
|
214
|
+
|
215
|
+
// Generate an alert
|
216
|
+
monitor['metrics'].frameRate = 30;
|
217
|
+
monitor['checkThresholds']();
|
218
|
+
|
219
|
+
expect(monitor.getAlerts().length).toBeGreaterThan(0);
|
220
|
+
|
221
|
+
monitor.clearAlerts();
|
222
|
+
|
223
|
+
expect(monitor.getAlerts().length).toBe(0);
|
224
|
+
});
|
225
|
+
|
226
|
+
it('should prevent duplicate alerts', () => {
|
227
|
+
const monitor = new PerformanceMonitor({ minFrameRate: 55 });
|
228
|
+
|
229
|
+
// Generate multiple alerts for the same metric
|
230
|
+
monitor['metrics'].frameRate = 30;
|
231
|
+
monitor['checkThresholds']();
|
232
|
+
monitor['checkThresholds']();
|
233
|
+
monitor['checkThresholds']();
|
234
|
+
|
235
|
+
const alerts = monitor.getAlerts();
|
236
|
+
|
237
|
+
expect(alerts.length).toBe(1); // Should only have one alert
|
238
|
+
});
|
239
|
+
});
|
240
|
+
|
241
|
+
describe('Callbacks', () => {
|
242
|
+
it('should add and call callbacks', () => {
|
243
|
+
const callback = vi.fn();
|
244
|
+
|
245
|
+
performanceMonitor.addCallback(callback);
|
246
|
+
performanceMonitor.updateMetrics();
|
247
|
+
|
248
|
+
expect(callback).toHaveBeenCalledWith(
|
249
|
+
expect.objectContaining({
|
250
|
+
frameRate: expect.any(Number),
|
251
|
+
memoryUsage: expect.any(Object)
|
252
|
+
})
|
253
|
+
);
|
254
|
+
});
|
255
|
+
|
256
|
+
it('should remove callbacks', () => {
|
257
|
+
const callback = vi.fn();
|
258
|
+
|
259
|
+
performanceMonitor.addCallback(callback);
|
260
|
+
performanceMonitor.removeCallback(callback);
|
261
|
+
performanceMonitor.updateMetrics();
|
262
|
+
|
263
|
+
expect(callback).not.toHaveBeenCalled();
|
264
|
+
});
|
265
|
+
|
266
|
+
it('should handle callback errors gracefully', () => {
|
267
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
268
|
+
const errorCallback = vi.fn(() => {
|
269
|
+
throw new Error('Callback error');
|
270
|
+
});
|
271
|
+
|
272
|
+
performanceMonitor.addCallback(errorCallback);
|
273
|
+
|
274
|
+
expect(() => {
|
275
|
+
performanceMonitor.updateMetrics();
|
276
|
+
}).not.toThrow();
|
277
|
+
|
278
|
+
expect(consoleSpy).toHaveBeenCalled();
|
279
|
+
consoleSpy.mockRestore();
|
280
|
+
});
|
281
|
+
});
|
282
|
+
|
283
|
+
describe('Recommendations', () => {
|
284
|
+
it('should provide frame rate recommendations', () => {
|
285
|
+
performanceMonitor['metrics'].frameRate = 30; // Below threshold
|
286
|
+
|
287
|
+
const recommendations = performanceMonitor.getRecommendations();
|
288
|
+
|
289
|
+
expect(recommendations.length).toBeGreaterThan(0);
|
290
|
+
expect(recommendations.some(r => r.includes('DOM manipulations'))).toBe(true);
|
291
|
+
});
|
292
|
+
|
293
|
+
it('should provide memory recommendations', () => {
|
294
|
+
performanceMonitor['metrics'].memoryUsage.percentage = 90; // High memory usage
|
295
|
+
|
296
|
+
const recommendations = performanceMonitor.getRecommendations();
|
297
|
+
|
298
|
+
expect(recommendations.length).toBeGreaterThan(0);
|
299
|
+
expect(recommendations.some(r => r.includes('Memory usage'))).toBe(true);
|
300
|
+
});
|
301
|
+
|
302
|
+
it('should provide DOM recommendations', () => {
|
303
|
+
performanceMonitor['metrics'].domNodes = 6000; // Above threshold
|
304
|
+
|
305
|
+
const recommendations = performanceMonitor.getRecommendations();
|
306
|
+
|
307
|
+
expect(recommendations.length).toBeGreaterThan(0);
|
308
|
+
expect(recommendations.some(r => r.includes('DOM tree'))).toBe(true);
|
309
|
+
});
|
310
|
+
|
311
|
+
it('should provide cache recommendations', () => {
|
312
|
+
performanceMonitor['metrics'].cacheHitRate = 50; // Low hit rate
|
313
|
+
|
314
|
+
const recommendations = performanceMonitor.getRecommendations();
|
315
|
+
|
316
|
+
expect(recommendations.length).toBeGreaterThan(0);
|
317
|
+
expect(recommendations.some(r => r.includes('Cache hit rate'))).toBe(true);
|
318
|
+
});
|
319
|
+
|
320
|
+
it('should return empty recommendations for good performance', () => {
|
321
|
+
// Set all metrics to good values
|
322
|
+
performanceMonitor['metrics'] = {
|
323
|
+
frameRate: 60,
|
324
|
+
averageFrameTime: 16.67,
|
325
|
+
memoryUsage: { used: 10 * 1024 * 1024, total: 100 * 1024 * 1024, percentage: 10 },
|
326
|
+
domNodes: 100,
|
327
|
+
eventListeners: 50,
|
328
|
+
observers: 5,
|
329
|
+
cacheHitRate: 90,
|
330
|
+
operationsPerSecond: 100,
|
331
|
+
lastMeasurement: performance.now()
|
332
|
+
};
|
333
|
+
|
334
|
+
const recommendations = performanceMonitor.getRecommendations();
|
335
|
+
|
336
|
+
expect(recommendations.length).toBe(0);
|
337
|
+
});
|
338
|
+
});
|
339
|
+
|
340
|
+
describe('Edge Cases', () => {
|
341
|
+
it('should handle missing performance.memory gracefully', () => {
|
342
|
+
// Remove performance.memory
|
343
|
+
delete (performance as any).memory;
|
344
|
+
|
345
|
+
expect(() => {
|
346
|
+
performanceMonitor.updateMetrics();
|
347
|
+
}).not.toThrow();
|
348
|
+
|
349
|
+
const metrics = performanceMonitor.getMetrics();
|
350
|
+
expect(metrics.memoryUsage.used).toBe(0);
|
351
|
+
});
|
352
|
+
|
353
|
+
it('should handle empty frame times', () => {
|
354
|
+
performanceMonitor['frameTimes'] = [];
|
355
|
+
|
356
|
+
expect(() => {
|
357
|
+
performanceMonitor['updateFrameMetrics']();
|
358
|
+
}).not.toThrow();
|
359
|
+
});
|
360
|
+
|
361
|
+
it('should handle zero cache operations', () => {
|
362
|
+
performanceMonitor.updateCacheHitRate(0, 0);
|
363
|
+
|
364
|
+
const metrics = performanceMonitor.getMetrics();
|
365
|
+
expect(metrics.cacheHitRate).toBe(0);
|
366
|
+
});
|
367
|
+
|
368
|
+
it('should limit alert history', () => {
|
369
|
+
const monitor = new PerformanceMonitor({ minFrameRate: 55 });
|
370
|
+
|
371
|
+
// Generate many alerts
|
372
|
+
for (let i = 0; i < 60; i++) {
|
373
|
+
monitor['addAlert']({
|
374
|
+
type: 'warning',
|
375
|
+
metric: 'test',
|
376
|
+
value: i,
|
377
|
+
threshold: 100,
|
378
|
+
message: `Test alert ${i}`,
|
379
|
+
timestamp: performance.now() + i * 1000, // Different timestamps
|
380
|
+
suggestions: []
|
381
|
+
});
|
382
|
+
}
|
383
|
+
|
384
|
+
const alerts = monitor.getAlerts();
|
385
|
+
expect(alerts.length).toBeLessThanOrEqual(50); // Should be limited to 50
|
386
|
+
});
|
387
|
+
});
|
388
|
+
|
389
|
+
describe('Integration', () => {
|
390
|
+
it('should work with real-time monitoring', async () => {
|
391
|
+
performanceMonitor.start();
|
392
|
+
|
393
|
+
// Simulate some activity
|
394
|
+
for (let i = 0; i < 5; i++) {
|
395
|
+
performanceMonitor.recordOperation();
|
396
|
+
await new Promise(resolve => setTimeout(resolve, 20));
|
397
|
+
}
|
398
|
+
|
399
|
+
const metrics = performanceMonitor.getMetrics();
|
400
|
+
|
401
|
+
expect(metrics.operationsPerSecond).toBeGreaterThanOrEqual(0);
|
402
|
+
expect(metrics.lastMeasurement).toBeGreaterThan(0);
|
403
|
+
});
|
404
|
+
|
405
|
+
it('should provide comprehensive metrics snapshot', () => {
|
406
|
+
performanceMonitor.updateMetrics();
|
407
|
+
|
408
|
+
const metrics = performanceMonitor.getMetrics();
|
409
|
+
|
410
|
+
// Verify all expected properties exist
|
411
|
+
expect(metrics).toHaveProperty('frameRate');
|
412
|
+
expect(metrics).toHaveProperty('averageFrameTime');
|
413
|
+
expect(metrics).toHaveProperty('memoryUsage');
|
414
|
+
expect(metrics).toHaveProperty('domNodes');
|
415
|
+
expect(metrics).toHaveProperty('eventListeners');
|
416
|
+
expect(metrics).toHaveProperty('observers');
|
417
|
+
expect(metrics).toHaveProperty('cacheHitRate');
|
418
|
+
expect(metrics).toHaveProperty('operationsPerSecond');
|
419
|
+
expect(metrics).toHaveProperty('lastMeasurement');
|
420
|
+
});
|
421
|
+
});
|
422
|
+
});
|