import { describe, expect, mock, test } from "bun:test"; const defaultPostsPreview = { items: [ { slug: "p1", title: "post-1" }, { slug: "p2", title: "post-2" }, { slug: "p3", title: "post-3" }, ], total: 3, }; const defaultTimelinePreview = { items: [ { id: 1, title: "timeline-1" }, { id: 2, title: "timeline-2" }, { id: 3, title: "timeline-3" }, ], total: 9, }; const defaultRssPreview = { items: [ { id: 10, title: "rss-1" }, { id: 11, title: "rss-2" }, { id: 12, title: "rss-3" }, ], total: 12, }; const getPublicPostsPreviewBySlug = mock(async () => defaultPostsPreview); const getPublicTimelinePreviewBySlug = mock(async () => defaultTimelinePreview); const getPublicRssPreviewBySlug = mock(async () => defaultRssPreview); const unusedPageMock = async () => { throw new Error("page service should not be called in public-hub tests"); }; mock.module("#server/service/posts", () => ({ getPublicPostsPreviewBySlug, getPublicPostsPageBySlug: unusedPageMock, })); mock.module("#server/service/timeline", () => ({ getPublicTimelinePreviewBySlug, getPublicTimelinePageBySlug: unusedPageMock, })); mock.module("#server/service/rss", () => ({ getPublicRssPreviewBySlug, getPublicRssPageBySlug: unusedPageMock, })); const { getPublicHubBySlug } = await import("./index"); describe("public hub service", () => { test("items 少于 2 时保持原样", async () => { getPublicPostsPreviewBySlug.mockResolvedValueOnce({ items: [{ slug: "only-post", title: "post-only" }], total: 1, }); getPublicTimelinePreviewBySlug.mockResolvedValueOnce({ items: [{ id: 100, title: "timeline-only" }], total: 1, }); getPublicRssPreviewBySlug.mockResolvedValueOnce({ items: [{ id: 200, title: "rss-only" }], total: 1, }); const result = await getPublicHubBySlug("short-list-user"); expect(result).toEqual({ modules: { posts: { items: [{ slug: "only-post", title: "post-only" }], total: 1, }, timeline: { items: [{ id: 100, title: "timeline-only" }], total: 1, }, reading: { items: [{ id: 200, title: "rss-only" }], total: 1, }, }, posts: { items: [{ slug: "only-post", title: "post-only" }], total: 1, }, timeline: { items: [{ id: 100, title: "timeline-only" }], total: 1, }, rssItems: { items: [{ id: 200, title: "rss-only" }], total: 1, }, }); }); test("聚合 posts/timeline/reading 的预览与 total,且预览上限 2", async () => { const result = await getPublicHubBySlug("demo-user"); expect(getPublicPostsPreviewBySlug).toHaveBeenCalledWith("demo-user"); expect(getPublicTimelinePreviewBySlug).toHaveBeenCalledWith("demo-user"); expect(getPublicRssPreviewBySlug).toHaveBeenCalledWith("demo-user"); expect(result).toEqual({ modules: { posts: { items: [ { slug: "p1", title: "post-1" }, { slug: "p2", title: "post-2" }, ], total: 3, }, timeline: { items: [ { id: 1, title: "timeline-1" }, { id: 2, title: "timeline-2" }, ], total: 9, }, reading: { items: [ { id: 10, title: "rss-1" }, { id: 11, title: "rss-2" }, ], total: 12, }, }, posts: { items: [ { slug: "p1", title: "post-1" }, { slug: "p2", title: "post-2" }, { slug: "p3", title: "post-3" }, ], total: 3, }, timeline: { items: [ { id: 1, title: "timeline-1" }, { id: 2, title: "timeline-2" }, { id: 3, title: "timeline-3" }, ], total: 9, }, rssItems: { items: [ { id: 10, title: "rss-1" }, { id: 11, title: "rss-2" }, { id: 12, title: "rss-3" }, ], total: 12, }, }); }); test("任一依赖 reject 时函数整体 reject", async () => { getPublicTimelinePreviewBySlug.mockRejectedValueOnce( new Error("timeline service failed"), ); await expect(getPublicHubBySlug("failing-user")).rejects.toThrow( "timeline service failed", ); }); });