From 3e6f632c4bc094042e2ffc05cabdb292a646dc57 Mon Sep 17 00:00:00 2001 From: Danijel Martinek Date: Mon, 4 May 2026 22:37:18 +0200 Subject: [PATCH] =?UTF-8?q?test(blog):=20add=20feature-level=20test=20exer?= =?UTF-8?q?cising=20router=20=E2=86=92=20controller=20=E2=86=92=20use-case?= =?UTF-8?q?=20=E2=86=92=20repo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/blog/tests/articles.feature.test.ts | 56 ++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 packages/blog/tests/articles.feature.test.ts diff --git a/packages/blog/tests/articles.feature.test.ts b/packages/blog/tests/articles.feature.test.ts new file mode 100644 index 0000000..b9c0066 --- /dev/null +++ b/packages/blog/tests/articles.feature.test.ts @@ -0,0 +1,56 @@ +// Feature-level test: exercises the full slice +// tRPC procedure -> controller -> use-case -> mock repo +// without going through a network or the actual Payload Local API. +// Verifies that the layers are correctly wired through the per-feature DI container. + +import { beforeEach, describe, expect, it } from "vitest"; +import { blogContainer } from "../src/di/container"; +import { BLOG_SYMBOLS } from "../src/di/symbols"; +import { MockArticlesRepository } from "../src/infrastructure/repositories/mock-articles.repository"; +import type { IArticlesRepository } from "../src/application/repositories/articles-repository.interface"; +import { blogRouter } from "../src/integrations/api/router"; + +describe("blog feature: article-by-slug end-to-end", () => { + let repo: MockArticlesRepository; + + beforeEach(() => { + if (blogContainer.isBound(BLOG_SYMBOLS.IArticlesRepository)) { + blogContainer.unbind(BLOG_SYMBOLS.IArticlesRepository); + } + repo = new MockArticlesRepository(); + blogContainer + .bind(BLOG_SYMBOLS.IArticlesRepository) + .toConstantValue(repo); + }); + + it("creates an article via tRPC, then fetches it back by slug", async () => { + const caller = blogRouter.createCaller({}); + + const created = await caller.createArticle({ + title: "The Vertical Refactor", + content: { type: "doc", children: [] }, + authorId: "u1", + slug: "vertical-refactor", + }); + expect(created.id).toBeTruthy(); + expect(created.slug).toBe("vertical-refactor"); + + const fetched = await caller.articleBySlug({ slug: "vertical-refactor" }); + expect(fetched?.id).toBe(created.id); + expect(fetched?.title).toBe("The Vertical Refactor"); + }); + + it("listArticles filters by status", async () => { + const caller = blogRouter.createCaller({}); + await caller.createArticle({ + title: "Draft One", + content: null, + authorId: "u1", + }); + const draftOnly = await caller.listArticles({ status: "draft" }); + expect(draftOnly).toHaveLength(1); + + const publishedOnly = await caller.listArticles({ status: "published" }); + expect(publishedOnly).toHaveLength(0); + }); +});