@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,328 @@
|
|
1
|
+
/**
|
2
|
+
* BrowserPolyfills Test Suite
|
3
|
+
* Tests for cross-browser compatibility polyfills
|
4
|
+
*/
|
5
|
+
|
6
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
7
|
+
import { BrowserPolyfills } from '../BrowserPolyfills';
|
8
|
+
|
9
|
+
describe('BrowserPolyfills', () => {
|
10
|
+
let polyfills: BrowserPolyfills;
|
11
|
+
let originalResizeObserver: any;
|
12
|
+
let originalIntersectionObserver: any;
|
13
|
+
let originalPerformance: any;
|
14
|
+
let originalCSS: any;
|
15
|
+
|
16
|
+
beforeEach(() => {
|
17
|
+
// Store original implementations
|
18
|
+
originalResizeObserver = (global as any).ResizeObserver;
|
19
|
+
originalIntersectionObserver = (global as any).IntersectionObserver;
|
20
|
+
originalPerformance = global.performance;
|
21
|
+
originalCSS = (global as any).CSS;
|
22
|
+
|
23
|
+
polyfills = BrowserPolyfills.getInstance();
|
24
|
+
});
|
25
|
+
|
26
|
+
afterEach(() => {
|
27
|
+
// Restore original implementations
|
28
|
+
(global as any).ResizeObserver = originalResizeObserver;
|
29
|
+
(global as any).IntersectionObserver = originalIntersectionObserver;
|
30
|
+
global.performance = originalPerformance;
|
31
|
+
(global as any).CSS = originalCSS;
|
32
|
+
});
|
33
|
+
|
34
|
+
describe('Singleton Pattern', () => {
|
35
|
+
it('should return the same instance', () => {
|
36
|
+
const instance1 = BrowserPolyfills.getInstance();
|
37
|
+
const instance2 = BrowserPolyfills.getInstance();
|
38
|
+
|
39
|
+
expect(instance1).toBe(instance2);
|
40
|
+
});
|
41
|
+
});
|
42
|
+
|
43
|
+
describe('Browser Support Detection', () => {
|
44
|
+
it('should detect supported features', () => {
|
45
|
+
const support = polyfills.checkBrowserSupport();
|
46
|
+
|
47
|
+
expect(support).toHaveProperty('supported');
|
48
|
+
expect(support).toHaveProperty('missing');
|
49
|
+
expect(support).toHaveProperty('warnings');
|
50
|
+
expect(Array.isArray(support.supported)).toBe(true);
|
51
|
+
expect(Array.isArray(support.missing)).toBe(true);
|
52
|
+
expect(Array.isArray(support.warnings)).toBe(true);
|
53
|
+
});
|
54
|
+
|
55
|
+
it('should detect missing ResizeObserver', () => {
|
56
|
+
delete (global as any).ResizeObserver;
|
57
|
+
|
58
|
+
const support = polyfills.checkBrowserSupport();
|
59
|
+
|
60
|
+
expect(support.missing).toContain('ResizeObserver');
|
61
|
+
});
|
62
|
+
|
63
|
+
it('should detect missing IntersectionObserver', () => {
|
64
|
+
delete (global as any).IntersectionObserver;
|
65
|
+
|
66
|
+
const support = polyfills.checkBrowserSupport();
|
67
|
+
|
68
|
+
expect(support.missing).toContain('IntersectionObserver');
|
69
|
+
});
|
70
|
+
|
71
|
+
it('should detect browser-specific warnings', () => {
|
72
|
+
// Mock IE user agent
|
73
|
+
Object.defineProperty(navigator, 'userAgent', {
|
74
|
+
value: 'Mozilla/5.0 (Windows NT 10.0; Trident/7.0; rv:11.0) like Gecko',
|
75
|
+
configurable: true
|
76
|
+
});
|
77
|
+
|
78
|
+
const support = polyfills.checkBrowserSupport();
|
79
|
+
|
80
|
+
expect(support.warnings.some(w => w.includes('Internet Explorer'))).toBe(true);
|
81
|
+
});
|
82
|
+
});
|
83
|
+
|
84
|
+
describe('ResizeObserver Polyfill', () => {
|
85
|
+
beforeEach(() => {
|
86
|
+
delete (global as any).ResizeObserver;
|
87
|
+
});
|
88
|
+
|
89
|
+
it('should load ResizeObserver polyfill when missing', async () => {
|
90
|
+
await polyfills.loadPolyfills({ resizeObserver: true });
|
91
|
+
|
92
|
+
expect(typeof (global as any).ResizeObserver).toBe('function');
|
93
|
+
expect(polyfills.getLoadedPolyfills()).toContain('ResizeObserver');
|
94
|
+
});
|
95
|
+
|
96
|
+
it('should create functional ResizeObserver polyfill', async () => {
|
97
|
+
await polyfills.loadPolyfills({ resizeObserver: true });
|
98
|
+
|
99
|
+
const callback = vi.fn();
|
100
|
+
const observer = new (global as any).ResizeObserver(callback);
|
101
|
+
|
102
|
+
expect(observer).toBeDefined();
|
103
|
+
expect(typeof observer.observe).toBe('function');
|
104
|
+
expect(typeof observer.unobserve).toBe('function');
|
105
|
+
expect(typeof observer.disconnect).toBe('function');
|
106
|
+
});
|
107
|
+
|
108
|
+
it('should not load polyfill when ResizeObserver exists', async () => {
|
109
|
+
(global as any).ResizeObserver = vi.fn();
|
110
|
+
|
111
|
+
await polyfills.loadPolyfills({ resizeObserver: true });
|
112
|
+
|
113
|
+
expect(polyfills.getLoadedPolyfills()).not.toContain('ResizeObserver');
|
114
|
+
});
|
115
|
+
});
|
116
|
+
|
117
|
+
describe('IntersectionObserver Polyfill', () => {
|
118
|
+
beforeEach(() => {
|
119
|
+
delete (global as any).IntersectionObserver;
|
120
|
+
});
|
121
|
+
|
122
|
+
it('should load IntersectionObserver polyfill when missing', async () => {
|
123
|
+
await polyfills.loadPolyfills({ intersectionObserver: true });
|
124
|
+
|
125
|
+
expect(typeof (global as any).IntersectionObserver).toBe('function');
|
126
|
+
expect(polyfills.getLoadedPolyfills()).toContain('IntersectionObserver');
|
127
|
+
});
|
128
|
+
|
129
|
+
it('should create functional IntersectionObserver polyfill', async () => {
|
130
|
+
await polyfills.loadPolyfills({ intersectionObserver: true });
|
131
|
+
|
132
|
+
const callback = vi.fn();
|
133
|
+
const observer = new (global as any).IntersectionObserver(callback);
|
134
|
+
|
135
|
+
expect(observer).toBeDefined();
|
136
|
+
expect(typeof observer.observe).toBe('function');
|
137
|
+
expect(typeof observer.unobserve).toBe('function');
|
138
|
+
expect(typeof observer.disconnect).toBe('function');
|
139
|
+
});
|
140
|
+
});
|
141
|
+
|
142
|
+
describe('Performance API Polyfill', () => {
|
143
|
+
it('should load performance polyfill when missing', async () => {
|
144
|
+
delete (global as any).performance;
|
145
|
+
|
146
|
+
await polyfills.loadPolyfills({ performance: true });
|
147
|
+
|
148
|
+
expect(typeof performance).toBe('object');
|
149
|
+
expect(typeof performance.now).toBe('function');
|
150
|
+
expect(polyfills.getLoadedPolyfills()).toContain('Performance');
|
151
|
+
});
|
152
|
+
|
153
|
+
it('should provide working performance.now', async () => {
|
154
|
+
delete (global as any).performance;
|
155
|
+
|
156
|
+
await polyfills.loadPolyfills({ performance: true });
|
157
|
+
|
158
|
+
const time1 = performance.now();
|
159
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
160
|
+
const time2 = performance.now();
|
161
|
+
|
162
|
+
expect(time2).toBeGreaterThan(time1);
|
163
|
+
});
|
164
|
+
});
|
165
|
+
|
166
|
+
describe('RequestAnimationFrame Polyfill', () => {
|
167
|
+
it('should load RAF polyfill when missing', async () => {
|
168
|
+
delete (global as any).requestAnimationFrame;
|
169
|
+
delete (global as any).cancelAnimationFrame;
|
170
|
+
|
171
|
+
await polyfills.loadPolyfills({ requestAnimationFrame: true });
|
172
|
+
|
173
|
+
expect(typeof requestAnimationFrame).toBe('function');
|
174
|
+
expect(typeof cancelAnimationFrame).toBe('function');
|
175
|
+
expect(polyfills.getLoadedPolyfills()).toContain('RequestAnimationFrame');
|
176
|
+
});
|
177
|
+
|
178
|
+
it('should provide working requestAnimationFrame', async () => {
|
179
|
+
delete (global as any).requestAnimationFrame;
|
180
|
+
|
181
|
+
await polyfills.loadPolyfills({ requestAnimationFrame: true });
|
182
|
+
|
183
|
+
const callback = vi.fn();
|
184
|
+
const id = requestAnimationFrame(callback);
|
185
|
+
|
186
|
+
expect(typeof id).toBe('number');
|
187
|
+
|
188
|
+
// Wait for callback
|
189
|
+
await new Promise(resolve => setTimeout(resolve, 20));
|
190
|
+
|
191
|
+
expect(callback).toHaveBeenCalled();
|
192
|
+
});
|
193
|
+
});
|
194
|
+
|
195
|
+
describe('CSS.supports Polyfill', () => {
|
196
|
+
it('should load CSS.supports polyfill when missing', async () => {
|
197
|
+
delete (global as any).CSS;
|
198
|
+
|
199
|
+
await polyfills.loadPolyfills({ cssSupports: true });
|
200
|
+
|
201
|
+
expect(typeof CSS).toBe('object');
|
202
|
+
expect(typeof CSS.supports).toBe('function');
|
203
|
+
expect(polyfills.getLoadedPolyfills()).toContain('CSS.supports');
|
204
|
+
});
|
205
|
+
|
206
|
+
it('should provide working CSS.supports', async () => {
|
207
|
+
delete (global as any).CSS;
|
208
|
+
|
209
|
+
await polyfills.loadPolyfills({ cssSupports: true });
|
210
|
+
|
211
|
+
// Test basic property support
|
212
|
+
const supportsColor = CSS.supports('color', 'red');
|
213
|
+
const supportsInvalid = CSS.supports('invalid-property', 'invalid-value');
|
214
|
+
|
215
|
+
expect(typeof supportsColor).toBe('boolean');
|
216
|
+
expect(typeof supportsInvalid).toBe('boolean');
|
217
|
+
});
|
218
|
+
});
|
219
|
+
|
220
|
+
describe('Element.classList Polyfill', () => {
|
221
|
+
it('should load classList polyfill when missing', async () => {
|
222
|
+
// Mock missing classList
|
223
|
+
const originalDescriptor = Object.getOwnPropertyDescriptor(Element.prototype, 'classList');
|
224
|
+
delete (Element.prototype as any).classList;
|
225
|
+
|
226
|
+
await polyfills.loadPolyfills({ classList: true });
|
227
|
+
|
228
|
+
const element = document.createElement('div');
|
229
|
+
expect(element.classList).toBeDefined();
|
230
|
+
expect(typeof element.classList.add).toBe('function');
|
231
|
+
expect(polyfills.getLoadedPolyfills()).toContain('Element.classList');
|
232
|
+
|
233
|
+
// Restore original
|
234
|
+
if (originalDescriptor) {
|
235
|
+
Object.defineProperty(Element.prototype, 'classList', originalDescriptor);
|
236
|
+
}
|
237
|
+
});
|
238
|
+
});
|
239
|
+
|
240
|
+
describe('Element.closest Polyfill', () => {
|
241
|
+
it('should load closest polyfill when missing', async () => {
|
242
|
+
const originalClosest = Element.prototype.closest;
|
243
|
+
delete (Element.prototype as any).closest;
|
244
|
+
|
245
|
+
await polyfills.loadPolyfills({ closest: true });
|
246
|
+
|
247
|
+
const element = document.createElement('div');
|
248
|
+
expect(typeof element.closest).toBe('function');
|
249
|
+
expect(polyfills.getLoadedPolyfills()).toContain('Element.closest');
|
250
|
+
|
251
|
+
// Restore original
|
252
|
+
Element.prototype.closest = originalClosest;
|
253
|
+
});
|
254
|
+
});
|
255
|
+
|
256
|
+
describe('Auto Initialization', () => {
|
257
|
+
it('should auto-initialize based on browser support', async () => {
|
258
|
+
// Remove some features to trigger polyfills
|
259
|
+
delete (global as any).ResizeObserver;
|
260
|
+
delete (global as any).IntersectionObserver;
|
261
|
+
|
262
|
+
await BrowserPolyfills.autoInit();
|
263
|
+
|
264
|
+
expect(typeof (global as any).ResizeObserver).toBe('function');
|
265
|
+
expect(typeof (global as any).IntersectionObserver).toBe('function');
|
266
|
+
});
|
267
|
+
|
268
|
+
it('should not load unnecessary polyfills', async () => {
|
269
|
+
// Ensure features exist
|
270
|
+
(global as any).ResizeObserver = vi.fn();
|
271
|
+
(global as any).IntersectionObserver = vi.fn();
|
272
|
+
|
273
|
+
const polyfillsBefore = polyfills.getLoadedPolyfills().length;
|
274
|
+
|
275
|
+
await BrowserPolyfills.autoInit();
|
276
|
+
|
277
|
+
const polyfillsAfter = polyfills.getLoadedPolyfills().length;
|
278
|
+
|
279
|
+
// Should not have loaded additional polyfills
|
280
|
+
expect(polyfillsAfter).toBe(polyfillsBefore);
|
281
|
+
});
|
282
|
+
});
|
283
|
+
|
284
|
+
describe('Configuration', () => {
|
285
|
+
it('should respect polyfill configuration', async () => {
|
286
|
+
delete (global as any).ResizeObserver;
|
287
|
+
delete (global as any).IntersectionObserver;
|
288
|
+
|
289
|
+
await polyfills.loadPolyfills({
|
290
|
+
resizeObserver: true,
|
291
|
+
intersectionObserver: false
|
292
|
+
});
|
293
|
+
|
294
|
+
expect(typeof (global as any).ResizeObserver).toBe('function');
|
295
|
+
expect(typeof (global as any).IntersectionObserver).toBe('undefined');
|
296
|
+
});
|
297
|
+
|
298
|
+
it('should use default configuration when none provided', async () => {
|
299
|
+
delete (global as any).ResizeObserver;
|
300
|
+
|
301
|
+
await polyfills.loadPolyfills();
|
302
|
+
|
303
|
+
expect(typeof (global as any).ResizeObserver).toBe('function');
|
304
|
+
});
|
305
|
+
});
|
306
|
+
|
307
|
+
describe('Error Handling', () => {
|
308
|
+
it('should handle polyfill loading errors gracefully', async () => {
|
309
|
+
// This test ensures no errors are thrown during polyfill loading
|
310
|
+
expect(async () => {
|
311
|
+
await polyfills.loadPolyfills();
|
312
|
+
}).not.toThrow();
|
313
|
+
});
|
314
|
+
|
315
|
+
it('should handle missing DOM gracefully', async () => {
|
316
|
+
// Mock missing document
|
317
|
+
const originalDocument = global.document;
|
318
|
+
delete (global as any).document;
|
319
|
+
|
320
|
+
expect(async () => {
|
321
|
+
await polyfills.loadPolyfills();
|
322
|
+
}).not.toThrow();
|
323
|
+
|
324
|
+
// Restore document
|
325
|
+
global.document = originalDocument;
|
326
|
+
});
|
327
|
+
});
|
328
|
+
});
|
@@ -0,0 +1,115 @@
|
|
1
|
+
/**
|
2
|
+
* Test setup file for Vitest
|
3
|
+
*/
|
4
|
+
|
5
|
+
import { vi } from 'vitest';
|
6
|
+
|
7
|
+
// Mock ResizeObserver
|
8
|
+
global.ResizeObserver = vi.fn().mockImplementation(() => ({
|
9
|
+
observe: vi.fn(),
|
10
|
+
unobserve: vi.fn(),
|
11
|
+
disconnect: vi.fn()
|
12
|
+
}));
|
13
|
+
|
14
|
+
// Mock IntersectionObserver
|
15
|
+
global.IntersectionObserver = vi.fn().mockImplementation(() => ({
|
16
|
+
observe: vi.fn(),
|
17
|
+
unobserve: vi.fn(),
|
18
|
+
disconnect: vi.fn(),
|
19
|
+
root: null,
|
20
|
+
rootMargin: '',
|
21
|
+
thresholds: []
|
22
|
+
}));
|
23
|
+
|
24
|
+
// Mock requestAnimationFrame
|
25
|
+
global.requestAnimationFrame = vi.fn().mockImplementation((cb) => {
|
26
|
+
return setTimeout(cb, 16);
|
27
|
+
});
|
28
|
+
|
29
|
+
global.cancelAnimationFrame = vi.fn().mockImplementation((id) => {
|
30
|
+
clearTimeout(id);
|
31
|
+
});
|
32
|
+
|
33
|
+
// Mock CSS.supports
|
34
|
+
Object.defineProperty(global, 'CSS', {
|
35
|
+
value: {
|
36
|
+
supports: vi.fn().mockReturnValue(true)
|
37
|
+
},
|
38
|
+
writable: true
|
39
|
+
});
|
40
|
+
|
41
|
+
// Mock window.getComputedStyle
|
42
|
+
global.getComputedStyle = vi.fn().mockImplementation(() => ({
|
43
|
+
getPropertyValue: vi.fn().mockReturnValue(''),
|
44
|
+
setProperty: vi.fn(),
|
45
|
+
removeProperty: vi.fn()
|
46
|
+
}));
|
47
|
+
|
48
|
+
// Mock Element.getBoundingClientRect
|
49
|
+
Element.prototype.getBoundingClientRect = vi.fn().mockImplementation(() => ({
|
50
|
+
width: 100,
|
51
|
+
height: 100,
|
52
|
+
top: 0,
|
53
|
+
left: 0,
|
54
|
+
bottom: 100,
|
55
|
+
right: 100,
|
56
|
+
x: 0,
|
57
|
+
y: 0,
|
58
|
+
toJSON: vi.fn()
|
59
|
+
}));
|
60
|
+
|
61
|
+
// Mock window.matchMedia
|
62
|
+
Object.defineProperty(window, 'matchMedia', {
|
63
|
+
writable: true,
|
64
|
+
value: vi.fn().mockImplementation((query: string) => ({
|
65
|
+
matches: false,
|
66
|
+
media: query,
|
67
|
+
onchange: null,
|
68
|
+
addListener: vi.fn(), // deprecated
|
69
|
+
removeListener: vi.fn(), // deprecated
|
70
|
+
addEventListener: vi.fn(),
|
71
|
+
removeEventListener: vi.fn(),
|
72
|
+
dispatchEvent: vi.fn()
|
73
|
+
}))
|
74
|
+
});
|
75
|
+
|
76
|
+
// Mock performance.memory for memory monitoring tests
|
77
|
+
Object.defineProperty(performance, 'memory', {
|
78
|
+
writable: true,
|
79
|
+
value: {
|
80
|
+
usedJSHeapSize: 10000000,
|
81
|
+
totalJSHeapSize: 20000000,
|
82
|
+
jsHeapSizeLimit: 100000000
|
83
|
+
}
|
84
|
+
});
|
85
|
+
|
86
|
+
// Mock performance timing methods
|
87
|
+
Object.defineProperty(performance, 'mark', {
|
88
|
+
writable: true,
|
89
|
+
value: vi.fn()
|
90
|
+
});
|
91
|
+
|
92
|
+
Object.defineProperty(performance, 'measure', {
|
93
|
+
writable: true,
|
94
|
+
value: vi.fn()
|
95
|
+
});
|
96
|
+
|
97
|
+
Object.defineProperty(performance, 'getEntriesByType', {
|
98
|
+
writable: true,
|
99
|
+
value: vi.fn().mockReturnValue([])
|
100
|
+
});
|
101
|
+
|
102
|
+
Object.defineProperty(performance, 'getEntriesByName', {
|
103
|
+
writable: true,
|
104
|
+
value: vi.fn().mockReturnValue([])
|
105
|
+
});
|
106
|
+
|
107
|
+
// Mock console methods in test environment
|
108
|
+
if (process.env['NODE_ENV'] === 'test') {
|
109
|
+
global.console = {
|
110
|
+
...console,
|
111
|
+
warn: vi.fn(),
|
112
|
+
error: vi.fn(),
|
113
|
+
log: vi.fn()
|
114
|
+
};
|
115
|
+
}
|