@@ -100,4 +100,94 @@ describe('Backtrace report generation tests', () => {
100100 expect ( messageReport . stackTrace [ name ] ) . toEqual ( expect . objectContaining ( expected ) ) ;
101101 } ) ;
102102 } ) ;
103+
104+ describe ( 'error annotation cause unwrapping' , ( ) => {
105+ type ErrorWithCause = Error & { cause ?: unknown } ;
106+
107+ /**
108+ * This function is a helper to fix a potential type issue between different
109+ * version of TypeScript's built-in Error type, which may or may not include the `cause` property.
110+ */
111+ function createError ( message : string , cause ?: unknown ) : ErrorWithCause {
112+ const error : ErrorWithCause = new Error ( message ) ;
113+ error . cause = cause ;
114+ return error ;
115+ }
116+
117+ it ( 'should include cause in error annotation' , ( ) => {
118+ const causeMessage = 'cause' ;
119+ const cause = new Error ( causeMessage ) ;
120+ const error = createError ( 'top level' , cause ) ;
121+ const report = new BacktraceReport ( error ) ;
122+
123+ const annotation = report . annotations [ 'error' ] as ErrorWithCause ;
124+ const causeAnnotation = annotation . cause as ErrorWithCause ;
125+ expect ( causeAnnotation . message ) . toBe ( causeMessage ) ;
126+ expect ( causeAnnotation . name ) . toBe ( 'Error' ) ;
127+ } ) ;
128+
129+ it ( 'should unwrap nested cause chain' , ( ) => {
130+ const root = new Error ( 'root' ) ;
131+ const mid = createError ( 'mid' , root ) ;
132+ const top = createError ( 'top' , mid ) ;
133+ const report = new BacktraceReport ( top ) ;
134+
135+ const annotation = report . annotations [ 'error' ] as ErrorWithCause ;
136+ const midAnnotation = annotation . cause as ErrorWithCause ;
137+ const rootAnnotation = midAnnotation . cause as ErrorWithCause ;
138+ expect ( midAnnotation . message ) . toBe ( mid . message ) ;
139+ expect ( rootAnnotation . message ) . toBe ( root . message ) ;
140+ expect ( rootAnnotation . cause ) . toBeUndefined ( ) ;
141+ } ) ;
142+
143+ it ( 'should handle circular cause without stack overflow' , ( ) => {
144+ const topLevelError = createError ( 'error a' ) ;
145+ const cause = createError ( 'error b' ) ;
146+ topLevelError . cause = cause ;
147+ cause . cause = topLevelError ;
148+
149+ const report = new BacktraceReport ( topLevelError ) ;
150+
151+ const annotation = report . annotations [ 'error' ] as ErrorWithCause ;
152+ const causeAnnotation = annotation . cause as ErrorWithCause ;
153+ expect ( causeAnnotation . message ) . toBe ( cause . message ) ;
154+ // circular reference back to `topLevelError` — not recursed, produces circular placeholder
155+ expect ( causeAnnotation . cause ) . toEqual ( `[Circular] ${ topLevelError . message } ` ) ;
156+ } ) ;
157+
158+ it ( 'should handle self-referencing cause without stack overflow' , ( ) => {
159+ const error = createError ( 'self' ) ;
160+ error . cause = error ;
161+
162+ const report = new BacktraceReport ( error ) ;
163+
164+ const annotation = report . annotations [ 'error' ] as ErrorWithCause ;
165+ // cause points to itself — not recursed, produces circular placeholder
166+ expect ( annotation . cause ) . toEqual ( `[Circular] ${ error . message } ` ) ;
167+ } ) ;
168+
169+ it ( 'should handle non-Error cause as string value' , ( ) => {
170+ const error = createError ( 'fail' , 'timeout' ) ;
171+ const report = new BacktraceReport ( error ) ;
172+
173+ const annotation = report . annotations [ 'error' ] as ErrorWithCause ;
174+ expect ( annotation . cause ) . toEqual ( 'timeout' ) ;
175+ } ) ;
176+
177+ it ( 'should handle non-Error object cause as string value' , ( ) => {
178+ const error = createError ( 'fail' , { code : 'ENOENT' } ) ;
179+ const report = new BacktraceReport ( error ) ;
180+
181+ const annotation = report . annotations [ 'error' ] as ErrorWithCause ;
182+ expect ( annotation . cause ) . toEqual ( { code : 'ENOENT' } ) ;
183+ } ) ;
184+
185+ it ( 'should set cause to undefined when no cause exists' , ( ) => {
186+ const error = new Error ( 'no cause' ) ;
187+ const report = new BacktraceReport ( error ) ;
188+
189+ const annotation = report . annotations [ 'error' ] as ErrorWithCause ;
190+ expect ( annotation . cause ) . toBeUndefined ( ) ;
191+ } ) ;
192+ } ) ;
103193} ) ;
0 commit comments