refactor: strip Phase/Plan/R-number references from source comments
This commit is contained in:
@@ -3,94 +3,93 @@ import { defineContractSuite } from "@repo/core-testing/contract";
|
||||
import type { IMediaRepository } from "../application/repositories/media.repository.interface.js";
|
||||
import { mediaFactory } from "../__factories__/media.factory.js";
|
||||
|
||||
export const mediaRepositoryContract =
|
||||
defineContractSuite<IMediaRepository>(
|
||||
"IMediaRepository",
|
||||
({ buildSubject, getTracer }) => {
|
||||
let repo: IMediaRepository;
|
||||
export const mediaRepositoryContract = defineContractSuite<IMediaRepository>(
|
||||
"IMediaRepository",
|
||||
({ buildSubject, getTracer }) => {
|
||||
let repo: IMediaRepository;
|
||||
|
||||
beforeEach(async () => {
|
||||
mediaFactory.reset();
|
||||
repo = await buildSubject();
|
||||
beforeEach(async () => {
|
||||
mediaFactory.reset();
|
||||
repo = await buildSubject();
|
||||
});
|
||||
|
||||
// --- getMedia ---
|
||||
|
||||
it("getMedia returns undefined for a missing id", async () => {
|
||||
const result = await repo.getMedia("does-not-exist");
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
// --- listMedia ---
|
||||
|
||||
it("listMedia returns empty array when no media exists", async () => {
|
||||
const result = await repo.listMedia();
|
||||
expect(result).toHaveLength(0);
|
||||
});
|
||||
|
||||
// --- deleteMedia ---
|
||||
|
||||
it("deleteMedia removes the item so getMedia returns undefined", async () => {
|
||||
const seed = mediaFactory.build({ id: "contract-1" });
|
||||
// @ts-expect-error _store is a test helper on MockMediaRepository
|
||||
if (typeof repo._store === "function") {
|
||||
// @ts-expect-error _store is a test helper
|
||||
await repo._store(seed);
|
||||
}
|
||||
await repo.deleteMedia("contract-1");
|
||||
const result = await repo.getMedia("contract-1");
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it("listMedia with limit returns at most limit items", async () => {
|
||||
// Only verifiable on mock; for real impl this checks the interface
|
||||
const result = await repo.listMedia({ limit: 0 });
|
||||
expect(Array.isArray(result)).toBe(true);
|
||||
});
|
||||
|
||||
it("listMedia with offset skips items", async () => {
|
||||
const result = await repo.listMedia({ offset: 100 });
|
||||
expect(Array.isArray(result)).toBe(true);
|
||||
});
|
||||
|
||||
it("getMedia returns undefined for empty string id", async () => {
|
||||
const result = await repo.getMedia("");
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
describe("span emission", () => {
|
||||
it("getMedia emits media.getMedia span with id attribute", async () => {
|
||||
if (!getTracer) return;
|
||||
const tracer = getTracer();
|
||||
tracer.reset();
|
||||
await repo.getMedia("nonexistent");
|
||||
const span = tracer.findSpan("media.getMedia");
|
||||
expect(span).toBeDefined();
|
||||
expect(span!.op).toBe("repository");
|
||||
expect(span!.attributes.id).toBe("nonexistent");
|
||||
});
|
||||
|
||||
// --- getMedia ---
|
||||
|
||||
it("getMedia returns undefined for a missing id", async () => {
|
||||
const result = await repo.getMedia("does-not-exist");
|
||||
expect(result).toBeUndefined();
|
||||
it("listMedia emits media.listMedia span with op=repository", async () => {
|
||||
if (!getTracer) return;
|
||||
const tracer = getTracer();
|
||||
tracer.reset();
|
||||
await repo.listMedia({ limit: 10 });
|
||||
const span = tracer.findSpan("media.listMedia");
|
||||
expect(span).toBeDefined();
|
||||
expect(span!.op).toBe("repository");
|
||||
expect(span!.attributes.limit).toBe(10);
|
||||
});
|
||||
|
||||
// --- listMedia ---
|
||||
|
||||
it("listMedia returns empty array when no media exists", async () => {
|
||||
const result = await repo.listMedia();
|
||||
expect(result).toHaveLength(0);
|
||||
it("deleteMedia emits media.deleteMedia span with id attribute", async () => {
|
||||
if (!getTracer) return;
|
||||
const tracer = getTracer();
|
||||
tracer.reset();
|
||||
await repo.deleteMedia("nonexistent");
|
||||
const span = tracer.findSpan("media.deleteMedia");
|
||||
expect(span).toBeDefined();
|
||||
expect(span!.op).toBe("repository");
|
||||
expect(span!.attributes.id).toBe("nonexistent");
|
||||
});
|
||||
|
||||
// --- deleteMedia ---
|
||||
|
||||
it("deleteMedia removes the item so getMedia returns undefined", async () => {
|
||||
const seed = mediaFactory.build({ id: "contract-1" });
|
||||
// @ts-expect-error _store is a test helper on MockMediaRepository
|
||||
if (typeof repo._store === "function") {
|
||||
// @ts-expect-error _store is a test helper
|
||||
await repo._store(seed);
|
||||
}
|
||||
await repo.deleteMedia("contract-1");
|
||||
const result = await repo.getMedia("contract-1");
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it("listMedia with limit returns at most limit items", async () => {
|
||||
// Only verifiable on mock; for real impl this checks the interface
|
||||
const result = await repo.listMedia({ limit: 0 });
|
||||
expect(Array.isArray(result)).toBe(true);
|
||||
});
|
||||
|
||||
it("listMedia with offset skips items", async () => {
|
||||
const result = await repo.listMedia({ offset: 100 });
|
||||
expect(Array.isArray(result)).toBe(true);
|
||||
});
|
||||
|
||||
it("getMedia returns undefined for empty string id", async () => {
|
||||
const result = await repo.getMedia("");
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
describe("span emission (R50)", () => {
|
||||
it("getMedia emits media.getMedia span with id attribute", async () => {
|
||||
if (!getTracer) return;
|
||||
const tracer = getTracer();
|
||||
tracer.reset();
|
||||
await repo.getMedia("nonexistent");
|
||||
const span = tracer.findSpan("media.getMedia");
|
||||
expect(span).toBeDefined();
|
||||
expect(span!.op).toBe("repository");
|
||||
expect(span!.attributes.id).toBe("nonexistent");
|
||||
});
|
||||
|
||||
it("listMedia emits media.listMedia span with op=repository", async () => {
|
||||
if (!getTracer) return;
|
||||
const tracer = getTracer();
|
||||
tracer.reset();
|
||||
await repo.listMedia({ limit: 10 });
|
||||
const span = tracer.findSpan("media.listMedia");
|
||||
expect(span).toBeDefined();
|
||||
expect(span!.op).toBe("repository");
|
||||
expect(span!.attributes.limit).toBe(10);
|
||||
});
|
||||
|
||||
it("deleteMedia emits media.deleteMedia span with id attribute", async () => {
|
||||
if (!getTracer) return;
|
||||
const tracer = getTracer();
|
||||
tracer.reset();
|
||||
await repo.deleteMedia("nonexistent");
|
||||
const span = tracer.findSpan("media.deleteMedia");
|
||||
expect(span).toBeDefined();
|
||||
expect(span!.op).toBe("repository");
|
||||
expect(span!.attributes.id).toBe("nonexistent");
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { ZodError } from "zod";
|
||||
import { getMediaUseCase, getMediaOutputSchema } from "@/application/use-cases/get-media.use-case";
|
||||
import {
|
||||
getMediaUseCase,
|
||||
getMediaOutputSchema,
|
||||
} from "@/application/use-cases/get-media.use-case";
|
||||
import { MockMediaRepository } from "@/infrastructure/repositories/media.repository.mock";
|
||||
import { MediaNotFoundError } from "@/entities/errors/media";
|
||||
import { mediaFactory } from "@/__factories__/media.factory";
|
||||
@@ -22,15 +25,17 @@ describe("getMediaUseCase", () => {
|
||||
const repo = new MockMediaRepository();
|
||||
const useCase = getMediaUseCase(repo);
|
||||
|
||||
await expect(useCase({ id: "missing" })).rejects.toThrow(MediaNotFoundError);
|
||||
await expect(useCase({ id: "missing" })).rejects.toThrow(
|
||||
MediaNotFoundError,
|
||||
);
|
||||
});
|
||||
|
||||
it("R25 — parses valid output without error", async () => {
|
||||
it("parses valid output without error", async () => {
|
||||
const validMedia = mediaFactory.build({ id: "m-r25" });
|
||||
expect(() => getMediaOutputSchema.parse(validMedia)).not.toThrow();
|
||||
});
|
||||
|
||||
it("R25 — throws ZodError when repository returns malformed media", async () => {
|
||||
it("throws ZodError when repository returns malformed media", async () => {
|
||||
const repo = new MockMediaRepository();
|
||||
// Store a malformed object (missing required fields) via type cast
|
||||
await repo._store({ id: "bad", alt: "alt", url: "u" } as never);
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { ZodError } from "zod";
|
||||
import { listMediaUseCase, listMediaOutputSchema } from "@/application/use-cases/list-media.use-case";
|
||||
import {
|
||||
listMediaUseCase,
|
||||
listMediaOutputSchema,
|
||||
} from "@/application/use-cases/list-media.use-case";
|
||||
import { MockMediaRepository } from "@/infrastructure/repositories/media.repository.mock";
|
||||
import { mediaFactory } from "@/__factories__/media.factory";
|
||||
|
||||
@@ -33,12 +36,12 @@ describe("listMediaUseCase", () => {
|
||||
expect(result).toHaveLength(2);
|
||||
});
|
||||
|
||||
it("R25 — parses valid output without error", async () => {
|
||||
it("parses valid output without error", async () => {
|
||||
const items = [mediaFactory.build(), mediaFactory.build()];
|
||||
expect(() => listMediaOutputSchema.parse(items)).not.toThrow();
|
||||
});
|
||||
|
||||
it("R25 — throws ZodError when repository returns malformed items", async () => {
|
||||
it("throws ZodError when repository returns malformed items", async () => {
|
||||
const repo = new MockMediaRepository();
|
||||
// Store a malformed object (missing required fields)
|
||||
await repo._store({ id: "bad", alt: "alt", url: "u" } as never);
|
||||
|
||||
@@ -40,8 +40,12 @@ export async function bindDevSeedMedia(ctx: BindContext): Promise<void> {
|
||||
if (mediaContainer.isBound(INSTRUMENTATION_SYMBOLS.LOGGER)) {
|
||||
mediaContainer.unbind(INSTRUMENTATION_SYMBOLS.LOGGER);
|
||||
}
|
||||
mediaContainer.bind<ITracer>(INSTRUMENTATION_SYMBOLS.TRACER).toConstantValue(tracer);
|
||||
mediaContainer.bind<ILogger>(INSTRUMENTATION_SYMBOLS.LOGGER).toConstantValue(logger);
|
||||
mediaContainer
|
||||
.bind<ITracer>(INSTRUMENTATION_SYMBOLS.TRACER)
|
||||
.toConstantValue(tracer);
|
||||
mediaContainer
|
||||
.bind<ILogger>(INSTRUMENTATION_SYMBOLS.LOGGER)
|
||||
.toConstantValue(logger);
|
||||
|
||||
if (mediaContainer.isBound(MEDIA_SYMBOLS.IMediaRepository)) {
|
||||
mediaContainer.unbind(MEDIA_SYMBOLS.IMediaRepository);
|
||||
@@ -95,9 +99,15 @@ export async function bindDevSeedMedia(ctx: BindContext): Promise<void> {
|
||||
]) {
|
||||
if (mediaContainer.isBound(sym)) mediaContainer.unbind(sym);
|
||||
}
|
||||
mediaContainer.bind(MEDIA_SYMBOLS.IGetMediaUseCase).toConstantValue(wrappedGetMedia);
|
||||
mediaContainer.bind(MEDIA_SYMBOLS.IListMediaUseCase).toConstantValue(wrappedListMedia);
|
||||
mediaContainer.bind(MEDIA_SYMBOLS.IDeleteMediaUseCase).toConstantValue(wrappedDeleteMedia);
|
||||
mediaContainer
|
||||
.bind(MEDIA_SYMBOLS.IGetMediaUseCase)
|
||||
.toConstantValue(wrappedGetMedia);
|
||||
mediaContainer
|
||||
.bind(MEDIA_SYMBOLS.IListMediaUseCase)
|
||||
.toConstantValue(wrappedListMedia);
|
||||
mediaContainer
|
||||
.bind(MEDIA_SYMBOLS.IDeleteMediaUseCase)
|
||||
.toConstantValue(wrappedDeleteMedia);
|
||||
|
||||
mediaContainer
|
||||
.bind(MEDIA_SYMBOLS.IGetMediaController)
|
||||
@@ -138,8 +148,7 @@ export async function bindDevSeedMedia(ctx: BindContext): Promise<void> {
|
||||
),
|
||||
),
|
||||
);
|
||||
// bus + queue are accept-and-forward in Phase 6; consumed by Phase 7 generator
|
||||
// output at the <gen:event-handlers> / <gen:jobs> anchors below.
|
||||
// bus + queue are passed through; generated handlers consume them at the anchors below.
|
||||
void bus;
|
||||
void queue;
|
||||
void realtime;
|
||||
|
||||
@@ -19,7 +19,8 @@ import { listMediaController } from "../interface-adapters/controllers/list-medi
|
||||
import { deleteMediaController } from "../interface-adapters/controllers/delete-media.controller";
|
||||
|
||||
export function bindProductionMedia(ctx: BindProductionContext): void {
|
||||
const { config, tracer, logger, bus, queue, realtime, realtimeRegistry } = ctx;
|
||||
const { config, tracer, logger, bus, queue, realtime, realtimeRegistry } =
|
||||
ctx;
|
||||
|
||||
// Bind shared instrumentation into feature container
|
||||
if (mediaContainer.isBound(INSTRUMENTATION_SYMBOLS.TRACER)) {
|
||||
@@ -28,17 +29,19 @@ export function bindProductionMedia(ctx: BindProductionContext): void {
|
||||
if (mediaContainer.isBound(INSTRUMENTATION_SYMBOLS.LOGGER)) {
|
||||
mediaContainer.unbind(INSTRUMENTATION_SYMBOLS.LOGGER);
|
||||
}
|
||||
mediaContainer.bind<ITracer>(INSTRUMENTATION_SYMBOLS.TRACER).toConstantValue(tracer);
|
||||
mediaContainer.bind<ILogger>(INSTRUMENTATION_SYMBOLS.LOGGER).toConstantValue(logger);
|
||||
mediaContainer
|
||||
.bind<ITracer>(INSTRUMENTATION_SYMBOLS.TRACER)
|
||||
.toConstantValue(tracer);
|
||||
mediaContainer
|
||||
.bind<ILogger>(INSTRUMENTATION_SYMBOLS.LOGGER)
|
||||
.toConstantValue(logger);
|
||||
|
||||
// Real repository
|
||||
if (mediaContainer.isBound(MEDIA_SYMBOLS.IMediaRepository)) {
|
||||
mediaContainer.unbind(MEDIA_SYMBOLS.IMediaRepository);
|
||||
}
|
||||
const repo = new MediaRepository(config, tracer, logger);
|
||||
mediaContainer
|
||||
.bind(MEDIA_SYMBOLS.IMediaRepository)
|
||||
.toConstantValue(repo);
|
||||
mediaContainer.bind(MEDIA_SYMBOLS.IMediaRepository).toConstantValue(repo);
|
||||
|
||||
// Use cases — wrapped with span + capture at bind time
|
||||
const wrappedGetMedia = withSpan(
|
||||
@@ -76,9 +79,15 @@ export function bindProductionMedia(ctx: BindProductionContext): void {
|
||||
]) {
|
||||
if (mediaContainer.isBound(sym)) mediaContainer.unbind(sym);
|
||||
}
|
||||
mediaContainer.bind(MEDIA_SYMBOLS.IGetMediaUseCase).toConstantValue(wrappedGetMedia);
|
||||
mediaContainer.bind(MEDIA_SYMBOLS.IListMediaUseCase).toConstantValue(wrappedListMedia);
|
||||
mediaContainer.bind(MEDIA_SYMBOLS.IDeleteMediaUseCase).toConstantValue(wrappedDeleteMedia);
|
||||
mediaContainer
|
||||
.bind(MEDIA_SYMBOLS.IGetMediaUseCase)
|
||||
.toConstantValue(wrappedGetMedia);
|
||||
mediaContainer
|
||||
.bind(MEDIA_SYMBOLS.IListMediaUseCase)
|
||||
.toConstantValue(wrappedListMedia);
|
||||
mediaContainer
|
||||
.bind(MEDIA_SYMBOLS.IDeleteMediaUseCase)
|
||||
.toConstantValue(wrappedDeleteMedia);
|
||||
|
||||
// Controllers — wrapped with span at bind time
|
||||
for (const sym of [
|
||||
@@ -127,8 +136,7 @@ export function bindProductionMedia(ctx: BindProductionContext): void {
|
||||
),
|
||||
),
|
||||
);
|
||||
// bus + queue are accept-and-forward in Phase 6; consumed by Phase 7 generator
|
||||
// output at the <gen:event-handlers> / <gen:jobs> anchors below.
|
||||
// bus + queue are passed through; generated handlers consume them at the anchors below.
|
||||
void bus;
|
||||
void queue;
|
||||
void realtime;
|
||||
|
||||
@@ -3,7 +3,7 @@ export { MediaNotFoundError } from "./entities/errors/media";
|
||||
export { InputParseError } from "./entities/errors/common";
|
||||
export type { MediaRouter } from "./integrations/api/router";
|
||||
|
||||
// Use case schemas + types (Plan 9 R18)
|
||||
// Use case schemas + types
|
||||
export {
|
||||
getMediaInputSchema,
|
||||
getMediaOutputSchema,
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { RecordingTracer, RecordingLogger } from "@repo/core-testing/instrumentation";
|
||||
import {
|
||||
RecordingTracer,
|
||||
RecordingLogger,
|
||||
} from "@repo/core-testing/instrumentation";
|
||||
import { MockMediaRepository } from "@/infrastructure/repositories/media.repository.mock";
|
||||
import type { Media } from "@/entities/models/media";
|
||||
|
||||
@@ -12,8 +15,8 @@ const SAMPLE_MEDIA: Media = {
|
||||
filesize: 1024,
|
||||
};
|
||||
|
||||
// Mock repo also wraps in spans (R42).
|
||||
describe("MockMediaRepository emits spans (R42)", () => {
|
||||
// Mock repo also wraps in spans.
|
||||
describe("MockMediaRepository emits spans", () => {
|
||||
it("getMedia emits one span with op='repository' and found attribute", async () => {
|
||||
const tracer = new RecordingTracer();
|
||||
const logger = new RecordingLogger();
|
||||
|
||||
@@ -36,7 +36,7 @@ describe("mediaRouter", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("mediaRouter (R26 error mapping)", () => {
|
||||
describe("mediaRouter error mapping", () => {
|
||||
beforeEach(() => {
|
||||
mediaContainer.unbindAll();
|
||||
mediaContainer.load(MediaModule);
|
||||
@@ -123,7 +123,9 @@ describe("mediaRouter (R26 error mapping)", () => {
|
||||
mediaContainer
|
||||
.bind(MEDIA_SYMBOLS.IDeleteMediaController)
|
||||
.toDynamicValue((ctx) =>
|
||||
deleteMediaController(ctx.container.get(MEDIA_SYMBOLS.IDeleteMediaUseCase)),
|
||||
deleteMediaController(
|
||||
ctx.container.get(MEDIA_SYMBOLS.IDeleteMediaUseCase),
|
||||
),
|
||||
);
|
||||
|
||||
const caller = mediaRouter.createCaller({});
|
||||
|
||||
Reference in New Issue
Block a user