@@ -244,4 +244,178 @@ describe('Devtools', () => {
244244 expect ( localStorage . getItem ( 'TanstackQueryDevtools.open' ) ) . toBe ( 'false' )
245245 } )
246246 } )
247+
248+ describe ( 'query list' , ( ) => {
249+ it ( 'should render a row for each query in the cache' , ( ) => {
250+ queryClient . setQueryData ( [ 'posts' ] , [ { id : 1 } ] )
251+ queryClient . setQueryData ( [ 'users' , 'me' ] , { id : 'u1' } )
252+ const rendered = renderDevtools ( { initialIsOpen : true } )
253+
254+ expect (
255+ rendered . getByLabelText ( / Q u e r y k e y \[ " p o s t s " \] / ) ,
256+ ) . toBeInTheDocument ( )
257+ expect (
258+ rendered . getByLabelText ( / Q u e r y k e y \[ " u s e r s " , " m e " \] / ) ,
259+ ) . toBeInTheDocument ( )
260+ } )
261+
262+ it ( 'should reflect a newly added query reactively' , ( ) => {
263+ const rendered = renderDevtools ( { initialIsOpen : true } )
264+
265+ expect (
266+ rendered . queryByLabelText ( / Q u e r y k e y \[ " n e w " \] / ) ,
267+ ) . not . toBeInTheDocument ( )
268+
269+ queryClient . setQueryData ( [ 'new' ] , 'hello' )
270+
271+ expect (
272+ rendered . getByLabelText ( / Q u e r y k e y \[ " n e w " \] / ) ,
273+ ) . toBeInTheDocument ( )
274+ } )
275+
276+ it ( 'should filter queries by "queryHash"' , ( ) => {
277+ queryClient . setQueryData ( [ 'posts' ] , [ ] )
278+ queryClient . setQueryData ( [ 'users' ] , [ ] )
279+ const rendered = renderDevtools ( { initialIsOpen : true } )
280+
281+ fireEvent . input ( rendered . getByLabelText ( 'Filter queries by query key' ) , {
282+ target : { value : 'posts' } ,
283+ } )
284+
285+ expect (
286+ rendered . getByLabelText ( / Q u e r y k e y \[ " p o s t s " \] / ) ,
287+ ) . toBeInTheDocument ( )
288+ expect (
289+ rendered . queryByLabelText ( / Q u e r y k e y \[ " u s e r s " \] / ) ,
290+ ) . not . toBeInTheDocument ( )
291+ } )
292+
293+ it ( 'should clear all queries when the clear cache button is clicked' , ( ) => {
294+ queryClient . setQueryData ( [ 'posts' ] , [ ] )
295+ queryClient . setQueryData ( [ 'users' ] , [ ] )
296+ const rendered = renderDevtools ( { initialIsOpen : true } )
297+
298+ fireEvent . click ( rendered . getByLabelText ( 'Clear query cache' ) )
299+
300+ expect (
301+ rendered . queryByLabelText ( / Q u e r y k e y \[ " p o s t s " \] / ) ,
302+ ) . not . toBeInTheDocument ( )
303+ expect (
304+ rendered . queryByLabelText ( / Q u e r y k e y \[ " u s e r s " \] / ) ,
305+ ) . not . toBeInTheDocument ( )
306+ } )
307+
308+ it ( 'should dispatch a "CLEAR_MUTATION_CACHE" event when clear cache is clicked in mutations view' , ( ) => {
309+ const rendered = renderDevtools ( { initialIsOpen : true } )
310+ fireEvent . click ( rendered . getByText ( 'Mutations' ) )
311+
312+ const listener = vi . fn ( )
313+ window . addEventListener ( '@tanstack/query-devtools-event' , listener )
314+
315+ try {
316+ fireEvent . click ( rendered . getByLabelText ( 'Clear query cache' ) )
317+
318+ expect ( listener ) . toHaveBeenCalled ( )
319+ const event = listener . mock . calls [ 0 ] ?. [ 0 ] as CustomEvent
320+ expect ( event . detail . type ) . toBe ( 'CLEAR_MUTATION_CACHE' )
321+ } finally {
322+ window . removeEventListener (
323+ '@tanstack/query-devtools-event' ,
324+ listener ,
325+ )
326+ }
327+ } )
328+ } )
329+
330+ describe ( 'view toggle' , ( ) => {
331+ it ( 'should switch to mutations view when the mutations toggle is clicked' , ( ) => {
332+ const rendered = renderDevtools ( { initialIsOpen : true } )
333+
334+ fireEvent . click ( rendered . getByText ( 'Mutations' ) )
335+
336+ expect (
337+ rendered . container . querySelector ( '.tsqd-mutations-container' ) ,
338+ ) . not . toBeNull ( )
339+ } )
340+
341+ it ( 'should render mutations in the mutations view' , async ( ) => {
342+ const rendered = renderDevtools ( { initialIsOpen : true } )
343+
344+ fireEvent . click ( rendered . getByText ( 'Mutations' ) )
345+
346+ const mutation = queryClient . getMutationCache ( ) . build ( queryClient , {
347+ mutationKey : [ 'add-post' ] ,
348+ mutationFn : ( ) => Promise . resolve ( 'ok' ) ,
349+ } )
350+ mutation . execute ( { } )
351+ await Promise . resolve ( )
352+
353+ expect (
354+ rendered . getByLabelText ( / M u t a t i o n s u b m i t t e d a t / ) ,
355+ ) . toBeInTheDocument ( )
356+ } )
357+ } )
358+
359+ describe ( 'disabled and static queries' , ( ) => {
360+ it ( 'should mark a disabled query in the row label' , ( ) => {
361+ const observer = queryClient . getQueryCache ( ) . build ( queryClient , {
362+ queryKey : [ 'disabled-q' ] ,
363+ queryFn : ( ) => 'x' ,
364+ } )
365+ observer . setOptions ( {
366+ ...observer . options ,
367+ enabled : false ,
368+ } as typeof observer . options )
369+ observer . setState ( { ...observer . state , data : 'x' } )
370+ const rendered = renderDevtools ( { initialIsOpen : true } )
371+
372+ expect ( rendered . getByLabelText ( / d i s a b l e d / ) ) . toBeInTheDocument ( )
373+ } )
374+ } )
375+
376+ describe ( 'status counts' , ( ) => {
377+ it ( 'should render status count badges' , ( ) => {
378+ const rendered = renderDevtools ( { initialIsOpen : true } )
379+
380+ expect ( rendered . getByLabelText ( / F r e s h : \d + / ) ) . toBeInTheDocument ( )
381+ expect ( rendered . getByLabelText ( / S t a l e : \d + / ) ) . toBeInTheDocument ( )
382+ expect ( rendered . getByLabelText ( / F e t c h i n g : \d + / ) ) . toBeInTheDocument ( )
383+ expect ( rendered . getByLabelText ( / P a u s e d : \d + / ) ) . toBeInTheDocument ( )
384+ expect ( rendered . getByLabelText ( / I n a c t i v e : \d + / ) ) . toBeInTheDocument ( )
385+ } )
386+
387+ it ( 'should reflect the inactive count when a query is added without observers' , ( ) => {
388+ const rendered = renderDevtools ( { initialIsOpen : true } )
389+
390+ expect ( rendered . getByLabelText ( 'Inactive: 0' ) ) . toBeInTheDocument ( )
391+
392+ queryClient . setQueryData ( [ 'posts' ] , [ { id : 1 } ] )
393+
394+ expect ( rendered . getByLabelText ( 'Inactive: 1' ) ) . toBeInTheDocument ( )
395+ } )
396+ } )
397+
398+ describe ( 'status tooltip' , ( ) => {
399+ it ( 'should show the tooltip on mouse enter when label is hidden' , ( ) => {
400+ const rendered = renderDevtools (
401+ { initialIsOpen : true } ,
402+ {
403+ 'TanstackQueryDevtools.open' : 'true' ,
404+ 'TanstackQueryDevtools.height' : '500' ,
405+ 'TanstackQueryDevtools.width' : '500' ,
406+ } ,
407+ )
408+
409+ const fresh = rendered . getByLabelText ( 'Fresh: 0' )
410+ fireEvent . mouseEnter ( fresh )
411+
412+ // tooltip is conditionally rendered based on showLabel + mouseOver/focused
413+ // not deterministic via panelWidth in jsdom but the handler itself runs
414+ fireEvent . mouseLeave ( fresh )
415+ fireEvent . focus ( fresh )
416+ fireEvent . blur ( fresh )
417+
418+ expect ( fresh ) . toBeInTheDocument ( )
419+ } )
420+ } )
247421} )
0 commit comments