11/**
2- * Tests for HomeLayout — lightweight nav shell for /home.
3- * Validates: layout rendering, user avatar , navigation links .
2+ * Tests for HomeLayout — unified sidebar nav shell for /home.
3+ * Validates: layout rendering, sidebar presence , navigation context .
44 *
55 * Note: Radix DropdownMenu portal rendering is limited in jsdom,
66 * so we test the trigger and visible elements rather than dropdown contents.
77 */
88import { describe , it , expect , vi , beforeEach } from 'vitest' ;
9- import { render , screen , fireEvent } from '@testing-library/react' ;
9+ import { render , screen } from '@testing-library/react' ;
1010import '@testing-library/jest-dom' ;
1111import { MemoryRouter } from 'react-router-dom' ;
1212import { HomeLayout } from '../pages/home/HomeLayout' ;
@@ -40,6 +40,9 @@ vi.mock('@object-ui/i18n', () => ({
4040 direction : 'ltr' ,
4141 i18n : { } ,
4242 } ) ,
43+ useObjectLabel : ( ) => ( {
44+ objectLabel : ( { name, label } : any ) => label || name ,
45+ } ) ,
4346} ) ) ;
4447
4548// Mock @object -ui/components to keep most components
@@ -51,6 +54,77 @@ vi.mock('@object-ui/components', async (importOriginal) => {
5154 } ;
5255} ) ;
5356
57+ // Mock @object -ui/layout AppShell
58+ vi . mock ( '@object-ui/layout' , ( ) => ( {
59+ AppShell : ( { children, sidebar } : any ) => (
60+ < div data-testid = "app-shell" >
61+ < div data-testid = "sidebar" > { sidebar } </ div >
62+ < div data-testid = "content" > { children } </ div >
63+ </ div >
64+ ) ,
65+ useAppShellBranding : ( ) => { } ,
66+ } ) ) ;
67+
68+ // Mock NavigationContext
69+ const mockSetContext = vi . fn ( ) ;
70+ vi . mock ( '../context/NavigationContext' , ( ) => ( {
71+ useNavigationContext : ( ) => ( {
72+ context : 'home' ,
73+ setContext : mockSetContext ,
74+ currentAppName : undefined ,
75+ setCurrentAppName : vi . fn ( ) ,
76+ } ) ,
77+ } ) ) ;
78+
79+ // Mock MetadataProvider
80+ vi . mock ( '../context/MetadataProvider' , ( ) => ( {
81+ useMetadata : ( ) => ( {
82+ apps : [ ] ,
83+ objects : [ ] ,
84+ loading : false ,
85+ } ) ,
86+ } ) ) ;
87+
88+ // Mock other required contexts
89+ vi . mock ( '../context/ExpressionProvider' , ( ) => ( {
90+ useExpressionContext : ( ) => ( {
91+ evaluator : { } ,
92+ } ) ,
93+ evaluateVisibility : ( ) => true ,
94+ } ) ) ;
95+
96+ vi . mock ( '@object-ui/permissions' , ( ) => ( {
97+ usePermissions : ( ) => ( {
98+ can : ( ) => true ,
99+ } ) ,
100+ } ) ) ;
101+
102+ vi . mock ( '../hooks/useRecentItems' , ( ) => ( {
103+ useRecentItems : ( ) => ( {
104+ recentItems : [ ] ,
105+ addRecentItem : vi . fn ( ) ,
106+ } ) ,
107+ } ) ) ;
108+
109+ vi . mock ( '../hooks/useFavorites' , ( ) => ( {
110+ useFavorites : ( ) => ( {
111+ favorites : [ ] ,
112+ addFavorite : vi . fn ( ) ,
113+ removeFavorite : vi . fn ( ) ,
114+ } ) ,
115+ } ) ) ;
116+
117+ vi . mock ( '../hooks/useNavPins' , ( ) => ( {
118+ useNavPins : ( ) => ( {
119+ togglePin : vi . fn ( ) ,
120+ applyPins : ( items : any [ ] ) => items ,
121+ } ) ,
122+ } ) ) ;
123+
124+ vi . mock ( '../hooks/useResponsiveSidebar' , ( ) => ( {
125+ useResponsiveSidebar : ( ) => { } ,
126+ } ) ) ;
127+
54128describe ( 'HomeLayout' , ( ) => {
55129 beforeEach ( ( ) => {
56130 vi . clearAllMocks ( ) ;
@@ -64,57 +138,20 @@ describe('HomeLayout', () => {
64138 ) ;
65139 } ;
66140
67- it ( 'renders the layout shell with data-testid ' , ( ) => {
141+ it ( 'renders the AppShell with sidebar and content ' , ( ) => {
68142 renderLayout ( ) ;
69- expect ( screen . getByTestId ( 'home-layout' ) ) . toBeInTheDocument ( ) ;
143+ expect ( screen . getByTestId ( 'app-shell' ) ) . toBeInTheDocument ( ) ;
144+ expect ( screen . getByTestId ( 'sidebar' ) ) . toBeInTheDocument ( ) ;
145+ expect ( screen . getByTestId ( 'content' ) ) . toBeInTheDocument ( ) ;
70146 } ) ;
71147
72- it ( 'renders the Home branding button in the top bar ' , ( ) => {
148+ it ( 'sets navigation context to "home" on mount ' , ( ) => {
73149 renderLayout ( ) ;
74- const brand = screen . getByTestId ( 'home-layout-brand' ) ;
75- expect ( brand ) . toBeInTheDocument ( ) ;
76- expect ( brand ) . toHaveTextContent ( 'Home' ) ;
150+ expect ( mockSetContext ) . toHaveBeenCalledWith ( 'home' ) ;
77151 } ) ;
78152
79153 it ( 'renders children inside the layout' , ( ) => {
80154 renderLayout ( < div data-testid = "child-content" > Hello World</ div > ) ;
81155 expect ( screen . getByTestId ( 'child-content' ) ) . toBeInTheDocument ( ) ;
82156 } ) ;
83-
84- it ( 'renders user avatar with initials fallback' , ( ) => {
85- renderLayout ( ) ;
86- // The avatar trigger should show user initials "AD" (Alice Dev)
87- expect ( screen . getByTestId ( 'home-layout-user-trigger' ) ) . toBeInTheDocument ( ) ;
88- expect ( screen . getByText ( 'AD' ) ) . toBeInTheDocument ( ) ;
89- } ) ;
90-
91- it ( 'renders Settings button in the top bar' , ( ) => {
92- renderLayout ( ) ;
93- expect ( screen . getByTestId ( 'home-layout-settings-btn' ) ) . toBeInTheDocument ( ) ;
94- } ) ;
95-
96- it ( 'navigates to /system when Settings button is clicked' , ( ) => {
97- renderLayout ( ) ;
98- fireEvent . click ( screen . getByTestId ( 'home-layout-settings-btn' ) ) ;
99- expect ( mockNavigate ) . toHaveBeenCalledWith ( '/system' ) ;
100- } ) ;
101-
102- it ( 'navigates to /home when brand button is clicked' , ( ) => {
103- renderLayout ( ) ;
104- fireEvent . click ( screen . getByTestId ( 'home-layout-brand' ) ) ;
105- expect ( mockNavigate ) . toHaveBeenCalledWith ( '/home' ) ;
106- } ) ;
107-
108- it ( 'renders sticky header element' , ( ) => {
109- renderLayout ( ) ;
110- const header = screen . getByTestId ( 'home-layout' ) . querySelector ( 'header' ) ;
111- expect ( header ) . toBeInTheDocument ( ) ;
112- expect ( header ?. className ) . toContain ( 'sticky' ) ;
113- } ) ;
114-
115- it ( 'renders user menu trigger as a round button' , ( ) => {
116- renderLayout ( ) ;
117- const trigger = screen . getByTestId ( 'home-layout-user-trigger' ) ;
118- expect ( trigger . className ) . toContain ( 'rounded-full' ) ;
119- } ) ;
120157} ) ;
0 commit comments