forked from Nova-reward/Nova-Rewards
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathauthenticateUser.test.js
More file actions
103 lines (90 loc) · 3.62 KB
/
Copy pathauthenticateUser.test.js
File metadata and controls
103 lines (90 loc) · 3.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// Unit tests for authenticateUser middleware
jest.mock('../db/index', () => ({ query: jest.fn() }));
jest.mock('../services/tokenService', () => ({
verifyToken: jest.fn(),
}));
const { query } = require('../db/index');
const { verifyToken } = require('../services/tokenService');
const { authenticateUser, requireAdmin, requireOwnershipOrAdmin } = require('../middleware/authenticateUser');
function mockReqRes(headers = {}, params = {}, method = 'GET') {
const req = { headers, params, method, user: null };
const res = {
status: jest.fn().mockReturnThis(),
json: jest.fn().mockReturnThis(),
};
const next = jest.fn();
return { req, res, next };
}
beforeEach(() => jest.clearAllMocks());
describe('authenticateUser', () => {
test('returns 401 when no Authorization header', async () => {
const { req, res, next } = mockReqRes();
await authenticateUser(req, res, next);
expect(res.status).toHaveBeenCalledWith(401);
expect(next).not.toHaveBeenCalled();
});
test('returns 401 when token verification throws (malformed token)', async () => {
verifyToken.mockImplementation(() => { throw new Error('invalid token'); });
const { req, res, next } = mockReqRes({ authorization: 'Bearer bad.token.here' });
await authenticateUser(req, res, next);
expect(res.status).toHaveBeenCalledWith(401);
});
test('returns 401 when user not found in DB', async () => {
verifyToken.mockReturnValue({ userId: 999 });
const { req, res, next } = mockReqRes({ authorization: 'Bearer valid.token.here' });
query.mockResolvedValue({ rows: [] });
await authenticateUser(req, res, next);
expect(res.status).toHaveBeenCalledWith(401);
});
test('attaches user to req and calls next on success', async () => {
const user = { id: 1, role: 'user' };
verifyToken.mockReturnValue({ userId: 1 });
const { req, res, next } = mockReqRes({ authorization: 'Bearer valid.token.here' });
query.mockResolvedValue({ rows: [user] });
await authenticateUser(req, res, next);
expect(req.user).toEqual(user);
expect(next).toHaveBeenCalled();
});
});
describe('requireAdmin', () => {
test('returns 403 for non-admin', () => {
const { req, res, next } = mockReqRes();
req.user = { role: 'user' };
requireAdmin(req, res, next);
expect(res.status).toHaveBeenCalledWith(403);
expect(next).not.toHaveBeenCalled();
});
test('calls next for admin', () => {
const { req, res, next } = mockReqRes();
req.user = { role: 'admin' };
requireAdmin(req, res, next);
expect(next).toHaveBeenCalled();
});
});
describe('requireOwnershipOrAdmin', () => {
test('allows GET requests through', () => {
const { req, res, next } = mockReqRes({}, { id: '2' }, 'GET');
req.user = { id: 1, role: 'user' };
requireOwnershipOrAdmin(req, res, next);
expect(next).toHaveBeenCalled();
});
test('allows owner on non-GET', () => {
const { req, res, next } = mockReqRes({}, { id: '1' }, 'PATCH');
req.user = { id: 1, role: 'user' };
requireOwnershipOrAdmin(req, res, next);
expect(next).toHaveBeenCalled();
});
test('allows admin on non-GET', () => {
const { req, res, next } = mockReqRes({}, { id: '2' }, 'DELETE');
req.user = { id: 1, role: 'admin' };
requireOwnershipOrAdmin(req, res, next);
expect(next).toHaveBeenCalled();
});
test('returns 403 for non-owner non-admin on non-GET', () => {
const { req, res, next } = mockReqRes({}, { id: '2' }, 'PATCH');
req.user = { id: 1, role: 'user' };
requireOwnershipOrAdmin(req, res, next);
expect(res.status).toHaveBeenCalledWith(403);
expect(next).not.toHaveBeenCalled();
});
});