const assert = require("node:assert/strict"); const { createRequire } = require("node:module"); const nodeRequire = createRequire(__filename); const routeModulePaths = [ "../src/routes.js", "../src/routes/index.js", "../src/routes/community.js", "../src/routes/notifications.js", ]; const contextPath = "../src/routes/context.js"; function passThrough(_req, _res, next) { next(); } function loadRouter(pool) { const contextResolvedPath = nodeRequire.resolve(contextPath); const originalContextModule = nodeRequire.cache[contextResolvedPath]; const resolvedRouteModules = routeModulePaths.map((modulePath) => nodeRequire.resolve(modulePath)); for (const resolvedPath of resolvedRouteModules) { delete nodeRequire.cache[resolvedPath]; } nodeRequire.cache[contextResolvedPath] = { id: contextResolvedPath, filename: contextResolvedPath, loaded: true, exports: { express: nodeRequire("express"), requireAuth: passThrough, requireAdmin: passThrough, requireEnterpriseAdmin: passThrough, requireManagementAccess: passThrough, pool, withTransaction: async (fn) => fn(pool), clampPositiveInteger: (value, fallback) => Math.max(1, Number(value) || fallback), clampNonNegativeInteger: (value, fallback) => Math.max(0, Number(value) || fallback), normalizeProjectOssKey: (value) => String(value || "").trim(), }, }; return { router: nodeRequire("../src/routes.js"), restore() { for (const resolvedPath of resolvedRouteModules) { delete nodeRequire.cache[resolvedPath]; } if (originalContextModule) { nodeRequire.cache[contextResolvedPath] = originalContextModule; } else { delete nodeRequire.cache[contextResolvedPath]; } }, }; } function readRouterInventory(router) { return router.stack .filter((layer) => Boolean(layer.route)) .flatMap((layer) => Object.keys(layer.route.methods) .filter((method) => layer.route.methods[method]) .map((method) => ({ method: method.toUpperCase(), path: layer.route.path })), ); } function getRouteHandler(router, method, routePath) { const layer = router.stack.find( (candidate) => candidate.route?.path === routePath && candidate.route.methods[method.toLowerCase()], ); const handler = layer?.route?.stack.at(-1)?.handle; if (!handler) throw new Error(`Route not found: ${method.toUpperCase()} ${routePath}`); return handler; } function createMockResponse() { const res = {}; res.status = (statusCode) => { res.statusCode = statusCode; return res; }; res.json = (body) => { res.body = body; return res; }; return res; } async function testNotificationRoutesAreMounted() { const { router, restore } = loadRouter({ query: async () => ({ rows: [] }) }); try { const inventory = readRouterInventory(router); assert(inventory.some((route) => route.method === "GET" && route.path === "/notifications")); assert(inventory.some((route) => route.method === "PATCH" && route.path === "/notifications/:id/read")); assert(inventory.some((route) => route.method === "POST" && route.path === "/notifications/read-all")); } finally { restore(); } } async function testReviewStatusSurvivesNotificationWriteFailure() { const calls = []; const pool = { async query(sql, params) { calls.push({ sql, params }); if (/UPDATE community_cases/.test(sql)) { return { rows: [ { id: 2, user_id: 9, username: "creator", project_id: null, title: "待审核案例", description: "desc", cover_url: null, tags_json: "[]", metadata_json: "{}", status: "approved", review_note: null, reviewed_by: 1, reviewed_at: "2026-05-19T00:00:00.000Z", published_at: "2026-05-19T00:00:00.000Z", copy_count: 0, created_at: "2026-05-19T00:00:00.000Z", updated_at: "2026-05-19T00:00:00.000Z", }, ], }; } if (/INSERT INTO web_notifications/.test(sql)) { throw new Error("relation web_notifications does not exist"); } if (/FROM community_case_assets/.test(sql)) return { rows: [] }; if (/FROM community_case_reactions/.test(sql)) return { rows: [] }; return { rows: [] }; }, }; const { router, restore } = loadRouter(pool); try { const handler = getRouteHandler(router, "patch", "/admin/community/cases/:id/status"); const res = createMockResponse(); await handler( { params: { id: "2" }, body: { status: "approved" }, user: { id: 1, role: "admin" }, }, res, ); assert.equal(res.statusCode, undefined); assert.equal(res.body.case.id, 2); assert.equal(res.body.case.status, "approved"); const updateCall = calls.find((call) => /UPDATE community_cases/.test(call.sql)); assert.match(updateCall.sql, /status = \$1::varchar\(24\)/); assert.match(updateCall.sql, /CASE WHEN \$1::varchar\(24\) = 'approved'/); assert(calls.some((call) => /INSERT INTO web_notifications/.test(call.sql))); } finally { restore(); } } async function main() { await testNotificationRoutesAreMounted(); await testReviewStatusSurvivesNotificationWriteFailure(); console.log("community route contract tests passed"); } main().catch((error) => { console.error(error); process.exit(1); });