Skip to content

Commit ba4637f

Browse files
committed
refactor for less flakiness??
1 parent 9038496 commit ba4637f

File tree

2 files changed

+72
-60
lines changed

2 files changed

+72
-60
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import { expect } from '@playwright/test';
2+
import type { Breadcrumb } from '@sentry/types';
23

34
import { sentryTest } from '../../../utils/fixtures';
4-
import { getCustomRecordingEvents, shouldSkipReplayTest, waitForReplayRequest } from '../../../utils/replayHelpers';
5+
import type { PerformanceSpan } from '../../../utils/replayHelpers';
6+
import {
7+
getCustomRecordingEvents,
8+
getReplayEventFromRequest,
9+
shouldSkipReplayTest,
10+
waitForReplayRequest,
11+
} from '../../../utils/replayHelpers';
512

613
const COUNT = 250;
714
const THROTTLE_LIMIT = 300;
@@ -49,86 +56,77 @@ sentryTest(
4956
await page.goto(url);
5057
await reqPromise0;
5158

52-
const reqPromise1 = waitForReplayRequest(
53-
page,
54-
(_event, res) => {
55-
const { performanceSpans } = getCustomRecordingEvents(res);
56-
57-
return performanceSpans.some(span => span.op === 'resource.script');
58-
},
59-
10_000,
60-
);
61-
const reqPromise1Breadcrumbs = waitForReplayRequest(
62-
page,
63-
(_event, res) => {
64-
const { breadcrumbs } = getCustomRecordingEvents(res);
65-
66-
return breadcrumbs.some(breadcrumb => breadcrumb.category === 'replay.throttled');
67-
},
68-
10_000,
69-
);
59+
let collectedSpans: PerformanceSpan[] = [];
60+
let collectedBreadcrumbs: Breadcrumb[] = [];
61+
62+
page.on('response', response => {
63+
// We only capture sentry stuff
64+
if (!response.url().includes('https://dsn.ingest.sentry')) {
65+
return;
66+
}
67+
68+
// If this is undefined, this is not a replay request
69+
if (!getReplayEventFromRequest(response.request())) {
70+
return;
71+
}
72+
73+
const { performanceSpans, breadcrumbs } = getCustomRecordingEvents(response);
74+
75+
collectedSpans.push(
76+
...performanceSpans.filter(span => span.op === 'resource.script' || span.op === 'resource.fetch'),
77+
);
78+
collectedBreadcrumbs.push(...breadcrumbs.filter(breadcrumb => breadcrumb.category === 'replay.throttled'));
79+
});
7080

7181
await page.click('[data-network]');
7282
await page.click('[data-fetch]');
7383

7484
await page.waitForFunction('window.__isLoaded()');
7585
await forceFlushReplay();
7686

77-
const { performanceSpans } = getCustomRecordingEvents(await reqPromise1);
78-
const { breadcrumbs } = getCustomRecordingEvents(await reqPromise1Breadcrumbs);
87+
await waitForFunction(() => collectedBreadcrumbs.length === 1, 10_000, 100);
7988

8089
// All assets have been _loaded_
8190
expect(scriptsLoaded).toBe(COUNT);
8291
expect(fetchLoaded).toBe(COUNT);
8392

8493
// But only some have been captured by replay
85-
// We check for <= THROTTLE_LIMIT, as there have been some captured before, which take up some of the throttle limit
86-
expect(performanceSpans.length).toBeLessThanOrEqual(THROTTLE_LIMIT);
87-
expect(performanceSpans.length).toBeGreaterThan(THROTTLE_LIMIT - 50);
88-
89-
expect(breadcrumbs.filter(({ category }) => category === 'replay.throttled').length).toBe(1);
94+
// We give it some wiggle room to account for flakyness
95+
expect(collectedSpans.length).toBeLessThanOrEqual(THROTTLE_LIMIT);
96+
expect(collectedSpans.length).toBeGreaterThanOrEqual(THROTTLE_LIMIT - 50);
97+
expect(collectedBreadcrumbs.length).toBe(1);
9098

9199
// Now we wait for 6s (5s + some wiggle room), and make some requests again
92-
await page.waitForTimeout(7_000);
100+
await page.waitForTimeout(6_000);
93101
await forceFlushReplay();
94102

95-
const reqPromise2 = waitForReplayRequest(
96-
page,
97-
(_event, res) => {
98-
const { performanceSpans } = getCustomRecordingEvents(res);
99-
100-
return performanceSpans.some(span => span.op === 'resource.script');
101-
},
102-
10_000,
103-
);
104-
const reqPromise2Breadcrumbs = waitForReplayRequest(
105-
page,
106-
(_event, res) => {
107-
const { breadcrumbs } = getCustomRecordingEvents(res);
108-
109-
return breadcrumbs.some(breadcrumb => breadcrumb.category === 'replay.throttled');
110-
},
111-
10_000,
112-
);
103+
// Reset collectors
104+
collectedSpans = [];
105+
collectedBreadcrumbs = [];
113106

114107
await page.click('[data-network]');
115108
await page.click('[data-fetch]');
116109

117110
await page.waitForFunction('window.__isLoaded(2)');
118111
await forceFlushReplay();
119112

120-
const { performanceSpans: performanceSpans2 } = getCustomRecordingEvents(await reqPromise2);
121-
const { breadcrumbs: breadcrumbs2 } = getCustomRecordingEvents(await reqPromise2Breadcrumbs);
113+
await waitForFunction(() => collectedBreadcrumbs.length === 1, 10_000, 100);
122114

123115
// All assets have been _loaded_
124116
expect(scriptsLoaded).toBe(COUNT * 2);
125117
expect(fetchLoaded).toBe(COUNT * 2);
126118

127119
// But only some have been captured by replay
128-
// We check for <= THROTTLE_LIMIT, as there have been some captured before, which take up some of the throttle limit
129-
expect(performanceSpans2.length).toBeLessThanOrEqual(THROTTLE_LIMIT);
130-
expect(performanceSpans2.length).toBeGreaterThan(THROTTLE_LIMIT - 50);
131-
132-
expect(breadcrumbs2.filter(({ category }) => category === 'replay.throttled').length).toBe(1);
120+
// We give it some wiggle room to account for flakyness
121+
expect(collectedSpans.length).toBeLessThanOrEqual(THROTTLE_LIMIT);
122+
expect(collectedSpans.length).toBeGreaterThanOrEqual(THROTTLE_LIMIT - 50);
123+
expect(collectedBreadcrumbs.length).toBe(1);
133124
},
134125
);
126+
127+
async function waitForFunction(cb: () => boolean, timeout = 2000, increment = 100) {
128+
while (timeout > 0 && !cb()) {
129+
await new Promise(resolve => setTimeout(resolve, increment));
130+
await waitForFunction(cb, timeout - increment, increment);
131+
}
132+
}

