'use strict'; const { requireClient, requireStaff, requireAdmin, requireOwnerOrStaff, requireOwnerOrAdmin, } = require('../../middleware/rbac.middleware'); // ── Mock helpers ────────────────────────────────────────────────────────────── function makeRes() { const res = { _status: null, _body: null, status(code) { this._status = code; return this; }, json(body) { this._body = body; return this; }, }; return res; } function makeReq(accType = null, userId = null, paramId = null) { return { user: accType ? { user_id: userId, acc_type: accType } : null, params: { id: paramId }, }; } // ── requireClient ───────────────────────────────────────────────────────────── describe('requireClient()', () => { test('user role → passes', () => { const next = jest.fn(); requireClient()(makeReq('user'), makeRes(), next); expect(next).toHaveBeenCalledTimes(1); }); test('staff role → passes', () => { const next = jest.fn(); requireClient()(makeReq('staff'), makeRes(), next); expect(next).toHaveBeenCalledTimes(1); }); test('admin role → passes', () => { const next = jest.fn(); requireClient()(makeReq('admin'), makeRes(), next); expect(next).toHaveBeenCalledTimes(1); }); test('no req.user → 401', () => { const res = makeRes(); const next = jest.fn(); requireClient()(makeReq(null), res, next); expect(next).not.toHaveBeenCalled(); expect(res._status).toBe(401); }); }); // ── requireStaff ────────────────────────────────────────────────────────────── describe('requireStaff()', () => { test('staff role → passes', () => { const next = jest.fn(); requireStaff()(makeReq('staff'), makeRes(), next); expect(next).toHaveBeenCalledTimes(1); }); test('admin role → passes', () => { const next = jest.fn(); requireStaff()(makeReq('admin'), makeRes(), next); expect(next).toHaveBeenCalledTimes(1); }); test('user role → 403', () => { const res = makeRes(); const next = jest.fn(); requireStaff()(makeReq('user'), res, next); expect(next).not.toHaveBeenCalled(); expect(res._status).toBe(403); }); test('no req.user → 401', () => { const res = makeRes(); const next = jest.fn(); requireStaff()(makeReq(null), res, next); expect(next).not.toHaveBeenCalled(); expect(res._status).toBe(401); }); }); // ── requireAdmin ────────────────────────────────────────────────────────────── describe('requireAdmin()', () => { test('admin role → passes', () => { const next = jest.fn(); requireAdmin()(makeReq('admin'), makeRes(), next); expect(next).toHaveBeenCalledTimes(1); }); test('staff role → 403', () => { const res = makeRes(); const next = jest.fn(); requireAdmin()(makeReq('staff'), res, next); expect(next).not.toHaveBeenCalled(); expect(res._status).toBe(403); }); test('user role → 403', () => { const res = makeRes(); const next = jest.fn(); requireAdmin()(makeReq('user'), res, next); expect(next).not.toHaveBeenCalled(); expect(res._status).toBe(403); }); test('no req.user → 401', () => { const res = makeRes(); const next = jest.fn(); requireAdmin()(makeReq(null), res, next); expect(next).not.toHaveBeenCalled(); expect(res._status).toBe(401); }); }); // ── requireOwnerOrStaff ─────────────────────────────────────────────────────── describe('requireOwnerOrStaff()', () => { test('owner (user) accessing own resource → passes', () => { const next = jest.fn(); const req = { user: { user_id: 10, acc_type: 'user' }, params: { id: '10' } }; requireOwnerOrStaff()(req, makeRes(), next); expect(next).toHaveBeenCalledTimes(1); }); test('staff accessing another user\'s resource → passes', () => { const next = jest.fn(); const req = { user: { user_id: 2, acc_type: 'staff' }, params: { id: '99' } }; requireOwnerOrStaff()(req, makeRes(), next); expect(next).toHaveBeenCalledTimes(1); }); test('admin accessing another user\'s resource → passes', () => { const next = jest.fn(); const req = { user: { user_id: 1, acc_type: 'admin' }, params: { id: '99' } }; requireOwnerOrStaff()(req, makeRes(), next); expect(next).toHaveBeenCalledTimes(1); }); test('user accessing another user\'s resource → 403', () => { const res = makeRes(); const next = jest.fn(); const req = { user: { user_id: 10, acc_type: 'user' }, params: { id: '99' } }; requireOwnerOrStaff()(req, res, next); expect(next).not.toHaveBeenCalled(); expect(res._status).toBe(403); }); test('no req.user → 401', () => { const res = makeRes(); const next = jest.fn(); const req = { user: null, params: { id: '10' } }; requireOwnerOrStaff()(req, res, next); expect(next).not.toHaveBeenCalled(); expect(res._status).toBe(401); }); }); // ── requireOwnerOrAdmin ─────────────────────────────────────────────────────── describe('requireOwnerOrAdmin()', () => { test('owner (user) accessing own resource → passes', () => { const next = jest.fn(); const req = { user: { user_id: 10, acc_type: 'user' }, params: { id: '10' } }; requireOwnerOrAdmin()(req, makeRes(), next); expect(next).toHaveBeenCalledTimes(1); }); test('admin accessing another user\'s resource → passes', () => { const next = jest.fn(); const req = { user: { user_id: 1, acc_type: 'admin' }, params: { id: '99' } }; requireOwnerOrAdmin()(req, makeRes(), next); expect(next).toHaveBeenCalledTimes(1); }); test('staff (non-owner) accessing another user\'s resource → 403', () => { const res = makeRes(); const next = jest.fn(); const req = { user: { user_id: 2, acc_type: 'staff' }, params: { id: '99' } }; requireOwnerOrAdmin()(req, res, next); expect(next).not.toHaveBeenCalled(); expect(res._status).toBe(403); }); test('no req.user → 401', () => { const res = makeRes(); const next = jest.fn(); const req = { user: null, params: { id: '10' } }; requireOwnerOrAdmin()(req, res, next); expect(next).not.toHaveBeenCalled(); expect(res._status).toBe(401); }); });