Skip to content

Commit 9ed2112

Browse files
authored
test: Unflake slow click test (#13252)
1 parent 69d4823 commit 9ed2112

File tree

2 files changed

+154
-148
lines changed

2 files changed

+154
-148
lines changed

.github/workflows/flaky-test-detector.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,10 @@ jobs:
6868
CHANGED_TEST_PATHS: ${{ steps.changed.outputs.browser_integration_files }}
6969
TEST_RUN_COUNT: 'AUTO'
7070

71-
- name: Artifacts upload
71+
- name: Upload Playwright Traces
7272
uses: actions/upload-artifact@v4
7373
if: failure() && steps.test.outcome == 'failure'
7474
with:
7575
name: playwright-test-results
76-
path: test-results
76+
path: dev-packages/browser-integration-tests/test-results
7777
retention-days: 5

dev-packages/browser-integration-tests/suites/replay/slowClick/mutation/test.ts

+152-146
Original file line numberDiff line numberDiff line change
@@ -18,49 +18,51 @@ sentryTest('mutation after threshold results in slow click', async ({ forceFlush
1818

1919
const url = await getLocalTestUrl({ testDir: __dirname });
2020

21-
await Promise.all([waitForReplayRequest(page, 0), page.goto(url)]);
22-
await forceFlushReplay();
21+
const replayRequestPromise = waitForReplayRequest(page, 0);
22+
23+
const segmentReqWithSlowClickBreadcrumbPromise = waitForReplayRequest(page, (event, res) => {
24+
const { breadcrumbs } = getCustomRecordingEvents(res);
25+
26+
return breadcrumbs.some(breadcrumb => breadcrumb.category === 'ui.slowClickDetected');
27+
});
2328

24-
const [req1] = await Promise.all([
25-
waitForReplayRequest(page, (event, res) => {
26-
const { breadcrumbs } = getCustomRecordingEvents(res);
29+
await page.goto(url);
30+
await replayRequestPromise;
2731

28-
return breadcrumbs.some(breadcrumb => breadcrumb.category === 'ui.slowClickDetected');
29-
}),
32+
await forceFlushReplay();
33+
34+
await page.locator('#mutationButton').click();
3035

31-
page.locator('#mutationButton').click(),
32-
]);
36+
const segmentReqWithSlowClick = await segmentReqWithSlowClickBreadcrumbPromise;
3337

34-
const { breadcrumbs } = getCustomRecordingEvents(req1);
38+
const { breadcrumbs } = getCustomRecordingEvents(segmentReqWithSlowClick);
3539

3640
const slowClickBreadcrumbs = breadcrumbs.filter(breadcrumb => breadcrumb.category === 'ui.slowClickDetected');
3741

38-
expect(slowClickBreadcrumbs).toEqual([
39-
{
40-
category: 'ui.slowClickDetected',
41-
type: 'default',
42-
data: {
43-
endReason: 'mutation',
44-
clickCount: 1,
45-
node: {
46-
attributes: {
47-
id: 'mutationButton',
48-
},
49-
id: expect.any(Number),
50-
tagName: 'button',
51-
textContent: '******* ********',
42+
expect(slowClickBreadcrumbs).toContainEqual({
43+
category: 'ui.slowClickDetected',
44+
type: 'default',
45+
data: {
46+
endReason: 'mutation',
47+
clickCount: 1,
48+
node: {
49+
attributes: {
50+
id: 'mutationButton',
5251
},
53-
nodeId: expect.any(Number),
54-
timeAfterClickMs: expect.any(Number),
55-
url: 'http://sentry-test.io/index.html',
52+
id: expect.any(Number),
53+
tagName: 'button',
54+
textContent: '******* ********',
5655
},
57-
message: 'body > button#mutationButton',
58-
timestamp: expect.any(Number),
56+
nodeId: expect.any(Number),
57+
timeAfterClickMs: expect.any(Number),
58+
url: 'http://sentry-test.io/index.html',
5959
},
60-
]);
60+
message: 'body > button#mutationButton',
61+
timestamp: expect.any(Number),
62+
});
6163

6264
expect(slowClickBreadcrumbs[0]?.data?.timeAfterClickMs).toBeGreaterThan(3000);
63-
expect(slowClickBreadcrumbs[0]?.data?.timeAfterClickMs).toBeLessThan(3500);
65+
expect(slowClickBreadcrumbs[0]?.data?.timeAfterClickMs).toBeLessThan(3501);
6466
});
6567

6668
sentryTest('multiple clicks are counted', async ({ getLocalTestUrl, page }) => {
@@ -78,49 +80,50 @@ sentryTest('multiple clicks are counted', async ({ getLocalTestUrl, page }) => {
7880

7981
const url = await getLocalTestUrl({ testDir: __dirname });
8082

81-
await Promise.all([waitForReplayRequest(page, 0), page.goto(url)]);
83+
const replayRequestPromise = waitForReplayRequest(page, 0);
84+
const segmentReqWithSlowClickBreadcrumbPromise = waitForReplayRequest(page, (event, res) => {
85+
const { breadcrumbs } = getCustomRecordingEvents(res);
8286

83-
const [req1] = await Promise.all([
84-
waitForReplayRequest(page, (event, res) => {
85-
const { breadcrumbs } = getCustomRecordingEvents(res);
87+
return breadcrumbs.some(breadcrumb => breadcrumb.category === 'ui.slowClickDetected');
88+
});
8689

87-
return breadcrumbs.some(breadcrumb => breadcrumb.category === 'ui.slowClickDetected');
88-
}),
89-
page.locator('#mutationButton').click({ clickCount: 4 }),
90-
]);
90+
await page.goto(url);
91+
await replayRequestPromise;
9192

92-
const { breadcrumbs } = getCustomRecordingEvents(req1);
93+
await page.locator('#mutationButton').click({ clickCount: 4 });
94+
95+
const segmentReqWithSlowClick = await segmentReqWithSlowClickBreadcrumbPromise;
96+
97+
const { breadcrumbs } = getCustomRecordingEvents(segmentReqWithSlowClick);
9398

9499
const slowClickBreadcrumbs = breadcrumbs.filter(breadcrumb => breadcrumb.category === 'ui.slowClickDetected');
95100
const multiClickBreadcrumbs = breadcrumbs.filter(breadcrumb => breadcrumb.category === 'ui.multiClick');
96101

97-
expect(slowClickBreadcrumbs).toEqual([
98-
{
99-
category: 'ui.slowClickDetected',
100-
type: 'default',
101-
data: {
102-
endReason: 'mutation',
103-
clickCount: 4,
104-
node: {
105-
attributes: {
106-
id: 'mutationButton',
107-
},
108-
id: expect.any(Number),
109-
tagName: 'button',
110-
textContent: '******* ********',
102+
expect(slowClickBreadcrumbs).toContainEqual({
103+
category: 'ui.slowClickDetected',
104+
type: 'default',
105+
data: {
106+
endReason: expect.stringMatching(/^(mutation|timeout)$/),
107+
clickCount: 4,
108+
node: {
109+
attributes: {
110+
id: 'mutationButton',
111111
},
112-
nodeId: expect.any(Number),
113-
timeAfterClickMs: expect.any(Number),
114-
url: 'http://sentry-test.io/index.html',
112+
id: expect.any(Number),
113+
tagName: 'button',
114+
textContent: '******* ********',
115115
},
116-
message: 'body > button#mutationButton',
117-
timestamp: expect.any(Number),
116+
nodeId: expect.any(Number),
117+
timeAfterClickMs: expect.any(Number),
118+
url: 'http://sentry-test.io/index.html',
118119
},
119-
]);
120+
message: 'body > button#mutationButton',
121+
timestamp: expect.any(Number),
122+
});
120123
expect(multiClickBreadcrumbs.length).toEqual(0);
121124

122125
expect(slowClickBreadcrumbs[0]?.data?.timeAfterClickMs).toBeGreaterThan(3000);
123-
expect(slowClickBreadcrumbs[0]?.data?.timeAfterClickMs).toBeLessThan(3500);
126+
expect(slowClickBreadcrumbs[0]?.data?.timeAfterClickMs).toBeLessThan(3501);
124127
});
125128

126129
sentryTest('immediate mutation does not trigger slow click', async ({ forceFlushReplay, getLocalTestUrl, page }) => {
@@ -138,7 +141,15 @@ sentryTest('immediate mutation does not trigger slow click', async ({ forceFlush
138141

139142
const url = await getLocalTestUrl({ testDir: __dirname });
140143

141-
await Promise.all([waitForReplayRequest(page, 0), page.goto(url)]);
144+
const replayRequestPromise = waitForReplayRequest(page, 0);
145+
const segmentReqWithClickBreadcrumbPromise = waitForReplayRequest(page, (_event, res) => {
146+
const { breadcrumbs } = getCustomRecordingEvents(res);
147+
148+
return breadcrumbs.some(breadcrumb => breadcrumb.category === 'ui.click');
149+
});
150+
151+
await page.goto(url);
152+
await replayRequestPromise;
142153
await forceFlushReplay();
143154

144155
let slowClickCount = 0;
@@ -150,36 +161,29 @@ sentryTest('immediate mutation does not trigger slow click', async ({ forceFlush
150161
slowClickCount += slowClicks.length;
151162
});
152163

153-
const [req1] = await Promise.all([
154-
waitForReplayRequest(page, (_event, res) => {
155-
const { breadcrumbs } = getCustomRecordingEvents(res);
156-
157-
return breadcrumbs.some(breadcrumb => breadcrumb.category === 'ui.click');
158-
}),
159-
page.locator('#mutationButtonImmediately').click(),
160-
]);
161-
162-
const { breadcrumbs } = getCustomRecordingEvents(req1);
163-
164-
expect(breadcrumbs).toEqual([
165-
{
166-
category: 'ui.click',
167-
data: {
168-
node: {
169-
attributes: {
170-
id: 'mutationButtonImmediately',
171-
},
172-
id: expect.any(Number),
173-
tagName: 'button',
174-
textContent: '******* ******** ***********',
164+
await page.locator('#mutationButtonImmediately').click();
165+
166+
const segmentReqWithSlowClick = await segmentReqWithClickBreadcrumbPromise;
167+
168+
const { breadcrumbs } = getCustomRecordingEvents(segmentReqWithSlowClick);
169+
170+
expect(breadcrumbs).toContainEqual({
171+
category: 'ui.click',
172+
data: {
173+
node: {
174+
attributes: {
175+
id: 'mutationButtonImmediately',
175176
},
176-
nodeId: expect.any(Number),
177+
id: expect.any(Number),
178+
tagName: 'button',
179+
textContent: '******* ******** ***********',
177180
},
178-
message: 'body > button#mutationButtonImmediately',
179-
timestamp: expect.any(Number),
180-
type: 'default',
181+
nodeId: expect.any(Number),
181182
},
182-
]);
183+
message: 'body > button#mutationButtonImmediately',
184+
timestamp: expect.any(Number),
185+
type: 'default',
186+
});
183187

184188
// Ensure we wait for timeout, to make sure no slow click is created
185189
// Waiting for 3500 + 1s rounding room
@@ -204,39 +208,41 @@ sentryTest('inline click handler does not trigger slow click', async ({ forceFlu
204208

205209
const url = await getLocalTestUrl({ testDir: __dirname });
206210

207-
await Promise.all([waitForReplayRequest(page, 0), page.goto(url)]);
211+
const replayRequestPromise = waitForReplayRequest(page, 0);
212+
const segmentReqWithClickBreadcrumbPromise = waitForReplayRequest(page, (event, res) => {
213+
const { breadcrumbs } = getCustomRecordingEvents(res);
214+
215+
return breadcrumbs.some(breadcrumb => breadcrumb.category === 'ui.click');
216+
});
217+
218+
await page.goto(url);
219+
await replayRequestPromise;
220+
208221
await forceFlushReplay();
209222

210-
const [req1] = await Promise.all([
211-
waitForReplayRequest(page, (event, res) => {
212-
const { breadcrumbs } = getCustomRecordingEvents(res);
213-
214-
return breadcrumbs.some(breadcrumb => breadcrumb.category === 'ui.click');
215-
}),
216-
page.locator('#mutationButtonInline').click(),
217-
]);
218-
219-
const { breadcrumbs } = getCustomRecordingEvents(req1);
220-
221-
expect(breadcrumbs).toEqual([
222-
{
223-
category: 'ui.click',
224-
data: {
225-
node: {
226-
attributes: {
227-
id: 'mutationButtonInline',
228-
},
229-
id: expect.any(Number),
230-
tagName: 'button',
231-
textContent: '******* ******** ***********',
223+
await page.locator('#mutationButtonInline').click();
224+
225+
const segmentReqWithClick = await segmentReqWithClickBreadcrumbPromise;
226+
227+
const { breadcrumbs } = getCustomRecordingEvents(segmentReqWithClick);
228+
229+
expect(breadcrumbs).toContainEqual({
230+
category: 'ui.click',
231+
data: {
232+
node: {
233+
attributes: {
234+
id: 'mutationButtonInline',
232235
},
233-
nodeId: expect.any(Number),
236+
id: expect.any(Number),
237+
tagName: 'button',
238+
textContent: '******* ******** ***********',
234239
},
235-
message: 'body > button#mutationButtonInline',
236-
timestamp: expect.any(Number),
237-
type: 'default',
240+
nodeId: expect.any(Number),
238241
},
239-
]);
242+
message: 'body > button#mutationButtonInline',
243+
timestamp: expect.any(Number),
244+
type: 'default',
245+
});
240246
});
241247

242248
sentryTest('mouseDown events are considered', async ({ getLocalTestUrl, page }) => {
@@ -254,36 +260,36 @@ sentryTest('mouseDown events are considered', async ({ getLocalTestUrl, page })
254260

255261
const url = await getLocalTestUrl({ testDir: __dirname });
256262

257-
await Promise.all([waitForReplayRequest(page, 0), page.goto(url)]);
258-
259-
const [req1] = await Promise.all([
260-
waitForReplayRequest(page, (event, res) => {
261-
const { breadcrumbs } = getCustomRecordingEvents(res);
262-
263-
return breadcrumbs.some(breadcrumb => breadcrumb.category === 'ui.click');
264-
}),
265-
page.locator('#mouseDownButton').click(),
266-
]);
267-
268-
const { breadcrumbs } = getCustomRecordingEvents(req1);
269-
270-
expect(breadcrumbs).toEqual([
271-
{
272-
category: 'ui.click',
273-
data: {
274-
node: {
275-
attributes: {
276-
id: 'mouseDownButton',
277-
},
278-
id: expect.any(Number),
279-
tagName: 'button',
280-
textContent: '******* ******** ** ***** ****',
263+
const replayRequestPromise = waitForReplayRequest(page, 0);
264+
const segmentReqWithClickBreadcrumbPromise = waitForReplayRequest(page, (event, res) => {
265+
const { breadcrumbs } = getCustomRecordingEvents(res);
266+
267+
return breadcrumbs.some(breadcrumb => breadcrumb.category === 'ui.click');
268+
});
269+
270+
await page.goto(url);
271+
await replayRequestPromise;
272+
273+
await page.locator('#mouseDownButton').click();
274+
const segmentReqWithClick = await segmentReqWithClickBreadcrumbPromise;
275+
276+
const { breadcrumbs } = getCustomRecordingEvents(segmentReqWithClick);
277+
278+
expect(breadcrumbs).toContainEqual({
279+
category: 'ui.click',
280+
data: {
281+
node: {
282+
attributes: {
283+
id: 'mouseDownButton',
281284
},
282-
nodeId: expect.any(Number),
285+
id: expect.any(Number),
286+
tagName: 'button',
287+
textContent: '******* ******** ** ***** ****',
283288
},
284-
message: 'body > button#mouseDownButton',
285-
timestamp: expect.any(Number),
286-
type: 'default',
289+
nodeId: expect.any(Number),
287290
},
288-
]);
291+
message: 'body > button#mouseDownButton',
292+
timestamp: expect.any(Number),
293+
type: 'default',
294+
});
289295
});

0 commit comments

Comments
 (0)