Initial commit
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { deleteMediaController } from "@/interface-adapters/controllers/delete-media.controller";
|
||||
import { deleteMediaUseCase } from "@/application/use-cases/delete-media.use-case";
|
||||
import { MockMediaRepository } from "@/infrastructure/repositories/media.repository.mock";
|
||||
import { MediaNotFoundError } from "@/entities/errors/media";
|
||||
import { InputParseError } from "@/entities/errors/common";
|
||||
import { mediaFactory } from "@/__factories__/media.factory";
|
||||
|
||||
describe("deleteMediaController", () => {
|
||||
it("deletes media successfully", async () => {
|
||||
const repo = new MockMediaRepository();
|
||||
const seed = mediaFactory.build({ id: "m-1" });
|
||||
await repo._store(seed);
|
||||
|
||||
const useCase = deleteMediaUseCase(repo);
|
||||
const controller = deleteMediaController(useCase);
|
||||
|
||||
await expect(controller({ id: "m-1" })).resolves.toBeUndefined();
|
||||
const result = await repo.getMedia("m-1");
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it("throws InputParseError when id is missing", async () => {
|
||||
const repo = new MockMediaRepository();
|
||||
const useCase = deleteMediaUseCase(repo);
|
||||
const controller = deleteMediaController(useCase);
|
||||
|
||||
await expect(controller({})).rejects.toThrow(InputParseError);
|
||||
});
|
||||
|
||||
it("throws MediaNotFoundError when media does not exist", async () => {
|
||||
const repo = new MockMediaRepository();
|
||||
const useCase = deleteMediaUseCase(repo);
|
||||
const controller = deleteMediaController(useCase);
|
||||
|
||||
await expect(controller({ id: "missing" })).rejects.toThrow(MediaNotFoundError);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
import { InputParseError } from "../../entities/errors/common";
|
||||
import {
|
||||
deleteMediaInputSchema,
|
||||
type IDeleteMediaUseCase,
|
||||
} from "../../application/use-cases/delete-media.use-case";
|
||||
|
||||
export type IDeleteMediaController = ReturnType<typeof deleteMediaController>;
|
||||
|
||||
export const deleteMediaController =
|
||||
(deleteMediaUseCase: IDeleteMediaUseCase) =>
|
||||
async (input: unknown): Promise<void> => {
|
||||
const parsed = deleteMediaInputSchema.safeParse(input);
|
||||
if (!parsed.success) {
|
||||
throw new InputParseError("Invalid delete-media input", { cause: parsed.error });
|
||||
}
|
||||
await deleteMediaUseCase(parsed.data);
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { getMediaController } from "@/interface-adapters/controllers/get-media.controller";
|
||||
import { getMediaUseCase } from "@/application/use-cases/get-media.use-case";
|
||||
import { MockMediaRepository } from "@/infrastructure/repositories/media.repository.mock";
|
||||
import { MediaNotFoundError } from "@/entities/errors/media";
|
||||
import { InputParseError } from "@/entities/errors/common";
|
||||
import { mediaFactory } from "@/__factories__/media.factory";
|
||||
|
||||
describe("getMediaController", () => {
|
||||
it("returns media on valid input", async () => {
|
||||
const repo = new MockMediaRepository();
|
||||
const seed = mediaFactory.build({ id: "m-1" });
|
||||
await repo._store(seed);
|
||||
|
||||
const useCase = getMediaUseCase(repo);
|
||||
const controller = getMediaController(useCase);
|
||||
|
||||
const result = await controller({ id: "m-1" });
|
||||
expect(result.id).toBe("m-1");
|
||||
});
|
||||
|
||||
it("throws InputParseError when id is missing", async () => {
|
||||
const repo = new MockMediaRepository();
|
||||
const useCase = getMediaUseCase(repo);
|
||||
const controller = getMediaController(useCase);
|
||||
|
||||
await expect(controller({})).rejects.toThrow(InputParseError);
|
||||
});
|
||||
|
||||
it("throws InputParseError when id is empty string", async () => {
|
||||
const repo = new MockMediaRepository();
|
||||
const useCase = getMediaUseCase(repo);
|
||||
const controller = getMediaController(useCase);
|
||||
|
||||
await expect(controller({ id: "" })).rejects.toThrow(InputParseError);
|
||||
});
|
||||
|
||||
it("throws MediaNotFoundError when media does not exist", async () => {
|
||||
const repo = new MockMediaRepository();
|
||||
const useCase = getMediaUseCase(repo);
|
||||
const controller = getMediaController(useCase);
|
||||
|
||||
await expect(controller({ id: "missing" })).rejects.toThrow(MediaNotFoundError);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { InputParseError } from "../../entities/errors/common";
|
||||
import {
|
||||
getMediaInputSchema,
|
||||
type GetMediaOutput,
|
||||
type IGetMediaUseCase,
|
||||
} from "../../application/use-cases/get-media.use-case";
|
||||
|
||||
function presenter(value: GetMediaOutput) {
|
||||
return value;
|
||||
}
|
||||
|
||||
export type IGetMediaController = ReturnType<typeof getMediaController>;
|
||||
|
||||
export const getMediaController =
|
||||
(getMediaUseCase: IGetMediaUseCase) =>
|
||||
async (input: unknown): Promise<ReturnType<typeof presenter>> => {
|
||||
const parsed = getMediaInputSchema.safeParse(input);
|
||||
if (!parsed.success) {
|
||||
throw new InputParseError("Invalid get-media input", { cause: parsed.error });
|
||||
}
|
||||
const result = await getMediaUseCase(parsed.data);
|
||||
return presenter(result);
|
||||
};
|
||||
@@ -0,0 +1,60 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { listMediaController } from "@/interface-adapters/controllers/list-media.controller";
|
||||
import { listMediaUseCase } from "@/application/use-cases/list-media.use-case";
|
||||
import { MockMediaRepository } from "@/infrastructure/repositories/media.repository.mock";
|
||||
import { InputParseError } from "@/entities/errors/common";
|
||||
import { mediaFactory } from "@/__factories__/media.factory";
|
||||
|
||||
describe("listMediaController", () => {
|
||||
it("returns empty array when no media exists", async () => {
|
||||
const repo = new MockMediaRepository();
|
||||
const useCase = listMediaUseCase(repo);
|
||||
const controller = listMediaController(useCase);
|
||||
|
||||
const result = await controller({});
|
||||
expect(result).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("returns all media", async () => {
|
||||
const repo = new MockMediaRepository();
|
||||
await repo._store(mediaFactory.build());
|
||||
await repo._store(mediaFactory.build());
|
||||
|
||||
const useCase = listMediaUseCase(repo);
|
||||
const controller = listMediaController(useCase);
|
||||
|
||||
const result = await controller({});
|
||||
expect(result).toHaveLength(2);
|
||||
});
|
||||
|
||||
it("passes limit and offset to use case", async () => {
|
||||
const repo = new MockMediaRepository();
|
||||
for (let i = 0; i < 5; i++) {
|
||||
await repo._store(mediaFactory.build());
|
||||
}
|
||||
|
||||
const useCase = listMediaUseCase(repo);
|
||||
const controller = listMediaController(useCase);
|
||||
|
||||
const result = await controller({ limit: 2, offset: 1 });
|
||||
expect(result).toHaveLength(2);
|
||||
});
|
||||
|
||||
it("throws InputParseError on unknown fields (strict schema)", async () => {
|
||||
const repo = new MockMediaRepository();
|
||||
const useCase = listMediaUseCase(repo);
|
||||
const controller = listMediaController(useCase);
|
||||
|
||||
await expect(controller({ unknownField: 1 })).rejects.toThrow(
|
||||
InputParseError,
|
||||
);
|
||||
});
|
||||
|
||||
it("throws InputParseError when limit is not a positive integer", async () => {
|
||||
const repo = new MockMediaRepository();
|
||||
const useCase = listMediaUseCase(repo);
|
||||
const controller = listMediaController(useCase);
|
||||
|
||||
await expect(controller({ limit: -1 })).rejects.toThrow(InputParseError);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { InputParseError } from "../../entities/errors/common";
|
||||
import {
|
||||
listMediaInputSchema,
|
||||
type ListMediaOutput,
|
||||
type IListMediaUseCase,
|
||||
} from "../../application/use-cases/list-media.use-case";
|
||||
|
||||
function presenter(value: ListMediaOutput) {
|
||||
return value;
|
||||
}
|
||||
|
||||
export type IListMediaController = ReturnType<typeof listMediaController>;
|
||||
|
||||
export const listMediaController =
|
||||
(listMediaUseCase: IListMediaUseCase) =>
|
||||
async (input: unknown): Promise<ReturnType<typeof presenter>> => {
|
||||
const parsed = listMediaInputSchema.safeParse(input);
|
||||
if (!parsed.success) {
|
||||
throw new InputParseError("Invalid list-media input", { cause: parsed.error });
|
||||
}
|
||||
const result = await listMediaUseCase(parsed.data);
|
||||
return presenter(result);
|
||||
};
|
||||
Reference in New Issue
Block a user