yap-blog/tests/integration/posts.test.ts
2026-07-02 21:32:33 -04:00

100 lines
3.7 KiB
TypeScript

import { beforeEach, describe, expect, it } from "vitest";
import type { PostInput } from "@/lib/services/posts";
import {
createPost,
getPublishedPostBySlug,
listPublishedPosts,
setPostStatus,
} from "@/lib/services/posts";
import { resetDb } from "../helpers/db";
const input = (overrides: Partial<PostInput> = {}): PostInput => ({
title: "A Post",
slug: "",
body: "Some body text for the post.",
authorName: "Tester",
featuredImageUrl: null,
featuredImageAlt: null,
status: "draft",
tagIds: [],
newTagNames: [],
...overrides,
});
beforeEach(resetDb);
describe("public post queries", () => {
it("excludes draft posts from listings and slug lookups", async () => {
await createPost(input({ title: "Published one", status: "published" }));
const draft = await createPost(input({ title: "Hidden draft", status: "draft" }));
const page = await listPublishedPosts({ page: 1, perPage: 10 });
expect(page.total).toBe(1);
expect(page.items.map((p) => p.title)).toEqual(["Published one"]);
expect(await getPublishedPostBySlug(draft.slug)).toBeNull();
});
it("orders posts in reverse chronological order of publication", async () => {
await createPost(input({ title: "Oldest", status: "published" }));
await createPost(input({ title: "Middle", status: "published" }));
await createPost(input({ title: "Newest", status: "published" }));
const page = await listPublishedPosts({ page: 1, perPage: 10 });
expect(page.items.map((p) => p.title)).toEqual(["Newest", "Middle", "Oldest"]);
});
it("paginates with correct totals", async () => {
for (let i = 1; i <= 7; i++) {
await createPost(input({ title: `Post ${i}`, status: "published" }));
}
const first = await listPublishedPosts({ page: 1, perPage: 5 });
expect(first.items).toHaveLength(5);
expect(first.total).toBe(7);
expect(first.pageCount).toBe(2);
const second = await listPublishedPosts({ page: 2, perPage: 5 });
expect(second.items).toHaveLength(2);
expect(second.items.map((p) => p.title)).toEqual(["Post 2", "Post 1"]);
});
});
describe("creating and publishing a post", () => {
it("keeps a new draft private, then makes it public on publish", async () => {
const draft = await createPost(input({ title: "Launch notes" }));
expect(draft.publishedAt).toBeNull();
expect(await getPublishedPostBySlug("launch-notes")).toBeNull();
const published = await setPostStatus(draft.id, "published");
expect(published?.status).toBe("published");
expect(published?.publishedAt).toBeInstanceOf(Date);
const publicPost = await getPublishedPostBySlug("launch-notes");
expect(publicPost?.title).toBe("Launch notes");
const listing = await listPublishedPosts({ page: 1, perPage: 10 });
expect(listing.items.map((p) => p.slug)).toContain("launch-notes");
});
it("stamps publishedAt once and keeps it across unpublish/republish", async () => {
const post = await createPost(input({ status: "published" }));
const firstDate = post.publishedAt;
expect(firstDate).toBeInstanceOf(Date);
const unpublished = await setPostStatus(post.id, "draft");
expect(unpublished?.publishedAt?.getTime()).toBe(firstDate?.getTime());
const republished = await setPostStatus(post.id, "published");
expect(republished?.publishedAt?.getTime()).toBe(firstDate?.getTime());
});
it("attaches existing and newly created tags", async () => {
const post = await createPost(
input({ status: "published", newTagNames: ["Fresh Tag", "Another"] }),
);
const publicPost = await getPublishedPostBySlug(post.slug);
expect(publicPost?.tags.map((t) => t.slug).sort()).toEqual(["another", "fresh-tag"]);
});
});