Files
frontend-miniapp/tests/unit/GuideModelPersistentCache.spec.ts
lyf 9ea1bfab71
Some checks failed
CI / verify (push) Has been cancelled
同步 sgs-frontend-mobile 源码
2026-07-27 11:26:01 +08:00

69 lines
2.5 KiB
TypeScript

// @vitest-environment happy-dom
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { GuideModelPersistentCache } from '@/services/model/GuideModelPersistentCache'
describe('GuideModelPersistentCache', () => {
const records = new Map<string, Response>()
const cache = {
match: vi.fn(async (key: string) => records.get(key)?.clone()),
put: vi.fn(async (key: string, response: Response) => {
records.set(key, response.clone())
}),
delete: vi.fn(async (key: string) => records.delete(key))
}
beforeEach(() => {
records.clear()
cache.match.mockClear()
cache.put.mockClear()
cache.delete.mockClear()
localStorage.clear()
vi.stubGlobal('caches', { open: vi.fn(async () => cache) })
vi.stubGlobal('fetch', vi.fn(async () => new Response(new Blob(['model']), { status: 200 })))
vi.stubGlobal('URL', {
createObjectURL: vi.fn(() => 'blob:cached-model'),
revokeObjectURL: vi.fn()
})
})
afterEach(() => {
vi.unstubAllGlobals()
})
it('stores a versioned asset and reuses it from persistent storage', async () => {
const modelCache = new GuideModelPersistentCache()
await modelCache.store('https://assets.example.com/exterior.glb', 'release-1')
const cached = await modelCache.get('https://assets.example.com/exterior.glb', 'release-1')
expect(fetch).toHaveBeenCalledWith('https://assets.example.com/exterior.glb', { cache: 'force-cache' })
expect(cache.put).toHaveBeenCalledTimes(1)
expect(cached?.url).toBe('blob:cached-model')
cached?.release()
expect(URL.revokeObjectURL).toHaveBeenCalledWith('blob:cached-model')
})
it('does not reuse a cached asset from another model version', async () => {
const modelCache = new GuideModelPersistentCache()
await modelCache.store('https://assets.example.com/exterior.glb', 'release-1')
const cached = await modelCache.get('https://assets.example.com/exterior.glb', 'release-2')
expect(cached).toBeNull()
})
it('deletes empty cached payloads before falling back to network', async () => {
const modelCache = new GuideModelPersistentCache()
await modelCache.store('https://assets.example.com/exterior.glb', 'release-1')
records.set(
'https://assets.example.com/exterior.glb?__sgs_model_version=release-1',
new Response(new Blob([]), { status: 200 })
)
const cached = await modelCache.get('https://assets.example.com/exterior.glb', 'release-1')
expect(cached).toBeNull()
expect(cache.delete).toHaveBeenCalled()
})
})