const express = require("express"); const request = require("supertest"); const mockQueue = { add: jest.fn(), close: jest.fn(), on: jest.fn(), getJob: jest.fn() }; const mockCheckDatabase = jest.fn(); const mockCheckRedis = jest.fn(); jest.mock("../../app/queues/activity.queue", () => mockQueue); jest.mock("../../app/queues/document.queue", () => mockQueue); jest.mock("../../app/queues/log.queue", () => mockQueue); jest.mock("../../app/config/redisClient", () => ({ status: "wait", connect: jest.fn(), ping: jest.fn(), get: jest.fn(), set: jest.fn(), del: jest.fn(), quit: jest.fn(), })); jest.mock("../../app/config/database.lifecycle", () => ({ checkDatabase: mockCheckDatabase })); jest.mock("../../app/config/redis.lifecycle", () => ({ checkRedis: mockCheckRedis })); jest.mock("../../app/config/bullBoard.config", () => { const express = require("express"); return { bullBoardRouter: express.Router().get("/", (_req, res) => res.json({ ok: true })) }; }); const app = require("../../app"); const { AppError, errorHandler } = require("../../app/middleware/error.middleware"); const db = require("../../app/models"); const { generateToken } = require("../../app/utils/jwt.util"); const authenticated = (accountType = "customer") => { const user = { id: "usr-self", firstName: "Test", lastName: "User", email: "test@example.com", accountType, accountStatus: "ACTIVE", tokenVersion: 0, emailVerifiedAt: new Date(), profile: null }; const session = { id: "session-self", user_id: user.id, revoked_at: null, expires_at: new Date(Date.now() + 60000), token_version: 0 }; jest.spyOn(db.User, "findByPk").mockResolvedValue(user); jest.spyOn(db.AuthSession, "findByPk").mockResolvedValue(session); jest.spyOn(db.UserRole, "findAll").mockResolvedValue([]); jest.spyOn(db.userPermission, "findAll").mockResolvedValue([]); return `Bearer ${generateToken({ userId: user.id, sessionId: session.id, tokenVersion: 0 })}`; }; describe("foundation HTTP behavior", () => { beforeEach(() => { jest.restoreAllMocks(); mockCheckDatabase.mockResolvedValue(true); mockCheckRedis.mockResolvedValue(true); }); test("GET /health/live reports process liveness", async () => { const response = await request(app).get("/health/live").expect(200); expect(response.body).toMatchObject({ status: "ok", service: "zumri-api" }); expect(response.body.timestamp).toBeDefined(); expect(response.headers["x-request-id"]).toBeDefined(); }); test("legacy GET /health remains a liveness alias", async () => { await request(app).get("/health").expect(200).expect(({ body }) => expect(body.status).toBe("ok")); }); test("GET /health/ready checks database and Redis", async () => { await request(app).get("/health/ready").expect(200).expect(({ body }) => { expect(body).toEqual({ status: "ready", checks: { database: "ok", redis: "ok" } }); }); expect(mockCheckDatabase).toHaveBeenCalled(); expect(mockCheckRedis).toHaveBeenCalled(); }); test("GET /health/ready returns 503 when a dependency fails", async () => { mockCheckDatabase.mockResolvedValueOnce(false); await request(app).get("/health/ready").expect(503).expect(({ body }) => { expect(body.status).toBe("not_ready"); expect(body.checks.database).toBe("error"); }); }); test("unknown routes use the centralized 404 response", async () => { const response = await request(app).get("/does-not-exist").expect(404); expect(response.body.error).toMatchObject({ code: "NOT_FOUND", message: "Route not found" }); }); test("global errors use the standard response and request ID", async () => { const errorApp = express(); errorApp.use(require("../../app/middleware/requestId.middleware")); errorApp.get("/error", (_req, _res, next) => next(new AppError(400, "TEST_ERROR", "Controlled failure"))); errorApp.use(errorHandler); const response = await request(errorApp).get("/error").expect(400); expect(response.body.error).toEqual({ code: "TEST_ERROR", message: "Controlled failure" }); expect(response.body.requestId).toBeDefined(); }); test("an authenticated route rejects missing credentials", async () => { await request(app).get("/api/auth/me").expect(401).expect(({ body }) => expect(body.success).toBe(false)); }); test("Bull Board rejects unauthenticated requests", async () => { await request(app).get("/admin/queues").expect(401); }); test("mounted permission administration rejects unauthenticated requests", async () => { await request(app).get("/api/v1/permissions").expect(401); }); test("customer cannot mass-assign account type", async () => { const token = authenticated("customer"); await request(app).patch("/api/v1/user/me").set("Authorization", token).send({ accountType: "admin" }).expect(400).expect(({ body }) => expect(body.error.code).toBe("UNSAFE_FIELD")); }); test("customer cannot mutate another user by ID", async () => { const token = authenticated("customer"); await request(app).patch("/api/v1/user/usr-other").set("Authorization", token).send({ firstName: "Attack" }).expect(403); }); test("authenticated admin can reach protected Bull Board", async () => { const token = authenticated("admin"); await request(app).get("/admin/queues").set("Authorization", token).expect(200); }); test("a suspended account cannot use an otherwise valid access token", async () => { const token = authenticated("customer"); db.User.findByPk.mockResolvedValue({ id: "usr-self", accountStatus: "SUSPENDED", tokenVersion: 0 }); await request(app).get("/api/v1/auth/me").set("Authorization", token).expect(401); }); });