import { fireEvent, render, screen } from '@testing-library/react'; import { describe, expect, it, vi } from 'vitest'; import { TripRouteOverviewPanel, TripRouteOverviewPill } from './TripRouteOverview'; import type { TripRouteOverview } from './useTripRouteOverview'; const overview = (over: Partial = {}): TripRouteOverview => ({ days: [ { dayId: 1, dayNumber: 1, date: '2025-06-01', title: null, color: { line: '#0a84ff', casing: '#0a5cc2' }, lines: [], segments: [], distance: 82000, duration: 3600, modes: ['driving'], }, { dayId: 2, dayNumber: 2, date: '2025-06-02', title: 'Coast road', color: { line: '#ff9f0a', casing: '#c2740a' }, lines: [], segments: [], distance: 140500, duration: 7200, modes: ['driving', 'walking'], }, ], lines: [], lineColors: [], segments: [], focusPoints: [], totalDistance: 222500, totalDuration: 10800, loading: false, ...over, }); describe('TripRouteOverviewPill', () => { it('FE-MAP-TROU-001: says which way it will take you, and reports its state', () => { const onToggle = vi.fn(); const { rerender } = render(); const button = screen.getByTestId('trip-overview-pill'); expect(button).toHaveAttribute('aria-pressed', 'false'); expect(button).toHaveAttribute('aria-label', 'map.overview.show'); fireEvent.click(button); expect(onToggle).toHaveBeenCalledTimes(1); rerender(); expect(screen.getByTestId('trip-overview-pill')).toHaveAttribute('aria-label', 'map.overview.hide'); }); }); describe('TripRouteOverviewPanel', () => { it("FE-MAP-TROU-002: leads with the trip total in the reader's own unit", () => { const { rerender } = render(); expect(screen.getByText('222.5 km')).toBeInTheDocument(); rerender(); expect(screen.getByText('138.3 mi')).toBeInTheDocument(); }); it('FE-MAP-TROU-003: names every day, its distance and how it is travelled', () => { render(); expect(screen.getByText('dayplan.dayN')).toBeInTheDocument(); // A day with a title is named by it rather than by its number. expect(screen.getByText('Coast road')).toBeInTheDocument(); expect(screen.getByText('82 km')).toBeInTheDocument(); expect(screen.getByText('140.5 km')).toBeInTheDocument(); }); it('FE-MAP-TROU-004: marks the total as partial while legs are still coming in', () => { const { container, rerender } = render( ); expect(container.textContent).toContain('…'); rerender(); expect(container.textContent).not.toContain('…'); }); it('FE-MAP-TROU-005: a day row picks that day when the shell offers it', () => { const onSelectDay = vi.fn(); render(); fireEvent.click(screen.getByText('Coast road')); expect(onSelectDay).toHaveBeenCalledWith(2); }); it('FE-MAP-TROU-006: read-only shells get rows, not buttons', () => { render(); expect(screen.queryAllByRole('button')).toHaveLength(0); }); it('FE-MAP-TROU-008: hugs its rows, and takes the cap the shell gives it', () => { const { container, rerender } = render(); const card = () => screen.getByTestId('trip-overview-panel'); expect(card().style.width).toBe('fit-content'); expect(card().style.maxWidth).toBe('320px'); // The phone shell asks for a narrower card so the map keeps the space. rerender(); expect(card().style.maxWidth).toBe('240px'); expect(container).not.toBeEmptyDOMElement(); }); it('FE-MAP-TROU-007: draws nothing at all for a trip with no routed day', () => { const { container } = render( ); expect(container).toBeEmptyDOMElement(); }); it('FE-MAP-TROU-009: says when legs could not be routed, and marks the day that is short', () => { // A refused leg stays a straight line and adds nothing to the sum, so a total shown // without a word about it reads as the whole trip when it is not. const days = overview().days; const short = overview({ days: [ { ...days[0], unroutedLegs: 1 }, { ...days[1], unroutedLegs: 0 }, ], unroutedLegs: 1, }); render(); expect(screen.getByTestId('trip-overview-unrouted')).toHaveTextContent('map.overview.unrouted'); expect(screen.getAllByRole('img', { name: 'map.overview.dayUnrouted' })).toHaveLength(1); }); it('FE-MAP-TROU-010: does not call a leg unrouted while the round is still running', () => { // Every leg still waiting is unrouted too; the ellipsis already says the number grows. const days = overview().days; const running = overview({ days: [ { ...days[0], unroutedLegs: 1 }, { ...days[1], unroutedLegs: 1 }, ], unroutedLegs: 2, loading: true, }); render(); expect(screen.queryByTestId('trip-overview-unrouted')).toBeNull(); expect(screen.queryByRole('img', { name: 'map.overview.dayUnrouted' })).toBeNull(); }); it('FE-MAP-TROU-011: a fully routed trip carries no warning at all', () => { render(); expect(screen.queryByTestId('trip-overview-unrouted')).toBeNull(); expect(screen.queryByRole('img', { name: 'map.overview.dayUnrouted' })).toBeNull(); }); });