WIP! A BB-style forum, on the ATmosphere! We're still working... we'll be back soon when we have something to show off!
node typescript hono htmx atproto
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

test(appview): add 401/403/PDS-failure tests for POST /api/admin/themes (ATB-57)

Malpercio 7c71a1bc 31d186e5

+45 -2
+44 -1
apps/appview/src/routes/__tests__/admin.test.ts
··· 2 2 import { createTestContext, type TestContext } from "../../lib/__tests__/test-context.js"; 3 3 import { Hono } from "hono"; 4 4 import type { Variables } from "../../types.js"; 5 - import { memberships, roles, rolePermissions, users, forums, categories, boards, posts, modActions, themes } from "@atbb/db"; 5 + import { memberships, roles, rolePermissions, users, forums, categories, boards, posts, modActions } from "@atbb/db"; 6 6 import { eq } from "drizzle-orm"; 7 7 8 8 // Mock middleware at module level ··· 2578 2578 expect(res.status).toBe(500); 2579 2579 const body = await res.json(); 2580 2580 expect(body.error).toContain("Forum agent not available"); 2581 + }); 2582 + 2583 + it("returns 401 when not authenticated", async () => { 2584 + mockUser = null; 2585 + const res = await app.request("/api/admin/themes", { 2586 + method: "POST", 2587 + headers: { "Content-Type": "application/json" }, 2588 + body: JSON.stringify({ name: "Test", colorScheme: "light", tokens: {} }), 2589 + }); 2590 + expect(res.status).toBe(401); 2591 + expect(mockPutRecord).not.toHaveBeenCalled(); 2592 + }); 2593 + 2594 + it("returns 403 when user lacks manageThemes permission", async () => { 2595 + const { requirePermission } = await import("../../middleware/permissions.js"); 2596 + const mockRequirePermission = requirePermission as any; 2597 + mockRequirePermission.mockImplementation(() => async (c: any) => { 2598 + return c.json({ error: "Forbidden" }, 403); 2599 + }); 2600 + 2601 + const testApp = new Hono<{ Variables: Variables }>().route("/api/admin", createAdminRoutes(ctx)); 2602 + const res = await testApp.request("/api/admin/themes", { 2603 + method: "POST", 2604 + headers: { "Content-Type": "application/json" }, 2605 + body: JSON.stringify({ name: "Test", colorScheme: "light", tokens: {} }), 2606 + }); 2607 + 2608 + expect(res.status).toBe(403); 2609 + expect(mockPutRecord).not.toHaveBeenCalled(); 2610 + 2611 + mockRequirePermission.mockImplementation(() => async (_c: any, next: any) => { 2612 + await next(); 2613 + }); 2614 + }); 2615 + 2616 + it("returns 503 when PDS write fails with a network error", async () => { 2617 + mockPutRecord.mockRejectedValueOnce(new Error("fetch failed")); 2618 + const res = await app.request("/api/admin/themes", { 2619 + method: "POST", 2620 + headers: { "Content-Type": "application/json" }, 2621 + body: JSON.stringify({ name: "Test", colorScheme: "light", tokens: {} }), 2622 + }); 2623 + expect(res.status).toBe(503); 2581 2624 }); 2582 2625 }); 2583 2626
+1 -1
apps/appview/src/routes/admin.ts
··· 3 3 import type { Variables } from "../types.js"; 4 4 import { requireAuth } from "../middleware/auth.js"; 5 5 import { requirePermission, requireAnyPermission, getUserRole } from "../middleware/permissions.js"; 6 - import { memberships, roles, rolePermissions, users, forums, backfillProgress, backfillErrors, categories, boards, posts, modActions, themes, themePolicies } from "@atbb/db"; 6 + import { memberships, roles, rolePermissions, users, forums, backfillProgress, backfillErrors, categories, boards, posts, modActions } from "@atbb/db"; 7 7 import { eq, and, sql, asc, desc, count, or } from "drizzle-orm"; 8 8 import { alias } from "drizzle-orm/pg-core"; 9 9 import { isProgrammingError } from "../lib/errors.js";