import { readFile } from "node:fs/promises"; import { describe, expect, it } from "vitest"; import type { BrowserDataResult, IndexedDbRepositoryPort, } from "../../../src/application/ports/browser-file-storage/index.ts"; import { createLocalDraftStore, type LocalDraft, } from "./fixtures/local-draft-feature.ts"; function success(value: Value): BrowserDataResult { return Object.freeze({ ok: true as const, value }); } function repositoryFixture(): IndexedDbRepositoryPort { let stored: Readonly<{ value: LocalDraft; revision: number }> | null = null; const repository: IndexedDbRepositoryPort = { async open() { return success(undefined); }, async read(key) { if (stored === null || stored.value.draftId !== key) { return success(null); } return success(stored); }, async query() { return success(Object.freeze({ items: [], nextCursor: null })); }, async compareAndSwap(input) { const currentRevision = stored?.revision ?? null; if (currentRevision !== input.expectedRevision) { return Object.freeze({ ok: false as const, error: Object.freeze({ code: "CONFLICT" as const, operation: "INDEXEDDB_WRITE" as const, retryable: false, recovery: "RECONCILE" as const, }), }); } const revision = (currentRevision ?? 0) + 1; stored = Object.freeze({ value: input.value, revision }); return success( Object.freeze({ key: input.key, revision, replayed: false, }), ); }, async remove(input) { if (stored === null || stored.revision !== input.expectedRevision) { return Object.freeze({ ok: false as const, error: Object.freeze({ code: "CONFLICT" as const, operation: "INDEXEDDB_WRITE" as const, retryable: false, recovery: "RECONCILE" as const, }), }); } stored = null; return success( Object.freeze({ key: input.key, revision: input.expectedRevision + 1, replayed: false, }), ); }, async enforceLifecycleBatch() { stored = null; return success( Object.freeze({ state: "COMPLETE" as const, scannedRows: 0, deletedRows: 0, budgetExhausted: false, }), ); }, getStatus() { return Object.freeze({ kind: "READY" as const, schemaVersion: 1 }); }, subscribeStatus() { return () => {}; }, close() {}, }; return Object.freeze(repository); } describe("IndexedDB local-draft consumer experience", () => { it("implements save/find/remove through the public application port", async () => { const store = createLocalDraftStore(repositoryFixture()); const draft = Object.freeze({ draftId: "draft-1", title: "Architecture notes", body: "Feature code owns the draft model.", }); await expect( store.save({ draft, expectedRevision: null, idempotencyKey: "draft-save-0001", }), ).resolves.toEqual({ ok: true, value: { revision: 1 } }); await expect(store.find("draft-1")).resolves.toEqual({ ok: true, value: { draft, revision: 1 }, }); await expect( store.remove({ draftId: "draft-1", expectedRevision: 1, idempotencyKey: "draft-remove-0001", }), ).resolves.toEqual({ ok: true, value: undefined }); await expect(store.find("draft-1")).resolves.toEqual({ ok: true, value: null, }); }); it("keeps native IndexedDB and runtime internals out of feature-owned code", async () => { const source = await readFile( new URL("./fixtures/local-draft-feature.ts", import.meta.url), "utf8", ); const importLines = source .split("\n") .filter((line) => line.startsWith("import ")); expect(importLines).toHaveLength(1); expect(source).toContain( "src/application/ports/browser-file-storage/index.ts", ); for (const forbidden of [ "src/adapters/storage/indexeddb", "globalThis.indexedDB", "IDBFactory", "IDBDatabase", "IDBTransaction", "IDBObjectStore", ]) { expect(source).not.toContain(forbidden); } }); });