11import { describe , expect , it , vi , beforeAll , afterAll } from 'vitest' ;
22import { render as defaultRender , screen } from '@testing-library/react' ;
33import TabNavigation from '../TabNavigation' ;
4- import WithMinimalProviders from 'test/wrappers/WithMinimalProviders' ;
54import '@testing-library/jest-dom' ;
65
6+ // Create a mock i18n instance - MOVED UP before any uses
7+ const mockI18n = {
8+ t : ( key : string , options ?: Record < string , unknown > ) => options ?. defaultValue || key ,
9+ language : 'en' ,
10+ languages : [ 'en' ] ,
11+ use : ( ) => mockI18n , // Return itself for chaining
12+ init : ( ) => mockI18n , // Return itself for chaining
13+ changeLanguage : vi . fn ( ) ,
14+ exists : vi . fn ( ( ) => true ) ,
15+ addResourceBundle : vi . fn ( ) ,
16+ } ;
17+
18+ // Mock i18next
19+ vi . mock ( 'i18next' , ( ) => ( {
20+ default : mockI18n ,
21+ } ) ) ;
22+
23+ // Mock i18next-browser-languagedetector
24+ vi . mock ( 'i18next-browser-languagedetector' , ( ) => ( {
25+ default : function ( ) {
26+ return { } ;
27+ } ,
28+ } ) ) ;
29+
30+ // Mock react-i18next
31+ vi . mock ( 'react-i18next' , ( ) => ( {
32+ useTranslation : ( ) => ( {
33+ t : ( key : string , options ?: Record < string , unknown > ) => options ?. defaultValue || key ,
34+ } ) ,
35+ initReactI18next : { } ,
36+ I18nextProvider : ( { children } : { children : React . ReactNode } ) => < > { children } </ > ,
37+ } ) ) ;
38+
39+ // Mock common/utils/i18n
40+ vi . mock ( 'common/utils/i18n' , ( ) => ( {
41+ default : mockI18n ,
42+ } ) ) ;
43+
744// Mock the window object for Ionic
845beforeAll ( ( ) => {
946 // Mock window.matchMedia
@@ -97,6 +134,11 @@ vi.mock('@ionic/react', async () => {
97134 }
98135 return tabButton ;
99136 } ,
137+ IonText : ( { children, className } : { children : React . ReactNode ; className ?: string } ) => (
138+ < div data-testid = "mock-ion-text" className = { className } >
139+ { children }
140+ </ div >
141+ ) ,
100142 } ;
101143} ) ;
102144
@@ -137,38 +179,73 @@ vi.mock('pages/Upload/UploadPage', () => ({
137179 default : ( ) => < div data-testid = "mock-upload-page" > Upload Page</ div > ,
138180} ) ) ;
139181
182+ vi . mock ( 'pages/Reports/ReportsListPage' , ( ) => ( {
183+ default : ( ) => < div data-testid = "mock-reports-list-page" > Reports List Page</ div > ,
184+ } ) ) ;
185+
186+ vi . mock ( 'pages/Reports/ReportDetailPage' , ( ) => ( {
187+ default : ( ) => < div data-testid = "mock-report-detail-page" > Report Detail Page</ div > ,
188+ } ) ) ;
189+
190+ vi . mock ( 'pages/Processing/ProcessingPage' , ( ) => ( {
191+ default : ( ) => < div data-testid = "mock-processing-page" > Processing Page</ div > ,
192+ } ) ) ;
193+
140194// Mock the AppMenu component
141195vi . mock ( '../../Menu/AppMenu' , ( ) => ( {
142196 default : ( ) => < div data-testid = "mock-app-menu" > App Menu</ div > ,
143197} ) ) ;
144198
145- // Mock the Icon component
146- vi . mock ( '../../Icon/Icon ' , ( ) => ( {
199+ // Mock the SvgIcon component
200+ vi . mock ( '../../Icon/SvgIcon ' , ( ) => ( {
147201 default : ( {
148- icon,
149- iconStyle,
202+ src,
203+ alt,
204+ active,
150205 className,
151- size,
152- fixedWidth,
206+ width,
207+ height,
208+ testid = 'svg-icon' ,
153209 } : {
154- icon : string ;
155- iconStyle ?: string ;
210+ src : string ;
211+ alt ?: string ;
212+ active ?: boolean ;
156213 className ?: string ;
157- size ?: string ;
158- fixedWidth ?: boolean ;
214+ width ?: number | string ;
215+ height ?: number | string ;
216+ testid ?: string ;
159217 } ) => (
160218 < div
161- data-testid = { `mock-icon-${ icon } ` }
162- data-icon-style = { iconStyle }
219+ data-testid = { testid }
220+ data-src = { src }
221+ data-alt = { alt }
222+ data-active = { active ? 'true' : 'false' }
163223 className = { className }
164- data-size = { size }
165- data-fixed-width = { fixedWidth ? 'true' : 'false' }
224+ data-width = { width }
225+ data-height = { height }
166226 >
167- { icon }
227+ < img data-testid = { ` ${ testid } -img` } src = { src } alt = { alt } />
168228 </ div >
169229 ) ,
170230} ) ) ;
171231
232+ // Mock the SVG icons
233+ vi . mock ( 'assets/icons/home.svg' , ( ) => ( {
234+ default : 'mocked-home-icon.svg'
235+ } ) ) ;
236+ vi . mock ( 'assets/icons/reports.svg' , ( ) => ( {
237+ default : 'mocked-reports-icon.svg'
238+ } ) ) ;
239+ vi . mock ( 'assets/icons/upload.svg' , ( ) => ( {
240+ default : 'mocked-upload-icon.svg'
241+ } ) ) ;
242+ vi . mock ( 'assets/icons/chat.svg' , ( ) => ( {
243+ default : 'mocked-chat-icon.svg'
244+ } ) ) ;
245+ vi . mock ( 'assets/icons/profile.svg' , ( ) => ( {
246+ default : 'mocked-profile-icon.svg'
247+ } ) ) ;
248+
172249// Mock the UploadModal component
173250vi . mock ( '../../Upload/UploadModal' , ( ) => ( {
174251 default : ( {
@@ -178,7 +255,7 @@ vi.mock('../../Upload/UploadModal', () => ({
178255 } : {
179256 isOpen : boolean ;
180257 onClose : ( ) => void ;
181- _onUploadComplete ?: ( report : Record < string , unknown > ) => void ;
258+ _onUploadComplete ?: ( ) => void ;
182259 } ) =>
183260 isOpen ? (
184261 < div data-testid = "mock-upload-modal" >
@@ -209,9 +286,15 @@ vi.mock('react-router-dom', async () => {
209286 useHistory : ( ) => ( {
210287 push : vi . fn ( ) ,
211288 } ) ,
289+ useLocation : ( ) => ( {
290+ pathname : '/tabs/home' ,
291+ } ) ,
212292 } ;
213293} ) ;
214294
295+ // Import the WithMinimalProviders wrapper - THIS NEEDS TO COME AFTER ALL THE MOCKS
296+ import WithMinimalProviders from 'test/wrappers/WithMinimalProviders' ;
297+
215298// Use a custom render that uses our minimal providers
216299const render = ( ui : React . ReactElement ) => {
217300 return defaultRender ( ui , { wrapper : WithMinimalProviders } ) ;
@@ -233,12 +316,31 @@ describe('TabNavigation', () => {
233316 render ( < TabNavigation /> ) ;
234317
235318 // ASSERT
236- // Check if all tab icons are rendered
237- expect ( screen . getByTestId ( 'mock-icon-home' ) ) . toBeInTheDocument ( ) ;
238- expect ( screen . getByTestId ( 'mock-icon-fileLines' ) ) . toBeInTheDocument ( ) ;
239- expect ( screen . getByTestId ( 'mock-icon-arrowUpFromBracket' ) ) . toBeInTheDocument ( ) ;
240- expect ( screen . getByTestId ( 'mock-icon-comment' ) ) . toBeInTheDocument ( ) ;
241- expect ( screen . getByTestId ( 'mock-icon-userCircle' ) ) . toBeInTheDocument ( ) ;
319+ // Check if all SvgIcon components are rendered
320+ const homeTab = screen . getByTestId ( 'mock-ion-tab-button-home' ) ;
321+ const svgIconInHomeTab = homeTab . querySelector ( '[data-testid="svg-icon"]' ) ;
322+ expect ( svgIconInHomeTab ) . toBeInTheDocument ( ) ;
323+ expect ( svgIconInHomeTab ) . toHaveAttribute ( 'data-src' , 'mocked-home-icon.svg' ) ;
324+
325+ const reportsTab = screen . getByTestId ( 'mock-ion-tab-button-reports' ) ;
326+ const svgIconInReportsTab = reportsTab . querySelector ( '[data-testid="svg-icon"]' ) ;
327+ expect ( svgIconInReportsTab ) . toBeInTheDocument ( ) ;
328+ expect ( svgIconInReportsTab ) . toHaveAttribute ( 'data-src' , 'mocked-reports-icon.svg' ) ;
329+
330+ const uploadTab = screen . getByTestId ( 'mock-ion-tab-button-upload' ) ;
331+ const svgIconInUploadTab = uploadTab . querySelector ( '[data-testid="svg-icon"]' ) ;
332+ expect ( svgIconInUploadTab ) . toBeInTheDocument ( ) ;
333+ expect ( svgIconInUploadTab ) . toHaveAttribute ( 'data-src' , 'mocked-upload-icon.svg' ) ;
334+
335+ const chatTab = screen . getByTestId ( 'mock-ion-tab-button-chat' ) ;
336+ const svgIconInChatTab = chatTab . querySelector ( '[data-testid="svg-icon"]' ) ;
337+ expect ( svgIconInChatTab ) . toBeInTheDocument ( ) ;
338+ expect ( svgIconInChatTab ) . toHaveAttribute ( 'data-src' , 'mocked-chat-icon.svg' ) ;
339+
340+ const accountTab = screen . getByTestId ( 'mock-ion-tab-button-account' ) ;
341+ const svgIconInAccountTab = accountTab . querySelector ( '[data-testid="svg-icon"]' ) ;
342+ expect ( svgIconInAccountTab ) . toBeInTheDocument ( ) ;
343+ expect ( svgIconInAccountTab ) . toHaveAttribute ( 'data-src' , 'mocked-profile-icon.svg' ) ;
242344 } ) ;
243345
244346 it ( 'should have correct href attributes on tab buttons' , ( ) => {
@@ -252,7 +354,7 @@ describe('TabNavigation', () => {
252354 '/tabs/home' ,
253355 ) ;
254356
255- // Check for analytics tab button
357+ // Check for reports tab button
256358 expect ( screen . getByTestId ( 'mock-ion-tab-button-reports' ) ) . toHaveAttribute (
257359 'data-href' ,
258360 '/tabs/reports' ,
@@ -283,7 +385,7 @@ describe('TabNavigation', () => {
283385 // Check for home tab button
284386 expect ( screen . getByTestId ( 'mock-ion-tab-button-home' ) ) . toHaveAttribute ( 'data-tab' , 'home' ) ;
285387
286- // Check for analytics tab button
388+ // Check for reports tab button
287389 expect ( screen . getByTestId ( 'mock-ion-tab-button-reports' ) ) . toHaveAttribute (
288390 'data-tab' ,
289391 'reports' ,
@@ -302,29 +404,19 @@ describe('TabNavigation', () => {
302404 ) ;
303405 } ) ;
304406
305- it ( 'should have correct icon styles ' , ( ) => {
407+ it ( 'should have active state based on current location ' , ( ) => {
306408 // ARRANGE
307409 render ( < TabNavigation /> ) ;
308410
309411 // ASSERT
310- // Home icon should not have a style (using default solid)
311- const homeIcon = screen . getByTestId ( 'mock-icon-home' ) ;
312- expect ( homeIcon ) . not . toHaveAttribute ( 'data-icon-style' ) ;
313-
314- // FileLines icon should have regular style
315- const fileLinesIcon = screen . getByTestId ( 'mock-icon-fileLines' ) ;
316- expect ( fileLinesIcon ) . toHaveAttribute ( 'data-icon-style' , 'regular' ) ;
317-
318- // Upload icon should not have a style (using default solid)
319- const uploadIcon = screen . getByTestId ( 'mock-icon-arrowUpFromBracket' ) ;
320- expect ( uploadIcon ) . not . toHaveAttribute ( 'data-icon-style' ) ;
321-
322- // Comment icon should have regular style
323- const commentIcon = screen . getByTestId ( 'mock-icon-comment' ) ;
324- expect ( commentIcon ) . toHaveAttribute ( 'data-icon-style' , 'regular' ) ;
325-
326- // User icon should not have a style (using default solid)
327- const userIcon = screen . getByTestId ( 'mock-icon-userCircle' ) ;
328- expect ( userIcon ) . not . toHaveAttribute ( 'data-icon-style' ) ;
412+ // Home icon should be active since we mocked location.pathname to be '/tabs/home'
413+ const homeTab = screen . getByTestId ( 'mock-ion-tab-button-home' ) ;
414+ const svgIconInHomeTab = homeTab . querySelector ( '[data-testid="svg-icon"]' ) ;
415+ expect ( svgIconInHomeTab ) . toHaveAttribute ( 'data-active' , 'true' ) ;
416+
417+ // Other tabs should not be active
418+ const reportsTab = screen . getByTestId ( 'mock-ion-tab-button-reports' ) ;
419+ const svgIconInReportsTab = reportsTab . querySelector ( '[data-testid="svg-icon"]' ) ;
420+ expect ( svgIconInReportsTab ) . toHaveAttribute ( 'data-active' , 'false' ) ;
329421 } ) ;
330422} ) ;
0 commit comments