mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-23 15:36:33 +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:
@@ -91,7 +91,7 @@ export function setTripOfflineEnabled(tripId: number, on: boolean): void {
|
||||
/** Subscribe to preference changes. Returns an unsubscribe function. */
|
||||
export function onOfflinePrefsChange(fn: () => void): () => void {
|
||||
listeners.add(fn)
|
||||
return () => listeners.delete(fn)
|
||||
return () => { listeners.delete(fn) }
|
||||
}
|
||||
|
||||
/** Reset to defaults — test helper only. */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// FE-SYNC-PREP-001 to FE-SYNC-PREP-020
|
||||
// FE-SYNC-PREP-001 to FE-SYNC-PREP-021
|
||||
// prepareForOffline, the idle tile pass and the file-blob caching branches that
|
||||
// tests/unit/sync/tripSyncManager.test.ts leaves untouched.
|
||||
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
|
||||
@@ -250,6 +250,20 @@ describe('tripSyncManager — file blob caching', () => {
|
||||
expect((await offlineDb.syncMeta.get(614))!.filesCachedCount).toBe(1)
|
||||
})
|
||||
|
||||
it('FE-SYNC-PREP-021: a trip that lost all its files has its cached-file count reset', async () => {
|
||||
const url = '/api/trips/617/files/908/download'
|
||||
await prepareWithFiles(617, [buildTripFile({ id: 908, trip_id: 617, url, mime_type: 'application/pdf' })])
|
||||
expect((await offlineDb.syncMeta.get(617))!.filesCachedCount).toBe(1)
|
||||
|
||||
// The count is derived from the trip being synced, not from the first file
|
||||
// row, so an empty list still updates the meta.
|
||||
tripSyncManager._resetSyncing()
|
||||
await offlineDb.tripFiles.clear()
|
||||
await prepareWithFiles(617, [])
|
||||
|
||||
expect((await offlineDb.syncMeta.get(617))!.filesCachedCount).toBe(0)
|
||||
})
|
||||
|
||||
it('FE-SYNC-PREP-016: a file row without a url is ignored', async () => {
|
||||
await prepareWithFiles(615, [
|
||||
buildTripFile({ id: 908, trip_id: 615, url: undefined, mime_type: 'application/pdf' }),
|
||||
|
||||
@@ -115,35 +115,35 @@ async function syncTrip(tripId: number): Promise<void> {
|
||||
}
|
||||
|
||||
/** Cache non-photo file blobs for a trip. Fire-and-forget safe. */
|
||||
async function cacheFilesForTrip(files: TripFile[]): Promise<void> {
|
||||
async function cacheFilesForTrip(tripId: number, files: TripFile[]): Promise<void> {
|
||||
const nonPhotos = files.filter(f => f.url && !isPhoto(f) && !isVideo(f))
|
||||
let cached = 0
|
||||
// `present` is what syncMeta.filesCachedCount reports (files available
|
||||
// offline afterwards); `downloaded` only counts what this run actually wrote.
|
||||
let present = 0
|
||||
let downloaded = 0
|
||||
|
||||
for (const file of nonPhotos) {
|
||||
// Skip if already cached
|
||||
const existing = await offlineDb.blobCache.get(file.url!)
|
||||
if (existing) { cached++; continue }
|
||||
if (existing) { present++; continue }
|
||||
|
||||
try {
|
||||
const resp = await fetch(file.url!, { credentials: 'include' })
|
||||
if (!resp.ok) continue
|
||||
const blob = await resp.blob()
|
||||
await offlineDb.blobCache.put({ url: file.url!, tripId: file.trip_id, blob, bytes: blob.size, mime: file.mime_type, cachedAt: Date.now() })
|
||||
cached++
|
||||
present++
|
||||
downloaded++
|
||||
} catch {
|
||||
// Network failure — skip this file, will retry next sync
|
||||
}
|
||||
}
|
||||
|
||||
// Keep the blob cache within its size/count budget after adding new files.
|
||||
if (cached > 0) await enforceBlobBudget().catch(() => {})
|
||||
if (downloaded > 0) await enforceBlobBudget().catch(() => {})
|
||||
|
||||
// Update filesCachedCount in syncMeta
|
||||
const tripId = files[0]?.trip_id
|
||||
if (tripId) {
|
||||
const meta = await offlineDb.syncMeta.get(tripId)
|
||||
if (meta) await upsertSyncMeta({ ...meta, filesCachedCount: cached })
|
||||
}
|
||||
const meta = await offlineDb.syncMeta.get(tripId)
|
||||
if (meta) await upsertSyncMeta({ ...meta, filesCachedCount: present })
|
||||
}
|
||||
|
||||
// ── Public API ────────────────────────────────────────────────────────────────
|
||||
@@ -205,7 +205,7 @@ export const tripSyncManager = {
|
||||
const tileUrl = useSettingsStore.getState().settings.map_tile_url || undefined
|
||||
for (const trip of toSync) {
|
||||
const files = await offlineDb.tripFiles.where('trip_id').equals(trip.id).toArray()
|
||||
cacheFilesForTrip(files).catch(console.error)
|
||||
cacheFilesForTrip(trip.id, files).catch(console.error)
|
||||
}
|
||||
|
||||
// Map tiles last, and only once the browser goes idle. syncAll runs right
|
||||
@@ -265,7 +265,7 @@ export const tripSyncManager = {
|
||||
for (const trip of toSync) {
|
||||
onProgress?.({ phase: 'files', current: ++i, total, label: trip.title })
|
||||
const files = await offlineDb.tripFiles.where('trip_id').equals(trip.id).toArray()
|
||||
await cacheFilesForTrip(files).catch(console.error)
|
||||
await cacheFilesForTrip(trip.id, files).catch(console.error)
|
||||
}
|
||||
|
||||
// 3) Map tiles — awaited, and only when the user opted to store them.
|
||||
|
||||
Reference in New Issue
Block a user