// @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() 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() }) })