diff --git a/app/src/ModalContent.tsx b/app/src/ModalContent.tsx index 88627061..ec59cf1b 100644 --- a/app/src/ModalContent.tsx +++ b/app/src/ModalContent.tsx @@ -64,7 +64,7 @@ export function Welcome1({ clickAction1, map }: ChapterProps) { export const ModalContent = ({ map }: { map: any }) => { const navigate = useNavigate() - const [chapter, setChapter] = useState(1) + const [chapter] = useState(1) const close = () => { void navigate('/') @@ -78,9 +78,6 @@ export const ModalContent = ({ map }: { map: any }) => { map={map} clickAction1={() => { close() - setTimeout(() => { - setChapter(1) - }, 1000) }} /> ) diff --git a/cypress/e2e/info-modal/info-modal.cy.ts b/cypress/e2e/info-modal/info-modal.cy.ts new file mode 100644 index 00000000..50bda6b8 --- /dev/null +++ b/cypress/e2e/info-modal/info-modal.cy.ts @@ -0,0 +1,50 @@ +/// + +/** + * Info Modal Route E2E Tests + * + * Validates the route-based info modal introduced by PR #657: + * - Route /info renders the modal (E1) + * - NavBar ? link navigates to /info (E2) + * - Content "Close" button navigates back to / (E3) + */ + +describe('Info Modal Route', () => { + it('E1: visiting /info renders the info modal', () => { + cy.visit('/info') + + cy.get('.tw\\:card', { timeout: 15000 }).should('be.visible') + cy.get('.tw\\:backdrop-brightness-75').should('exist') + cy.contains('Close').should('be.visible') + cy.location('pathname').should('eq', '/info') + }) + + it('E2: NavBar ? icon navigates to /info', () => { + cy.visit('/') + cy.waitForMapReady() + + // Dismiss auto-opened modal if info_open is true in backend + cy.get('body').then(($body) => { + if ($body.find('.tw\\:backdrop-brightness-75').length > 0) { + cy.get('.tw\\:card button').contains('✕').click() + cy.location('pathname').should('eq', '/') + } + }) + + cy.get('a[href="/info"]').should('be.visible').click() + + cy.location('pathname').should('eq', '/info') + cy.get('.tw\\:card', { timeout: 10000 }).should('be.visible') + }) + + it('E3: content "Close" button closes modal and navigates to /', () => { + cy.visit('/info') + cy.get('.tw\\:card', { timeout: 15000 }).should('be.visible') + + cy.contains('label', 'Close').click() + + cy.location('pathname').should('eq', '/') + cy.get('.tw\\:backdrop-brightness-75').should('not.exist') + }) +}) + diff --git a/lib/src/Components/AppShell/InfoRedirect.spec.tsx b/lib/src/Components/AppShell/InfoRedirect.spec.tsx new file mode 100644 index 00000000..4f0f6249 --- /dev/null +++ b/lib/src/Components/AppShell/InfoRedirect.spec.tsx @@ -0,0 +1,78 @@ +import { render, cleanup } from '@testing-library/react' +import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' + +import { InfoRedirect } from './InfoRedirect' + +// --- Mocks --- + +const mockNavigate = vi.fn() + +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom') + return { + ...actual, + useNavigate: () => mockNavigate, + } +}) + +// Save original location so we can restore it after each test +const originalLocation = window.location + +// Helper to set window.location.pathname for tests +function setPathname(pathname: string) { + Object.defineProperty(window, 'location', { + value: { pathname, search: '', hash: '', href: `http://localhost${pathname}` }, + writable: true, + configurable: true, + }) +} + +// --- Tests --- + +describe('', () => { + beforeEach(() => { + vi.clearAllMocks() + setPathname('/') + }) + + afterEach(() => { + cleanup() + // Restore original window.location to avoid leaking into other test files + Object.defineProperty(window, 'location', { + value: originalLocation, + writable: true, + configurable: true, + }) + }) + + it('U1: navigates to /info when enabled and pathname is "/"', () => { + render() + + expect(mockNavigate).toHaveBeenCalledTimes(1) + expect(mockNavigate).toHaveBeenCalledWith('/info') + }) + + it('U2: does NOT navigate when enabled is false', () => { + render() + + expect(mockNavigate).not.toHaveBeenCalled() + }) + + it('U3: does NOT navigate when pathname is not "/"', () => { + setPathname('/login') + + render() + + expect(mockNavigate).not.toHaveBeenCalled() + }) + + it('U4: only navigates once even if re-rendered', () => { + const { rerender } = render() + + expect(mockNavigate).toHaveBeenCalledTimes(1) + + rerender() + + expect(mockNavigate).toHaveBeenCalledTimes(1) + }) +})