diff --git a/frontend/src/views/__tests__/CloudFolderOpenPreview.test.js b/frontend/src/views/__tests__/CloudFolderOpenPreview.test.js index 29be2e9..97da920 100644 --- a/frontend/src/views/__tests__/CloudFolderOpenPreview.test.js +++ b/frontend/src/views/__tests__/CloudFolderOpenPreview.test.js @@ -446,3 +446,59 @@ describe('preview_does_not_trigger_device_download', () => { createElementSpy.mockRestore() }) }) + +// ── Phase 14 Plan 06: Cache transparency — frontend never sees object_key ────── + +describe('cache_backed_response_has_no_object_key', () => { + it('openCloudFile response processed by the view does not expose cache object_key', async () => { + /** + * Phase 14 Plan 06 / T-14-02: Even when the backend serves bytes from the + * byte cache (MinIO), the API response shape seen by CloudFolderView must + * not include an object_key field. + * + * The cache lifecycle is entirely backend-owned — the frontend receives + * the same {kind: 'open', url: ...} JSON response regardless of whether + * bytes came from the provider or from the MinIO cache. + */ + // Response matching what the backend sends (cache hit or miss — same shape) + const OPEN_RESPONSE_WITH_NO_CACHE_FIELDS = { + kind: 'open', + url: '/api/cloud/connections/uuid-conn-preview/items/provider-id/download', + reason: 'authorized', + } + api.openCloudFile.mockResolvedValue(OPEN_RESPONSE_WITH_NO_CACHE_FIELDS) + + api.getCloudFoldersByConnectionId.mockResolvedValue({ + items: [PDF_FILE], + capabilities: null, + freshness: { refresh_state: 'fresh', last_refreshed_at: '2026-06-20T00:00:00Z' }, + }) + + const BrowserStub = makeBrowserStub() + const w = mount(CloudFolderView, { + global: { stubs: { StorageBrowser: BrowserStub } }, + }) + await flushPromises() + + const browser = w.findComponent({ name: 'StorageBrowser' }) + await browser.vm.$emit('file-open', PDF_FILE) + await flushPromises() + + // The rendered HTML must not expose any cache internals + const html = w.html() + expect(html).not.toContain('object_key') + expect(html).not.toContain('cache/') + expect(html).not.toContain('credentials_enc') + + // The API call arguments must not contain object_key or MinIO paths + if (api.openCloudFile.mock.calls.length > 0) { + const callArgs = api.openCloudFile.mock.calls[0] + callArgs.forEach(arg => { + if (typeof arg === 'string') { + expect(arg).not.toContain('object_key') + expect(arg).not.toMatch(/^cache\/[0-9a-f-]+\//) + } + }) + } + }) +})