|
1 | | -import { vi } from 'vitest'; |
| 1 | +import type { PerformanceEntry } from 'node:perf_hooks'; |
| 2 | +import { type MockInstance, afterEach, beforeEach, vi } from 'vitest'; |
2 | 3 | import { MockPerformanceObserver } from '@code-pushup/test-utils'; |
3 | 4 |
|
| 5 | +const MOCK_DATE_NOW_MS = 1_000_000; |
| 6 | +const MOCK_TIME_ORIGIN = 500_000; |
| 7 | + |
| 8 | +const dateNow = MOCK_DATE_NOW_MS; |
| 9 | +const performanceTimeOrigin = MOCK_TIME_ORIGIN; |
| 10 | + |
| 11 | +/* eslint-disable functional/no-let */ |
| 12 | +let dateNowSpy: MockInstance<[], number> | undefined; |
| 13 | +/* eslint-enable functional/no-let */ |
| 14 | + |
| 15 | +const clearPerformanceEntries = ( |
| 16 | + entryType: 'mark' | 'measure', |
| 17 | + name?: string, |
| 18 | +) => { |
| 19 | + if (name) { |
| 20 | + const index = MockPerformanceObserver.globalEntries.findIndex( |
| 21 | + entry => entry.entryType === entryType && entry.name === name, |
| 22 | + ); |
| 23 | + if (index > -1) MockPerformanceObserver.globalEntries.splice(index, 1); |
| 24 | + } else { |
| 25 | + MockPerformanceObserver.globalEntries = |
| 26 | + MockPerformanceObserver.globalEntries.filter( |
| 27 | + entry => entry.entryType !== entryType, |
| 28 | + ); |
| 29 | + } |
| 30 | +}; |
| 31 | + |
4 | 32 | vi.mock('node:perf_hooks', () => ({ |
5 | 33 | performance: { |
6 | | - getEntriesByType: vi.fn((type: string) => { |
7 | | - const entries = |
8 | | - MockPerformanceObserver.lastInstance()?.bufferedEntries || []; |
9 | | - return entries.filter(entry => entry.entryType === type); |
| 34 | + getEntries: vi.fn(() => MockPerformanceObserver.globalEntries.slice()), |
| 35 | + getEntriesByType: vi.fn((type: string) => |
| 36 | + MockPerformanceObserver.globalEntries.filter( |
| 37 | + entry => entry.entryType === type, |
| 38 | + ), |
| 39 | + ), |
| 40 | + getEntriesByName: vi.fn((name: string, type?: string) => |
| 41 | + MockPerformanceObserver.globalEntries.filter( |
| 42 | + entry => |
| 43 | + entry.name === name && |
| 44 | + (type === undefined || entry.entryType === type), |
| 45 | + ), |
| 46 | + ), |
| 47 | + mark: vi.fn((name: string) => { |
| 48 | + const entry: PerformanceEntry = { |
| 49 | + name, |
| 50 | + entryType: 'mark', |
| 51 | + startTime: performance.now(), |
| 52 | + duration: 0, |
| 53 | + } as PerformanceEntry; |
| 54 | + MockPerformanceObserver.globalEntries.push(entry); |
| 55 | + }), |
| 56 | + measure: vi.fn((name: string, startMark?: string, endMark?: string) => { |
| 57 | + const startEntry = startMark |
| 58 | + ? MockPerformanceObserver.globalEntries.find( |
| 59 | + entry => entry.name === startMark && entry.entryType === 'mark', |
| 60 | + ) |
| 61 | + : undefined; |
| 62 | + const endEntry = endMark |
| 63 | + ? MockPerformanceObserver.globalEntries.find( |
| 64 | + entry => entry.name === endMark && entry.entryType === 'mark', |
| 65 | + ) |
| 66 | + : undefined; |
| 67 | + |
| 68 | + const startTime = startEntry ? startEntry.startTime : performance.now(); |
| 69 | + const endTime = endEntry ? endEntry.startTime : performance.now(); |
| 70 | + |
| 71 | + const entry: PerformanceEntry = { |
| 72 | + name, |
| 73 | + entryType: 'measure', |
| 74 | + startTime, |
| 75 | + duration: endTime - startTime, |
| 76 | + } as PerformanceEntry; |
| 77 | + MockPerformanceObserver.globalEntries.push(entry); |
10 | 78 | }), |
11 | | - clearMarks: vi.fn(), |
12 | | - clearMeasures: vi.fn(), |
| 79 | + clearMarks: vi.fn((name?: string) => clearPerformanceEntries('mark', name)), |
| 80 | + clearMeasures: vi.fn((name?: string) => |
| 81 | + clearPerformanceEntries('measure', name), |
| 82 | + ), |
| 83 | + now: vi.fn(() => Date.now()), |
13 | 84 | }, |
14 | 85 | PerformanceObserver: MockPerformanceObserver, |
15 | 86 | })); |
| 87 | + |
| 88 | +beforeEach(() => { |
| 89 | + // Mock browser timing APIs |
| 90 | + dateNowSpy = vi.spyOn(Date, 'now').mockReturnValue(dateNow); |
| 91 | + |
| 92 | + // Mock global performance.timeOrigin for browser API |
| 93 | + vi.stubGlobal('performance', { |
| 94 | + timeOrigin: performanceTimeOrigin, |
| 95 | + now: vi.fn(() => dateNow - performanceTimeOrigin), |
| 96 | + }); |
| 97 | + |
| 98 | + // Clear performance observer entries for clean test state |
| 99 | + MockPerformanceObserver.globalEntries = []; |
| 100 | +}); |
| 101 | + |
| 102 | +afterEach(() => { |
| 103 | + vi.unstubAllGlobals(); |
| 104 | + |
| 105 | + if (dateNowSpy) { |
| 106 | + dateNowSpy.mockRestore(); |
| 107 | + dateNowSpy = undefined; |
| 108 | + } |
| 109 | +}); |
0 commit comments