22 * @vitest -environment jsdom
33 */
44import { act } from 'react'
5+ import { QueryClient , QueryClientProvider } from '@tanstack/react-query'
56import { createRoot , type Root } from 'react-dom/client'
67import { afterEach , beforeEach , describe , expect , it , vi } from 'vitest'
78import type { OrganizationChat } from '@/app/o/[organizationId]/components/organization-sidebar/hooks'
89
910const hoverState = vi . hoisted ( ( ) => ( { isOpen : false } ) )
1011
1112vi . mock ( 'next/link' , ( ) => ( {
12- default : ( { href, children, ...props } : { href : string ; children : React . ReactNode } ) => (
13+ default : ( {
14+ href,
15+ children,
16+ prefetch : _prefetch ,
17+ ...props
18+ } : {
19+ href : string
20+ children : React . ReactNode
21+ prefetch ?: boolean
22+ } ) => (
1323 < a href = { href } { ...props } >
1424 { children }
1525 </ a >
@@ -36,6 +46,8 @@ const CHATS: OrganizationChat[] = Array.from({ length: 8 }, (_, index) => ({
3646
3747let container : HTMLDivElement
3848let root : Root
49+ let queryClient : QueryClient
50+ let prefetchQuery : ReturnType < typeof vi . spyOn >
3951
4052beforeEach ( ( ) => {
4153 ; ( globalThis as { IS_REACT_ACT_ENVIRONMENT ?: boolean } ) . IS_REACT_ACT_ENVIRONMENT = true
@@ -48,6 +60,8 @@ beforeEach(() => {
4860 }
4961 )
5062 hoverState . isOpen = false
63+ queryClient = new QueryClient ( { defaultOptions : { queries : { retry : false } } } )
64+ prefetchQuery = vi . spyOn ( queryClient , 'prefetchQuery' ) . mockResolvedValue ( )
5165 container = document . createElement ( 'div' )
5266 document . body . appendChild ( container )
5367 root = createRoot ( container )
@@ -56,22 +70,25 @@ beforeEach(() => {
5670afterEach ( async ( ) => {
5771 await act ( async ( ) => root . unmount ( ) )
5872 container . remove ( )
73+ queryClient . clear ( )
5974 vi . unstubAllGlobals ( )
6075} )
6176
6277async function render ( props : Partial < Parameters < typeof ChatsSection > [ 0 ] > = { } ) {
6378 await act ( async ( ) => {
6479 root . render (
65- < ChatsSection
66- chats = { CHATS }
67- isLoading = { false }
68- isCollapsed = { false }
69- pathname = { null }
70- menuOpenHref = { null }
71- onContextMenu = { ( ) => { } }
72- onMoreClick = { ( ) => { } }
73- { ...props }
74- />
80+ < QueryClientProvider client = { queryClient } >
81+ < ChatsSection
82+ chats = { CHATS }
83+ isLoading = { false }
84+ isCollapsed = { false }
85+ pathname = { null }
86+ menuOpenHref = { null }
87+ onContextMenu = { ( ) => { } }
88+ onMoreClick = { ( ) => { } }
89+ { ...props }
90+ />
91+ </ QueryClientProvider >
7592 )
7693 } )
7794}
@@ -103,6 +120,28 @@ describe('ChatsSection', () => {
103120 await act ( async ( ) => button ?. click ( ) )
104121
105122 expect ( onMoreClick ) . toHaveBeenCalledWith ( expect . anything ( ) , '/o/org-1/chat/chat-2' )
123+ expect ( prefetchQuery ) . not . toHaveBeenCalled ( )
124+ } )
125+
126+ it . each ( [ false , true ] ) (
127+ 'prefetches focused destination history with collapsed=%s' ,
128+ async ( isCollapsed ) => {
129+ hoverState . isOpen = isCollapsed
130+ await render ( { isCollapsed } )
131+ prefetchQuery . mockClear ( )
132+ const link = document . body . querySelector < HTMLAnchorElement > ( 'a[href="/o/org-1/chat/chat-3"]' ) !
133+ await act ( async ( ) => link . focus ( ) )
134+ expect ( prefetchQuery ) . toHaveBeenCalledWith (
135+ expect . objectContaining ( { queryKey : [ 'mothership-chats' , 'detail' , 'chat-3' ] } )
136+ )
137+ }
138+ )
139+
140+ it ( 'does not prefetch the active conversation' , async ( ) => {
141+ await render ( { pathname : '/o/org-1/chat/chat-3' } )
142+ const link = container . querySelector < HTMLAnchorElement > ( 'a[href="/o/org-1/chat/chat-3"]' ) !
143+ await act ( async ( ) => link . focus ( ) )
144+ expect ( prefetchQuery ) . not . toHaveBeenCalled ( )
106145 } )
107146
108147 it ( 'shows the empty state when there are no chats' , async ( ) => {
0 commit comments