test(trips): the suites follow the settings dialog's areas and the journal link

The dialog's nav buttons are named by their area alone (aria-label), so a hint line naming invites no longer matches the invite button. The sharing cases open the Sharing area first, the wiring and More sheet tests drive the settings button and row, the hook test reads the toasts as keys (renderHook loads no locale), and the lazy list and store registry know the journal panel and store.
This commit is contained in:
Maurice
2026-10-18 20:49:38 +02:00
parent ffa7333bb1
commit 92181cdefb
7 changed files with 21 additions and 14 deletions
@@ -291,6 +291,7 @@ describe('TripMembersModal', () => {
);
render(<TripMembersModal {...defaultProps} />);
await user.click(await screen.findByRole('button', { name: 'Sharing' }));
const createBtn = await screen.findByText('Create link');
await user.click(createBtn);
@@ -689,6 +690,7 @@ describe('TripMembersModal', () => {
http.delete('/api/trips/1/invite-link', () => HttpResponse.json({ success: true })),
);
const view = render(<TripMembersModal {...defaultProps} />);
await user.click(await screen.findByRole('button', { name: 'Sharing' }));
const createBtn = await screen.findByRole('button', { name: /Create invite link/i });
fireEvent.click(createBtn);
@@ -719,6 +721,7 @@ describe('TripMembersModal', () => {
asShareOwner();
server.use(http.post('/api/trips/1/invite-link', () => HttpResponse.json({}, { status: 500 })));
render(<TripMembersModal {...defaultProps} />);
await user.click(await screen.findByRole('button', { name: 'Sharing' }));
await user.click(await screen.findByRole('button', { name: /Create invite link/i }));
@@ -734,6 +737,7 @@ describe('TripMembersModal', () => {
http.delete('/api/trips/1/invite-link', () => HttpResponse.json({}, { status: 500 })),
);
render(<TripMembersModal {...defaultProps} />);
await user.click(await screen.findByRole('button', { name: 'Sharing' }));
await user.click(await screen.findByRole('button', { name: /Disable/i }));
@@ -133,7 +133,7 @@ function AreaNav({ areas, current, onPick }: { areas: typeof AREAS; current: Are
{areas.map(a => {
const on = a.id === current
return (
<button key={a.id} type="button" aria-current={on ? 'page' : undefined} onClick={() => onPick(a.id)}
<button key={a.id} type="button" aria-current={on ? 'page' : undefined} aria-label={t(a.labelKey)} onClick={() => onPick(a.id)}
className={`flex flex-none items-center gap-2.5 rounded-[12px] px-2.5 py-2 text-start transition-colors ${on ? 'bg-surface-card text-content shadow-sm ring-1 ring-edge-faint' : 'text-content-muted hover:bg-surface-hover hover:text-content'}`}>
<span className={`grid h-8 w-8 flex-none place-items-center rounded-[9px] ${on ? 'bg-accent text-accent-text' : 'bg-surface-tertiary'}`}>{a.icon(on)}</span>
<span className="min-w-0">
@@ -206,7 +206,7 @@ describe('useTripJournalLink', () => {
await result.current.save();
});
expect(writes).toEqual([{ method: 'PUT', body: { journey_id: 9, members: [{ user_id: 2, role: 'editor' }] } }]);
expect(toast.success).toHaveBeenCalledWith('Journal linked');
expect(toast.success).toHaveBeenCalledWith('trip.journal.linked');
expect(result.current.mode).toBe('view');
expect(result.current.link?.title).toBe('Japan');
});
@@ -234,7 +234,7 @@ describe('useTripJournalLink', () => {
},
},
]);
expect(toast.success).toHaveBeenCalledWith('Access saved');
expect(toast.success).toHaveBeenCalledWith('trip.journal.membersSaved');
});
it('FE-TJL-HOOK-011: unlinking takes the journal off the trip', async () => {
@@ -246,7 +246,7 @@ describe('useTripJournalLink', () => {
});
expect(writes).toEqual([{ method: 'DELETE', body: null }]);
expect(result.current.link).toBeNull();
expect(toast.success).toHaveBeenCalledWith('Journal unlinked');
expect(toast.success).toHaveBeenCalledWith('trip.journal.unlinked');
});
it('FE-TJL-HOOK-012: a refused save says it was not allowed and keeps the form open', async () => {
@@ -259,7 +259,7 @@ describe('useTripJournalLink', () => {
await act(async () => {
await result.current.save();
});
expect(toast.error).toHaveBeenCalledWith('You are not allowed to do that.');
expect(toast.error).toHaveBeenCalledWith('trip.journal.errorForbidden');
expect(result.current.mode).toBe('pick');
expect(result.current.busy).toBe(false);
});
@@ -269,7 +269,7 @@ describe('useTripJournalLink', () => {
await waitFor(() => expect(result.current.visible).toBe(true));
setForcedOffline(true);
act(() => result.current.startPick());
await waitFor(() => expect(toast.error).toHaveBeenCalledWith('Linking a journal needs a connection.'));
await waitFor(() => expect(toast.error).toHaveBeenCalledWith('trip.journal.errorOffline'));
expect(result.current.journals).toEqual([]);
});
@@ -281,7 +281,7 @@ describe('useTripJournalLink', () => {
await waitFor(() => expect(result.current.visible).toBe(true));
act(() => result.current.startPick());
act(() => result.current.pickJournal(9));
await waitFor(() => expect(toast.error).toHaveBeenCalledWith('That did not work. Please try again.'));
await waitFor(() => expect(toast.error).toHaveBeenCalledWith('trip.journal.errorGeneric'));
expect(result.current.candidates).toEqual([]);
act(() => result.current.cancel());
expect(result.current.mode).toBe('view');
@@ -657,14 +657,14 @@ describe('TripPlannerPage — shell', () => {
expect(container).toBeEmptyDOMElement()
})
it('FE-PAGE-TPW-005: the navbar gets the trip title and drives back / share', () => {
it('FE-PAGE-TPW-005: the navbar gets the trip title and drives back / settings', () => {
renderPage()
expect(props('navbar').tripTitle).toBe('Kyoto')
act(() => { props('navbar').onBack() })
expect(hookState.navigate).toHaveBeenCalledWith('/dashboard')
act(() => { props('navbar').onShare() })
act(() => { props('navbar').onSettings() })
expect(hookState.setShowMembersModal).toHaveBeenCalledWith(true)
})
@@ -24,6 +24,7 @@ vi.mock('../../components/Tours/planner/TourPlannerPanels', () => ({
TourPlannerToursRail: label('tour planner tours rail'),
}))
vi.mock('../../components/Planner/TransportModal', () => ({ TransportModal: label('transport modal') }))
vi.mock('./TripJournalPanel', () => ({ default: label('trip journal panel') }))
const cases: Array<[keyof typeof lazy, string]> = [
['ReservationsPanel', 'reservations panel'],
@@ -43,6 +44,7 @@ const cases: Array<[keyof typeof lazy, string]> = [
['TourWorkspaceRail', 'tour workspace rail'],
['TourPlannerToursRail', 'tour planner tours rail'],
['TransportModal', 'transport modal'],
['TripJournalPanel', 'trip journal panel'],
]
function renderLazy(name: keyof typeof lazy) {
+1
View File
@@ -59,4 +59,5 @@ export const UNRESET_STORES: Record<string, string> = {
useSystemNoticeStore: NOT_YET,
useTourFerrataCrossingStore: 'set by the tour map stage; the tests that read it reset it in their own beforeEach',
useTourPlaceToolStore: 'reset in the tour tests themselves to initialTourPlaceToolState()',
useTripJournalLinkStore: 'the journal link per trip; the tests that read it reset it in their own beforeEach',
};
@@ -104,7 +104,7 @@ describe('MMehrSheet', () => {
it('FE-MOB-MEHR-009: the action rows open the share, export and edit sheets', () => {
const { shell } = renderSheet()
fireEvent.click(screen.getByRole('button', { name: 'Share Trip' }))
fireEvent.click(screen.getByRole('button', { name: 'Trip settings' }))
fireEvent.click(screen.getByRole('button', { name: 'Export' }))
fireEvent.click(screen.getByRole('button', { name: 'Edit Trip' }))
expect(shell.openSheet).toHaveBeenNthCalledWith(1, 'members')
@@ -116,7 +116,7 @@ describe('MMehrSheet', () => {
const { planner } = renderSheet({ can: vi.fn(() => false) })
expect(planner.can).toHaveBeenCalledWith('trip_edit', planner.trip)
expect(screen.queryByRole('button', { name: 'Edit Trip' })).not.toBeInTheDocument()
expect(screen.getByRole('button', { name: 'Share Trip' })).toBeInTheDocument()
expect(screen.getByRole('button', { name: 'Trip settings' })).toBeInTheDocument()
})
it('FE-MOB-MEHR-011: renders only the action rows when every section sits in the dock', () => {
@@ -124,13 +124,13 @@ describe('MMehrSheet', () => {
TRIP_TABS: TABS.filter(tab => tab.id !== 'dateien' && tab.id !== 'collab') as TripPlanner['TRIP_TABS'],
})
expect(screen.queryByText(/files$/)).not.toBeInTheDocument()
const rows = screen.getByRole('button', { name: 'Share Trip' }).parentElement
const rows = screen.getByRole('button', { name: 'Trip settings' }).parentElement
expect(rows).not.toHaveClass('mt-2')
})
it('FE-MOB-MEHR-012: separates the action rows from the tile grid when both are present', () => {
renderSheet()
const rows = screen.getByRole('button', { name: 'Share Trip' }).parentElement
const rows = screen.getByRole('button', { name: 'Trip settings' }).parentElement
expect(rows).toHaveClass('mt-2')
})
@@ -172,7 +172,7 @@ describe('MMehrSheet', () => {
// Five sections still fit beside the More button, so nothing overflows and the
// sheet is the action rows alone.
expect(screen.queryByRole('button', { name: 'Lists' })).not.toBeInTheDocument()
expect(screen.getByRole('button', { name: 'Share Trip' }).parentElement).not.toHaveClass('mt-2')
expect(screen.getByRole('button', { name: 'Trip settings' }).parentElement).not.toHaveClass('mt-2')
})
})
})