@@ -2,6 +2,7 @@ import { beforeEach, describe, expect, test, vi } from 'vitest';
22import type { ComponentPublicInstance } from 'vue' ;
33
44import { flareVue } from '../src/flareVue' ;
5+ import type { FlareVueContext , FlareVueOptions } from '../src/types' ;
56
67const mockReport = vi . fn ( ) ;
78
@@ -239,4 +240,253 @@ describe('flareVue', () => {
239240 app . config . errorHandler ! ( new Error ( 'original' ) , null , 'setup function' ) ;
240241 } ) . toThrow ( 'report failed' ) ;
241242 } ) ;
243+
244+ test ( 'works without options' , ( ) => {
245+ const app = createMockApp ( ) ;
246+ ( flareVue as Function ) ( app ) ;
247+
248+ callHandler ( app , new Error ( 'test' ) , null , 'setup function' ) ;
249+
250+ expect ( mockReport ) . toHaveBeenCalledOnce ( ) ;
251+ } ) ;
252+
253+ test ( 'calls beforeEvaluate before building context and reporting' , ( ) => {
254+ const callOrder : string [ ] = [ ] ;
255+
256+ const beforeEvaluate = vi . fn ( ( ) => callOrder . push ( 'beforeEvaluate' ) ) ;
257+ mockReport . mockImplementation ( ( ) => callOrder . push ( 'report' ) ) ;
258+
259+ const app = createMockApp ( ) ;
260+ ( flareVue as Function ) ( app , { beforeEvaluate } satisfies FlareVueOptions ) ;
261+
262+ callHandler ( app , new Error ( 'test' ) , null , 'setup function' ) ;
263+
264+ expect ( beforeEvaluate ) . toHaveBeenCalledOnce ( ) ;
265+ expect ( callOrder ) . toEqual ( [ 'beforeEvaluate' , 'report' ] ) ;
266+ } ) ;
267+
268+ test ( 'calls beforeEvaluate with error, instance, and info' , ( ) => {
269+ const beforeEvaluate = vi . fn ( ) ;
270+
271+ const app = createMockApp ( ) ;
272+ ( flareVue as Function ) ( app , { beforeEvaluate } satisfies FlareVueOptions ) ;
273+
274+ const error = new Error ( 'test' ) ;
275+ const instance = createMockInstance ( 'MyComponent' ) ;
276+
277+ callHandler ( app , error , instance , 'setup function' ) ;
278+
279+ expect ( beforeEvaluate . mock . calls [ 0 ] [ 0 ] . error ) . toBe ( error ) ;
280+ expect ( beforeEvaluate . mock . calls [ 0 ] [ 0 ] . instance ) . toBe ( instance ) ;
281+ expect ( beforeEvaluate . mock . calls [ 0 ] [ 0 ] . info ) . toBe ( 'setup function' ) ;
282+ } ) ;
283+
284+ test ( 'passes the converted error (not raw value) to beforeEvaluate' , ( ) => {
285+ const beforeEvaluate = vi . fn ( ) ;
286+
287+ const app = createMockApp ( ) ;
288+ ( flareVue as Function ) ( app , { beforeEvaluate } satisfies FlareVueOptions ) ;
289+
290+ callHandler ( app , 'string error' , null , 'setup function' ) ;
291+
292+ expect ( beforeEvaluate . mock . calls [ 0 ] [ 0 ] . error ) . toBeInstanceOf ( Error ) ;
293+ expect ( beforeEvaluate . mock . calls [ 0 ] [ 0 ] . error . message ) . toBe ( 'string error' ) ;
294+ } ) ;
295+
296+ test ( 'calls beforeSubmit after beforeEvaluate and before reporting' , ( ) => {
297+ const callOrder : string [ ] = [ ] ;
298+
299+ const beforeEvaluate = vi . fn ( ( ) => callOrder . push ( 'beforeEvaluate' ) ) ;
300+ const beforeSubmit = vi . fn ( ( params : { context : FlareVueContext } ) => {
301+ callOrder . push ( 'beforeSubmit' ) ;
302+ return params . context ;
303+ } ) ;
304+ mockReport . mockImplementation ( ( ) => callOrder . push ( 'report' ) ) ;
305+
306+ const app = createMockApp ( ) ;
307+ ( flareVue as Function ) ( app , { beforeEvaluate, beforeSubmit } satisfies FlareVueOptions ) ;
308+
309+ callHandler ( app , new Error ( 'test' ) , null , 'setup function' ) ;
310+
311+ expect ( beforeSubmit ) . toHaveBeenCalledOnce ( ) ;
312+ expect ( callOrder ) . toEqual ( [ 'beforeEvaluate' , 'beforeSubmit' , 'report' ] ) ;
313+ } ) ;
314+
315+ test ( 'calls beforeSubmit with error, instance, info, and context' , ( ) => {
316+ const beforeSubmit = vi . fn (
317+ ( params : { error : Error ; instance : unknown ; info : string ; context : FlareVueContext } ) => params . context
318+ ) ;
319+
320+ const app = createMockApp ( ) ;
321+ ( flareVue as Function ) ( app , { beforeSubmit } satisfies FlareVueOptions ) ;
322+
323+ const error = new Error ( 'test' ) ;
324+ const instance = createMockInstance ( 'MyComponent' ) ;
325+
326+ callHandler ( app , error , instance , 'render function' ) ;
327+
328+ expect ( beforeSubmit . mock . calls [ 0 ] [ 0 ] . error ) . toBe ( error ) ;
329+ expect ( beforeSubmit . mock . calls [ 0 ] [ 0 ] . instance ) . toBe ( instance ) ;
330+ expect ( beforeSubmit . mock . calls [ 0 ] [ 0 ] . info ) . toBe ( 'render function' ) ;
331+ expect ( beforeSubmit . mock . calls [ 0 ] [ 0 ] . context . vue . componentName ) . toBe ( 'MyComponent' ) ;
332+ expect ( beforeSubmit . mock . calls [ 0 ] [ 0 ] . context . vue . componentHierarchy ) . toEqual ( [ 'MyComponent' ] ) ;
333+ } ) ;
334+
335+ test ( 'beforeSubmit can modify the context before reporting' , ( ) => {
336+ const customHierarchy = [ 'Custom' , 'Modified' ] ;
337+ const beforeSubmit = vi . fn ( ( { context } : { context : FlareVueContext } ) => ( {
338+ ...context ,
339+ vue : {
340+ ...context . vue ,
341+ componentHierarchy : customHierarchy ,
342+ } ,
343+ } ) ) ;
344+
345+ const app = createMockApp ( ) ;
346+ ( flareVue as Function ) ( app , { beforeSubmit } satisfies FlareVueOptions ) ;
347+
348+ callHandler ( app , new Error ( 'test' ) , createMockInstance ( 'MyComponent' ) , 'setup function' ) ;
349+
350+ const reportedContext = mockReport . mock . calls [ 0 ] [ 1 ] ;
351+ expect ( reportedContext . vue . componentHierarchy ) . toBe ( customHierarchy ) ;
352+ } ) ;
353+
354+ test ( 'uses original context when beforeSubmit does not return' , ( ) => {
355+ const beforeSubmit = vi . fn ( ( ) => {
356+ // user forgot to return context
357+ } ) ;
358+
359+ const app = createMockApp ( ) ;
360+ // @ts -expect-error - intentionally testing a user mistake where beforeSubmit does not return
361+ ( flareVue as Function ) ( app , { beforeSubmit } ) ;
362+
363+ callHandler ( app , new Error ( 'test' ) , createMockInstance ( 'MyComponent' ) , 'setup function' ) ;
364+
365+ expect ( beforeSubmit ) . toHaveBeenCalledOnce ( ) ;
366+ const reportedContext = mockReport . mock . calls [ 0 ] [ 1 ] ;
367+ expect ( reportedContext . vue . componentName ) . toBe ( 'MyComponent' ) ;
368+ } ) ;
369+
370+ test ( 'calls afterSubmit after reporting' , ( ) => {
371+ const callOrder : string [ ] = [ ] ;
372+
373+ mockReport . mockImplementation ( ( ) => callOrder . push ( 'report' ) ) ;
374+ const afterSubmit = vi . fn ( ( ) => {
375+ callOrder . push ( 'afterSubmit' ) ;
376+ } ) ;
377+
378+ const app = createMockApp ( ) ;
379+ ( flareVue as Function ) ( app , { afterSubmit } satisfies FlareVueOptions ) ;
380+
381+ const error = new Error ( 'test' ) ;
382+ const instance = createMockInstance ( 'MyComponent' ) ;
383+
384+ callHandler ( app , error , instance , 'render function' ) ;
385+
386+ expect ( afterSubmit ) . toHaveBeenCalledOnce ( ) ;
387+ expect ( afterSubmit . mock . calls [ 0 ] [ 0 ] . error ) . toBe ( error ) ;
388+ expect ( afterSubmit . mock . calls [ 0 ] [ 0 ] . instance ) . toBe ( instance ) ;
389+ expect ( afterSubmit . mock . calls [ 0 ] [ 0 ] . info ) . toBe ( 'render function' ) ;
390+ expect ( afterSubmit . mock . calls [ 0 ] [ 0 ] . context . vue . componentHierarchy ) . toBeInstanceOf ( Array ) ;
391+ expect ( callOrder ) . toEqual ( [ 'report' , 'afterSubmit' ] ) ;
392+ } ) ;
393+
394+ test ( 'beforeSubmit modified context is passed to afterSubmit' , ( ) => {
395+ const customHierarchy = [ 'Custom' , 'Modified' ] ;
396+ const beforeSubmit = vi . fn ( ( { context } : { context : FlareVueContext } ) => ( {
397+ ...context ,
398+ vue : {
399+ ...context . vue ,
400+ componentHierarchy : customHierarchy ,
401+ } ,
402+ } ) ) ;
403+ const afterSubmit = vi . fn ( ) ;
404+
405+ const app = createMockApp ( ) ;
406+ ( flareVue as Function ) ( app , { beforeSubmit, afterSubmit } satisfies FlareVueOptions ) ;
407+
408+ callHandler ( app , new Error ( 'test' ) , createMockInstance ( 'MyComponent' ) , 'setup function' ) ;
409+
410+ expect ( afterSubmit . mock . calls [ 0 ] [ 0 ] . context . vue . componentHierarchy ) . toBe ( customHierarchy ) ;
411+ } ) ;
412+
413+ test ( 'beforeEvaluate throwing prevents reporting and propagates' , ( ) => {
414+ const beforeEvaluate = vi . fn ( ( ) => {
415+ throw new Error ( 'beforeEvaluate error' ) ;
416+ } ) ;
417+
418+ const app = createMockApp ( ) ;
419+ ( flareVue as Function ) ( app , { beforeEvaluate } satisfies FlareVueOptions ) ;
420+
421+ expect ( ( ) => {
422+ app . config . errorHandler ! ( new Error ( 'test' ) , null , 'setup function' ) ;
423+ } ) . toThrow ( 'beforeEvaluate error' ) ;
424+
425+ expect ( beforeEvaluate ) . toHaveBeenCalledOnce ( ) ;
426+ expect ( mockReport ) . not . toHaveBeenCalled ( ) ;
427+ } ) ;
428+
429+ test ( 'beforeSubmit throwing prevents reporting and propagates' , ( ) => {
430+ const beforeSubmit = vi . fn ( ( ) => {
431+ throw new Error ( 'beforeSubmit error' ) ;
432+ } ) ;
433+
434+ const app = createMockApp ( ) ;
435+ ( flareVue as Function ) ( app , { beforeSubmit } satisfies FlareVueOptions ) ;
436+
437+ expect ( ( ) => {
438+ app . config . errorHandler ! ( new Error ( 'test' ) , null , 'setup function' ) ;
439+ } ) . toThrow ( 'beforeSubmit error' ) ;
440+
441+ expect ( beforeSubmit ) . toHaveBeenCalledOnce ( ) ;
442+ expect ( mockReport ) . not . toHaveBeenCalled ( ) ;
443+ } ) ;
444+
445+ test ( 'afterSubmit throwing propagates after reporting' , ( ) => {
446+ const afterSubmit = vi . fn ( ( ) => {
447+ throw new Error ( 'afterSubmit error' ) ;
448+ } ) ;
449+
450+ const app = createMockApp ( ) ;
451+ ( flareVue as Function ) ( app , { afterSubmit } satisfies FlareVueOptions ) ;
452+
453+ expect ( ( ) => {
454+ app . config . errorHandler ! ( new Error ( 'test' ) , null , 'setup function' ) ;
455+ } ) . toThrow ( 'afterSubmit error' ) ;
456+
457+ expect ( afterSubmit ) . toHaveBeenCalledOnce ( ) ;
458+ expect ( mockReport ) . toHaveBeenCalledOnce ( ) ;
459+ } ) ;
460+
461+ test ( 'callbacks fire for each error when called multiple times' , ( ) => {
462+ const initialHandler = vi . fn ( ) ;
463+ const beforeEvaluate = vi . fn ( ) ;
464+ const beforeSubmit = vi . fn ( ( params : { context : FlareVueContext } ) => params . context ) ;
465+ const afterSubmit = vi . fn ( ) ;
466+
467+ const app = createMockApp ( initialHandler ) ;
468+ ( flareVue as Function ) ( app , { beforeEvaluate, beforeSubmit, afterSubmit } satisfies FlareVueOptions ) ;
469+
470+ app . config . errorHandler ! ( new Error ( 'first' ) , null , 'setup function' ) ;
471+ app . config . errorHandler ! ( new Error ( 'second' ) , null , 'render function' ) ;
472+
473+ expect ( beforeEvaluate ) . toHaveBeenCalledTimes ( 2 ) ;
474+ expect ( beforeSubmit ) . toHaveBeenCalledTimes ( 2 ) ;
475+ expect ( afterSubmit ) . toHaveBeenCalledTimes ( 2 ) ;
476+ } ) ;
477+
478+ test ( 'afterSubmit is called before initial error handler' , ( ) => {
479+ const callOrder : string [ ] = [ ] ;
480+
481+ const initialHandler = vi . fn ( ( ) => callOrder . push ( 'initialHandler' ) ) ;
482+ mockReport . mockImplementation ( ( ) => callOrder . push ( 'report' ) ) ;
483+ const afterSubmit = vi . fn ( ( ) => callOrder . push ( 'afterSubmit' ) ) ;
484+
485+ const app = createMockApp ( initialHandler ) ;
486+ ( flareVue as Function ) ( app , { afterSubmit } satisfies FlareVueOptions ) ;
487+
488+ app . config . errorHandler ! ( new Error ( 'test' ) , null , 'setup function' ) ;
489+
490+ expect ( callOrder ) . toEqual ( [ 'report' , 'afterSubmit' , 'initialHandler' ] ) ;
491+ } ) ;
242492} ) ;
0 commit comments