fix(header): close navigation dropdown immediately on pathname change
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Successful in 1m9s
Build & Deploy / 🏗️ Build (push) Successful in 2m39s
Build & Deploy / 🚀 Deploy (push) Successful in 26s
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Successful in 1m9s
Build & Deploy / 🏗️ Build (push) Successful in 2m39s
Build & Deploy / 🚀 Deploy (push) Successful in 26s
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
This commit is contained in:
86
components/layout/Header.test.tsx
Normal file
86
components/layout/Header.test.tsx
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||||
|
import { render, screen, fireEvent, act, waitFor } from '@testing-library/react';
|
||||||
|
import { Header, NavLink } from './Header';
|
||||||
|
import { usePathname } from 'next/navigation';
|
||||||
|
|
||||||
|
// Mock next/navigation
|
||||||
|
vi.mock('next/navigation', () => ({
|
||||||
|
usePathname: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Mock TransitionLink to render standard anchor tag and forward all props
|
||||||
|
vi.mock('@/components/ui/TransitionLink', () => ({
|
||||||
|
TransitionLink: ({ children, href, onClick, ...props }: any) => (
|
||||||
|
<a href={href} onClick={onClick} {...props}>
|
||||||
|
{children}
|
||||||
|
</a>
|
||||||
|
),
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Mock next/image
|
||||||
|
vi.mock('next/image', () => ({
|
||||||
|
default: ({ src, alt, ...props }: any) => <img src={src} alt={alt} {...props} />,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Mock LanguageSwitcher
|
||||||
|
vi.mock('./LanguageSwitcher', () => ({
|
||||||
|
LanguageSwitcher: () => <div data-testid="language-switcher" />,
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('Header Dropdown Navigation TDD', () => {
|
||||||
|
const mockNavLinks: NavLink[] = [
|
||||||
|
{
|
||||||
|
label: 'Home',
|
||||||
|
url: '/',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Leistungen',
|
||||||
|
url: '/leistungen',
|
||||||
|
children: [
|
||||||
|
{ label: 'Kabelbau', url: '/leistungen/kabelbau' },
|
||||||
|
{ label: 'Bohrtechnik', url: '/leistungen/bohrtechnik' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('closes the dropdown menu immediately after a page navigation occurs', async () => {
|
||||||
|
// 1. Set initial pathname
|
||||||
|
let currentPath = '/de';
|
||||||
|
vi.mocked(usePathname).mockImplementation(() => currentPath);
|
||||||
|
|
||||||
|
// 2. Render Header
|
||||||
|
const { rerender } = render(<Header navLinks={mockNavLinks} />);
|
||||||
|
|
||||||
|
// 3. Hover over "Leistungen" menu item to open dropdown
|
||||||
|
const leistungenNavItem = screen.getByText('Leistungen');
|
||||||
|
const navItemContainer = leistungenNavItem.closest('.group');
|
||||||
|
expect(navItemContainer).toBeTruthy();
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
fireEvent.mouseEnter(navItemContainer!);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 4. Assert dropdown is open and children are rendered
|
||||||
|
expect(screen.getByText('Kabelbau')).toBeTruthy();
|
||||||
|
expect(screen.getByText('Bohrtechnik')).toBeTruthy();
|
||||||
|
|
||||||
|
// 5. Simulate page navigation by changing the path
|
||||||
|
currentPath = '/de/leistungen/kabelbau';
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
// Trigger pathname hook change and force rerender
|
||||||
|
rerender(<Header navLinks={mockNavLinks} />);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 6. Assert dropdown is closed (children are not in the document)
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.queryByText('Kabelbau')).toBeNull();
|
||||||
|
expect(screen.queryByText('Bohrtechnik')).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -164,6 +164,10 @@ export function Header({ navLinks }: HeaderProps) {
|
|||||||
function NavItem({ link, currentLocale, pathname, isSolidMode }: { link: NavLink, currentLocale: string, pathname: string, isSolidMode: boolean }) {
|
function NavItem({ link, currentLocale, pathname, isSolidMode }: { link: NavLink, currentLocale: string, pathname: string, isSolidMode: boolean }) {
|
||||||
const [isHovered, setIsHovered] = React.useState(false);
|
const [isHovered, setIsHovered] = React.useState(false);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
setIsHovered(false);
|
||||||
|
}, [pathname]);
|
||||||
|
|
||||||
const mappedUrl = link.url.startsWith('/') && !link.url.match(/^\/(en|de)/)
|
const mappedUrl = link.url.startsWith('/') && !link.url.match(/^\/(en|de)/)
|
||||||
? `/${currentLocale}${link.url}`
|
? `/${currentLocale}${link.url}`
|
||||||
: link.url;
|
: link.url;
|
||||||
|
|||||||
Reference in New Issue
Block a user