11import type { Event } from '@sentry/node' ;
2+ import type { SerializedSession } from '@sentry/types' ;
23import { parseSemver } from '@sentry/utils' ;
34import * as childProcess from 'child_process' ;
45import * as path from 'path' ;
56
67const NODE_VERSION = parseSemver ( process . versions . node ) . major || 0 ;
78
89/** The output will contain logging so we need to find the line that parses as JSON */
9- function parseJsonLine < T > ( input : string ) : T {
10- return (
11- input
12- . split ( '\n' )
13- . map ( line => {
14- try {
15- return JSON . parse ( line ) as T ;
16- } catch {
17- return undefined ;
18- }
19- } )
20- . filter ( a => a ) as T [ ]
21- ) [ 0 ] ;
10+ function parseJsonLines < T extends unknown [ ] > ( input : string , expected : number ) : T {
11+ const results = input
12+ . split ( '\n' )
13+ . map ( line => {
14+ try {
15+ return JSON . parse ( line ) as T ;
16+ } catch {
17+ return undefined ;
18+ }
19+ } )
20+ . filter ( a => a ) as T ;
21+
22+ expect ( results . length ) . toEqual ( expected ) ;
23+
24+ return results ;
2225}
2326
2427describe ( 'should report ANR when event loop blocked' , ( ) => {
2528 test ( 'CJS' , done => {
2629 // The stack trace is different when node < 12
2730 const testFramesDetails = NODE_VERSION >= 12 ;
2831
29- expect . assertions ( testFramesDetails ? 6 : 4 ) ;
32+ expect . assertions ( testFramesDetails ? 7 : 5 ) ;
3033
3134 const testScriptPath = path . resolve ( __dirname , 'basic.js' ) ;
3235
3336 childProcess . exec ( `node ${ testScriptPath } ` , { encoding : 'utf8' } , ( _ , stdout ) => {
34- const event = parseJsonLine < Event > ( stdout ) ;
37+ const [ event ] = parseJsonLines < [ Event ] > ( stdout , 1 ) ;
3538
3639 expect ( event . exception ?. values ?. [ 0 ] . mechanism ) . toEqual ( { type : 'ANR' } ) ;
3740 expect ( event . exception ?. values ?. [ 0 ] . type ) . toEqual ( 'ApplicationNotResponding' ) ;
@@ -53,12 +56,12 @@ describe('should report ANR when event loop blocked', () => {
5356 return ;
5457 }
5558
56- expect . assertions ( 6 ) ;
59+ expect . assertions ( 7 ) ;
5760
5861 const testScriptPath = path . resolve ( __dirname , 'basic.mjs' ) ;
5962
6063 childProcess . exec ( `node ${ testScriptPath } ` , { encoding : 'utf8' } , ( _ , stdout ) => {
61- const event = parseJsonLine < Event > ( stdout ) ;
64+ const [ event ] = parseJsonLines < [ Event ] > ( stdout , 1 ) ;
6265
6366 expect ( event . exception ?. values ?. [ 0 ] . mechanism ) . toEqual ( { type : 'ANR' } ) ;
6467 expect ( event . exception ?. values ?. [ 0 ] . type ) . toEqual ( 'ApplicationNotResponding' ) ;
@@ -71,16 +74,44 @@ describe('should report ANR when event loop blocked', () => {
7174 } ) ;
7275 } ) ;
7376
77+ test ( 'With session' , done => {
78+ // The stack trace is different when node < 12
79+ const testFramesDetails = NODE_VERSION >= 12 ;
80+
81+ expect . assertions ( testFramesDetails ? 9 : 7 ) ;
82+
83+ const testScriptPath = path . resolve ( __dirname , 'basic-session.js' ) ;
84+
85+ childProcess . exec ( `node ${ testScriptPath } ` , { encoding : 'utf8' } , ( _ , stdout ) => {
86+ const [ session , event ] = parseJsonLines < [ SerializedSession , Event ] > ( stdout , 2 ) ;
87+
88+ expect ( event . exception ?. values ?. [ 0 ] . mechanism ) . toEqual ( { type : 'ANR' } ) ;
89+ expect ( event . exception ?. values ?. [ 0 ] . type ) . toEqual ( 'ApplicationNotResponding' ) ;
90+ expect ( event . exception ?. values ?. [ 0 ] . value ) . toEqual ( 'Application Not Responding for at least 200 ms' ) ;
91+ expect ( event . exception ?. values ?. [ 0 ] . stacktrace ?. frames ?. length ) . toBeGreaterThan ( 4 ) ;
92+
93+ if ( testFramesDetails ) {
94+ expect ( event . exception ?. values ?. [ 0 ] . stacktrace ?. frames ?. [ 2 ] . function ) . toEqual ( '?' ) ;
95+ expect ( event . exception ?. values ?. [ 0 ] . stacktrace ?. frames ?. [ 3 ] . function ) . toEqual ( 'longWork' ) ;
96+ }
97+
98+ expect ( session . status ) . toEqual ( 'abnormal' ) ;
99+ expect ( session . abnormal_mechanism ) . toEqual ( 'anr_foreground' ) ;
100+
101+ done ( ) ;
102+ } ) ;
103+ } ) ;
104+
74105 test ( 'from forked process' , done => {
75106 // The stack trace is different when node < 12
76107 const testFramesDetails = NODE_VERSION >= 12 ;
77108
78- expect . assertions ( testFramesDetails ? 6 : 4 ) ;
109+ expect . assertions ( testFramesDetails ? 7 : 5 ) ;
79110
80111 const testScriptPath = path . resolve ( __dirname , 'forker.js' ) ;
81112
82113 childProcess . exec ( `node ${ testScriptPath } ` , { encoding : 'utf8' } , ( _ , stdout ) => {
83- const event = parseJsonLine < Event > ( stdout ) ;
114+ const [ event ] = parseJsonLines < [ Event ] > ( stdout , 1 ) ;
84115
85116 expect ( event . exception ?. values ?. [ 0 ] . mechanism ) . toEqual ( { type : 'ANR' } ) ;
86117 expect ( event . exception ?. values ?. [ 0 ] . type ) . toEqual ( 'ApplicationNotResponding' ) ;
0 commit comments