import { describe, expect, it } from "vitest"; import type { IndexedDbRepositoryPort, } from "../../../src/application/ports/browser-file-storage/index.ts"; import type { InstalledHttpOperationExecutor, } from "../../../src/adapters/http/index.ts"; import { composeFeatureAdapterInputs, defineFeatureAdapterContribution, type IndexedDbRepositoryProvider, } from "../../../src/features/feature-adapter-contribution.ts"; import { LOCAL_DRAFT_FEATURE_ADAPTER_CONTRIBUTION, } from "../../../src/features/local-draft-feature/adapters/create-local-draft-feature-input.ts"; import type { LocalDraft } from "../../../src/features/local-draft-feature/domain/local-draft.ts"; type TestHttpFeatureInput = Readonly<{ ping(): Promise<"pong">; }>; declare module "../../../src/application/ports/in/application-api.ts" { interface ApplicationFeatureInputs { "test-http-feature": TestHttpFeatureInput; } } const TEST_HTTP_FEATURE_ADAPTER_CONTRIBUTION = defineFeatureAdapterContribution({ featureId: "test-http-feature", needs: ["http"] as const, createInput() { return Object.freeze({ featureId: "test-http-feature" as const, input: Object.freeze({ async ping() { return "pong" as const; }, }), }); }, }); function localDraftRepository() { let stored: Readonly<{ value: LocalDraft; revision: number }> | null = null; const repository = Object.freeze({ async compareAndSwap(input: Readonly<{ value: LocalDraft }>) { stored = Object.freeze({ value: input.value, revision: 1 }); return Object.freeze({ ok: true as const, value: Object.freeze({ revision: 1 }), }); }, async read() { return Object.freeze({ ok: true as const, value: stored }); }, async remove() { stored = null; return Object.freeze({ ok: true as const, value: Object.freeze({ revision: 2 }), }); }, }) as unknown as IndexedDbRepositoryPort; return repository; } describe("feature adapter composition", () => { it("composes HTTP-only and IndexedDB-only concrete contributions together", async () => { const repository = localDraftRepository(); const get = ((repositoryId: string) => { expect(repositoryId).toBe("local-draft"); return repository; }) as unknown as IndexedDbRepositoryProvider["get"]; const indexedDb = Object.freeze({ get }) satisfies IndexedDbRepositoryProvider; const http = Object.freeze({ execute: async () => { throw new Error("HTTP should not execute during composition"); }, }) as unknown as InstalledHttpOperationExecutor; const inputs = composeFeatureAdapterInputs( Object.freeze([ TEST_HTTP_FEATURE_ADAPTER_CONTRIBUTION, LOCAL_DRAFT_FEATURE_ADAPTER_CONTRIBUTION, ] as const), Object.freeze(["test-http-feature", "local-draft"]), Object.freeze({ http, indexedDb }), ); expect(Object.keys(inputs).sort()).toEqual([ "local-draft", "test-http-feature", ]); await expect(inputs["test-http-feature"]?.ping()).resolves.toBe("pong"); const localDraft = inputs["local-draft"]; if (!localDraft) throw new Error("local-draft input was not composed"); const draft = Object.freeze({ draftId: "draft-1", title: "Local draft", body: "Body", }); await expect( localDraft.saveDraft({ draft, expectedRevision: null, idempotencyKey: "save-draft-1", }), ).resolves.toEqual({ ok: true, value: { revision: 1 } }); await expect(localDraft.findDraft("draft-1")).resolves.toEqual({ ok: true, value: { draft, revision: 1 }, }); }); });