@@ -4,6 +4,7 @@ import { TestBed } from '@angular/core/testing'
44import {
55 ENVIRONMENT_INITIALIZER ,
66 EnvironmentInjector ,
7+ InjectionToken ,
78 PLATFORM_ID ,
89 createEnvironmentInjector ,
910 isDevMode ,
@@ -53,55 +54,57 @@ describe('withDevtools feature', () => {
5354
5455 afterEach ( ( ) => {
5556 vi . restoreAllMocks ( )
57+ vi . useRealTimers ( )
58+ TestBed . resetTestingModule ( )
5659 } )
5760
5861 test . each ( [
5962 {
60- description : 'should load developer tools in development mode' ,
63+ description : 'should load devtools in development mode' ,
6164 isDevMode : true ,
6265 expectedCalled : true ,
6366 } ,
6467 {
65- description : 'should not load developer tools in production mode' ,
68+ description : 'should not load devtools in production mode' ,
6669 isDevMode : false ,
6770 expectedCalled : false ,
6871 } ,
6972 {
70- description : `should load developer tools in development mode when 'loadDevtools' is set to 'auto'` ,
73+ description : `should load devtools in development mode when 'loadDevtools' is set to 'auto'` ,
7174 isDevMode : true ,
7275 loadDevtools : 'auto' ,
7376 expectedCalled : true ,
7477 } ,
7578 {
76- description : `should not load developer tools in production mode when 'loadDevtools' is set to 'auto'` ,
79+ description : `should not load devtools in production mode when 'loadDevtools' is set to 'auto'` ,
7780 isDevMode : false ,
7881 loadDevtools : 'auto' ,
7982 expectedCalled : false ,
8083 } ,
8184 {
8285 description :
83- "should load developer tools in development mode when 'loadDevtools' is set to true" ,
86+ "should load devtools in development mode when 'loadDevtools' is set to true" ,
8487 isDevMode : true ,
8588 loadDevtools : true ,
8689 expectedCalled : true ,
8790 } ,
8891 {
8992 description :
90- "should load developer tools in production mode when 'loadDevtools' is set to true" ,
93+ "should load devtools in production mode when 'loadDevtools' is set to true" ,
9194 isDevMode : false ,
9295 loadDevtools : true ,
9396 expectedCalled : true ,
9497 } ,
9598 {
9699 description :
97- "should not load developer tools in development mode when 'loadDevtools' is set to false" ,
100+ "should not load devtools in development mode when 'loadDevtools' is set to false" ,
98101 isDevMode : true ,
99102 loadDevtools : false ,
100103 expectedCalled : false ,
101104 } ,
102105 {
103106 description :
104- "should not load developer tools in production mode when 'loadDevtools' is set to false" ,
107+ "should not load devtools in production mode when 'loadDevtools' is set to false" ,
105108 isDevMode : false ,
106109 loadDevtools : false ,
107110 expectedCalled : false ,
@@ -139,8 +142,10 @@ describe('withDevtools feature', () => {
139142
140143 if ( expectedCalled ) {
141144 expect ( mockTanstackQueryDevtools ) . toHaveBeenCalled ( )
145+ expect ( mockDevtoolsInstance . mount ) . toHaveBeenCalled ( )
142146 } else {
143147 expect ( mockTanstackQueryDevtools ) . not . toHaveBeenCalled ( )
148+ expect ( mockDevtoolsInstance . mount ) . not . toHaveBeenCalled ( )
144149 }
145150 } ,
146151 )
@@ -162,6 +167,7 @@ describe('withDevtools feature', () => {
162167 // Destroys injector
163168 TestBed . resetTestingModule ( )
164169 await vi . advanceTimersByTimeAsync ( 0 )
170+ await vi . dynamicImportSettled ( )
165171
166172 expect ( mockTanstackQueryDevtools ) . not . toHaveBeenCalled ( )
167173 } )
@@ -247,16 +253,21 @@ describe('withDevtools feature', () => {
247253
248254 expect ( mockDevtoolsInstance . setErrorTypes ) . toHaveBeenCalledTimes ( 0 )
249255
250- errorTypes . set ( [
256+ const newErrorTypes = [
251257 {
252258 name : '' ,
253259 initializer : ( ) => new Error ( ) ,
254260 } ,
255- ] )
261+ ]
262+
263+ errorTypes . set ( newErrorTypes )
256264
257265 TestBed . tick ( )
258266
259267 expect ( mockDevtoolsInstance . setErrorTypes ) . toHaveBeenCalledTimes ( 1 )
268+ expect ( mockDevtoolsInstance . setErrorTypes ) . toHaveBeenCalledWith (
269+ newErrorTypes ,
270+ )
260271 } )
261272
262273 it ( 'should update client' , async ( ) => {
@@ -282,11 +293,13 @@ describe('withDevtools feature', () => {
282293
283294 expect ( mockDevtoolsInstance . setClient ) . toHaveBeenCalledTimes ( 0 )
284295
285- client . set ( new QueryClient ( ) )
296+ const newClient = new QueryClient ( )
297+ client . set ( newClient )
286298
287299 TestBed . tick ( )
288300
289301 expect ( mockDevtoolsInstance . setClient ) . toHaveBeenCalledTimes ( 1 )
302+ expect ( mockDevtoolsInstance . setClient ) . toHaveBeenCalledWith ( newClient )
290303 } )
291304
292305 it ( 'should update position' , async ( ) => {
@@ -317,6 +330,7 @@ describe('withDevtools feature', () => {
317330 TestBed . tick ( )
318331
319332 expect ( mockDevtoolsInstance . setPosition ) . toHaveBeenCalledTimes ( 1 )
333+ expect ( mockDevtoolsInstance . setPosition ) . toHaveBeenCalledWith ( 'left' )
320334 } )
321335
322336 it ( 'should update button position' , async ( ) => {
@@ -347,6 +361,9 @@ describe('withDevtools feature', () => {
347361 TestBed . tick ( )
348362
349363 expect ( mockDevtoolsInstance . setButtonPosition ) . toHaveBeenCalledTimes ( 1 )
364+ expect ( mockDevtoolsInstance . setButtonPosition ) . toHaveBeenCalledWith (
365+ 'bottom-right' ,
366+ )
350367 } )
351368
352369 it ( 'should update initialIsOpen' , async ( ) => {
@@ -377,6 +394,7 @@ describe('withDevtools feature', () => {
377394 TestBed . tick ( )
378395
379396 expect ( mockDevtoolsInstance . setInitialIsOpen ) . toHaveBeenCalledTimes ( 1 )
397+ expect ( mockDevtoolsInstance . setInitialIsOpen ) . toHaveBeenCalledWith ( true )
380398 } )
381399
382400 it ( 'should destroy devtools' , async ( ) => {
@@ -406,4 +424,225 @@ describe('withDevtools feature', () => {
406424
407425 expect ( mockDevtoolsInstance . unmount ) . toHaveBeenCalledTimes ( 1 )
408426 } )
427+
428+ it ( 'should unmount devtools when injector is destroyed' , async ( ) => {
429+ TestBed . configureTestingModule ( {
430+ providers : [
431+ provideZonelessChangeDetection ( ) ,
432+ provideTanStackQuery (
433+ new QueryClient ( ) ,
434+ withDevtools ( ( ) => ( {
435+ loadDevtools : true ,
436+ } ) ) ,
437+ ) ,
438+ ] ,
439+ } )
440+
441+ TestBed . inject ( ENVIRONMENT_INITIALIZER )
442+ await vi . advanceTimersByTimeAsync ( 0 )
443+ TestBed . tick ( )
444+ await vi . dynamicImportSettled ( )
445+
446+ expect ( mockTanstackQueryDevtools ) . toHaveBeenCalled ( )
447+ expect ( mockDevtoolsInstance . mount ) . toHaveBeenCalledTimes ( 1 )
448+ expect ( mockDevtoolsInstance . unmount ) . toHaveBeenCalledTimes ( 0 )
449+
450+ // Destroy the injector
451+ TestBed . resetTestingModule ( )
452+
453+ expect ( mockDevtoolsInstance . unmount ) . toHaveBeenCalledTimes ( 1 )
454+ } )
455+
456+ it ( 'should remount devtools when toggled from false to true' , async ( ) => {
457+ const loadDevtools = signal ( false )
458+
459+ TestBed . configureTestingModule ( {
460+ providers : [
461+ provideZonelessChangeDetection ( ) ,
462+ provideTanStackQuery (
463+ new QueryClient ( ) ,
464+ withDevtools ( ( ) => ( {
465+ loadDevtools : loadDevtools ( ) ,
466+ } ) ) ,
467+ ) ,
468+ ] ,
469+ } )
470+
471+ TestBed . inject ( ENVIRONMENT_INITIALIZER )
472+ await vi . advanceTimersByTimeAsync ( 0 )
473+
474+ // Initially false, devtools should not be loaded
475+ expect ( mockTanstackQueryDevtools ) . not . toHaveBeenCalled ( )
476+ expect ( mockDevtoolsInstance . mount ) . not . toHaveBeenCalled ( )
477+
478+ // Toggle to true
479+ loadDevtools . set ( true )
480+ TestBed . tick ( )
481+ await vi . dynamicImportSettled ( )
482+
483+ // Devtools should now be loaded and mounted
484+ expect ( mockTanstackQueryDevtools ) . toHaveBeenCalledTimes ( 1 )
485+ expect ( mockDevtoolsInstance . mount ) . toHaveBeenCalledTimes ( 1 )
486+ expect ( mockDevtoolsInstance . unmount ) . not . toHaveBeenCalled ( )
487+
488+ // Toggle back to false
489+ loadDevtools . set ( false )
490+ TestBed . tick ( )
491+
492+ // Should unmount
493+ expect ( mockDevtoolsInstance . unmount ) . toHaveBeenCalledTimes ( 1 )
494+ expect ( mockDevtoolsInstance . mount ) . toHaveBeenCalledTimes ( 1 )
495+
496+ // Toggle back to true again
497+ loadDevtools . set ( true )
498+ TestBed . tick ( )
499+ await vi . dynamicImportSettled ( )
500+
501+ // Should remount (mount called twice now)
502+ expect ( mockDevtoolsInstance . mount ) . toHaveBeenCalledTimes ( 2 )
503+ expect ( mockDevtoolsInstance . unmount ) . toHaveBeenCalledTimes ( 1 )
504+ } )
505+
506+ it ( 'should handle rapid toggles correctly' , async ( ) => {
507+ const loadDevtools = signal ( true )
508+
509+ TestBed . configureTestingModule ( {
510+ providers : [
511+ provideZonelessChangeDetection ( ) ,
512+ provideTanStackQuery (
513+ new QueryClient ( ) ,
514+ withDevtools ( ( ) => ( {
515+ loadDevtools : loadDevtools ( ) ,
516+ } ) ) ,
517+ ) ,
518+ ] ,
519+ } )
520+
521+ TestBed . inject ( ENVIRONMENT_INITIALIZER )
522+ await vi . advanceTimersByTimeAsync ( 0 )
523+ TestBed . tick ( )
524+ await vi . dynamicImportSettled ( )
525+
526+ expect ( mockDevtoolsInstance . mount ) . toHaveBeenCalledTimes ( 1 )
527+
528+ // Rapid toggles
529+ loadDevtools . set ( false )
530+ TestBed . tick ( )
531+ loadDevtools . set ( true )
532+ TestBed . tick ( )
533+ await vi . dynamicImportSettled ( )
534+ loadDevtools . set ( false )
535+ TestBed . tick ( )
536+ loadDevtools . set ( true )
537+ TestBed . tick ( )
538+ await vi . dynamicImportSettled ( )
539+
540+ // Should handle all toggles correctly
541+ expect ( mockDevtoolsInstance . mount ) . toHaveBeenCalledTimes ( 3 )
542+ expect ( mockDevtoolsInstance . unmount ) . toHaveBeenCalledTimes ( 2 )
543+ } )
544+
545+ describe ( 'deps parameter' , ( ) => {
546+ it ( 'should inject dependencies and pass them to withDevtoolsFn in correct order' , async ( ) => {
547+ const mockService1 = { value : 'service1' }
548+ const mockService2 = { value : 'service2' }
549+ const mockService1Token = new InjectionToken ( 'MockService1' )
550+ const mockService2Token = new InjectionToken ( 'MockService2' )
551+ const withDevtoolsFn = vi . fn ( ) . mockReturnValue ( { loadDevtools : true } )
552+
553+ TestBed . configureTestingModule ( {
554+ providers : [
555+ provideZonelessChangeDetection ( ) ,
556+ {
557+ provide : mockService1Token ,
558+ useValue : mockService1 ,
559+ } ,
560+ {
561+ provide : mockService2Token ,
562+ useValue : mockService2 ,
563+ } ,
564+ provideTanStackQuery (
565+ new QueryClient ( ) ,
566+ withDevtools ( withDevtoolsFn , {
567+ deps : [ mockService1Token , mockService2Token ] ,
568+ } ) ,
569+ ) ,
570+ ] ,
571+ } )
572+
573+ TestBed . inject ( ENVIRONMENT_INITIALIZER )
574+ await vi . advanceTimersByTimeAsync ( 0 )
575+
576+ expect ( withDevtoolsFn ) . toHaveBeenCalledWith ( mockService1 , mockService2 )
577+ } )
578+
579+ it ( 'should work with empty deps array' , async ( ) => {
580+ const withDevtoolsFn = vi . fn ( ) . mockReturnValue ( { loadDevtools : true } )
581+
582+ TestBed . configureTestingModule ( {
583+ providers : [
584+ provideZonelessChangeDetection ( ) ,
585+ provideTanStackQuery (
586+ new QueryClient ( ) ,
587+ withDevtools ( withDevtoolsFn , {
588+ deps : [ ] ,
589+ } ) ,
590+ ) ,
591+ ] ,
592+ } )
593+
594+ TestBed . inject ( ENVIRONMENT_INITIALIZER )
595+ await vi . advanceTimersByTimeAsync ( 0 )
596+
597+ expect ( withDevtoolsFn ) . toHaveBeenCalledWith ( )
598+ } )
599+
600+ it ( 'should reactively update when injected services change' , async ( ) => {
601+ class ReactiveService {
602+ enabled = signal ( false )
603+ position = signal < DevtoolsPosition > ( 'bottom' )
604+ }
605+
606+ const withDevtoolsFn = ( service : ReactiveService ) => ( {
607+ loadDevtools : service . enabled ( ) ,
608+ position : service . position ( ) ,
609+ } )
610+
611+ TestBed . configureTestingModule ( {
612+ providers : [
613+ provideZonelessChangeDetection ( ) ,
614+ ReactiveService ,
615+ provideTanStackQuery (
616+ new QueryClient ( ) ,
617+ withDevtools ( withDevtoolsFn , {
618+ deps : [ ReactiveService ] ,
619+ } ) ,
620+ ) ,
621+ ] ,
622+ } )
623+
624+ TestBed . inject ( ENVIRONMENT_INITIALIZER )
625+ await vi . advanceTimersByTimeAsync ( 0 )
626+
627+ const service = TestBed . inject ( ReactiveService )
628+
629+ expect ( mockTanstackQueryDevtools ) . not . toHaveBeenCalled ( )
630+
631+ service . enabled . set ( true )
632+ TestBed . tick ( )
633+ await vi . dynamicImportSettled ( )
634+
635+ expect ( mockTanstackQueryDevtools ) . toHaveBeenCalledTimes ( 1 )
636+ expect ( mockTanstackQueryDevtools ) . toHaveBeenCalledWith (
637+ expect . objectContaining ( {
638+ position : 'bottom' ,
639+ } ) ,
640+ )
641+
642+ service . position . set ( 'top' )
643+ TestBed . tick ( )
644+
645+ expect ( mockDevtoolsInstance . setPosition ) . toHaveBeenCalledWith ( 'top' )
646+ } )
647+ } )
409648} )
0 commit comments