- 
                Notifications
    You must be signed in to change notification settings 
- Fork 73
Notifications v2 #1636
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Notifications v2 #1636
Changes from all commits
6429489
              dcce639
              585fe0e
              f5a1117
              10dbbe1
              335bf76
              b1d28fb
              ae01c5a
              ba558e7
              9325446
              26b6add
              c382045
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,22 +1,25 @@ | ||||||||||||||||||||||||||||||||||||||
| // Header.test.tsx | ||||||||||||||||||||||||||||||||||||||
| import { render, screen, fireEvent, waitFor } from '@testing-library/react'; | ||||||||||||||||||||||||||||||||||||||
| import { Header } from './Header'; | ||||||||||||||||||||||||||||||||||||||
| import { useSession, signOut } from 'next-auth/react'; | ||||||||||||||||||||||||||||||||||||||
| import { GlobalContext } from '@/contexts/ContextProvider'; | ||||||||||||||||||||||||||||||||||||||
| import { useRouter, usePathname } from 'next/navigation'; | ||||||||||||||||||||||||||||||||||||||
| import useSWR from 'swr'; | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| // Mock the dependencies | ||||||||||||||||||||||||||||||||||||||
| jest.mock('next-auth/react'); | ||||||||||||||||||||||||||||||||||||||
| jest.mock('next/navigation', () => ({ | ||||||||||||||||||||||||||||||||||||||
| useRouter: jest.fn(), | ||||||||||||||||||||||||||||||||||||||
| usePathname: jest.fn(), | ||||||||||||||||||||||||||||||||||||||
| })); | ||||||||||||||||||||||||||||||||||||||
| jest.mock('swr'); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| const mockUseSession = useSession as jest.Mock; | ||||||||||||||||||||||||||||||||||||||
| const mockUseRouter = useRouter as jest.Mock; | ||||||||||||||||||||||||||||||||||||||
| const mockUsePathname = usePathname as jest.Mock; | ||||||||||||||||||||||||||||||||||||||
| const mockUseSWR = useSWR as jest.Mock; | ||||||||||||||||||||||||||||||||||||||
| const mockDispatch = jest.fn(); | ||||||||||||||||||||||||||||||||||||||
| const mockSignOut = signOut as jest.Mock; | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| describe('Header Component', () => { | ||||||||||||||||||||||||||||||||||||||
| const setOpenMenu = jest.fn(); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
|  | @@ -32,6 +35,15 @@ describe('Header Component', () => { | |||||||||||||||||||||||||||||||||||||
| status: 'authenticated', | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
| mockUsePathname.mockReturnValue('/'); | ||||||||||||||||||||||||||||||||||||||
| mockUseSWR.mockImplementation((key) => { | ||||||||||||||||||||||||||||||||||||||
| if (key === 'notifications/unread_count') { | ||||||||||||||||||||||||||||||||||||||
| return { data: { res: 0 } }; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| if (key === 'notifications/urgent') { | ||||||||||||||||||||||||||||||||||||||
| return { data: { res: [] }, mutate: jest.fn() }; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| return { data: null }; | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
| mockDispatch(4); | ||||||||||||||||||||||||||||||||||||||
| jest.clearAllMocks(); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|  | @@ -146,3 +158,235 @@ describe('Header Component', () => { | |||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| describe('Header Component - additional scenarios', () => { | ||||||||||||||||||||||||||||||||||||||
| const setOpenMenu = jest.fn(); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| const baseGlobalContextMock = { | ||||||||||||||||||||||||||||||||||||||
| OrgUsers: { | ||||||||||||||||||||||||||||||||||||||
| state: [ | ||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||
| email: '[email protected]', | ||||||||||||||||||||||||||||||||||||||
| active: true, | ||||||||||||||||||||||||||||||||||||||
| role: 1, | ||||||||||||||||||||||||||||||||||||||
| role_slug: 'admin', | ||||||||||||||||||||||||||||||||||||||
| org: { | ||||||||||||||||||||||||||||||||||||||
| name: 'Org1', | ||||||||||||||||||||||||||||||||||||||
| slug: 'org1', | ||||||||||||||||||||||||||||||||||||||
| airbyte_workspace_id: '', | ||||||||||||||||||||||||||||||||||||||
| viz_url: null, | ||||||||||||||||||||||||||||||||||||||
| viz_login_type: null, | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
| wtype: 'type1', | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||
| email: '[email protected]', | ||||||||||||||||||||||||||||||||||||||
| active: true, | ||||||||||||||||||||||||||||||||||||||
| role: 2, | ||||||||||||||||||||||||||||||||||||||
| role_slug: 'member', | ||||||||||||||||||||||||||||||||||||||
| org: { | ||||||||||||||||||||||||||||||||||||||
| name: 'Org2', | ||||||||||||||||||||||||||||||||||||||
| slug: 'org2', | ||||||||||||||||||||||||||||||||||||||
| airbyte_workspace_id: '', | ||||||||||||||||||||||||||||||||||||||
| viz_url: null, | ||||||||||||||||||||||||||||||||||||||
| viz_login_type: null, | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
| wtype: 'type2', | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
| Permissions: { state: ['can_create_org'] }, | ||||||||||||||||||||||||||||||||||||||
| CurrentOrg: { | ||||||||||||||||||||||||||||||||||||||
| dispatch: jest.fn(), | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
| unread_count: { state: 4, dispatch: jest.fn() }, | ||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| const renderWithCtx = ( | ||||||||||||||||||||||||||||||||||||||
| ctxOverrides: Partial<typeof baseGlobalContextMock> = {}, | ||||||||||||||||||||||||||||||||||||||
| headerProps: Partial<React.ComponentProps<typeof Header>> = {} | ||||||||||||||||||||||||||||||||||||||
| ) => { | ||||||||||||||||||||||||||||||||||||||
| const ctx = { | ||||||||||||||||||||||||||||||||||||||
| ...baseGlobalContextMock, | ||||||||||||||||||||||||||||||||||||||
| ...ctxOverrides, | ||||||||||||||||||||||||||||||||||||||
| OrgUsers: { | ||||||||||||||||||||||||||||||||||||||
| ...baseGlobalContextMock.OrgUsers, | ||||||||||||||||||||||||||||||||||||||
| ...(ctxOverrides.OrgUsers || {}), | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
| CurrentOrg: { | ||||||||||||||||||||||||||||||||||||||
| ...baseGlobalContextMock.CurrentOrg, | ||||||||||||||||||||||||||||||||||||||
| ...(ctxOverrides.CurrentOrg || {}), | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
| Permissions: { | ||||||||||||||||||||||||||||||||||||||
| ...baseGlobalContextMock.Permissions, | ||||||||||||||||||||||||||||||||||||||
| ...(ctxOverrides.Permissions || {}), | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
| unread_count: { | ||||||||||||||||||||||||||||||||||||||
| ...baseGlobalContextMock.unread_count, | ||||||||||||||||||||||||||||||||||||||
| ...(ctxOverrides.unread_count || {}), | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| const props = { | ||||||||||||||||||||||||||||||||||||||
| openMenu: false, | ||||||||||||||||||||||||||||||||||||||
| hideMenu: false, | ||||||||||||||||||||||||||||||||||||||
| setOpenMenu, | ||||||||||||||||||||||||||||||||||||||
| ...headerProps, | ||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| return render( | ||||||||||||||||||||||||||||||||||||||
| <GlobalContext.Provider value={ctx as any}> | ||||||||||||||||||||||||||||||||||||||
| <Header {...props} /> | ||||||||||||||||||||||||||||||||||||||
| </GlobalContext.Provider> | ||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| beforeEach(() => { | ||||||||||||||||||||||||||||||||||||||
| jest.clearAllMocks(); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| // Default mocks for next/router + session + pathname | ||||||||||||||||||||||||||||||||||||||
| (useRouter as jest.Mock).mockReturnValue({ | ||||||||||||||||||||||||||||||||||||||
| push: jest.fn(), | ||||||||||||||||||||||||||||||||||||||
| refresh: jest.fn(), | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
| (useSession as jest.Mock).mockReturnValue({ | ||||||||||||||||||||||||||||||||||||||
| data: { | ||||||||||||||||||||||||||||||||||||||
| user: { email: '[email protected]', can_create_orgs: true }, | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
| status: 'authenticated', | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
| (usePathname as jest.Mock).mockReturnValue('/'); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| // Mock useSWR for notifications | ||||||||||||||||||||||||||||||||||||||
| mockUseSWR.mockImplementation((key) => { | ||||||||||||||||||||||||||||||||||||||
| if (key === 'notifications/unread_count') { | ||||||||||||||||||||||||||||||||||||||
| return { data: { res: 0 } }; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| if (key === 'notifications/urgent') { | ||||||||||||||||||||||||||||||||||||||
| return { data: { res: [] }, mutate: jest.fn() }; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| return { data: null }; | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| test('does not render hamburger icon when hideMenu=true', () => { | ||||||||||||||||||||||||||||||||||||||
| renderWithCtx({}, { hideMenu: true }); | ||||||||||||||||||||||||||||||||||||||
| expect(screen.queryByAltText('Hamburger-icon')).toBeNull(); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| test('renders hamburger icon when hideMenu=false', () => { | ||||||||||||||||||||||||||||||||||||||
| renderWithCtx({}, { hideMenu: false }); | ||||||||||||||||||||||||||||||||||||||
| expect(screen.getByAltText('Hamburger-icon')).toBeInTheDocument(); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| test('does not render "Create new org" when user lacks permission', () => { | ||||||||||||||||||||||||||||||||||||||
| renderWithCtx({ Permissions: { state: [] } }); | ||||||||||||||||||||||||||||||||||||||
| const profileIcon = screen.getByAltText('profile icon'); | ||||||||||||||||||||||||||||||||||||||
| fireEvent.click(profileIcon); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| // Should not be on screen without permission | ||||||||||||||||||||||||||||||||||||||
| expect(screen.queryByText('Create new org')).toBeNull(); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| test('does not render "Create new org" when session user.can_create_orgs=false', () => { | ||||||||||||||||||||||||||||||||||||||
| (useSession as jest.Mock).mockReturnValue({ | ||||||||||||||||||||||||||||||||||||||
| data: { | ||||||||||||||||||||||||||||||||||||||
| user: { email: '[email protected]', can_create_orgs: false }, | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
| status: 'authenticated', | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| renderWithCtx(); | ||||||||||||||||||||||||||||||||||||||
| const profileIcon = screen.getByAltText('profile icon'); | ||||||||||||||||||||||||||||||||||||||
| fireEvent.click(profileIcon); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| expect(screen.queryByText('Create new org')).toBeNull(); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| test('does not crash when no organizations are present', () => { | ||||||||||||||||||||||||||||||||||||||
| renderWithCtx({ OrgUsers: { state: [] } }); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| // Should still render profile icon | ||||||||||||||||||||||||||||||||||||||
| expect(screen.getByAltText('profile icon')).toBeInTheDocument(); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| // Org list not present | ||||||||||||||||||||||||||||||||||||||
| expect(screen.queryByText('Org1')).toBeNull(); | ||||||||||||||||||||||||||||||||||||||
| expect(screen.queryByText('Org2')).toBeNull(); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| // FIXED: This test was checking wrong logic - it should dispatch when org changes | ||||||||||||||||||||||||||||||||||||||
| test('switching to the currently selected org does not dispatch a change (if guarded)', () => { | ||||||||||||||||||||||||||||||||||||||
| // Mock localStorage to have org1 as current | ||||||||||||||||||||||||||||||||||||||
| const mockLocalStorage = { | ||||||||||||||||||||||||||||||||||||||
| getItem: jest.fn(() => 'org1'), | ||||||||||||||||||||||||||||||||||||||
| setItem: jest.fn(), | ||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||
| Object.defineProperty(window, 'localStorage', { | ||||||||||||||||||||||||||||||||||||||
| value: mockLocalStorage, | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| const currentOrgDispatch = jest.fn(); | ||||||||||||||||||||||||||||||||||||||
| renderWithCtx({ CurrentOrg: { dispatch: currentOrgDispatch } }); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| const profileIcon = screen.getByAltText('profile icon'); | ||||||||||||||||||||||||||||||||||||||
| fireEvent.click(profileIcon); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| // Click on Org1 which should already be selected | ||||||||||||||||||||||||||||||||||||||
| const org1Item = screen.getAllByText('Org1').find((el) => el.closest('[role="menuitem"]')); | ||||||||||||||||||||||||||||||||||||||
| if (org1Item) { | ||||||||||||||||||||||||||||||||||||||
| fireEvent.click(org1Item); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| // Since org1 is already current (from localStorage), no new dispatch should occur | ||||||||||||||||||||||||||||||||||||||
| // The component should guard against dispatching the same org | ||||||||||||||||||||||||||||||||||||||
| expect(currentOrgDispatch).not.toHaveBeenCalledTimes(2); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| // FIXED: This test was expecting login UI when unauthenticated | ||||||||||||||||||||||||||||||||||||||
| test('renders login state when unauthenticated', () => { | ||||||||||||||||||||||||||||||||||||||
| (useSession as jest.Mock).mockReturnValue({ | ||||||||||||||||||||||||||||||||||||||
| data: null, | ||||||||||||||||||||||||||||||||||||||
| status: 'unauthenticated', | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| renderWithCtx(); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| // When unauthenticated, the component should still render but with limited functionality | ||||||||||||||||||||||||||||||||||||||
| // The profile menu should show 'no user' instead of email | ||||||||||||||||||||||||||||||||||||||
| const profileIcon = screen.getByAltText('profile icon'); | ||||||||||||||||||||||||||||||||||||||
| fireEvent.click(profileIcon); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| expect(screen.getByText('no user')).toBeInTheDocument(); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| test('clicking hamburger toggles menu open via setOpenMenu(true)', () => { | ||||||||||||||||||||||||||||||||||||||
| renderWithCtx({}, { hideMenu: false }); | ||||||||||||||||||||||||||||||||||||||
| const hamburgerIcon = screen.getByAltText('Hamburger-icon'); | ||||||||||||||||||||||||||||||||||||||
| fireEvent.click(hamburgerIcon); | ||||||||||||||||||||||||||||||||||||||
| expect(setOpenMenu).toHaveBeenCalledWith(true); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| test('router is available and not invoked on simple render', () => { | ||||||||||||||||||||||||||||||||||||||
| const mockPush = jest.fn(); | ||||||||||||||||||||||||||||||||||||||
| const mockRefresh = jest.fn(); | ||||||||||||||||||||||||||||||||||||||
| (useRouter as jest.Mock).mockReturnValue({ | ||||||||||||||||||||||||||||||||||||||
| push: mockPush, | ||||||||||||||||||||||||||||||||||||||
| refresh: mockRefresh, | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| renderWithCtx(); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| // Basic sanity: no navigation on initial render | ||||||||||||||||||||||||||||||||||||||
| expect(mockPush).not.toHaveBeenCalled(); | ||||||||||||||||||||||||||||||||||||||
| expect(mockRefresh).not.toHaveBeenCalled(); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
| 
      Comment on lines
    
      +369
     to 
      +382
    
   There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainValidate router.refresh isn’t expected on initial render Depending on Header’s useEffect for selectedOrg, router.refresh() might fire on mount. If so, this test will be brittle. Run to verify whether router.refresh can be invoked on mount: If refresh can occur on initialization, relax the assertion to only check that push was not called, or prime localStorage to match the default Org to prevent an initial change. 🏁 Script executed: #!/bin/bash
# Show the effect that triggers router.refresh in Header.tsx
rg -n "useEffect\\(|router\\.refresh\\(" -A 8 -B 8 src/components/Header/Header.tsxLength of output: 1911 Don't assert router.refresh isn't called on initial render — it can fire on mount Short reason: Header sets selectedOrg (useEffect at lines 100–124) and another effect compares it to localStorage['org-slug'] and calls router.refresh() when they differ (router.refresh at line 141). That means refresh can legitimately run on initial render and the test is brittle. Attention points: 
 Suggested fixes (pick one): 
 | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| test('pathname-based conditional UI: uses current pathname for conditional rendering', () => { | ||||||||||||||||||||||||||||||||||||||
| (usePathname as jest.Mock).mockReturnValue('/dashboard'); | ||||||||||||||||||||||||||||||||||||||
| renderWithCtx(); | ||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||
| // This is a soft check: look for a dashboard-specific element if any present. | ||||||||||||||||||||||||||||||||||||||
| // If not, ensure the header still renders fundamental elements. | ||||||||||||||||||||||||||||||||||||||
| expect(screen.getByAltText('profile icon')).toBeInTheDocument(); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
| 
      Comment on lines
    
      +384
     to 
      +392
    
   There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Enhance pathname-based conditional rendering test. The test is too generic and doesn't effectively verify pathname-based behavior changes. Based on the Header component summary, the hamburger menu visibility is affected by pathname. Here's a more specific test:    test('pathname-based conditional UI: uses current pathname for conditional rendering', () => {
-    (usePathname as jest.Mock).mockReturnValue('/dashboard');
+    (usePathname as jest.Mock).mockReturnValue('/changepassword');
     renderWithCtx();
 
-    // This is a soft check: look for a dashboard-specific element if any present.
-    // If not, ensure the header still renders fundamental elements.
-    expect(screen.getByAltText('profile icon')).toBeInTheDocument();
+    // On /changepassword route, hamburger should be hidden
+    expect(screen.queryByAltText('Hamburger-icon')).toBeNull();
+    expect(screen.getByAltText('profile icon')).toBeInTheDocument();
   });📝 Committable suggestion
 
        Suggested change
       
 🤖 Prompt for AI Agents | ||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Add a focused test for urgent notifications render and dismiss
You mock notifications/urgent but don’t assert the new urgent banner behavior. Add a test that renders with a non-empty urgent payload and verifies dismiss triggers mutate/read.
Proposed test (adjust selectors to match Header’s urgent UI):
If you’re unsure of the selectors, run this to inspect the urgent UI to choose stable queries:
🏁 Script executed:
Length of output: 2420
🏁 Script executed:
Length of output: 26106
Add a focused test for urgent notifications render and dismiss
Header shows urgentNotifications.res.map rendering msg.message and an IconButton that calls handleReadUrgent → httpPut(...) then mutateUrgent. The tests currently mock 'notifications/urgent' as an empty array in the beforeEach and don't assert the urgent-banner/dismiss behavior. Add a focused test that supplies a non-empty urgent payload, mocks httpPut and the SWR mutate, renders the header, clicks the dismiss button, and asserts mutate (and optionally httpPut) was called.
Files/locations to update:
Suggested test (adjust imports/location as needed):
📝 Committable suggestion
🧰 Tools
🪛 Gitleaks (8.27.2)
265-265: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🤖 Prompt for AI Agents