Skip to content

Commit 0322d8f

Browse files
author
John Doe
committed
refactor: increase coverage of int and unit tests
1 parent 4b9846c commit 0322d8f

File tree

7 files changed

+362
-185
lines changed

7 files changed

+362
-185
lines changed

packages/utils/src/lib/clock-epoch.unit.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ describe('epochClock', () => {
3333
it('should support performance clock by default for epochNowUs', () => {
3434
const c = epochClock();
3535
expect(c.timeOriginMs).toBe(500_000);
36-
expect(c.epochNowUs()).toBe(1_000_000_000); // timeOrigin + (Date.now() - timeOrigin) = Date.now()
36+
expect(c.epochNowUs()).toBe(500_000_000); // timeOrigin + performance.now() = timeOrigin + 0
3737
});
3838

3939
it.each([

packages/utils/src/lib/performance-observer.int.test.ts

Lines changed: 115 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,141 @@
11
import { type PerformanceEntry, performance } from 'node:perf_hooks';
2-
import { beforeEach, describe, expect, it, vi } from 'vitest';
2+
import {
3+
type MockedFunction,
4+
beforeEach,
5+
describe,
6+
expect,
7+
it,
8+
vi,
9+
} from 'vitest';
10+
import { MockPerformanceObserver } from '@code-pushup/test-utils';
311
import { MockSink } from '../../mocks/sink.mock';
412
import {
513
type PerformanceObserverOptions,
614
PerformanceObserverSink,
715
} from './performance-observer.js';
8-
import type { Sink } from './sink-source.types';
916

1017
describe('PerformanceObserverSink', () => {
18+
let encode: MockedFunction<(entry: PerformanceEntry) => string[]>;
1119
let sink: MockSink;
1220
let options: PerformanceObserverOptions<string>;
1321

22+
const awaitObserverCallback = () =>
23+
new Promise(resolve => setTimeout(resolve, 10));
24+
1425
beforeEach(() => {
15-
vi.clearAllMocks();
16-
performance.clearMeasures();
17-
performance.clearMarks();
1826
sink = new MockSink();
27+
encode = vi.fn((entry: PerformanceEntry) => [
28+
`${entry.name}:${entry.entryType}`,
29+
]);
1930

2031
options = {
2132
sink,
22-
encode: vi.fn((entry: PerformanceEntry) => [
23-
`${entry.name}:${entry.entryType}`,
24-
]),
33+
encode,
2534
};
26-
});
2735

28-
afterEach(() => {
29-
vi.restoreAllMocks();
36+
performance.clearMarks();
37+
performance.clearMeasures();
3038
});
3139

32-
it('creates instance with default options', () => {
40+
it('creates instance with required options', () => {
3341
expect(() => new PerformanceObserverSink(options)).not.toThrow();
3442
});
3543

36-
it('creates instance with custom options', () => {
37-
expect(
38-
() =>
39-
new PerformanceObserverSink({
40-
...options,
41-
buffered: true,
42-
flushThreshold: 10,
43-
}),
44-
).not.toThrow();
44+
it('internal PerformanceObserver should process observed entries', () => {
45+
const observer = new PerformanceObserverSink(options);
46+
observer.subscribe();
47+
48+
performance.mark('test-mark');
49+
performance.measure('test-measure');
50+
observer.flush();
51+
expect(encode).toHaveBeenCalledTimes(2);
52+
expect(encode).toHaveBeenNthCalledWith(
53+
1,
54+
expect.objectContaining({
55+
name: 'test-mark',
56+
entryType: 'mark',
57+
}),
58+
);
59+
expect(encode).toHaveBeenNthCalledWith(
60+
2,
61+
expect.objectContaining({
62+
name: 'test-measure',
63+
entryType: 'measure',
64+
}),
65+
);
66+
});
67+
68+
it('internal PerformanceObserver calls flush if flushThreshold exceeded', async () => {
69+
const observer = new PerformanceObserverSink({
70+
...options,
71+
flushThreshold: 3,
72+
});
73+
observer.subscribe();
74+
75+
performance.mark('test-mark1');
76+
performance.mark('test-mark2');
77+
performance.mark('test-mark3');
78+
79+
await awaitObserverCallback();
80+
81+
expect(encode).toHaveBeenCalledTimes(3);
82+
});
83+
84+
it('flush flushes observed entries when subscribed', () => {
85+
const observer = new PerformanceObserverSink(options);
86+
observer.subscribe();
87+
88+
performance.mark('test-mark1');
89+
performance.mark('test-mark2');
90+
expect(sink.getWrittenItems()).toStrictEqual([]);
91+
92+
observer.flush();
93+
expect(sink.getWrittenItems()).toStrictEqual([
94+
'test-mark1:mark',
95+
'test-mark2:mark',
96+
]);
97+
});
98+
99+
it('flush calls encode for each entry', () => {
100+
const observer = new PerformanceObserverSink(options);
101+
observer.subscribe();
102+
103+
performance.mark('test-mark1');
104+
performance.mark('test-mark2');
105+
106+
observer.flush();
107+
108+
expect(encode).toHaveBeenCalledWith(
109+
expect.objectContaining({
110+
name: 'test-mark1',
111+
entryType: 'mark',
112+
}),
113+
);
114+
expect(encode).toHaveBeenCalledWith(
115+
expect.objectContaining({
116+
name: 'test-mark2',
117+
entryType: 'mark',
118+
}),
119+
);
120+
});
121+
122+
it('unsubscribe stops observing performance entries', async () => {
123+
const observer = new PerformanceObserverSink({
124+
...options,
125+
flushThreshold: 1,
126+
});
127+
128+
observer.subscribe();
129+
performance.mark('subscribed-mark1');
130+
performance.mark('subscribed-mark2');
131+
await awaitObserverCallback();
132+
expect(encode).toHaveBeenCalledTimes(2);
133+
134+
observer.unsubscribe();
135+
performance.mark('unsubscribed-mark1');
136+
performance.mark('unsubscribed-mark2');
137+
await awaitObserverCallback();
138+
expect(encode).toHaveBeenCalledTimes(2);
45139
});
46140

47141
it('should observe performance entries and write them to the sink on flush', () => {

packages/utils/src/lib/performance-observer.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export class PerformanceObserverSink<T>
4949
const entries = this.#getEntries(list);
5050
this.#observedCount += entries.length;
5151
if (this.#observedCount >= this.#flushThreshold) {
52-
this.flush();
52+
this.flush(entries);
5353
}
5454
});
5555

@@ -59,18 +59,22 @@ export class PerformanceObserverSink<T>
5959
});
6060
}
6161

62-
flush(): void {
62+
flush(entriesToProcess?: PerformanceEntry[]): void {
6363
if (!this.#observer) {
6464
return;
6565
}
6666

67-
const entries = this.#getEntries(performance);
67+
const entries = entriesToProcess || this.#getEntries(performance);
6868
entries.forEach(entry => {
6969
const encoded = this.encode(entry);
7070
encoded.forEach(item => {
7171
this.#sink.write(item);
7272
});
7373
});
74+
75+
// In real PerformanceObserver, entries remain in the global buffer
76+
// They are only cleared when explicitly requested via performance.clearMarks/clearMeasures
77+
7478
this.#observedCount = 0;
7579
}
7680

0 commit comments

Comments
 (0)