11import { errorHandler , cleanStackFrameFilePath , addBugsnagMetadata , sendErrorToBugsnag } from './error-handler.js'
2+ import * as metadata from './metadata.js'
23import { ciPlatform , cloudEnvironment , isUnitTest , macAddress } from './context/local.js'
34import { mockAndCaptureOutput } from './testing/output.js'
45import * as error from './error.js'
@@ -8,16 +9,23 @@ import {settings} from '@oclif/core'
89import { beforeEach , describe , expect , test , vi } from 'vitest'
910
1011const onNotify = vi . fn ( )
12+ let lastBugsnagEvent : { addMetadata : ReturnType < typeof vi . fn > } | undefined
1113
1214vi . mock ( 'process' )
1315vi . mock ( '@bugsnag/js' , ( ) => {
1416 return {
1517 default : {
1618 notify : ( reportedError : any , args : any , callback : any ) => {
1719 onNotify ( reportedError )
20+ if ( typeof args === 'function' ) {
21+ const event = { addMetadata : vi . fn ( ) }
22+ lastBugsnagEvent = event as any
23+ args ( event )
24+ }
1825 callback ( null )
1926 } ,
2027 isStarted : ( ) => true ,
28+ addOnError : vi . fn ( ) ,
2129 } ,
2230 }
2331} )
@@ -39,6 +47,7 @@ beforeEach(() => {
3947 vi . mocked ( hashString ) . mockReturnValue ( 'hashed-macaddress' )
4048 vi . mocked ( isUnitTest ) . mockReturnValue ( true )
4149 onNotify . mockClear ( )
50+ lastBugsnagEvent = undefined
4251 vi . mocked ( settings ) . debug = false
4352 vi . mocked ( isLocalEnvironment ) . mockReturnValue ( false )
4453} )
@@ -207,4 +216,39 @@ describe('sends errors to Bugsnag', () => {
207216 expect ( res . error ) . toEqual ( toThrow )
208217 expect ( mockOutput . debug ( ) ) . toMatch ( 'Error reporting to Bugsnag: Error: Bugsnag is down' )
209218 } )
219+
220+ test ( 'attaches custom metadata with allowed slice_name when startCommand is present' , async ( ) => {
221+ await metadata . addSensitiveMetadata ( ( ) => ( {
222+ commandStartOptions : { startTime : Date . now ( ) , startCommand : 'app dev' , startArgs : [ ] } ,
223+ } ) )
224+
225+ await sendErrorToBugsnag ( new Error ( 'boom' ) , 'unexpected_error' )
226+
227+ expect ( lastBugsnagEvent ) . toBeDefined ( )
228+ expect ( lastBugsnagEvent ! . addMetadata ) . toHaveBeenCalledWith ( 'custom' , { slice_name : 'app' } )
229+ } )
230+
231+ test ( 'does not attach custom slice_name when startCommand is missing' , async ( ) => {
232+ await metadata . addSensitiveMetadata ( ( ) => ( {
233+ commandStartOptions : { startTime : Date . now ( ) , startCommand : undefined as unknown as string , startArgs : [ ] } ,
234+ } ) )
235+
236+ await sendErrorToBugsnag ( new Error ( 'boom' ) , 'unexpected_error' )
237+
238+ expect ( lastBugsnagEvent ) . toBeDefined ( )
239+ const calls = ( lastBugsnagEvent ! . addMetadata as any ) . mock . calls as any [ ]
240+ const customCall = calls . find ( ( [ section ] : [ string ] ) => section === 'custom' )
241+ expect ( customCall ) . toBeUndefined ( )
242+ } )
243+
244+ test ( 'defaults slice_name to cli when first word not allowed' , async ( ) => {
245+ await metadata . addSensitiveMetadata ( ( ) => ( {
246+ commandStartOptions : { startTime : Date . now ( ) , startCommand : 'version' , startArgs : [ ] } ,
247+ } ) )
248+
249+ await sendErrorToBugsnag ( new Error ( 'boom' ) , 'unexpected_error' )
250+
251+ expect ( lastBugsnagEvent ) . toBeDefined ( )
252+ expect ( lastBugsnagEvent ! . addMetadata ) . toHaveBeenCalledWith ( 'custom' , { slice_name : 'cli' } )
253+ } )
210254} )
0 commit comments