diff --git a/client/src/pages/DashboardPage.test.tsx b/client/src/pages/DashboardPage.test.tsx index 2a3530ee..90f079de 100644 --- a/client/src/pages/DashboardPage.test.tsx +++ b/client/src/pages/DashboardPage.test.tsx @@ -7,10 +7,12 @@ import { resetAllStores, seedStore } from '../../tests/helpers/store'; import { buildUser, buildAdmin, buildTrip } from '../../tests/helpers/factories'; import { useAuthStore } from '../store/authStore'; import { usePermissionsStore } from '../store/permissionsStore'; +import { offlineDb } from '../db/offlineDb'; import DashboardPage from './DashboardPage'; -beforeEach(() => { +beforeEach(async () => { vi.clearAllMocks(); + await Promise.all(offlineDb.tables.map(t => t.clear())); resetAllStores(); // Seed auth with authenticated user seedStore(useAuthStore, { isAuthenticated: true, user: buildUser() }); @@ -329,7 +331,8 @@ describe('DashboardPage', () => { const tokyoTrip = screen.getAllByText('Tokyo Trip')[0]; await user.click(tokyoTrip); - expect(tokyoTrip).toBeInTheDocument(); + // Re-query after click — background refresh may re-render the list + expect(screen.getAllByText('Tokyo Trip').length).toBeGreaterThan(0); }); }); diff --git a/client/src/repo/accommodationRepo.ts b/client/src/repo/accommodationRepo.ts index c31ea2ba..80a587a1 100644 --- a/client/src/repo/accommodationRepo.ts +++ b/client/src/repo/accommodationRepo.ts @@ -9,10 +9,9 @@ export const accommodationRepo = { .where('trip_id').equals(Number(tripId)).toArray() const refresh = (async () => { - if (!navigator.onLine) return null try { const result = await accommodationsApi.list(tripId) - upsertAccommodations(result.accommodations || []).catch(() => {}) + await upsertAccommodations(result.accommodations || []) return result } catch { return null @@ -23,7 +22,7 @@ export const accommodationRepo = { const fresh = await refresh if (!fresh) return { accommodations: [], refresh: Promise.resolve(null) } - return { accommodations: fresh.accommodations, refresh: Promise.resolve(fresh) } + return { accommodations: fresh.accommodations, refresh: Promise.resolve(null) } }, async create(tripId: number | string, data: Record): Promise<{ accommodation: Accommodation }> { diff --git a/client/src/repo/budgetRepo.ts b/client/src/repo/budgetRepo.ts index f674faab..81b28662 100644 --- a/client/src/repo/budgetRepo.ts +++ b/client/src/repo/budgetRepo.ts @@ -11,10 +11,9 @@ export const budgetRepo = { .toArray() const refresh = (async () => { - if (!navigator.onLine) return null try { const result = await budgetApi.list(tripId) - upsertBudgetItems(result.items) + await upsertBudgetItems(result.items) return result } catch { return null @@ -25,7 +24,7 @@ export const budgetRepo = { const fresh = await refresh if (!fresh) return { items: [], refresh: Promise.resolve(null) } - return { items: fresh.items, refresh: Promise.resolve(fresh) } + return { items: fresh.items, refresh: Promise.resolve(null) } }, async create(tripId: number | string, data: Record): Promise<{ item: BudgetItem }> { diff --git a/client/src/repo/dayRepo.ts b/client/src/repo/dayRepo.ts index 74129707..9ddb1d6a 100644 --- a/client/src/repo/dayRepo.ts +++ b/client/src/repo/dayRepo.ts @@ -11,10 +11,9 @@ export const dayRepo = { .sortBy('day_number' as keyof Day)) as Day[] const refresh = (async () => { - if (!navigator.onLine) return null try { const result = await daysApi.list(tripId) - upsertDays(result.days) + await upsertDays(result.days) return result } catch { return null @@ -25,7 +24,7 @@ export const dayRepo = { const fresh = await refresh if (!fresh) return { days: [], refresh: Promise.resolve(null) } - return { days: fresh.days, refresh: Promise.resolve(fresh) } + return { days: fresh.days, refresh: Promise.resolve(null) } }, async update(tripId: number | string, dayId: number | string, data: Record): Promise<{ day: Day }> { diff --git a/client/src/repo/fileRepo.ts b/client/src/repo/fileRepo.ts index 030ca815..691c753e 100644 --- a/client/src/repo/fileRepo.ts +++ b/client/src/repo/fileRepo.ts @@ -11,10 +11,9 @@ export const fileRepo = { .toArray() const refresh = (async () => { - if (!navigator.onLine) return null try { const result = await filesApi.list(tripId) - upsertTripFiles(result.files) + await upsertTripFiles(result.files) return result } catch { return null @@ -25,7 +24,7 @@ export const fileRepo = { const fresh = await refresh if (!fresh) return { files: [], refresh: Promise.resolve(null) } - return { files: fresh.files, refresh: Promise.resolve(fresh) } + return { files: fresh.files, refresh: Promise.resolve(null) } }, async update(tripId: number | string, id: number, data: Record): Promise<{ file: TripFile }> { diff --git a/client/src/repo/packingRepo.ts b/client/src/repo/packingRepo.ts index 49130813..18a2c001 100644 --- a/client/src/repo/packingRepo.ts +++ b/client/src/repo/packingRepo.ts @@ -11,10 +11,9 @@ export const packingRepo = { .toArray() const refresh = (async () => { - if (!navigator.onLine) return null try { const result = await packingApi.list(tripId) - upsertPackingItems(result.items) + await upsertPackingItems(result.items) return result } catch { return null @@ -25,7 +24,7 @@ export const packingRepo = { const fresh = await refresh if (!fresh) return { items: [], refresh: Promise.resolve(null) } - return { items: fresh.items, refresh: Promise.resolve(fresh) } + return { items: fresh.items, refresh: Promise.resolve(null) } }, async create(tripId: number | string, data: Record): Promise<{ item: PackingItem }> { diff --git a/client/src/repo/placeRepo.ts b/client/src/repo/placeRepo.ts index 320f44b9..dad8fcae 100644 --- a/client/src/repo/placeRepo.ts +++ b/client/src/repo/placeRepo.ts @@ -11,10 +11,9 @@ export const placeRepo = { .toArray() const refresh = (async () => { - if (!navigator.onLine) return null try { const result = await placesApi.list(tripId, params) - upsertPlaces(result.places) + await upsertPlaces(result.places) return result } catch { return null @@ -25,7 +24,7 @@ export const placeRepo = { const fresh = await refresh if (!fresh) return { places: [], refresh: Promise.resolve(null) } - return { places: fresh.places, refresh: Promise.resolve(fresh) } + return { places: fresh.places, refresh: Promise.resolve(null) } }, async create(tripId: number | string, data: Record): Promise<{ place: Place }> { diff --git a/client/src/repo/reservationRepo.ts b/client/src/repo/reservationRepo.ts index d0a4759c..ea104b0f 100644 --- a/client/src/repo/reservationRepo.ts +++ b/client/src/repo/reservationRepo.ts @@ -11,10 +11,9 @@ export const reservationRepo = { .toArray() const refresh = (async () => { - if (!navigator.onLine) return null try { const result = await reservationsApi.list(tripId) - upsertReservations(result.reservations) + await upsertReservations(result.reservations) return result } catch { return null @@ -25,7 +24,7 @@ export const reservationRepo = { const fresh = await refresh if (!fresh) return { reservations: [], refresh: Promise.resolve(null) } - return { reservations: fresh.reservations, refresh: Promise.resolve(fresh) } + return { reservations: fresh.reservations, refresh: Promise.resolve(null) } }, async create(tripId: number | string, data: Record): Promise<{ reservation: Reservation }> { diff --git a/client/src/repo/todoRepo.ts b/client/src/repo/todoRepo.ts index 27b54db6..6cf8f7c4 100644 --- a/client/src/repo/todoRepo.ts +++ b/client/src/repo/todoRepo.ts @@ -11,10 +11,9 @@ export const todoRepo = { .toArray() const refresh = (async () => { - if (!navigator.onLine) return null try { const result = await todoApi.list(tripId) - upsertTodoItems(result.items) + await upsertTodoItems(result.items) return result } catch { return null @@ -25,7 +24,7 @@ export const todoRepo = { const fresh = await refresh if (!fresh) return { items: [], refresh: Promise.resolve(null) } - return { items: fresh.items, refresh: Promise.resolve(fresh) } + return { items: fresh.items, refresh: Promise.resolve(null) } }, async create(tripId: number | string, data: Record): Promise<{ item: TodoItem }> { diff --git a/client/src/repo/tripRepo.ts b/client/src/repo/tripRepo.ts index 07efc624..1d91019b 100644 --- a/client/src/repo/tripRepo.ts +++ b/client/src/repo/tripRepo.ts @@ -11,14 +11,15 @@ export const tripRepo = { const all = await offlineDb.trips.toArray() const refresh: TripsRefresh = (async () => { - if (!navigator.onLine) return null try { const [active, archived] = await Promise.all([ tripsApi.list(), tripsApi.list({ archived: 1 }), ]) - active.trips.forEach(t => upsertTrip(t)) - archived.trips.forEach(t => upsertTrip(t)) + await Promise.all([ + ...active.trips.map(t => upsertTrip(t)), + ...archived.trips.map(t => upsertTrip(t)), + ]) return { trips: active.trips, archivedTrips: archived.trips } } catch { return null @@ -35,17 +36,17 @@ export const tripRepo = { const fresh = await refresh if (!fresh) return { trips: [], archivedTrips: [], refresh: Promise.resolve(null) } - return { ...fresh, refresh: Promise.resolve(fresh) } + // Data came straight from network — no background re-fetch needed + return { ...fresh, refresh: Promise.resolve(null) } }, async get(tripId: number | string): Promise<{ trip: Trip; refresh: TripRefresh }> { const cached = await offlineDb.trips.get(Number(tripId)) const refresh: TripRefresh = (async () => { - if (!navigator.onLine) return null try { const result = await tripsApi.get(tripId) - upsertTrip(result.trip) + await upsertTrip(result.trip) return result } catch { return null @@ -56,7 +57,7 @@ export const tripRepo = { const fresh = await refresh if (!fresh) throw new Error('No cached trip data available offline') - return { trip: fresh.trip, refresh: Promise.resolve(fresh) } + return { trip: fresh.trip, refresh: Promise.resolve(null) } }, async update(tripId: number | string, data: Partial): Promise<{ trip: Trip }> { diff --git a/client/tests/unit/repo/packingRepo.test.ts b/client/tests/unit/repo/packingRepo.test.ts index 97c9b44b..855e0100 100644 --- a/client/tests/unit/repo/packingRepo.test.ts +++ b/client/tests/unit/repo/packingRepo.test.ts @@ -58,8 +58,10 @@ describe('packingRepo.list', () => { expect(restCalled).toBe(false); }); - it('offline — returns empty array when nothing cached', async () => { - Object.defineProperty(navigator, 'onLine', { value: false }); + it('offline — returns empty array when nothing cached and network fails', async () => { + server.use( + http.get('/api/trips/99/packing', () => HttpResponse.error()), + ); const result = await packingRepo.list(99); expect(result.items).toHaveLength(0); }); diff --git a/client/tests/unit/repo/placeRepo.test.ts b/client/tests/unit/repo/placeRepo.test.ts index 9ee808ff..d88f2dfe 100644 --- a/client/tests/unit/repo/placeRepo.test.ts +++ b/client/tests/unit/repo/placeRepo.test.ts @@ -59,8 +59,10 @@ describe('placeRepo.list', () => { expect(restCalled).toBe(false); }); - it('offline — returns empty array when nothing cached', async () => { - Object.defineProperty(navigator, 'onLine', { value: false }); + it('offline — returns empty array when nothing cached and network fails', async () => { + server.use( + http.get('/api/trips/99/places', () => HttpResponse.error()), + ); const result = await placeRepo.list(99); expect(result.places).toHaveLength(0); });