grocery-app/backend/tests/group-invites.routes.test.js

111 lines
3.4 KiB
JavaScript

jest.mock("../middleware/auth", () => (req, res, next) => {
req.user = { id: 42, role: "user" };
next();
});
jest.mock("../middleware/optional-auth", () => (req, res, next) => next());
jest.mock("../services/group-invites.service", () => {
const actual = jest.requireActual("../services/group-invites.service");
return {
...actual,
acceptInviteLink: jest.fn(),
createInviteLink: jest.fn(),
deleteInviteLink: jest.fn(),
decideJoinRequest: jest.fn(),
getGroupJoinPolicy: jest.fn(),
getInviteLinkSummaryByToken: jest.fn(),
listPendingJoinRequests: jest.fn(),
listInviteLinks: jest.fn(),
resolveManagedGroupId: jest.fn(),
revokeInviteLink: jest.fn(),
reviveInviteLink: jest.fn(),
setGroupJoinPolicy: jest.fn(),
};
});
const request = require("supertest");
const invitesService = require("../services/group-invites.service");
const app = require("../app");
describe("group invites routes", () => {
beforeEach(() => {
jest.clearAllMocks();
invitesService.resolveManagedGroupId.mockResolvedValue(1);
invitesService.listInviteLinks.mockResolvedValue([]);
invitesService.listPendingJoinRequests.mockResolvedValue([]);
invitesService.createInviteLink.mockResolvedValue({
id: 1,
token: "abcd",
status: "ACTIVE",
});
invitesService.getInviteLinkSummaryByToken.mockResolvedValue({
id: 1,
token: "abcd",
group_name: "Test Group",
status: "ACTIVE",
active_policy: "AUTO_ACCEPT",
});
});
test("admin-only checks are enforced on invite management routes", async () => {
invitesService.createInviteLink.mockRejectedValue(
new invitesService.InviteServiceError(
"FORBIDDEN",
"Admin or owner role required",
403
)
);
const response = await request(app).post("/api/groups/invites").send({
policy: "AUTO_ACCEPT",
singleUse: false,
ttlDays: 3,
});
expect(response.status).toBe(403);
expect(response.body.error.code).toBe("FORBIDDEN");
expect(response.body.request_id).toBeTruthy();
});
test("request_id is present in invite responses", async () => {
const response = await request(app).get("/api/invite-links/abcd1234");
expect(response.status).toBe(200);
expect(response.body.request_id).toBeTruthy();
expect(response.body.link).toBeTruthy();
});
test("pending join requests can be listed with request_id", async () => {
invitesService.listPendingJoinRequests.mockResolvedValue([
{ id: 12, user_id: 77, username: "pending-user", status: "PENDING" },
]);
const response = await request(app).get("/api/groups/join-requests");
expect(response.status).toBe(200);
expect(response.body.request_id).toBeTruthy();
expect(response.body.requests).toEqual([
{ id: 12, user_id: 77, username: "pending-user", status: "PENDING" },
]);
});
test("decision route maps service validation errors", async () => {
invitesService.decideJoinRequest.mockRejectedValue(
new invitesService.InviteServiceError(
"JOIN_REQUEST_NOT_FOUND",
"Pending join request not found",
404
)
);
const response = await request(app)
.post("/api/groups/join-requests/decision")
.send({ requestId: 99, decision: "APPROVE" });
expect(response.status).toBe(404);
expect(response.body.request_id).toBeTruthy();
expect(response.body.error.code).toBe("JOIN_REQUEST_NOT_FOUND");
});
});