mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-21 06:26:26 +00:00
fix(client): work through the findings from the coverage pass
214 items came out of writing the tests. Real defects are corrected, dead code is removed rather than covered, and the tests that pinned the old behaviour move with them. Also drops two agent coverage scratch files that slipped into the coverage PR and adds the ignore rule that keeps them out.
This commit is contained in:
@@ -229,24 +229,28 @@ describe('KategorieGruppe — bulk actions', () => {
|
||||
await waitFor(() => expect(puts).toEqual([1]))
|
||||
})
|
||||
|
||||
it('FE-W5CAT-012: a throwing toggle during Check All surfaces a save error', async () => {
|
||||
useTripStore.setState({ togglePackingItem: async () => { throw new Error('offline') } })
|
||||
it('FE-W5CAT-012: a failing PUT during Check All is reported by the store, once', async () => {
|
||||
server.use(http.put('/api/trips/1/packing/:itemId', () => new HttpResponse(null, { status: 500 })))
|
||||
seedStore(useTripStore, { packingItems: [buildPackingItem({ id: 1, name: 'Tent', checked: 0 })] })
|
||||
const { container } = setup({ items: [buildPackingItem({ id: 1, name: 'Tent', checked: 0 })] })
|
||||
openCategoryMenu(container)
|
||||
|
||||
fireEvent.click(screen.getByText('Check All'))
|
||||
|
||||
await waitFor(() => expect(toastSpy).toHaveBeenCalledWith('Failed to save', 'error', undefined))
|
||||
await waitFor(() => expect(toastSpy).toHaveBeenCalledWith('Error updating item', 'error', undefined))
|
||||
expect(toastSpy).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('FE-W5CAT-013: a throwing toggle during Uncheck All surfaces a save error', async () => {
|
||||
useTripStore.setState({ togglePackingItem: async () => { throw new Error('offline') } })
|
||||
it('FE-W5CAT-013: a failing PUT during Uncheck All is reported by the store, once', async () => {
|
||||
server.use(http.put('/api/trips/1/packing/:itemId', () => new HttpResponse(null, { status: 500 })))
|
||||
seedStore(useTripStore, { packingItems: [buildPackingItem({ id: 1, name: 'Tent', checked: 1 })] })
|
||||
const { container } = setup({ items: [buildPackingItem({ id: 1, name: 'Tent', checked: 1 })] })
|
||||
openCategoryMenu(container)
|
||||
|
||||
fireEvent.click(screen.getByText('Uncheck All'))
|
||||
|
||||
await waitFor(() => expect(toastSpy).toHaveBeenCalledWith('Failed to save', 'error', undefined))
|
||||
await waitFor(() => expect(toastSpy).toHaveBeenCalledWith('Error updating item', 'error', undefined))
|
||||
expect(toastSpy).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('FE-W5CAT-014: Delete List hands the whole category to the panel and closes the menu', async () => {
|
||||
|
||||
@@ -98,19 +98,17 @@ export function KategorieGruppe({ kategorie, items, tripId, allCategories, onRen
|
||||
catch { toast.error(t('packing.toast.renameError')) }
|
||||
}
|
||||
|
||||
// togglePackingItem rolls its own optimistic update back and reports the
|
||||
// failure itself, so the bulk actions just drive it item by item.
|
||||
const handleCheckAll = async () => {
|
||||
try {
|
||||
for (const item of Array.from(items)) {
|
||||
if (!item.checked) await togglePackingItem(tripId, item.id, true)
|
||||
}
|
||||
} catch { toast.error(t('packing.toast.saveError')) }
|
||||
for (const item of Array.from(items)) {
|
||||
if (!item.checked) await togglePackingItem(tripId, item.id, true)
|
||||
}
|
||||
}
|
||||
const handleUncheckAll = async () => {
|
||||
try {
|
||||
for (const item of Array.from(items)) {
|
||||
if (item.checked) await togglePackingItem(tripId, item.id, false)
|
||||
}
|
||||
} catch { toast.error(t('packing.toast.saveError')) }
|
||||
for (const item of Array.from(items)) {
|
||||
if (item.checked) await togglePackingItem(tripId, item.id, false)
|
||||
}
|
||||
}
|
||||
const handleDeleteAll = async () => {
|
||||
await onDeleteAll(items)
|
||||
@@ -304,7 +302,8 @@ export function KategorieGruppe({ kategorie, items, tripId, allCategories, onRen
|
||||
placeholder={t('packing.addItemPlaceholder')}
|
||||
style={{ flex: 1, padding: '6px 10px', borderRadius: 8, border: '1px solid var(--border-primary)', fontSize: 'calc(12.5px * var(--fs-scale-body, 1))', fontFamily: 'inherit', outline: 'none', color: 'var(--text-primary)', background: 'var(--bg-input)' }}
|
||||
/>
|
||||
<button onClick={() => { if (newItemName.trim()) { onAddItem(kategorie, newItemName.trim()); setNewItemName(''); setTimeout(() => addItemRef.current?.focus(), 30) } }}
|
||||
{/* disabled while the field is empty, so no extra guard here */}
|
||||
<button onClick={() => { onAddItem(kategorie, newItemName.trim()); setNewItemName(''); setTimeout(() => addItemRef.current?.focus(), 30) }}
|
||||
disabled={!newItemName.trim()}
|
||||
style={{ padding: '5px 8px', borderRadius: 8, border: 'none', background: newItemName.trim() ? 'var(--text-primary)' : 'var(--border-primary)', color: 'var(--bg-primary)', cursor: newItemName.trim() ? 'pointer' : 'default', display: 'flex' }}>
|
||||
<Plus size={14} />
|
||||
|
||||
@@ -120,7 +120,7 @@ function Row({ icon, label, sub, active, onClick }: { icon: React.ReactNode; lab
|
||||
<button onClick={onClick}
|
||||
style={{ display: 'flex', alignItems: 'flex-start', gap: 8, width: '100%', padding: '7px 10px', borderRadius: 7, border: 'none', cursor: 'pointer', background: active ? 'var(--bg-tertiary)' : 'none', fontFamily: 'inherit', textAlign: 'left' }}
|
||||
onMouseEnter={e => { if (!active) e.currentTarget.style.background = 'var(--bg-tertiary)' }}
|
||||
onMouseLeave={e => { if (!active) e.currentTarget.style.background = active ? 'var(--bg-tertiary)' : 'none' }}>
|
||||
onMouseLeave={e => { if (!active) e.currentTarget.style.background = 'none' }}>
|
||||
<span style={{ color: active ? 'var(--accent)' : 'var(--text-muted)', marginTop: 1 }}>{icon}</span>
|
||||
<span style={{ flex: 1, minWidth: 0 }}>
|
||||
<span style={{ display: 'block', fontSize: 'calc(12.5px * var(--fs-scale-body, 1))', fontWeight: 600, color: 'var(--text-primary)' }}>{label}</span>
|
||||
|
||||
Reference in New Issue
Block a user