import { describe, expect, it, vi } from 'vitest' import MTripTabPanel from '../../../../src/mobile/screens/trip/tabs/MTripTabPanel' import type { MTabScreenProps } from '../../../../src/mobile/screens/trip/tabs/tabModel' import { buildPlanner, buildShell } from '../../../helpers/mobileTrip' import { render, screen } from '../../../helpers/render' // FE-MOB-TABPANEL-001 to FE-MOB-TABPANEL-010 /** Each tab is stubbed so the routing itself is what gets asserted. */ function stub(name: string) { return function Stub({ planner, shell }: MTabScreenProps) { return
} } vi.mock('../../../../src/mobile/screens/trip/tabs/MTransportsTab', () => ({ default: stub('transports') })) vi.mock('../../../../src/mobile/screens/trip/tabs/MBookingsTab', () => ({ default: stub('bookings') })) vi.mock('../../../../src/mobile/screens/trip/tabs/MCostsTab', () => ({ default: stub('costs') })) vi.mock('../../../../src/mobile/screens/trip/tabs/MFilesTab', () => ({ default: stub('files') })) vi.mock('../../../../src/mobile/screens/trip/tabs/MCollabTab', () => ({ default: stub('collab') })) vi.mock('../../../../src/mobile/screens/trip/tabs/MListsTab', () => ({ default: stub('lists') })) vi.mock('../../../../src/components/Plugins/PluginFrame', () => ({ default: ({ pluginId, tripId, fill, surface }: { pluginId: string; tripId: string | null; fill?: boolean; surface?: string }) => (
), })) function renderTab(tab: string, plannerOverrides = {}) { const planner = buildPlanner(plannerOverrides) const shell = buildShell({ trTab: tab }) return { ...render(), planner, shell } } describe('MTripTabPanel', () => { it('FE-MOB-TABPANEL-001: routes transports and hands both props down', () => { renderTab('transports') const panel = screen.getByTestId('transports') expect(panel).toHaveAttribute('data-trip', '1') expect(panel).toHaveAttribute('data-tab', 'transports') expect(screen.queryByTestId('bookings')).not.toBeInTheDocument() }) it('FE-MOB-TABPANEL-002: routes buchungen to the bookings panel', () => { renderTab('buchungen') expect(screen.getByTestId('bookings')).toBeInTheDocument() }) it('FE-MOB-TABPANEL-003: routes finanzplan to the costs panel', () => { renderTab('finanzplan') expect(screen.getByTestId('costs')).toBeInTheDocument() }) it('FE-MOB-TABPANEL-004: routes dateien to the files panel', () => { renderTab('dateien') expect(screen.getByTestId('files')).toBeInTheDocument() }) it('FE-MOB-TABPANEL-005: routes collab to the collab panel', () => { renderTab('collab') expect(screen.getByTestId('collab')).toBeInTheDocument() }) it('FE-MOB-TABPANEL-006: routes listen to the lists panel', () => { renderTab('listen') expect(screen.getByTestId('lists')).toBeInTheDocument() }) it('FE-MOB-TABPANEL-007: mounts the sandboxed frame for a plugin tab', () => { renderTab('plugin:trip-todos') const frame = screen.getByTestId('plugin-frame') expect(frame).toHaveAttribute('data-plugin', 'trip-todos') expect(frame).toHaveAttribute('data-trip', '1') expect(frame).toHaveAttribute('data-fill', 'true') // Both clearances come from the variables TabScroller uses, so the frame // cannot drift away from the native tabs. The top one was missing entirely, // which put the plugin's first row under the floating back button; the bottom // one was a hard-coded 84 that ignored the safe area. const wrapper = frame.parentElement as HTMLElement expect(wrapper.className).toContain('--m-safe-top') expect(wrapper.className).toContain('--bottom-nav-h') }) it('FE-MOB-TABPANEL-007b: tells the plugin which surface it is mounted in', () => { // A trip tab fills and scrolls itself; a widget reports its height. The plugin // cannot see the difference from inside the frame. renderTab('plugin:trip-todos') expect(screen.getByTestId('plugin-frame')).toHaveAttribute('data-surface', 'trip-tab') }) it('FE-MOB-TABPANEL-008: passes a null tripId to the plugin frame before the trip is known', () => { renderTab('plugin:koffi', { tripId: null }) expect(screen.getByTestId('plugin-frame')).toHaveAttribute('data-trip', 'null') }) it('FE-MOB-TABPANEL-009: keeps a plugin id that itself contains a colon intact', () => { renderTab('plugin:acme:maps') expect(screen.getByTestId('plugin-frame')).toHaveAttribute('data-plugin', 'acme:maps') }) it('FE-MOB-TABPANEL-010: an unbuilt tab falls back to the empty scroll body', () => { const { container } = renderTab('plan') expect(container.querySelector('[data-testid]')).toBeNull() const body = container.querySelector('.overflow-y-auto') as HTMLElement expect(body).not.toBeNull() expect(body).toBeEmptyDOMElement() }) })