11import { join } from 'node:path' ;
22import type { Event } from '@sentry/core' ;
33import { afterAll , describe , expect , test } from 'vitest' ;
4+ import { NODE_VERSION } from '../../utils/index' ;
45import { cleanupChildProcesses , createRunner } from '../../utils/runner' ;
56
67function EXCEPTION ( thread_id = '0' , fn = 'longWork' ) {
@@ -34,9 +35,17 @@ function EXCEPTION(thread_id = '0', fn = 'longWork') {
3435 } ;
3536}
3637
37- const ANR_EVENT = {
38+ const ANR_EVENT = ( trace : boolean = false ) => ( {
3839 // Ensure we have context
3940 contexts : {
41+ ...( trace
42+ ? {
43+ trace : {
44+ span_id : expect . stringMatching ( / [ a - f 0 - 9 ] { 16 } / ) ,
45+ trace_id : expect . stringMatching ( / [ a - f 0 - 9 ] { 32 } / ) ,
46+ } ,
47+ }
48+ : { } ) ,
4049 device : {
4150 arch : expect . any ( String ) ,
4251 } ,
@@ -63,11 +72,11 @@ const ANR_EVENT = {
6372 } ,
6473 // and an exception that is our ANR
6574 exception : EXCEPTION ( ) ,
66- } ;
75+ } ) ;
6776
6877function ANR_EVENT_WITH_DEBUG_META ( file : string ) : Event {
6978 return {
70- ...ANR_EVENT ,
79+ ...ANR_EVENT ( ) ,
7180 debug_meta : {
7281 images : [
7382 {
@@ -103,7 +112,7 @@ describe('Thread Blocked Native', { timeout: 30_000 }, () => {
103112
104113 test ( 'Custom appRootPath' , async ( ) => {
105114 const ANR_EVENT_WITH_SPECIFIC_DEBUG_META : Event = {
106- ...ANR_EVENT ,
115+ ...ANR_EVENT ( ) ,
107116 debug_meta : {
108117 images : [
109118 {
@@ -134,7 +143,7 @@ describe('Thread Blocked Native', { timeout: 30_000 }, () => {
134143 test ( 'blocked indefinitely' , async ( ) => {
135144 await createRunner ( __dirname , 'indefinite.mjs' )
136145 . withMockSentryServer ( )
137- . expect ( { event : ANR_EVENT } )
146+ . expect ( { event : ANR_EVENT ( ) } )
138147 . start ( )
139148 . completed ( ) ;
140149 } ) ;
@@ -160,7 +169,7 @@ describe('Thread Blocked Native', { timeout: 30_000 }, () => {
160169 . withMockSentryServer ( )
161170 . expect ( {
162171 event : {
163- ...ANR_EVENT ,
172+ ...ANR_EVENT ( ) ,
164173 exception : EXCEPTION ( '0' , 'longWorkOther' ) ,
165174 } ,
166175 } )
@@ -179,7 +188,7 @@ describe('Thread Blocked Native', { timeout: 30_000 }, () => {
179188 expect ( crashedThread ) . toBeDefined ( ) ;
180189
181190 expect ( event ) . toMatchObject ( {
182- ...ANR_EVENT ,
191+ ...ANR_EVENT ( ) ,
183192 exception : {
184193 ...EXCEPTION ( crashedThread ) ,
185194 } ,
@@ -210,4 +219,52 @@ describe('Thread Blocked Native', { timeout: 30_000 }, () => {
210219 . start ( )
211220 . completed ( ) ;
212221 } ) ;
222+
223+ test ( 'Capture scope via AsyncLocalStorage' , async ctx => {
224+ if ( NODE_VERSION < 24 ) {
225+ ctx . skip ( ) ;
226+ return ;
227+ }
228+
229+ const instrument = join ( __dirname , 'instrument.mjs' ) ;
230+ await createRunner ( __dirname , 'isolated.mjs' )
231+ . withMockSentryServer ( )
232+ . withInstrument ( instrument )
233+ . expect ( {
234+ event : event => {
235+ const crashedThread = event . threads ?. values ?. find ( thread => thread . crashed ) ?. id as string ;
236+ expect ( crashedThread ) . toBeDefined ( ) ;
237+
238+ expect ( event ) . toMatchObject ( {
239+ ...ANR_EVENT ( true ) ,
240+ exception : {
241+ ...EXCEPTION ( crashedThread ) ,
242+ } ,
243+ breadcrumbs : [
244+ {
245+ timestamp : expect . any ( Number ) ,
246+ category : 'console' ,
247+ data : { arguments : [ 'Starting task 5' ] , logger : 'console' } ,
248+ level : 'log' ,
249+ message : 'Starting task 5' ,
250+ } ,
251+ ] ,
252+ user : { id : 5 } ,
253+ threads : {
254+ values : [
255+ {
256+ id : '0' ,
257+ name : 'main' ,
258+ crashed : true ,
259+ current : true ,
260+ main : true ,
261+ } ,
262+ ] ,
263+ } ,
264+ } ) ;
265+ } ,
266+ } )
267+ . start ( )
268+ . completed ( ) ;
269+ } ) ;
213270} ) ;
0 commit comments