mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-19 21:31:46 +00:00
Fix a batch of reported bugs (#1145)
* fix(maps): fall back to OSM/Wikipedia for place photos and normalize non-standard language codes (#1137) * fix(auth): refuse password reset for OIDC/SSO-linked accounts (#1129) * fix(docker): ship server/assets (airports + atlas geo) in the runtime image (#1133, #1119) * fix(unraid): point the template at a PNG icon Unraid can render (#1073) * fix(offline): serve cached file blobs when offline or on network failure (#1046, #1069) * fix(map): centre the selected pin in the visible map area above the bottom panel (#1125) * fix(pdf): render persisted place-photo proxy URLs as images (#1130) * fix(planner): show the selected place category in the edit form (#1134) * fix(dashboard): collapse list-view trip cards to a compact row on mobile (#1132)
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
||||
import { downloadFile, openFile } from '../../../src/utils/fileDownload'
|
||||
import { getCachedBlob } from '../../../src/db/offlineDb'
|
||||
|
||||
// Mock the offline DB so these tests never touch Dexie/IndexedDB.
|
||||
vi.mock('../../../src/db/offlineDb', () => ({ getCachedBlob: vi.fn() }))
|
||||
|
||||
function makeFetchMock(status: number, blob: Blob = new Blob(['data'], { type: 'application/pdf' })) {
|
||||
return vi.fn().mockResolvedValue({
|
||||
@@ -170,3 +174,52 @@ describe('openFile', () => {
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('offline fallback (#1046)', () => {
|
||||
function setOnline(value: boolean) {
|
||||
Object.defineProperty(navigator, 'onLine', { value, configurable: true })
|
||||
}
|
||||
beforeEach(() => vi.mocked(getCachedBlob).mockReset())
|
||||
afterEach(() => setOnline(true))
|
||||
|
||||
it('serves the cached blob without a network call when offline', async () => {
|
||||
setOnline(false)
|
||||
const blob = new Blob(['x'], { type: 'application/pdf' })
|
||||
vi.mocked(getCachedBlob).mockResolvedValue(blob)
|
||||
const fetchSpy = vi.fn()
|
||||
vi.stubGlobal('fetch', fetchSpy)
|
||||
vi.spyOn(HTMLAnchorElement.prototype, 'click').mockImplementation(() => {})
|
||||
|
||||
await downloadFile('/uploads/files/cached.pdf')
|
||||
|
||||
expect(fetchSpy).not.toHaveBeenCalled()
|
||||
expect(getCachedBlob).toHaveBeenCalledWith('/uploads/files/cached.pdf')
|
||||
expect(URL.createObjectURL).toHaveBeenCalledWith(blob)
|
||||
})
|
||||
|
||||
it('falls back to the cache when a live fetch rejects (network error) while online', async () => {
|
||||
setOnline(true)
|
||||
vi.stubGlobal('fetch', vi.fn().mockRejectedValue(new Error('network down')))
|
||||
const blob = new Blob(['x'], { type: 'application/pdf' })
|
||||
vi.mocked(getCachedBlob).mockResolvedValue(blob)
|
||||
vi.spyOn(HTMLAnchorElement.prototype, 'click').mockImplementation(() => {})
|
||||
|
||||
await downloadFile('/uploads/files/cached.pdf')
|
||||
|
||||
expect(getCachedBlob).toHaveBeenCalledWith('/uploads/files/cached.pdf')
|
||||
expect(URL.createObjectURL).toHaveBeenCalledWith(blob)
|
||||
})
|
||||
|
||||
it('throws when offline and the file was never cached', async () => {
|
||||
setOnline(false)
|
||||
vi.mocked(getCachedBlob).mockResolvedValue(null)
|
||||
await expect(downloadFile('/uploads/files/missing.pdf')).rejects.toThrow(/offline/i)
|
||||
})
|
||||
|
||||
it('does not consult the cache on an HTTP error — a 401 still surfaces', async () => {
|
||||
setOnline(true)
|
||||
vi.stubGlobal('fetch', makeFetchMock(401))
|
||||
await expect(downloadFile('/uploads/files/secret.pdf')).rejects.toThrow('Unauthorized')
|
||||
expect(getCachedBlob).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user