feat(core): add content use cases with tests (create-article, get-articles)
This commit is contained in:
@@ -0,0 +1,32 @@
|
|||||||
|
import type { Article } from "@/entities/models/article.js";
|
||||||
|
import { getInjection } from "@/di/container.js";
|
||||||
|
|
||||||
|
function generateSlug(title: string): string {
|
||||||
|
return title
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/[^a-z0-9]+/g, "-")
|
||||||
|
.replace(/^-|-$/g, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createArticleUseCase(input: {
|
||||||
|
title: string;
|
||||||
|
content: string;
|
||||||
|
authorId: string;
|
||||||
|
slug?: string;
|
||||||
|
}): Promise<Article> {
|
||||||
|
const articlesRepository = getInjection("IArticlesRepository");
|
||||||
|
|
||||||
|
const now = new Date();
|
||||||
|
const article: Article = {
|
||||||
|
id: crypto.randomUUID(),
|
||||||
|
title: input.title,
|
||||||
|
slug: input.slug ?? generateSlug(input.title),
|
||||||
|
content: input.content,
|
||||||
|
status: "draft",
|
||||||
|
authorId: input.authorId,
|
||||||
|
createdAt: now,
|
||||||
|
updatedAt: now,
|
||||||
|
};
|
||||||
|
|
||||||
|
return await articlesRepository.createArticle(article);
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import type { Article } from "@/entities/models/article.js";
|
||||||
|
import { getInjection } from "@/di/container.js";
|
||||||
|
|
||||||
|
export async function getArticlesUseCase(options?: {
|
||||||
|
status?: string;
|
||||||
|
authorId?: string;
|
||||||
|
limit?: number;
|
||||||
|
offset?: number;
|
||||||
|
}): Promise<Article[]> {
|
||||||
|
const articlesRepository = getInjection("IArticlesRepository");
|
||||||
|
return await articlesRepository.getArticles(options);
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import "reflect-metadata";
|
||||||
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
import {
|
||||||
|
destroyContainer,
|
||||||
|
initializeContainer,
|
||||||
|
} from "@/di/container.js";
|
||||||
|
import { createArticleUseCase } from "@/application/use-cases/content/create-article.use-case.js";
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
initializeContainer();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
destroyContainer();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("createArticleUseCase", () => {
|
||||||
|
it("creates an article with generated slug and draft status", async () => {
|
||||||
|
const result = await createArticleUseCase({
|
||||||
|
title: "My First Article",
|
||||||
|
content: "Hello world",
|
||||||
|
authorId: "1",
|
||||||
|
});
|
||||||
|
expect(result.title).toBe("My First Article");
|
||||||
|
expect(result.slug).toBe("my-first-article");
|
||||||
|
expect(result.status).toBe("draft");
|
||||||
|
expect(result.authorId).toBe("1");
|
||||||
|
expect(result.id).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses provided slug if given", async () => {
|
||||||
|
const result = await createArticleUseCase({
|
||||||
|
title: "Another Article",
|
||||||
|
content: "Content here",
|
||||||
|
authorId: "1",
|
||||||
|
slug: "custom-slug",
|
||||||
|
});
|
||||||
|
expect(result.slug).toBe("custom-slug");
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import "reflect-metadata";
|
||||||
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
import {
|
||||||
|
destroyContainer,
|
||||||
|
initializeContainer,
|
||||||
|
} from "@/di/container.js";
|
||||||
|
import { createArticleUseCase } from "@/application/use-cases/content/create-article.use-case.js";
|
||||||
|
import { getArticlesUseCase } from "@/application/use-cases/content/get-articles.use-case.js";
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
initializeContainer();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
destroyContainer();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("getArticlesUseCase", () => {
|
||||||
|
it("returns empty array when no articles exist", async () => {
|
||||||
|
const result = await getArticlesUseCase();
|
||||||
|
expect(result).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns created articles", async () => {
|
||||||
|
await createArticleUseCase({
|
||||||
|
title: "Article One",
|
||||||
|
content: "Content one",
|
||||||
|
authorId: "1",
|
||||||
|
});
|
||||||
|
await createArticleUseCase({
|
||||||
|
title: "Article Two",
|
||||||
|
content: "Content two",
|
||||||
|
authorId: "1",
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await getArticlesUseCase();
|
||||||
|
expect(result).toHaveLength(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("filters by status", async () => {
|
||||||
|
await createArticleUseCase({
|
||||||
|
title: "Draft Article",
|
||||||
|
content: "Draft",
|
||||||
|
authorId: "1",
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await getArticlesUseCase({ status: "published" });
|
||||||
|
expect(result).toHaveLength(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user