@@ -10,13 +10,17 @@ jest.mock('../img/robot-logo.png', () => 'robot-logo.png');
1010jest . mock ( '../../components/appVersionCache' , ( ) => ( {
1111 getAppVersion : jest . fn ( ) ,
1212} ) ) ;
13+ jest . mock ( '../../components/auth' , ( ) => ( {
14+ getAuthStatus : jest . fn ( ) ,
15+ } ) ) ;
1316
1417// Mock currentUserCache
1518jest . mock ( '../../components/currentUserCache' , ( ) => ( {
1619 getCurrentUser : jest . fn ( ) ,
1720} ) ) ;
1821
1922import { getAppVersion } from '../../components/appVersionCache' ;
23+ import { getAuthStatus } from '../../components/auth' ;
2024import { getCurrentUser } from '../../components/currentUserCache' ;
2125
2226// Helper to render with router context
@@ -32,6 +36,7 @@ describe('Navbar', () => {
3236
3337 it ( 'renders logo, brand, and navigation links' , ( ) => {
3438 ( getAppVersion as jest . Mock ) . mockResolvedValue ( '1.2.3' ) ;
39+ ( getAuthStatus as jest . Mock ) . mockResolvedValue ( { authenticated : false } ) ;
3540 ( getCurrentUser as jest . Mock ) . mockResolvedValue ( 'test-user' ) ;
3641 renderWithRouter ( < Navbar /> ) ;
3742 expect ( screen . getByAltText ( 'Logo' ) ) . toBeInTheDocument ( ) ;
@@ -40,17 +45,20 @@ describe('Navbar', () => {
4045 expect ( screen . getByRole ( 'link' , { name : 'Bookings' } ) ) . toHaveAttribute ( 'href' , '/reservations' ) ;
4146 expect ( screen . getByRole ( 'link' , { name : 'Django-Admin' } ) ) . toHaveAttribute ( 'href' , '/admin' ) ;
4247 expect ( screen . getByRole ( 'link' , { name : 'Swagger' } ) ) . toHaveAttribute ( 'href' , '/api/docs/' ) ;
48+ expect ( screen . getByRole ( 'link' , { name : 'Login' } ) ) . toHaveAttribute ( 'href' , '/login' ) ;
4349 } ) ;
4450
4551 it ( 'renders initial version as ellipsis' , ( ) => {
4652 ( getAppVersion as jest . Mock ) . mockImplementation ( ( ) => new Promise ( ( ) => { } ) ) ;
53+ ( getAuthStatus as jest . Mock ) . mockResolvedValue ( { authenticated : false } ) ;
4754 ( getCurrentUser as jest . Mock ) . mockImplementation ( ( ) => new Promise ( ( ) => { } ) ) ;
4855 renderWithRouter ( < Navbar /> ) ;
49- expect ( screen . getByText ( / V e r s i o n : … / ) ) . toBeInTheDocument ( ) ;
56+ expect ( screen . getByText ( / V e r s i o n : \u2026 / ) ) . toBeInTheDocument ( ) ;
5057 } ) ;
5158
5259 it ( 'fetches and displays the app version on success' , async ( ) => {
5360 ( getAppVersion as jest . Mock ) . mockResolvedValue ( '1.2.3' ) ;
61+ ( getAuthStatus as jest . Mock ) . mockResolvedValue ( { authenticated : false } ) ;
5462 ( getCurrentUser as jest . Mock ) . mockResolvedValue ( 'test-user' ) ;
5563 renderWithRouter ( < Navbar /> ) ;
5664 await waitFor ( ( ) => {
@@ -60,6 +68,7 @@ describe('Navbar', () => {
6068
6169 it ( 'displays "unknown" if fetch fails' , async ( ) => {
6270 ( getAppVersion as jest . Mock ) . mockRejectedValue ( new Error ( 'Network error' ) ) ;
71+ ( getAuthStatus as jest . Mock ) . mockResolvedValue ( { authenticated : false } ) ;
6372 ( getCurrentUser as jest . Mock ) . mockResolvedValue ( 'unknown' ) ;
6473 renderWithRouter ( < Navbar /> ) ;
6574 await waitFor ( ( ) => {
@@ -69,6 +78,7 @@ describe('Navbar', () => {
6978
7079 it ( 'has external link to the GitHub repo' , ( ) => {
7180 ( getAppVersion as jest . Mock ) . mockResolvedValue ( '1.2.3' ) ;
81+ ( getAuthStatus as jest . Mock ) . mockResolvedValue ( { authenticated : false } ) ;
7282 ( getCurrentUser as jest . Mock ) . mockResolvedValue ( 'test-user' ) ;
7383 renderWithRouter ( < Navbar /> ) ;
7484 const link = screen . getByRole ( 'link' , { name : / V e r s i o n : / } ) ;
@@ -77,15 +87,27 @@ describe('Navbar', () => {
7787 expect ( link ) . toHaveAttribute ( 'rel' , expect . stringContaining ( 'noopener' ) ) ;
7888 } ) ;
7989
90+ it ( 'shows logout when user is authenticated' , async ( ) => {
91+ ( getAppVersion as jest . Mock ) . mockResolvedValue ( '1.2.3' ) ;
92+ ( getAuthStatus as jest . Mock ) . mockResolvedValue ( { authenticated : true } ) ;
93+ ( getCurrentUser as jest . Mock ) . mockResolvedValue ( 'admin' ) ;
94+ renderWithRouter ( < Navbar /> ) ;
95+ await waitFor ( ( ) => {
96+ expect ( screen . getByRole ( 'link' , { name : 'Logout' } ) ) . toHaveAttribute ( 'href' , '/logout' ) ;
97+ } ) ;
98+ } ) ;
99+
80100 it ( 'renders initial user state as ellipsis' , ( ) => {
81101 ( getAppVersion as jest . Mock ) . mockImplementation ( ( ) => new Promise ( ( ) => { } ) ) ;
102+ ( getAuthStatus as jest . Mock ) . mockResolvedValue ( { authenticated : false } ) ;
82103 ( getCurrentUser as jest . Mock ) . mockImplementation ( ( ) => new Promise ( ( ) => { } ) ) ;
83104 renderWithRouter ( < Navbar /> ) ;
84- expect ( screen . getByText ( / U s e r : … / ) ) . toBeInTheDocument ( ) ;
105+ expect ( screen . getByText ( / U s e r : \u2026 / ) ) . toBeInTheDocument ( ) ;
85106 } ) ;
86107
87108 it ( 'fetches and displays the current user on success' , async ( ) => {
88109 ( getAppVersion as jest . Mock ) . mockResolvedValue ( '1.2.3' ) ;
110+ ( getAuthStatus as jest . Mock ) . mockResolvedValue ( { authenticated : true } ) ;
89111 ( getCurrentUser as jest . Mock ) . mockResolvedValue ( 'admin' ) ;
90112 renderWithRouter ( < Navbar /> ) ;
91113 await waitFor ( ( ) => {
@@ -95,6 +117,7 @@ describe('Navbar', () => {
95117
96118 it ( 'displays "unknown" for user if fetch fails' , async ( ) => {
97119 ( getAppVersion as jest . Mock ) . mockResolvedValue ( '1.2.3' ) ;
120+ ( getAuthStatus as jest . Mock ) . mockResolvedValue ( { authenticated : false } ) ;
98121 ( getCurrentUser as jest . Mock ) . mockRejectedValue ( new Error ( 'Network error' ) ) ;
99122 renderWithRouter ( < Navbar /> ) ;
100123 await waitFor ( ( ) => {
@@ -104,6 +127,7 @@ describe('Navbar', () => {
104127
105128 it ( 'displays user ID in dropdown item' , async ( ) => {
106129 ( getAppVersion as jest . Mock ) . mockResolvedValue ( '1.2.3' ) ;
130+ ( getAuthStatus as jest . Mock ) . mockResolvedValue ( { authenticated : true } ) ;
107131 ( getCurrentUser as jest . Mock ) . mockResolvedValue ( 'johndoe' ) ;
108132 renderWithRouter ( < Navbar /> ) ;
109133 await waitFor ( ( ) => {
0 commit comments