11import { describe , it , expect , vi , beforeEach } from 'vitest' ;
2- import { render , screen , fireEvent } from '@testing-library/react' ;
2+ import { render , screen } from '@testing-library/react' ;
33import '@testing-library/jest-dom/vitest' ;
44import IMView from '@/views/IMView' ;
55
6- // jsdom does not implement scrollIntoView
76Element . prototype . scrollIntoView = vi . fn ( ) ;
87
9- // Mock useIMChat
108vi . mock ( '@/hooks/useIMChat' , ( ) => ( {
119 useIMChat : vi . fn ( ( ) => ( {
12- messages : new Map ( ) ,
10+ messages : [ ] ,
1311 contacts : [
1412 { id : 'c1' , name : 'Alice' , type : 'user' as const , online : true } ,
1513 { id : 'c2' , name : 'Bob' , type : 'user' as const , online : false } ,
1614 ] ,
15+ hubContacts : [ ] ,
1716 sendMessage : vi . fn ( ) ,
1817 getSessionMessages : vi . fn ( ( ) => [ ] ) ,
1918 upsertContact : vi . fn ( ) ,
2019 removeContact : vi . fn ( ) ,
21- searchContacts : vi . fn ( ( q : string ) =>
22- q
23- ? [ { id : 'c1' , name : 'Alice' , type : 'user' as const , online : true } ]
24- : [
25- { id : 'c1' , name : 'Alice' , type : 'user' as const , online : true } ,
26- { id : 'c2' , name : 'Bob' , type : 'user' as const , online : false } ,
27- ] ,
28- ) ,
29- // Trump IM additions
20+ searchContacts : vi . fn ( ( ) => [ ] ) ,
3021 friendRequests : [ ] ,
3122 notifications : [ ] ,
3223 acceptFriendRequest : vi . fn ( ) ,
@@ -39,13 +30,21 @@ vi.mock('@/hooks/useIMChat', () => ({
3930 createGroupSession : vi . fn ( ) ,
4031 selectContact : vi . fn ( ) ,
4132 actionState : { } ,
33+ activeSessionId : null ,
34+ status : 'loaded' as const ,
35+ actionCapabilities : { } ,
36+ markSessionRead : vi . fn ( ) ,
37+ sessionReadError : null ,
38+ addContact : vi . fn ( ( ) => Promise . resolve ( { ok : true } ) ) ,
39+ error : null ,
40+ label : ( key : string , fallback : string ) => fallback ,
41+ actionPending : ( ) => false ,
4242 } ) ) ,
4343} ) ) ;
4444
45- // Mock useHubStore
4645vi . mock ( '@/stores/hubStore' , ( ) => ( {
47- useHubStore : vi . fn ( ( selector ?: ( s : { authenticated : boolean ; userId : string | null ; username : string | null } ) => unknown ) => {
48- const state = { authenticated : true , userId : 'user-1' , username : 'testuser' } ;
46+ useHubStore : vi . fn ( ( selector ?: ( s : { authenticated : boolean ; userId : string | null } ) => unknown ) => {
47+ const state = { authenticated : true , userId : 'user-1' } ;
4948 return selector ? selector ( state ) : state ;
5049 } ) ,
5150} ) ) ;
@@ -55,45 +54,23 @@ describe('IMView', () => {
5554 vi . clearAllMocks ( ) ;
5655 } ) ;
5756
58- it ( 'renders contact list with contacts' , ( ) => {
57+ it ( 'renders with contacts' , ( ) => {
5958 render ( < IMView online = { false } isConnected = { false } isStreaming = { false } isMobile = { false } isTablet = { false } /> ) ;
6059 expect ( screen . getByText ( 'Alice' ) ) . toBeInTheDocument ( ) ;
6160 expect ( screen . getByText ( 'Bob' ) ) . toBeInTheDocument ( ) ;
6261 } ) ;
6362
64- it ( 'renders contacts sidebar header' , ( ) => {
63+ it ( 'shows empty state when no conversations' , ( ) => {
64+ // Re-mock with empty state for this test
65+ vi . mocked ( useIMChat ) . mockReturnValue ( {
66+ ...vi . mocked ( useIMChat ) ( ) ,
67+ contacts : [ ] ,
68+ status : 'loaded' as const ,
69+ } as never ) ;
6570 render ( < IMView online = { false } isConnected = { false } isStreaming = { false } isMobile = { false } isTablet = { false } /> ) ;
66- expect ( screen . getByText ( 'Contacts' ) ) . toBeInTheDocument ( ) ;
67- } ) ;
68-
69- it ( 'renders Select a contact placeholder when no contact selected' , ( ) => {
70- render ( < IMView online = { false } isConnected = { false } isStreaming = { false } isMobile = { false } isTablet = { false } /> ) ;
71- expect ( screen . getByText ( 'Select a contact to start messaging' ) ) . toBeInTheDocument ( ) ;
72- } ) ;
73-
74- it ( 'shows empty message area when no contact selected' , ( ) => {
75- render ( < IMView online = { false } isConnected = { false } isStreaming = { false } isMobile = { false } isTablet = { false } /> ) ;
76- expect ( screen . getByRole ( 'listbox' , { name : 'Contacts' } ) ) . toBeInTheDocument ( ) ;
77- } ) ;
78-
79- it ( 'has message input enabled after selecting a contact' , ( ) => {
80- render ( < IMView online = { false } isConnected = { false } isStreaming = { false } isMobile = { false } isTablet = { false } /> ) ;
81- // Click on the first contact (Alice) to select it
82- const contact = screen . getByRole ( 'option' , { name : / A l i c e / i } ) ;
83- fireEvent . click ( contact ) ;
84- // After selection, the message input should appear and be enabled
85- const input = screen . getByRole ( 'textbox' , { name : 'Message input' } ) ;
86- expect ( input ) . toBeInTheDocument ( ) ;
87- expect ( input ) . not . toBeDisabled ( ) ;
88- } ) ;
89-
90- it ( 'renders search contact input' , ( ) => {
91- render ( < IMView online = { false } isConnected = { false } isStreaming = { false } isMobile = { false } isTablet = { false } /> ) ;
92- expect ( screen . getByPlaceholderText ( 'Search contacts...' ) ) . toBeInTheDocument ( ) ;
93- } ) ;
94-
95- it ( 'renders add contact button' , ( ) => {
96- render ( < IMView online = { false } isConnected = { false } isStreaming = { false } isMobile = { false } isTablet = { false } /> ) ;
97- expect ( screen . getByRole ( 'button' , { name : 'Add contact' } ) ) . toBeInTheDocument ( ) ;
71+ expect ( screen . getByText ( "No Hub conversations yet" ) ) . toBeInTheDocument ( ) ;
9872 } ) ;
9973} ) ;
74+
75+ // Re-import for mock manipulation
76+ import { useIMChat } from '@/hooks/useIMChat' ;
0 commit comments