import { beforeEach, describe, expect, it, vi } from "vitest"; import { PERMS } from "@/lib/permission-slugs"; import type { HousekeepingCapabilityContext } from "../../../foundation/contracts"; import { CONTENT_ROUTE_IDS } from "../routes"; import { type ContentQueryData, type ContentQueryInput, createContentQuery, type NormalizedContentQueryInput, } from "./content-queries"; import { CONTENT_QUERY_DEFINITIONS, loadProductionContentQuery, } from "./content-queries-production"; const queryMocks = vi.hoisted(() => ({ execute: vi.fn(), join: vi.fn((chunks: unknown[], separator: unknown) => ({ chunks, separator, })), raw: vi.fn((statement: string) => ({ statement })), tagged: vi.fn((strings: TemplateStringsArray, ...values: unknown[]) => ({ strings: Array.from(strings), values, })), })); vi.mock("drizzle-orm", () => ({ sql: Object.assign(queryMocks.tagged, { join: queryMocks.join, raw: queryMocks.raw, }), })); vi.mock("@/lib/db", () => ({ db: { execute: queryMocks.execute } })); function context(granted: readonly string[]): HousekeepingCapabilityContext { const permissions = new Set(granted); return { actor: { id: 42, username: "operator", rank: 7 }, isSuperAdmin: false, has: (slug) => permissions.has(slug), hasAny: (...slugs) => slugs.some((slug) => permissions.has(slug)), hasAll: (...slugs) => slugs.every((slug) => permissions.has(slug)), }; } const ready: ContentQueryData = { kind: "editorial", items: [ { id: "18446744073709551615", title: "Published article", status: "published", href: "/ase-next/content/editorial/articles/18446744073709551615", }, ], total: 1, partialDependencies: [], }; const normalizedResponsePage = { responseQuestionId: "", responsePageSize: 25, responseOffset: 0, } as const; const pollDetail = { kind: "poll-detail" as const, description: "Complete poll", showResults: true, multipleChoice: false, startsAt: "2026-09-02T18:00:00.000Z", endsAt: null, questionCount: 1, voterCount: 2, answerCount: 2, questions: [ { id: "21", question: "Favourite colour?", type: "single" as const, sortOrder: 0, options: ["Red", "Blue"], answerCount: 2, choiceResults: [{ option: "Red", count: 2 }], }, ], textResponses: { questionId: null, items: [], total: 0, pageSize: 25, offset: 0, }, }; describe("Content query", () => { beforeEach(() => queryMocks.execute.mockReset()); it("reports totals beyond the former 500-row adapter cap", async () => { const pageRows = Array.from({ length: 25 }, (_, index) => ({ id: index + 1, title: `Article ${index + 1}`, status: "published", updated_at: null, })); queryMocks.execute .mockResolvedValueOnce([[{ total: 600 }]]) .mockResolvedValueOnce([pageRows]); const result = await loadProductionContentQuery({ routeId: "content.editorial.articles", params: {}, list: { ...normalizedResponsePage, search: "", pageSize: 25, offset: 0 }, }); expect(result.total).toBe(600); expect(result.items).toHaveLength(25); expect(queryMocks.execute).toHaveBeenCalledTimes(2); const pageQuery = queryMocks.execute.mock.calls[1]?.[0]; expect(JSON.stringify(pageQuery)).toContain("25"); expect(JSON.stringify(pageQuery)).toContain("0"); }); it("binds search, limit, and offset into the bounded page query", async () => { queryMocks.execute .mockResolvedValueOnce([[{ total: 1 }]]) .mockResolvedValueOnce([ [{ id: 9, title: "Launch", status: "published", updated_at: null }], ]); await loadProductionContentQuery({ routeId: "content.editorial.articles", params: {}, list: { ...normalizedResponsePage, search: "Launch", pageSize: 7, offset: 14, }, }); const serialized = JSON.stringify(queryMocks.execute.mock.calls); expect(serialized).toContain("%launch%"); expect(serialized).toContain("7"); expect(serialized).toContain("14"); }); it("searches event titles and projected event-type descriptions", async () => { queryMocks.execute .mockResolvedValueOnce([[{ total: 0 }]]) .mockResolvedValueOnce([[]]); await loadProductionContentQuery({ routeId: "content.engagement.events", params: {}, list: { ...normalizedResponsePage, search: "launch", pageSize: 25, offset: 0, }, }); const serialized = JSON.stringify(queryMocks.execute.mock.calls.slice(-2)); expect(serialized).toContain("COALESCE(title"); expect(serialized).toContain("COALESCE(description"); }); it("never selects email template bodies into summary query results", () => { const emailTemplates = CONTENT_QUERY_DEFINITIONS["content.help.email-templates"]; expect(emailTemplates.statement).not.toMatch(/\bbody\b|private_payload/iu); }); it("loads the editable payload only for an individual article", async () => { queryMocks.execute .mockResolvedValueOnce([[{ total: 1 }]]) .mockResolvedValueOnce([ [ { id: 7, title: "Launch day", description: "launch-day", status: "published", updated_at: null, slug: "launch-day", image: "/media/launch.webp", short_story: "Short launch summary", full_story: "
Complete launch story
", }, ], ]); const result = await loadProductionContentQuery({ routeId: "content.editorial.article-detail", params: { id: "7" }, list: { ...normalizedResponsePage, search: "", pageSize: 25, offset: 0 }, }); expect(result.items[0]?.privatePayload).toEqual({ slug: "launch-day", image: "/media/launch.webp", shortStory: "Short launch summary", fullStory: "Complete launch story
", }); expect( CONTENT_QUERY_DEFINITIONS["content.editorial.articles"].statement, ).not.toMatch(/short_story|full_story/iu); }); it("loads event summaries with operational metadata and a bound status filter", async () => { queryMocks.execute .mockResolvedValueOnce([[{ total: 1 }]]) .mockResolvedValueOnce([ [ { id: 11, title: "Battle Ball", status: "published", updated_at: new Date("2026-09-01T08:00:00.000Z"), type_id: 2, type_name: "Tournament", type_color: "#ff9900", starts_at: new Date("2026-09-02T18:00:00.000Z"), ends_at: new Date("2026-09-02T19:00:00.000Z"), max_players: 20, registration_count: 12, }, ], ]); const result = await loadProductionContentQuery({ routeId: "content.engagement.events", params: {}, list: { ...normalizedResponsePage, search: "", status: "published", pageSize: 25, offset: 0, }, }); expect(result.items[0]?.privatePayload).toEqual({ kind: "event-summary", typeId: "2", typeName: "Tournament", typeColor: "#ff9900", startsAt: "2026-09-02T18:00:00.000Z", endsAt: "2026-09-02T19:00:00.000Z", maxPlayers: 20, registrationCount: 12, }); expect(JSON.stringify(queryMocks.execute.mock.calls)).toContain( "published", ); }); it("loads active event types for event creation", async () => { queryMocks.execute.mockResolvedValueOnce([ [ { id: 2, name: "Tournament", slug: "tournament", description: "Ranked competition", color: "#ff9900", icon: "trophy", is_active: 1, min_rank: 1, }, ], ]); const result = await loadProductionContentQuery({ routeId: "content.engagement.event-create", params: {}, list: { ...normalizedResponsePage, search: "", pageSize: 25, offset: 0 }, }); expect(result.items[0]).toMatchObject({ id: "2", title: "Tournament", privatePayload: { kind: "event-type", slug: "tournament", isActive: true, }, }); }); it("loads bounded poll summaries with operator counts and bound filters", async () => { queryMocks.execute .mockResolvedValueOnce([[{ total: 1 }]]) .mockResolvedValueOnce([ [ { id: 7, title: "Autumn plans", status: "active", updated_at: new Date("2026-09-01T08:00:00.000Z"), show_results: 1, multiple_choice: 0, starts_at: new Date("2026-09-02T18:00:00.000Z"), ends_at: null, question_count: 3, voter_count: 12, answer_count: 30, }, ], ]); const result = await loadProductionContentQuery({ routeId: "content.engagement.polls", params: {}, list: { ...normalizedResponsePage, search: "Autumn", status: "active", pageSize: 25, offset: 0, }, }); expect(result.items[0]?.privatePayload).toEqual({ kind: "poll-summary", showResults: true, multipleChoice: false, startsAt: "2026-09-02T18:00:00.000Z", endsAt: null, questionCount: 3, voterCount: 12, answerCount: 30, }); const sql = JSON.stringify(queryMocks.execute.mock.calls); expect(sql).toContain("%autumn%"); expect(sql).toContain("active"); }); it("returns the stable poll-create payload without database access", async () => { const result = await loadProductionContentQuery({ routeId: "content.engagement.poll-create", params: {}, list: { ...normalizedResponsePage, search: "", pageSize: 25, offset: 0 }, }); expect(result).toEqual({ kind: "engagement", items: [ { id: "create", title: "Create poll", href: "/ase-next/content/engagement/polls/create", privatePayload: { kind: "poll-create" }, }, ], total: 1, partialDependencies: [], }); expect(queryMocks.execute).not.toHaveBeenCalled(); }); it("loads selected poll results from bounded grouped aggregates and response pages", async () => { queryMocks.execute .mockResolvedValueOnce([ [ { id: 7, title: "Autumn plans", description: "Complete poll", status: "active", updated_at: new Date("2026-09-01T08:00:00.000Z"), show_results: 1, multiple_choice: 0, starts_at: new Date("2026-09-02T18:00:00.000Z"), ends_at: null, question_count: 2, voter_count: 12, answer_count: 30, }, ], ]) .mockResolvedValueOnce([ [ { id: 21, question: "Favourite colour?", type: "single", sort_order: 0, options: "Red\nBlue", }, { id: 22, question: "What should improve?", type: "text", sort_order: 1, options: "", }, ], ]) .mockResolvedValueOnce([ [ { question_id: 21, answer: "Red", answer_count: 3 }, { question_id: 21, answer: "Blue", answer_count: 1 }, ], ]) .mockResolvedValueOnce([[{ total: 51 }]]) .mockResolvedValueOnce([ [ { id: 1, question_id: 22, user_id: 9, username: "Alice", answer: "More events", created_at: new Date("2026-09-02T20:00:00.000Z"), }, { id: 2, question_id: 22, user_id: 10, username: null, answer: "Better prizes", created_at: new Date("2026-09-02T19:00:00.000Z"), }, ], ]); const result = await loadProductionContentQuery({ routeId: "content.engagement.poll-detail", params: { id: "7" }, list: { ...normalizedResponsePage, search: "", pageSize: 25, offset: 0, responseQuestionId: "22", responsePageSize: 25, responseOffset: 25, }, }); expect(result.items[0]?.privatePayload).toMatchObject({ kind: "poll-detail", questions: [ { id: "21", options: ["Red", "Blue"], answerCount: 4, choiceResults: [ { option: "Red", count: 3 }, { option: "Blue", count: 1 }, ], }, { id: "22", type: "text", options: [], answerCount: 0, choiceResults: [], }, ], textResponses: { questionId: "22", total: 51, pageSize: 25, offset: 25, items: [ { userId: "9", username: "Alice", answer: "More events" }, { userId: "10", username: null, answer: "Better prizes" }, ], }, }); const sql = JSON.stringify(queryMocks.execute.mock.calls); expect(sql).toContain("LIMIT 101"); expect(sql).toContain("LIMIT 10001"); expect(sql).toContain("7"); expect(sql).toContain("22"); expect(sql).toContain("25"); expect(queryMocks.execute).toHaveBeenCalledTimes(5); }); it("rejects a poll detail with 101 questions before loading results", async () => { queryMocks.execute .mockResolvedValueOnce([ [{ id: 7, title: "Oversized poll", status: "draft" }], ]) .mockResolvedValueOnce([ Array.from({ length: 101 }, (_, index) => ({ id: index + 1, question: `Question ${index + 1}`, type: "single", sort_order: index, options: "Yes\nNo", })), ]); await expect( loadProductionContentQuery({ routeId: "content.engagement.poll-detail", params: { id: "7" }, list: { ...normalizedResponsePage, search: "", pageSize: 25, offset: 0, }, }), ).rejects.toThrow("poll question limit"); expect(queryMocks.execute).toHaveBeenCalledTimes(2); }); it("rejects 10001 grouped poll result rows before aggregating them", async () => { queryMocks.execute .mockResolvedValueOnce([ [{ id: 7, title: "Oversized results", status: "active" }], ]) .mockResolvedValueOnce([ [ { id: 21, question: "Favourite colour?", type: "single", sort_order: 0, options: "Red\nBlue", }, ], ]) .mockResolvedValueOnce([ Array.from({ length: 10_001 }, (_, index) => ({ question_id: 21, answer: `Choice ${index + 1}`, answer_count: 1, })), ]); await expect( loadProductionContentQuery({ routeId: "content.engagement.poll-detail", params: { id: "7" }, list: { ...normalizedResponsePage, search: "", pageSize: 25, offset: 0, }, }), ).rejects.toThrow("poll aggregate limit"); expect(queryMocks.execute).toHaveBeenCalledTimes(3); }); it("rejects a poll question with more than 100 parsed options", async () => { queryMocks.execute .mockResolvedValueOnce([ [{ id: 7, title: "Oversized options", status: "draft" }], ]) .mockResolvedValueOnce([ [ { id: 21, question: "Choose one", type: "single", sort_order: 0, options: Array.from( { length: 101 }, (_, index) => `Option ${index + 1}`, ).join("\n"), }, ], ]); await expect( loadProductionContentQuery({ routeId: "content.engagement.poll-detail", params: { id: "7" }, list: { ...normalizedResponsePage, search: "", pageSize: 25, offset: 0, }, }), ).rejects.toThrow("poll option limit"); expect(queryMocks.execute).toHaveBeenCalledTimes(2); }); it.each([ ["a foreign question", "999"], ["a non-text question", "21"], ])( "falls back to the first text question for %s", async (_label, requestedId) => { queryMocks.execute .mockResolvedValueOnce([ [{ id: 7, title: "Response fallback", status: "active" }], ]) .mockResolvedValueOnce([ [ { id: 21, question: "Favourite colour?", type: "single", sort_order: 0, options: "Red\nBlue", }, { id: 22, question: "What should improve?", type: "text", sort_order: 1, options: "", }, ], ]) .mockResolvedValueOnce([[]]) .mockResolvedValueOnce([[{ total: 0 }]]) .mockResolvedValueOnce([[]]); const result = await loadProductionContentQuery({ routeId: "content.engagement.poll-detail", params: { id: "7" }, list: { ...normalizedResponsePage, search: "", pageSize: 25, offset: 0, responseQuestionId: requestedId, }, }); expect(result.items[0]?.privatePayload).toMatchObject({ textResponses: { questionId: "22" }, }); expect(JSON.stringify(queryMocks.execute.mock.calls.slice(3))).toContain( "22", ); expect(queryMocks.execute).toHaveBeenCalledTimes(5); }, ); it("returns a valid empty detail result when the selected poll is missing", async () => { queryMocks.execute.mockResolvedValueOnce([[]]); await expect( loadProductionContentQuery({ routeId: "content.engagement.poll-detail", params: { id: "7" }, list: { ...normalizedResponsePage, search: "", pageSize: 25, offset: 0, }, }), ).resolves.toEqual({ kind: "engagement", items: [], total: 0, partialDependencies: [], }); }); it("loads only the selected event with all related operator data", async () => { queryMocks.execute .mockResolvedValueOnce([ [ { id: 11, title: "Battle Ball", status: "published", updated_at: new Date("2026-09-01T08:00:00.000Z"), description: "Complete event", type_id: 2, host_user_id: 5, room_id: 99, starts_at: new Date("2026-09-02T18:00:00.000Z"), ends_at: null, max_players: 20, is_recurring: 0, recurrence_rule: null, image: "/media/event.webp", }, ], ]) .mockResolvedValueOnce([ [ { id: 2, name: "Tournament", slug: "tournament", description: "Ranked competition", color: "#ff9900", icon: "trophy", is_active: 1, min_rank: 1, }, ], ]) .mockResolvedValueOnce([ [ { id: 4, position: 1, prize_type: "badge", badge_code: "WIN1", credits: 0, pixels: 0, points: 0, item_id: null, description: "Winner badge", }, ], ]) .mockResolvedValueOnce([ [ { id: 6, user_id: 9, position: 1, username: "Alice", created_at: new Date("2026-09-02T20:00:00.000Z"), }, ], ]) .mockResolvedValueOnce([ [ { id: 8, user_id: 10, username: "Bob", created_at: new Date("2026-09-01T12:00:00.000Z"), }, ], ]); const result = await loadProductionContentQuery({ routeId: "content.engagement.event-detail", params: { id: "11" }, list: { ...normalizedResponsePage, search: "", pageSize: 25, offset: 0 }, }); expect(result.items).toHaveLength(1); expect(result.items[0]?.privatePayload).toMatchObject({ kind: "event-detail", description: "Complete event", eventTypes: [{ id: "2", name: "Tournament" }], prizes: [{ id: "4", prizeType: "badge" }], winners: [{ userId: "9", username: "Alice" }], registrations: [{ userId: "10", username: "Bob" }], }); const sql = JSON.stringify(queryMocks.execute.mock.calls); expect(sql).toContain("11"); expect(queryMocks.execute).toHaveBeenCalledTimes(5); }); it("fails closed before production adapters are invoked", async () => { const load = vi.fn(async () => ready); const query = createContentQuery({ load }); const result = await query.run(context([]), { routeId: "content.editorial.articles", list: { search: "", pageSize: 25, offset: 0 }, }); expect(result).toMatchObject({ ok: false, error: { code: "FORBIDDEN" }, }); expect(load).not.toHaveBeenCalled(); }); it("bounds list input, preserves canonical BIGINT strings, and returns real adapter data", async () => { const load = vi.fn(async (_input: ContentQueryInput) => ready); const query = createContentQuery({ load }); const result = await query.run(context([PERMS.NEWS_VIEW]), { routeId: "content.editorial.articles", list: { search: " launch ", pageSize: 1000, offset: 999_999, }, }); expect(load).toHaveBeenCalledWith({ routeId: "content.editorial.articles", params: {}, list: { search: "launch", pageSize: 100, offset: 100_000, responseQuestionId: "", responsePageSize: 25, responseOffset: 0, }, }); expect(result).toMatchObject({ ok: true, data: { items: [{ id: "18446744073709551615" }], total: 1, partialDependencies: [], }, }); }); it("normalizes bounded poll response-page input before invoking the adapter", async () => { const load = vi.fn(async () => ({ kind: "engagement" as const, items: [], total: 0, partialDependencies: [], })); const query = createContentQuery({ load }); await query.run(context([PERMS.POLLS_VIEW, PERMS.POLLS_EDIT]), { routeId: "content.engagement.poll-detail", params: { id: "7" }, list: { responseQuestionId: " 22 ", responsePageSize: 50, responseOffset: 100_000, }, }); expect(load).toHaveBeenCalledWith({ routeId: "content.engagement.poll-detail", params: { id: "7" }, list: { search: "", pageSize: 25, offset: 0, responseQuestionId: "22", responsePageSize: 50, responseOffset: 100_000, }, }); }); it("requires response-page defaults in normalized adapter inputs", () => { const incomplete: NormalizedContentQueryInput = { routeId: "content.engagement.events", params: {}, // @ts-expect-error Normalized adapter inputs must always include response paging. list: { search: "", pageSize: 25, offset: 0 }, }; expect(incomplete.routeId).toBe("content.engagement.events"); }); it.each([ ["mismatched id", "8", pollDetail], [ "too many questions", "7", { ...pollDetail, questions: Array(101).fill(pollDetail.questions[0]) }, ], [ "invalid response user", "7", { ...pollDetail, textResponses: { questionId: "22", items: [ { id: "1", questionId: "22", userId: "0", username: null, answer: "Text", createdAt: "2026-09-02T18:00:00.000Z", }, ], total: 1, pageSize: 25, offset: 0, }, }, ], ] as const)( "fails closed for poll detail with %s", async (_label, itemId, payload) => { const query = createContentQuery({ load: async () => ({ kind: "engagement" as const, items: [{ id: itemId, title: "Poll", privatePayload: payload }], total: 1, partialDependencies: [], }), }); const result = await query.run( context([PERMS.POLLS_VIEW, PERMS.POLLS_EDIT]), { routeId: "content.engagement.poll-detail", params: { id: "7" }, }, ); expect(result).toMatchObject({ ok: false, error: { code: "DEPENDENCY_UNAVAILABLE" }, }); }, ); it("fails closed when poll creation does not return the exact create payload", async () => { const query = createContentQuery({ load: async () => ({ kind: "engagement" as const, items: [ { id: "7", title: "Poll", privatePayload: { kind: "poll-create" } }, ], total: 1, partialDependencies: [], }), }); expect( await query.run(context([PERMS.POLLS_EDIT]), { routeId: "content.engagement.poll-create", }), ).toMatchObject({ ok: false, error: { code: "DEPENDENCY_UNAVAILABLE" }, }); }); it("accepts an empty poll response page past its total", async () => { const query = createContentQuery({ load: async () => ({ kind: "engagement" as const, items: [ { id: "7", title: "Poll", privatePayload: { ...pollDetail, textResponses: { questionId: null, items: [], total: 1, pageSize: 25, offset: 100_000, }, }, }, ], total: 1, partialDependencies: [], }), }); expect( await query.run(context([PERMS.POLLS_VIEW, PERMS.POLLS_EDIT]), { routeId: "content.engagement.poll-detail", params: { id: "7" }, }), ).toMatchObject({ ok: true }); }); it.each([ ["an offset at the response total", 1, 1, 1], ["a response page extending beyond its total", 3, 2, 2], ])("fails closed for %s", async (_label, total, offset, itemCount) => { const items = Array.from({ length: itemCount }, (_, index) => ({ id: String(index + 1), questionId: "22", userId: String(index + 1), username: null, answer: "Text", createdAt: "2026-09-02T18:00:00.000Z", })); const query = createContentQuery({ load: async () => ({ kind: "engagement" as const, items: [ { id: "7", title: "Poll", privatePayload: { ...pollDetail, questions: [ { ...pollDetail.questions[0], id: "22", type: "text" as const, options: [], answerCount: total, choiceResults: [], }, ], textResponses: { questionId: "22", items, total, pageSize: 25, offset, }, }, }, ], total: 1, partialDependencies: [], }), }); expect( await query.run(context([PERMS.POLLS_VIEW, PERMS.POLLS_EDIT]), { routeId: "content.engagement.poll-detail", params: { id: "7" }, }), ).toMatchObject({ ok: false, error: { code: "DEPENDENCY_UNAVAILABLE" }, }); }); it("fails closed when an article detail payload is incomplete", async () => { const query = createContentQuery({ load: async () => ({ kind: "editorial", items: [ { id: "7", title: "Launch day", privatePayload: { slug: "launch-day" }, }, ], total: 1, partialDependencies: [], }), }); const result = await query.run(context([PERMS.NEWS_VIEW]), { routeId: "content.editorial.article-detail", params: { id: "7" }, }); expect(result).toMatchObject({ ok: false, error: { code: "DEPENDENCY_UNAVAILABLE" }, }); }); it("normalizes a bounded event status before invoking the adapter", async () => { const load = vi.fn(async () => ({ kind: "engagement" as const, items: [], total: 0, partialDependencies: [], })); const query = createContentQuery({ load }); await query.run(context([PERMS.EVENTS_VIEW]), { routeId: "content.engagement.events", list: { status: ` PUBLISHED${"x".repeat(40)} `, } as ContentQueryInput["list"] & { status: string }, }); expect(load).toHaveBeenCalledWith({ routeId: "content.engagement.events", params: {}, list: { search: "", status: `published${"x".repeat(23)}`, pageSize: 25, offset: 0, responseQuestionId: "", responsePageSize: 25, responseOffset: 0, }, }); }); it.each([ { label: "missing payload", items: [{ id: "7", title: "Launch day", status: "published" }], }, { label: "more than one selected event", items: [ { id: "7", title: "Launch day", status: "published" }, { id: "8", title: "After party", status: "draft" }, ], }, ])("fails closed for an event detail with $label", async ({ items }) => { const query = createContentQuery({ load: async () => ({ kind: "engagement", items, total: items.length, partialDependencies: [], }), }); const result = await query.run(context([PERMS.EVENTS_EDIT]), { routeId: "content.engagement.event-detail", params: { id: "7" }, }); expect(result).toMatchObject({ ok: false, error: { code: "DEPENDENCY_UNAVAILABLE" }, }); }); it("rejects a fake partial result and maps complete adapter failure", async () => { const malformed = createContentQuery({ load: async () => ({ kind: "media", items: [], total: 0, partialDependencies: ["imaginary"], }) as ContentQueryData, }); const unavailable = createContentQuery({ load: async () => { throw new Error("database unavailable"); }, }); expect( await malformed.run(context([PERMS.PAGES_VIEW]), { routeId: "content.media.library", }), ).toMatchObject({ ok: false, error: { code: "DEPENDENCY_UNAVAILABLE" }, }); expect( await unavailable.run(context([PERMS.PAGES_VIEW]), { routeId: "content.media.library", }), ).toMatchObject({ ok: false, error: { code: "DEPENDENCY_UNAVAILABLE" }, }); }); it("has an authorized production query path for every Content route", async () => { const load = vi.fn(async (input: ContentQueryInput) => { const isPollCreate = input.routeId === "content.engagement.poll-create"; return { kind: input.routeId.split(".")[1] as ContentQueryData["kind"], items: isPollCreate ? [ { id: "create", title: "Create poll", privatePayload: { kind: "poll-create" }, }, ] : [], total: isPollCreate ? 1 : 0, partialDependencies: [], }; }); const query = createContentQuery({ load }); const all = context(Object.values(PERMS)); for (const routeId of CONTENT_ROUTE_IDS) { const result = await query.run(all, { routeId, ...(routeId === "content.engagement.event-detail" || routeId === "content.engagement.poll-detail" ? { params: { id: "1" } } : {}), }); expect(result.ok, routeId).toBe(true); } expect(load).toHaveBeenCalledTimes(CONTENT_ROUTE_IDS.length); }); it("loads more than one page of active event types for event creation", async () => { queryMocks.execute.mockResolvedValueOnce([ Array.from({ length: 30 }, (_, index) => ({ id: index + 1, name: `Type ${index + 1}`, slug: `type-${index + 1}`, description: "Event category", color: "#ff9900", icon: "calendar", is_active: 1, min_rank: 1, })), ]); const result = await loadProductionContentQuery({ routeId: "content.engagement.event-create", params: {}, list: { ...normalizedResponsePage, search: "", pageSize: 25, offset: 0 }, }); expect(result.items).toHaveLength(30); expect(result.total).toBe(30); expect(JSON.stringify(queryMocks.execute.mock.calls)).toContain("501"); }); it("bounds every event-detail dependency and fails closed on overflow", async () => { queryMocks.execute .mockResolvedValueOnce([ [ { id: 11, title: "Battle Ball", type_id: 2, host_user_id: 5, starts_at: new Date("2026-09-02T18:00:00.000Z"), }, ], ]) .mockResolvedValueOnce([ Array.from({ length: 501 }, (_, index) => ({ id: index + 1, name: `Type ${index + 1}`, slug: `type-${index + 1}`, description: "Event category", color: "#ff9900", icon: "calendar", is_active: 1, min_rank: 1, })), ]); await expect( loadProductionContentQuery({ routeId: "content.engagement.event-detail", params: { id: "11" }, list: { ...normalizedResponsePage, search: "", pageSize: 25, offset: 0, }, }), ).rejects.toThrow("event type limit"); const sql = JSON.stringify(queryMocks.execute.mock.calls); expect(sql).toContain("501"); expect(queryMocks.execute).toHaveBeenCalledTimes(2); }); it("applies explicit limits to all event-detail dependency queries", async () => { queryMocks.execute .mockResolvedValueOnce([ [ { id: 11, title: "Battle Ball", type_id: 2, host_user_id: 5, starts_at: new Date("2026-09-02T18:00:00.000Z"), }, ], ]) .mockResolvedValueOnce([[]]) .mockResolvedValueOnce([[]]) .mockResolvedValueOnce([[]]) .mockResolvedValueOnce([[]]); await loadProductionContentQuery({ routeId: "content.engagement.event-detail", params: { id: "11" }, list: { ...normalizedResponsePage, search: "", pageSize: 25, offset: 0 }, }); const sql = JSON.stringify(queryMocks.execute.mock.calls); expect(sql).toContain("101"); expect(sql).toContain("501"); expect(sql).toContain("1001"); }); it.each([ { label: "an invalid requested identifier", requestedId: "0", itemId: "7", total: 1, startsAt: "2026-09-02T18:00:00.000Z", }, { label: "a mismatched selected identifier", requestedId: "7", itemId: "8", total: 1, startsAt: "2026-09-02T18:00:00.000Z", }, { label: "an invalid start date", requestedId: "7", itemId: "7", total: 1, startsAt: "tomorrow", }, { label: "an inconsistent total", requestedId: "7", itemId: "7", total: 0, startsAt: "2026-09-02T18:00:00.000Z", }, ])( "fails closed for event detail data with $label", async ({ requestedId, itemId, total, startsAt }) => { const query = createContentQuery({ load: async () => ({ kind: "engagement", items: [ { id: itemId, title: "Battle Ball", privatePayload: { kind: "event-detail", description: "Complete event", typeId: "2", hostUserId: "5", roomId: null, startsAt, endsAt: null, maxPlayers: null, isRecurring: false, recurrenceRule: null, image: null, eventTypes: [], prizes: [], winners: [], registrations: [], }, }, ], total, partialDependencies: [], }), }); const result = await query.run(context([PERMS.EVENTS_EDIT]), { routeId: "content.engagement.event-detail", params: { id: requestedId }, }); expect(result).toMatchObject({ ok: false, error: { code: "DEPENDENCY_UNAVAILABLE" }, }); }, ); it("rejects malformed event summary and event type identifiers", async () => { const summaryQuery = createContentQuery({ load: async () => ({ kind: "engagement", items: [ { id: "11", title: "Battle Ball", privatePayload: { kind: "event-summary", typeId: "0", typeName: "Tournament", typeColor: "#ff9900", startsAt: "not-a-date", endsAt: null, maxPlayers: null, registrationCount: 0, }, }, ], total: 1, partialDependencies: [], }), }); expect( await summaryQuery.run(context([PERMS.EVENTS_VIEW]), { routeId: "content.engagement.events", }), ).toMatchObject({ ok: false, error: { code: "DEPENDENCY_UNAVAILABLE" }, }); const typeQuery = createContentQuery({ load: async () => ({ kind: "engagement", items: [ { id: "0", title: "Tournament", privatePayload: { kind: "event-type", name: "Tournament", slug: "tournament", description: "Ranked competition", color: "#ff9900", icon: "calendar", isActive: true, minRank: 1, }, }, ], total: 1, partialDependencies: [], }), }); expect( await typeQuery.run(context([PERMS.EVENTS_EDIT]), { routeId: "content.engagement.event-types", }), ).toMatchObject({ ok: false, error: { code: "DEPENDENCY_UNAVAILABLE" }, }); }); });