11import { expect } from '@playwright/test' ;
22
33import { sentryTest } from '../../../../utils/fixtures' ;
4- import { envelopeRequestParser } from '../../../../utils/helpers' ;
4+ import { envelopeRequestParser , waitForErrorRequest } from '../../../../utils/helpers' ;
55import {
66 expectedClickBreadcrumb ,
77 expectedConsoleBreadcrumb ,
@@ -10,124 +10,133 @@ import {
1010import {
1111 getReplayEvent ,
1212 getReplayRecordingContent ,
13+ isReplayEvent ,
1314 shouldSkipReplayTest ,
1415 waitForReplayRequest ,
1516} from '../../../../utils/replayHelpers' ;
1617
17- sentryTest (
18- '[error-mode] should start recording and switch to session mode once an error is thrown' ,
19- async ( { getLocalTestPath, page } ) => {
20- if ( shouldSkipReplayTest ( ) ) {
21- sentryTest . skip ( ) ;
22- }
23-
24- let callsToSentry = 0 ;
25- let errorEventId : string | undefined ;
26- const reqPromise0 = waitForReplayRequest ( page , 0 ) ;
27- const reqPromise1 = waitForReplayRequest ( page , 1 ) ;
28- const reqPromise2 = waitForReplayRequest ( page , 2 ) ;
29-
30- await page . route ( 'https://dsn.ingest.sentry.io/**/*' , route => {
31- const event = envelopeRequestParser ( route . request ( ) ) ;
32- // error events have no type field
33- if ( event && ! event . type && event . event_id ) {
34- errorEventId = event . event_id ;
18+ // TODO: Try to run this many times to identify flakes
19+ for ( let i = 0 ; i < 100 ; i ++ ) {
20+ sentryTest (
21+ `[error-mode] should start recording and switch to session mode once an error is thrown RUN ${ i } ` ,
22+ async ( { getLocalTestPath, page } ) => {
23+ if ( shouldSkipReplayTest ( ) ) {
24+ sentryTest . skip ( ) ;
3525 }
36- callsToSentry ++ ;
3726
38- return route . fulfill ( {
39- status : 200 ,
40- contentType : 'application/json' ,
41- body : JSON . stringify ( { id : 'test-id' } ) ,
27+ let callsToSentry = 0 ;
28+ let errorEventId : string | undefined ;
29+ const reqPromise0 = waitForReplayRequest ( page , 0 ) ;
30+ const reqPromise1 = waitForReplayRequest ( page , 1 ) ;
31+ const reqPromise2 = waitForReplayRequest ( page , 2 ) ;
32+ const reqErrorPromise = waitForErrorRequest ( page ) ;
33+
34+ await page . route ( 'https://dsn.ingest.sentry.io/**/*' , route => {
35+ const event = envelopeRequestParser ( route . request ( ) ) ;
36+ // error events have no type field
37+ if ( event && ! event . type && event . event_id ) {
38+ errorEventId = event . event_id ;
39+ }
40+ // We only want to count errors & replays here
41+ if ( event && ( ! event . type || isReplayEvent ( event ) ) ) {
42+ callsToSentry ++ ;
43+ }
44+
45+ return route . fulfill ( {
46+ status : 200 ,
47+ contentType : 'application/json' ,
48+ body : JSON . stringify ( { id : 'test-id' } ) ,
49+ } ) ;
4250 } ) ;
43- } ) ;
44-
45- const url = await getLocalTestPath ( { testDir : __dirname } ) ;
46-
47- await page . goto ( url ) ;
48- await page . click ( '#go-background' ) ;
49- expect ( callsToSentry ) . toEqual ( 0 ) ;
50-
51- await page . click ( '#error' ) ;
52- const req0 = await reqPromise0 ;
53-
54- await page . click ( '#go-background' ) ;
55- const req1 = await reqPromise1 ;
56-
57- expect ( callsToSentry ) . toEqual ( 3 ) ; // 1 error, 2 replay events
58-
59- await page . click ( '#log' ) ;
60- await page . click ( '#go-background' ) ;
61- const req2 = await reqPromise2 ;
62-
63- const event0 = getReplayEvent ( req0 ) ;
64- const content0 = getReplayRecordingContent ( req0 ) ;
65-
66- const event1 = getReplayEvent ( req1 ) ;
67- const content1 = getReplayRecordingContent ( req1 ) ;
68-
69- const event2 = getReplayEvent ( req2 ) ;
70- const content2 = getReplayRecordingContent ( req2 ) ;
71-
72- expect ( event0 ) . toEqual (
73- getExpectedReplayEvent ( {
74- contexts : { replay : { error_sample_rate : 1 , session_sample_rate : 0 } } ,
75- // @ts -ignore this is fine
76- error_ids : [ errorEventId ] ,
77- replay_type : 'error' ,
78- } ) ,
79- ) ;
80-
81- // The first event should have both, full and incremental snapshots,
82- // as we recorded and kept all events in the buffer
83- expect ( content0 . fullSnapshots ) . toHaveLength ( 1 ) ;
84- // We don't know how many incremental snapshots we'll have (also browser-dependent),
85- // but we know that we have at least 5
86- expect ( content0 . incrementalSnapshots . length ) . toBeGreaterThan ( 5 ) ;
87- // We want to make sure that the event that triggered the error was recorded.
88- expect ( content0 . breadcrumbs ) . toEqual (
89- expect . arrayContaining ( [
90- {
91- ...expectedClickBreadcrumb ,
92- message : 'body > button#error' ,
93- } ,
94- ] ) ,
95- ) ;
96-
97- expect ( event1 ) . toEqual (
98- getExpectedReplayEvent ( {
99- contexts : { replay : { error_sample_rate : 1 , session_sample_rate : 0 } } ,
100- // @ts -ignore this is fine
101- replay_type : 'error' , // although we're in session mode, we still send 'error' as replay_type
102- replay_start_timestamp : undefined ,
103- segment_id : 1 ,
104- urls : [ ] ,
105- } ) ,
106- ) ;
107-
108- // Also the second snapshot should have a full snapshot, as we switched from error to session
109- // mode which triggers another checkout
110- expect ( content1 . fullSnapshots ) . toHaveLength ( 1 ) ;
111- expect ( content1 . incrementalSnapshots ) . toHaveLength ( 0 ) ;
112-
113- // The next event should just be a normal replay event as we're now in session mode and
114- // we continue recording everything
115- expect ( event2 ) . toEqual (
116- getExpectedReplayEvent ( {
117- contexts : { replay : { error_sample_rate : 1 , session_sample_rate : 0 } } ,
118- // @ts -ignore this is fine
119- replay_type : 'error' ,
120- replay_start_timestamp : undefined ,
121- segment_id : 2 ,
122- urls : [ ] ,
123- } ) ,
124- ) ;
125-
126- expect ( content2 . breadcrumbs ) . toEqual (
127- expect . arrayContaining ( [
128- { ...expectedClickBreadcrumb , message : 'body > button#log' } ,
129- { ...expectedConsoleBreadcrumb , level : 'log' , message : 'Some message' } ,
130- ] ) ,
131- ) ;
132- } ,
133- ) ;
51+
52+ const url = await getLocalTestPath ( { testDir : __dirname } ) ;
53+
54+ await page . goto ( url ) ;
55+ await page . click ( '#go-background' ) ;
56+ expect ( callsToSentry ) . toEqual ( 0 ) ;
57+
58+ await page . click ( '#error' ) ;
59+ const req0 = await reqPromise0 ;
60+
61+ void page . click ( '#go-background' ) ;
62+ const req1 = await reqPromise1 ;
63+ await reqErrorPromise ;
64+
65+ expect ( callsToSentry ) . toEqual ( 3 ) ; // 1 error, 2 replay events
66+
67+ void page . click ( '#log' ) ;
68+ void page . click ( '#go-background' ) ;
69+ const req2 = await reqPromise2 ;
70+
71+ const event0 = getReplayEvent ( req0 ) ;
72+ const content0 = getReplayRecordingContent ( req0 ) ;
73+
74+ const event1 = getReplayEvent ( req1 ) ;
75+ const content1 = getReplayRecordingContent ( req1 ) ;
76+
77+ const event2 = getReplayEvent ( req2 ) ;
78+ const content2 = getReplayRecordingContent ( req2 ) ;
79+
80+ expect ( event0 ) . toEqual (
81+ getExpectedReplayEvent ( {
82+ contexts : { replay : { error_sample_rate : 1 , session_sample_rate : 0 } } ,
83+ // @ts -ignore this is fine
84+ error_ids : [ errorEventId ] ,
85+ replay_type : 'error' ,
86+ } ) ,
87+ ) ;
88+
89+ // The first event should have both, full and incremental snapshots,
90+ // as we recorded and kept all events in the buffer
91+ expect ( content0 . fullSnapshots ) . toHaveLength ( 1 ) ;
92+ // We don't know how many incremental snapshots we'll have (also browser-dependent),
93+ // but we know that we have at least 5
94+ expect ( content0 . incrementalSnapshots . length ) . toBeGreaterThan ( 5 ) ;
95+ // We want to make sure that the event that triggered the error was recorded.
96+ expect ( content0 . breadcrumbs ) . toEqual (
97+ expect . arrayContaining ( [
98+ {
99+ ...expectedClickBreadcrumb ,
100+ message : 'body > button#error' ,
101+ } ,
102+ ] ) ,
103+ ) ;
104+
105+ expect ( event1 ) . toEqual (
106+ getExpectedReplayEvent ( {
107+ contexts : { replay : { error_sample_rate : 1 , session_sample_rate : 0 } } ,
108+ // @ts -ignore this is fine
109+ replay_type : 'error' , // although we're in session mode, we still send 'error' as replay_type
110+ replay_start_timestamp : undefined ,
111+ segment_id : 1 ,
112+ urls : [ ] ,
113+ } ) ,
114+ ) ;
115+
116+ // Also the second snapshot should have a full snapshot, as we switched from error to session
117+ // mode which triggers another checkout
118+ expect ( content1 . fullSnapshots ) . toHaveLength ( 1 ) ;
119+ expect ( content1 . incrementalSnapshots ) . toHaveLength ( 0 ) ;
120+
121+ // The next event should just be a normal replay event as we're now in session mode and
122+ // we continue recording everything
123+ expect ( event2 ) . toEqual (
124+ getExpectedReplayEvent ( {
125+ contexts : { replay : { error_sample_rate : 1 , session_sample_rate : 0 } } ,
126+ // @ts -ignore this is fine
127+ replay_type : 'error' ,
128+ replay_start_timestamp : undefined ,
129+ segment_id : 2 ,
130+ urls : [ ] ,
131+ } ) ,
132+ ) ;
133+
134+ expect ( content2 . breadcrumbs ) . toEqual (
135+ expect . arrayContaining ( [
136+ { ...expectedClickBreadcrumb , message : 'body > button#log' } ,
137+ { ...expectedConsoleBreadcrumb , level : 'log' , message : 'Some message' } ,
138+ ] ) ,
139+ ) ;
140+ } ,
141+ ) ;
142+ }
0 commit comments