import { describe, expect, it, vi } from "vitest"; import type { AuditEntry } from "@/lib/services/audit"; import type { HousekeepingCapabilityContext } from "../../../foundation/contracts"; import { CONTENT_MUTATION_OPERATIONS } from "./mutations"; import { CONTENT_DATABASE_OPERATIONS, CONTENT_EXTERNAL_OPERATIONS, CONTENT_MIXED_OPERATIONS, ContentCommittedExternalFailure, createContentProductionMutationAdapter, } from "./mutations-production"; const capability: HousekeepingCapabilityContext = { actor: { id: 42, username: "operator", rank: 7 }, isSuperAdmin: false, has: () => true, hasAny: () => true, hasAll: () => true, }; const mutationContext = { capability, correlationId: "production-matrix", legacy: false, }; function dependencies() { const transactionToken = { transaction: true }; const writeAudit = vi.fn( async (_entry: AuditEntry, _transaction?: unknown) => undefined, ); const executeOperation = vi.fn(async (operation: string) => ({ before: { operation, state: "before" }, after: { operation, state: "after" }, output: { id: "18446744073709551615" }, })); const transaction = vi.fn(async (run) => run(transactionToken)); return { transactionToken, writeAudit, executeOperation, transaction, adapter: createContentProductionMutationAdapter({ transaction, writeAudit, executeOperation, }), }; } describe("Content production mutation adapter", () => { it("classifies every operation exactly once", () => { const classified = [ ...CONTENT_DATABASE_OPERATIONS, ...CONTENT_EXTERNAL_OPERATIONS, ...CONTENT_MIXED_OPERATIONS, ]; expect([...classified].sort()).toEqual( [...CONTENT_MUTATION_OPERATIONS].sort(), ); expect(new Set(classified).size).toBe(classified.length); }); it("executes every production operation and serializes identifiers", async () => { const deps = dependencies(); for (const operation of CONTENT_MUTATION_OPERATIONS) { const snapshot = await deps.adapter.execute( operation, { action: "update" }, mutationContext, ); expect(snapshot.output?.id, operation).toBe("18446744073709551615"); } expect(deps.executeOperation).toHaveBeenCalledTimes( CONTENT_MUTATION_OPERATIONS.length, ); }); it("commits database mutation and canonical success audit in one transaction", async () => { const deps = dependencies(); await deps.adapter.execute( "article.change", { action: "update", id: "18446744073709551615" }, mutationContext, ); expect(deps.transaction).toHaveBeenCalledTimes(1); expect(deps.executeOperation).toHaveBeenCalledWith( "article.change", expect.anything(), mutationContext, deps.transactionToken, ); expect(deps.writeAudit).toHaveBeenCalledWith( expect.objectContaining({ action: "content.article.change", outcome: "success", domain: "content", correlationId: "production-matrix", }), deps.transactionToken, ); }); it("persists correlated intent and truthful outcome around external storage writes", async () => { const deps = dependencies(); await deps.adapter.execute( "translation.cms.save", { locale: "en", data: { welcome: "Hello" } }, mutationContext, ); expect(deps.transaction).not.toHaveBeenCalled(); expect(deps.writeAudit.mock.calls.map(([entry]) => entry.outcome)).toEqual([ "intent", "success", ]); expect( deps.writeAudit.mock.calls.every( ([entry]) => entry.correlationId === "production-matrix", ), ).toBe(true); expect(JSON.stringify(deps.writeAudit.mock.calls)).not.toContain("Hello"); }); it("returns typed partial when database committed but the external effect failed", async () => { const deps = dependencies(); deps.executeOperation.mockRejectedValueOnce( new ContentCommittedExternalFailure({ before: { value: "/old.ico" }, after: { value: "/new.ico" }, }), ); const snapshot = await deps.adapter.execute( "favicon.save", { file: { name: "favicon.ico" } }, mutationContext, ); expect(snapshot).toMatchObject({ before: { value: "/old.ico" }, after: { value: "/new.ico" }, completion: { status: "partial", external: "failed", audit: "persisted", }, }); expect(deps.writeAudit.mock.calls.at(-1)?.[0]).toMatchObject({ outcome: "partial", }); }); it("records failure without optimistic after-state when external storage fails before commit", async () => { const deps = dependencies(); deps.executeOperation.mockRejectedValueOnce(new Error("disk offline")); await expect( deps.adapter.execute( "media.upload", { file: { name: "image.png" } }, mutationContext, ), ).rejects.toThrow("disk offline"); expect(deps.writeAudit.mock.calls.at(-1)?.[0]).toMatchObject({ outcome: "failure", before: undefined, after: undefined, }); }); });