fix(tests): restore packing panel inline header + update tests for ui changes

- PackingListPanel accepts inlineHeader prop (default true) to keep its
  legacy title and inline import button; ListsContainer passes
  inlineHeader={false} since the toolbar now owns those controls
- ReservationModal tests look for the renamed 'Car' button (was 'Rental Car')
- Budget total-budget test asserts against the split integer/decimal
  spans that replaced the single text node
This commit is contained in:
Maurice
2026-04-17 23:56:42 +02:00
parent 189b257254
commit 71637a8483
4 changed files with 34 additions and 13 deletions
@@ -416,8 +416,8 @@ describe('BudgetPanel', () => {
render(<BudgetPanel tripId={1} />); render(<BudgetPanel tripId={1} />);
await screen.findByText('Flight'); await screen.findByText('Flight');
await screen.findByText('Hotel'); await screen.findByText('Hotel');
// Grand total card shows 300.00 // Grand total card shows 300.00 (integer and decimal are rendered in separate spans)
expect(screen.getByText('300.00')).toBeInTheDocument(); expect(document.body.textContent?.replace(/\s+/g, '')).toMatch(/300[,.]00/);
}); });
it('FE-COMP-BUDGET-033: read-only mode hides add/delete/edit controls', async () => { it('FE-COMP-BUDGET-033: read-only mode hides add/delete/edit controls', async () => {
@@ -730,9 +730,10 @@ interface PackingListPanelProps {
tripId: number tripId: number
items: PackingItem[] items: PackingItem[]
openImportSignal?: number openImportSignal?: number
inlineHeader?: boolean
} }
export default function PackingListPanel({ tripId, items, openImportSignal = 0 }: PackingListPanelProps) { export default function PackingListPanel({ tripId, items, openImportSignal = 0, inlineHeader = true }: PackingListPanelProps) {
const [filter, setFilter] = useState('alle') // 'alle' | 'offen' | 'erledigt' const [filter, setFilter] = useState('alle') // 'alle' | 'offen' | 'erledigt'
const [addingCategory, setAddingCategory] = useState(false) const [addingCategory, setAddingCategory] = useState(false)
const [newCatName, setNewCatName] = useState('') const [newCatName, setNewCatName] = useState('')
@@ -1008,14 +1009,34 @@ export default function PackingListPanel({ tripId, items, openImportSignal = 0 }
<div style={{ display: 'flex', flexDirection: 'column', height: '100%', ...font }}> <div style={{ display: 'flex', flexDirection: 'column', height: '100%', ...font }}>
{/* ── Header ── */} {/* ── Header ── */}
<div style={{ padding: '0 0 16px', flexShrink: 0 }}> <div style={{ padding: inlineHeader ? '20px 24px 16px' : '0 0 16px', flexShrink: 0, borderBottom: inlineHeader ? '1px solid rgba(0,0,0,0.06)' : undefined }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 14 }}> <div style={{ display: 'flex', alignItems: inlineHeader ? 'flex-start' : 'center', justifyContent: 'space-between', gap: 14 }}>
{items.length > 0 ? ( {inlineHeader ? (
<p style={{ margin: 0, fontSize: 12.5, color: 'var(--text-faint)' }}> <div>
{t('packing.progress', { packed: abgehakt, total: items.length, percent: fortschritt })} <h2 style={{ margin: 0, fontSize: 18, fontWeight: 700, color: 'var(--text-primary)' }}>{t('packing.title')}</h2>
</p> {items.length > 0 && (
) : <span />} <p style={{ margin: '2px 0 0', fontSize: 12.5, color: 'var(--text-faint)' }}>
{t('packing.progress', { packed: abgehakt, total: items.length, percent: fortschritt })}
</p>
)}
</div>
) : (
items.length > 0 ? (
<p style={{ margin: 0, fontSize: 12.5, color: 'var(--text-faint)' }}>
{t('packing.progress', { packed: abgehakt, total: items.length, percent: fortschritt })}
</p>
) : <span />
)}
<div style={{ display: 'flex', gap: 6 }}> <div style={{ display: 'flex', gap: 6 }}>
{inlineHeader && canEdit && (
<button onClick={() => setShowImportModal(true)} style={{
display: 'flex', alignItems: 'center', gap: 5, padding: '5px 11px', borderRadius: 99,
border: '1px solid var(--border-primary)', fontSize: 12, fontWeight: 500, cursor: 'pointer',
fontFamily: 'inherit', background: 'var(--bg-card)', color: 'var(--text-muted)',
}}>
<Upload size={12} /> <span className="hidden sm:inline">{t('packing.import')}</span>
</button>
)}
{canEdit && abgehakt > 0 && ( {canEdit && abgehakt > 0 && (
<button onClick={handleClearChecked} style={{ <button onClick={handleClearChecked} style={{
fontSize: 11.5, padding: '5px 10px', borderRadius: 99, border: '1px solid rgba(239,68,68,0.3)', fontSize: 11.5, padding: '5px 10px', borderRadius: 99, border: '1px solid rgba(239,68,68,0.3)',
@@ -107,7 +107,7 @@ describe('ReservationModal', () => {
expect(screen.getByRole('button', { name: /Accommodation/i })).toBeInTheDocument(); expect(screen.getByRole('button', { name: /Accommodation/i })).toBeInTheDocument();
expect(screen.getByRole('button', { name: /Restaurant/i })).toBeInTheDocument(); expect(screen.getByRole('button', { name: /Restaurant/i })).toBeInTheDocument();
expect(screen.getByRole('button', { name: /Train/i })).toBeInTheDocument(); expect(screen.getByRole('button', { name: /Train/i })).toBeInTheDocument();
expect(screen.getByRole('button', { name: /Rental Car/i })).toBeInTheDocument(); expect(screen.getByRole('button', { name: /^Car$/i })).toBeInTheDocument();
expect(screen.getByRole('button', { name: /Cruise/i })).toBeInTheDocument(); expect(screen.getByRole('button', { name: /Cruise/i })).toBeInTheDocument();
expect(screen.getByRole('button', { name: /Event/i })).toBeInTheDocument(); expect(screen.getByRole('button', { name: /Event/i })).toBeInTheDocument();
expect(screen.getByRole('button', { name: /Tour/i })).toBeInTheDocument(); expect(screen.getByRole('button', { name: /Tour/i })).toBeInTheDocument();
@@ -636,7 +636,7 @@ describe('ReservationModal', () => {
it('FE-PLANNER-RESMODAL-045: car type shows date/time section', async () => { it('FE-PLANNER-RESMODAL-045: car type shows date/time section', async () => {
render(<ReservationModal {...defaultProps} />); render(<ReservationModal {...defaultProps} />);
await userEvent.click(screen.getByRole('button', { name: /Rental Car/i })); await userEvent.click(screen.getByRole('button', { name: /^Car$/i }));
// Car type still shows date fields (not hotel which hides them) // Car type still shows date fields (not hotel which hides them)
await waitFor(() => { await waitFor(() => {
expect(screen.getAllByTestId('date-picker').length).toBeGreaterThan(0); expect(screen.getAllByTestId('date-picker').length).toBeGreaterThan(0);
+1 -1
View File
@@ -129,7 +129,7 @@ function ListsContainer({ tripId, packingItems, todoItems }: { tripId: number; p
</div> </div>
</div> </div>
<div style={{ padding: '16px 28px 0' }} className="max-md:!px-4"> <div style={{ padding: '16px 28px 0' }} className="max-md:!px-4">
{subTab === 'packing' && <PackingListPanel tripId={tripId} items={packingItems} openImportSignal={importPackingSignal} />} {subTab === 'packing' && <PackingListPanel tripId={tripId} items={packingItems} openImportSignal={importPackingSignal} inlineHeader={false} />}
{subTab === 'todo' && <TodoListPanel tripId={tripId} items={todoItems} addItemSignal={addTodoSignal} />} {subTab === 'todo' && <TodoListPanel tripId={tripId} items={todoItems} addItemSignal={addTodoSignal} />}
</div> </div>
</div> </div>