packages/browser-integration-tests/utils/replayHelpers.ts

+22-8
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,25 @@ export type IncrementalRecordingSnapshot = eventWithTime & {
3434

3535
export type RecordingSnapshot = FullRecordingSnapshot | IncrementalRecordingSnapshot;
3636

37+
/** Returns the replay event from the given request, or undefined if this is not a replay request. */
38+
export function getReplayEventFromRequest(req: Request): ReplayEvent | undefined {
39+
const postData = req.postData();
40+
if (!postData) {
41+
return undefined;
42+
}
43+
44+
try {
45+
const event = envelopeRequestParser(req);
46+
47+
if (!isReplayEvent(event)) {
48+
return undefined;
49+
}
50+
51+
return event;
52+
} catch {
53+
return undefined;
54+
}
55+
}
3756
/**
3857
* Waits for a replay request to be sent by the page and returns it.
3958
*
@@ -58,18 +77,13 @@ export function waitForReplayRequest(
5877
res => {
5978
const req = res.request();
6079

61-
const postData = req.postData();
62-
if (!postData) {
80+
const event = getReplayEventFromRequest(req);
81+
82+
if (!event) {
6383
return false;
6484
}
6585

6686
try {
67-
const event = envelopeRequestParser(req);
68-
69-
if (!isReplayEvent(event)) {
70-
return false;
71-
}
72-
7387
if (callback) {
7488
return callback(event, res);
7589
}

0 commit comments

Comments
 (0)