diff --git a/src/App.test.tsx b/src/App.test.tsx index e90da4b..9a69242 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -18,7 +18,7 @@ describe('App Component', () => { // Check if navigation elements are present expect(screen.getAllByText('About').length).toBeGreaterThan(0) - expect(screen.getAllByText('Partners').length).toBeGreaterThan(0) + expect(screen.getAllByText('Verticals').length).toBeGreaterThan(0) expect(screen.getAllByText('News & Updates').length).toBeGreaterThan(0) }) diff --git a/src/__tests__/home.test.tsx b/src/__tests__/home.test.tsx index 7a48a0a..8721aa7 100644 --- a/src/__tests__/home.test.tsx +++ b/src/__tests__/home.test.tsx @@ -46,37 +46,4 @@ describe('Home page', () => { renderHome(false) expect(screen.getByText(/Built for Developers,/i)).toBeInTheDocument() }) - - describe('Partners section', () => { - it('renders the Partners section heading', () => { - renderHome(false) - const heading = screen.getByRole('heading', { - level: 2, - name: /Our Partners/i, - }) - expect(heading).toBeInTheDocument() - }) - - it('renders the Partners section tagline', () => { - renderHome(false) - expect( - screen.getByText(/Building a foundation of trust for every industry/i) - ).toBeInTheDocument() - }) - - it('renders the View All Partners button', () => { - renderHome(false) - expect( - screen.getByRole('button', { name: /View All Partners/i }) - ).toBeInTheDocument() - }) - - it('renders at least one partner logo', () => { - renderHome(false) - const imgs = screen.getAllByRole('img', { - name: 'Institute of Technical Education', - }) - expect(imgs[0]).toBeInTheDocument() - }) - }) }) diff --git a/src/components/common/Navbar/Navbar.test.tsx b/src/components/common/Navbar/Navbar.test.tsx index c87fd6e..f3868a9 100644 --- a/src/components/common/Navbar/Navbar.test.tsx +++ b/src/components/common/Navbar/Navbar.test.tsx @@ -1,6 +1,6 @@ import React from 'react' import { describe, it, expect, vi, beforeEach } from 'vitest' -import { render, screen, fireEvent } from '@testing-library/react' +import { render, screen, fireEvent, within } from '@testing-library/react' import { MemoryRouter } from 'react-router-dom' import Navbar from './Navbar' @@ -37,10 +37,74 @@ describe('Navbar Component', () => { ) // home remove from navbar expect(screen.getAllByText('About').length).toBeGreaterThan(0) - expect(screen.getAllByText('Partners').length).toBeGreaterThan(0) + expect(screen.getAllByText('Verticals').length).toBeGreaterThan(0) expect(screen.getAllByText('News & Updates').length).toBeGreaterThan(0) }) + it('opens the Verticals dropdown with external links', () => { + renderWithRouter( + + ) + + fireEvent.click( + screen.getByRole('button', { name: /toggle verticals menu/i }) + ) + + const menu = screen.getByRole('menu', { name: /verticals menu/i }) + expect(menu).toBeInTheDocument() + expect( + screen.getByRole('menuitem', { name: 'TradeTrust' }) + ).toHaveAttribute('href', 'https://tradetrust.io/') + expect(screen.getByRole('menuitem', { name: 'OpenCerts' })).toHaveAttribute( + 'href', + 'https://opencerts.io/' + ) + expect(screen.getByRole('menuitem', { name: 'SAL' })).toHaveAttribute( + 'href', + 'https://legalisation.sal.sg/' + ) + }) + + it('selecting a mobile Verticals link closes both mobile and desktop menus', () => { + renderWithRouter( + + ) + + // Open the mobile menu via the hamburger button + const hamburgerButton = screen + .getAllByRole('button') + .find(btn => btn.querySelector('svg path[d*="M20.1694 16.75"]')) + fireEvent.click(hamburgerButton!) + + const mobileMenu = screen.getByRole('navigation', { + name: /mobile navigation menu/i, + }) + + // Open the Verticals submenu from within the mobile menu + fireEvent.click( + within(mobileMenu).getByRole('button', { + name: /toggle verticals menu/i, + }) + ) + + const mobileLink = within(mobileMenu).getByText('TradeTrust') + + // mousedown must NOT close the submenu (clicks inside the mobile + // container are contained), or the link unmounts before click fires + fireEvent.mouseDown(mobileLink) + expect(within(mobileMenu).getByText('TradeTrust')).toBeInTheDocument() + + fireEvent.click(mobileLink) + + // Selecting the link closes both the mobile menu and the dropdown + expect( + screen.queryByRole('navigation', { name: /mobile navigation menu/i }) + ).not.toBeInTheDocument() + expect( + screen.queryByRole('menu', { name: /verticals menu/i }) + ).not.toBeInTheDocument() + }) + it('renders Contact Us button', () => { renderWithRouter( diff --git a/src/components/common/Navbar/Navbar.tsx b/src/components/common/Navbar/Navbar.tsx index dafc516..c0e7a97 100644 --- a/src/components/common/Navbar/Navbar.tsx +++ b/src/components/common/Navbar/Navbar.tsx @@ -7,14 +7,22 @@ interface NavbarProps { setIsDarkMode: Dispatch> } +const VERTICAL_LINKS = [ + { label: 'TradeTrust', href: 'https://tradetrust.io/' }, + { label: 'OpenCerts', href: 'https://opencerts.io/' }, + { label: 'SAL', href: 'https://legalisation.sal.sg/' }, +] + const Navbar = ({ isDarkMode, setIsDarkMode: _setIsDarkMode }: NavbarProps) => { const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false) const [_isEcosystemOpen, setIsEcosystemOpen] = useState(false) + const [isVerticalsOpen, setIsVerticalsOpen] = useState(false) const navRef = useRef(null) + const verticalsRef = useRef(null) + const mobileMenuRef = useRef(null) const location = useLocation() const isSettingsActive = location.pathname.startsWith('/settings') const isNewsActive = location.pathname.startsWith('/news-updates') - const isPartnersActive = location.pathname.startsWith('/partners') const isAboutActive = location.pathname.startsWith('/about') useEffect(() => { @@ -26,11 +34,20 @@ const Navbar = ({ isDarkMode, setIsDarkMode: _setIsDarkMode }: NavbarProps) => { ) { setIsMobileMenuOpen(false) setIsEcosystemOpen(false) + setIsVerticalsOpen(false) + } + if ( + isVerticalsOpen && + verticalsRef.current && + !verticalsRef.current.contains(e.target as Node) && + !mobileMenuRef.current?.contains(e.target as Node) + ) { + setIsVerticalsOpen(false) } } document.addEventListener('mousedown', handleClickOutside) return () => document.removeEventListener('mousedown', handleClickOutside) - }, [isMobileMenuOpen]) + }, [isMobileMenuOpen, isVerticalsOpen]) return (