740 lines
20 KiB
JavaScript
740 lines
20 KiB
JavaScript
const { authenticateToken, optionalAuth, requireVerifiedEmail, requireAdmin } = require('../../../middleware/auth');
|
|
const jwt = require('jsonwebtoken');
|
|
|
|
jest.mock('jsonwebtoken');
|
|
jest.mock('../../../models', () => ({
|
|
User: {
|
|
findByPk: jest.fn()
|
|
}
|
|
}));
|
|
|
|
const { User } = require('../../../models');
|
|
|
|
describe('Auth Middleware', () => {
|
|
let req, res, next;
|
|
|
|
beforeEach(() => {
|
|
req = {
|
|
cookies: {}
|
|
};
|
|
res = {
|
|
status: jest.fn().mockReturnThis(),
|
|
json: jest.fn()
|
|
};
|
|
next = jest.fn();
|
|
jest.clearAllMocks();
|
|
process.env.JWT_ACCESS_SECRET = 'test-secret';
|
|
});
|
|
|
|
describe('Valid token', () => {
|
|
it('should verify valid token from cookie and call next', async () => {
|
|
const mockUser = { id: 1, email: 'test@test.com', jwtVersion: 1 };
|
|
req.cookies.accessToken = 'validtoken';
|
|
jwt.verify.mockReturnValue({ id: 1, jwtVersion: 1 });
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
|
|
await authenticateToken(req, res, next);
|
|
|
|
expect(jwt.verify).toHaveBeenCalledWith('validtoken', process.env.JWT_ACCESS_SECRET);
|
|
expect(User.findByPk).toHaveBeenCalledWith(1);
|
|
expect(req.user).toEqual(mockUser);
|
|
expect(next).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should handle token with valid user', async () => {
|
|
const mockUser = { id: 2, email: 'user@test.com', firstName: 'Test', jwtVersion: 1 };
|
|
req.cookies.accessToken = 'validtoken2';
|
|
jwt.verify.mockReturnValue({ id: 2, jwtVersion: 1 });
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
|
|
await authenticateToken(req, res, next);
|
|
|
|
expect(jwt.verify).toHaveBeenCalledWith('validtoken2', process.env.JWT_ACCESS_SECRET);
|
|
expect(User.findByPk).toHaveBeenCalledWith(2);
|
|
expect(req.user).toEqual(mockUser);
|
|
expect(next).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('Invalid token', () => {
|
|
it('should return 401 for missing token', async () => {
|
|
req.cookies = {};
|
|
|
|
await authenticateToken(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(401);
|
|
expect(res.json).toHaveBeenCalledWith({
|
|
error: 'Access token required',
|
|
code: 'NO_TOKEN'
|
|
});
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should return 401 for invalid token', async () => {
|
|
req.cookies.accessToken = 'invalidtoken';
|
|
jwt.verify.mockImplementation(() => {
|
|
throw new Error('Invalid token');
|
|
});
|
|
|
|
await authenticateToken(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(403);
|
|
expect(res.json).toHaveBeenCalledWith({
|
|
error: 'Invalid token',
|
|
code: 'INVALID_TOKEN'
|
|
});
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should return 401 for expired token', async () => {
|
|
req.cookies.accessToken = 'expiredtoken';
|
|
const error = new Error('jwt expired');
|
|
error.name = 'TokenExpiredError';
|
|
jwt.verify.mockImplementation(() => {
|
|
throw error;
|
|
});
|
|
|
|
await authenticateToken(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(401);
|
|
expect(res.json).toHaveBeenCalledWith({
|
|
error: 'Token expired',
|
|
code: 'TOKEN_EXPIRED'
|
|
});
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should return 401 for invalid token format (missing user id)', async () => {
|
|
req.cookies.accessToken = 'tokenwithnoid';
|
|
jwt.verify.mockReturnValue({ email: 'test@test.com' }); // Missing id
|
|
|
|
await authenticateToken(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(401);
|
|
expect(res.json).toHaveBeenCalledWith({
|
|
error: 'Invalid token format',
|
|
code: 'INVALID_TOKEN_FORMAT'
|
|
});
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should return 401 when user not found', async () => {
|
|
req.cookies.accessToken = 'validtoken';
|
|
jwt.verify.mockReturnValue({ id: 999 });
|
|
User.findByPk.mockResolvedValue(null);
|
|
|
|
await authenticateToken(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(401);
|
|
expect(res.json).toHaveBeenCalledWith({
|
|
error: 'User not found',
|
|
code: 'USER_NOT_FOUND'
|
|
});
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('Edge cases', () => {
|
|
it('should handle empty string token', async () => {
|
|
req.cookies.accessToken = '';
|
|
|
|
await authenticateToken(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(401);
|
|
expect(res.json).toHaveBeenCalledWith({
|
|
error: 'Access token required',
|
|
code: 'NO_TOKEN'
|
|
});
|
|
});
|
|
|
|
it('should handle JWT malformed error', async () => {
|
|
req.cookies.accessToken = 'malformed.token';
|
|
const error = new Error('jwt malformed');
|
|
error.name = 'JsonWebTokenError';
|
|
jwt.verify.mockImplementation(() => {
|
|
throw error;
|
|
});
|
|
|
|
await authenticateToken(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(403);
|
|
expect(res.json).toHaveBeenCalledWith({
|
|
error: 'Invalid token',
|
|
code: 'INVALID_TOKEN'
|
|
});
|
|
});
|
|
|
|
it('should handle database error when finding user', async () => {
|
|
req.cookies.accessToken = 'validtoken';
|
|
jwt.verify.mockReturnValue({ id: 1 });
|
|
User.findByPk.mockRejectedValue(new Error('Database error'));
|
|
|
|
await authenticateToken(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(403);
|
|
expect(res.json).toHaveBeenCalledWith({
|
|
error: 'Invalid token',
|
|
code: 'INVALID_TOKEN'
|
|
});
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should handle undefined cookies', async () => {
|
|
req.cookies = undefined;
|
|
|
|
await authenticateToken(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(401);
|
|
expect(res.json).toHaveBeenCalledWith({
|
|
error: 'Access token required',
|
|
code: 'NO_TOKEN'
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('requireVerifiedEmail Middleware', () => {
|
|
let req, res, next;
|
|
|
|
beforeEach(() => {
|
|
req = {
|
|
user: null
|
|
};
|
|
res = {
|
|
status: jest.fn().mockReturnThis(),
|
|
json: jest.fn()
|
|
};
|
|
next = jest.fn();
|
|
jest.clearAllMocks();
|
|
});
|
|
|
|
describe('Verified users', () => {
|
|
it('should call next for verified user', () => {
|
|
req.user = {
|
|
id: 1,
|
|
email: 'verified@test.com',
|
|
isVerified: true
|
|
};
|
|
|
|
requireVerifiedEmail(req, res, next);
|
|
|
|
expect(next).toHaveBeenCalled();
|
|
expect(res.status).not.toHaveBeenCalled();
|
|
expect(res.json).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should call next for verified OAuth user', () => {
|
|
req.user = {
|
|
id: 2,
|
|
email: 'google@test.com',
|
|
authProvider: 'google',
|
|
isVerified: true
|
|
};
|
|
|
|
requireVerifiedEmail(req, res, next);
|
|
|
|
expect(next).toHaveBeenCalled();
|
|
expect(res.status).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('Unverified users', () => {
|
|
it('should return 403 for unverified user', () => {
|
|
req.user = {
|
|
id: 1,
|
|
email: 'unverified@test.com',
|
|
isVerified: false
|
|
};
|
|
|
|
requireVerifiedEmail(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(403);
|
|
expect(res.json).toHaveBeenCalledWith({
|
|
error: 'Email verification required. Please verify your email address to perform this action.',
|
|
code: 'EMAIL_NOT_VERIFIED'
|
|
});
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should return 403 when isVerified is null', () => {
|
|
req.user = {
|
|
id: 1,
|
|
email: 'test@test.com',
|
|
isVerified: null
|
|
};
|
|
|
|
requireVerifiedEmail(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(403);
|
|
expect(res.json).toHaveBeenCalledWith({
|
|
error: 'Email verification required. Please verify your email address to perform this action.',
|
|
code: 'EMAIL_NOT_VERIFIED'
|
|
});
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should return 403 when isVerified is undefined', () => {
|
|
req.user = {
|
|
id: 1,
|
|
email: 'test@test.com'
|
|
// isVerified is undefined
|
|
};
|
|
|
|
requireVerifiedEmail(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(403);
|
|
expect(res.json).toHaveBeenCalledWith({
|
|
error: 'Email verification required. Please verify your email address to perform this action.',
|
|
code: 'EMAIL_NOT_VERIFIED'
|
|
});
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('No user', () => {
|
|
it('should return 401 when user is not set', () => {
|
|
req.user = null;
|
|
|
|
requireVerifiedEmail(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(401);
|
|
expect(res.json).toHaveBeenCalledWith({
|
|
error: 'Authentication required',
|
|
code: 'NO_AUTH'
|
|
});
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should return 401 when user is undefined', () => {
|
|
req.user = undefined;
|
|
|
|
requireVerifiedEmail(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(401);
|
|
expect(res.json).toHaveBeenCalledWith({
|
|
error: 'Authentication required',
|
|
code: 'NO_AUTH'
|
|
});
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('Edge cases', () => {
|
|
it('should handle user object with extra fields', () => {
|
|
req.user = {
|
|
id: 1,
|
|
email: 'test@test.com',
|
|
isVerified: true,
|
|
firstName: 'Test',
|
|
lastName: 'User',
|
|
phone: '1234567890'
|
|
};
|
|
|
|
requireVerifiedEmail(req, res, next);
|
|
|
|
expect(next).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should prioritize missing user over unverified user', () => {
|
|
// If called without authenticateToken first
|
|
req.user = null;
|
|
|
|
requireVerifiedEmail(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(401);
|
|
expect(res.json).toHaveBeenCalledWith({
|
|
error: 'Authentication required',
|
|
code: 'NO_AUTH'
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('optionalAuth Middleware', () => {
|
|
let req, res, next;
|
|
|
|
beforeEach(() => {
|
|
req = {
|
|
cookies: {}
|
|
};
|
|
res = {
|
|
status: jest.fn().mockReturnThis(),
|
|
json: jest.fn()
|
|
};
|
|
next = jest.fn();
|
|
jest.clearAllMocks();
|
|
process.env.JWT_ACCESS_SECRET = 'test-secret';
|
|
});
|
|
|
|
describe('No token present', () => {
|
|
it('should set req.user to null when no token present', async () => {
|
|
req.cookies = {};
|
|
|
|
await optionalAuth(req, res, next);
|
|
|
|
expect(req.user).toBeNull();
|
|
expect(next).toHaveBeenCalled();
|
|
expect(res.status).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should set req.user to null when cookies is undefined', async () => {
|
|
req.cookies = undefined;
|
|
|
|
await optionalAuth(req, res, next);
|
|
|
|
expect(req.user).toBeNull();
|
|
expect(next).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should set req.user to null for empty string token', async () => {
|
|
req.cookies.accessToken = '';
|
|
|
|
await optionalAuth(req, res, next);
|
|
|
|
expect(req.user).toBeNull();
|
|
expect(next).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('Valid token present', () => {
|
|
it('should set req.user when valid token present', async () => {
|
|
const mockUser = { id: 1, email: 'test@test.com', jwtVersion: 1 };
|
|
req.cookies.accessToken = 'validtoken';
|
|
jwt.verify.mockReturnValue({ id: 1, jwtVersion: 1 });
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
|
|
await optionalAuth(req, res, next);
|
|
|
|
expect(jwt.verify).toHaveBeenCalledWith('validtoken', process.env.JWT_ACCESS_SECRET);
|
|
expect(User.findByPk).toHaveBeenCalledWith(1);
|
|
expect(req.user).toEqual(mockUser);
|
|
expect(next).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('Invalid token handling', () => {
|
|
it('should set req.user to null for invalid token (no error returned)', async () => {
|
|
req.cookies.accessToken = 'invalidtoken';
|
|
jwt.verify.mockImplementation(() => {
|
|
throw new Error('Invalid token');
|
|
});
|
|
|
|
await optionalAuth(req, res, next);
|
|
|
|
expect(req.user).toBeNull();
|
|
expect(next).toHaveBeenCalled();
|
|
expect(res.status).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should set req.user to null for expired token (no error returned)', async () => {
|
|
req.cookies.accessToken = 'expiredtoken';
|
|
const error = new Error('jwt expired');
|
|
error.name = 'TokenExpiredError';
|
|
jwt.verify.mockImplementation(() => {
|
|
throw error;
|
|
});
|
|
|
|
await optionalAuth(req, res, next);
|
|
|
|
expect(req.user).toBeNull();
|
|
expect(next).toHaveBeenCalled();
|
|
expect(res.status).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should set req.user to null when token has no user id', async () => {
|
|
req.cookies.accessToken = 'tokenwithnoid';
|
|
jwt.verify.mockReturnValue({ email: 'test@test.com' }); // Missing id
|
|
|
|
await optionalAuth(req, res, next);
|
|
|
|
expect(req.user).toBeNull();
|
|
expect(next).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('User state handling', () => {
|
|
it('should set req.user to null for banned user', async () => {
|
|
const mockUser = { id: 1, email: 'banned@test.com', isBanned: true, jwtVersion: 1 };
|
|
req.cookies.accessToken = 'validtoken';
|
|
jwt.verify.mockReturnValue({ id: 1, jwtVersion: 1 });
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
|
|
await optionalAuth(req, res, next);
|
|
|
|
expect(req.user).toBeNull();
|
|
expect(next).toHaveBeenCalled();
|
|
expect(res.status).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should set req.user to null for JWT version mismatch', async () => {
|
|
const mockUser = { id: 1, email: 'test@test.com', jwtVersion: 2 };
|
|
req.cookies.accessToken = 'validtoken';
|
|
jwt.verify.mockReturnValue({ id: 1, jwtVersion: 1 }); // Old version
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
|
|
await optionalAuth(req, res, next);
|
|
|
|
expect(req.user).toBeNull();
|
|
expect(next).toHaveBeenCalled();
|
|
expect(res.status).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should set req.user to null when user not found', async () => {
|
|
req.cookies.accessToken = 'validtoken';
|
|
jwt.verify.mockReturnValue({ id: 999, jwtVersion: 1 });
|
|
User.findByPk.mockResolvedValue(null);
|
|
|
|
await optionalAuth(req, res, next);
|
|
|
|
expect(req.user).toBeNull();
|
|
expect(next).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('Edge cases', () => {
|
|
it('should handle database error gracefully', async () => {
|
|
req.cookies.accessToken = 'validtoken';
|
|
jwt.verify.mockReturnValue({ id: 1, jwtVersion: 1 });
|
|
User.findByPk.mockRejectedValue(new Error('Database error'));
|
|
|
|
await optionalAuth(req, res, next);
|
|
|
|
expect(req.user).toBeNull();
|
|
expect(next).toHaveBeenCalled();
|
|
expect(res.status).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('requireAdmin Middleware', () => {
|
|
let req, res, next;
|
|
|
|
beforeEach(() => {
|
|
req = {
|
|
user: null
|
|
};
|
|
res = {
|
|
status: jest.fn().mockReturnThis(),
|
|
json: jest.fn()
|
|
};
|
|
next = jest.fn();
|
|
jest.clearAllMocks();
|
|
});
|
|
|
|
describe('Admin users', () => {
|
|
it('should call next() for admin user', () => {
|
|
req.user = {
|
|
id: 1,
|
|
email: 'admin@test.com',
|
|
role: 'admin'
|
|
};
|
|
|
|
requireAdmin(req, res, next);
|
|
|
|
expect(next).toHaveBeenCalled();
|
|
expect(res.status).not.toHaveBeenCalled();
|
|
expect(res.json).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should call next() for admin user with additional properties', () => {
|
|
req.user = {
|
|
id: 1,
|
|
email: 'admin@test.com',
|
|
role: 'admin',
|
|
firstName: 'Admin',
|
|
lastName: 'User',
|
|
isVerified: true
|
|
};
|
|
|
|
requireAdmin(req, res, next);
|
|
|
|
expect(next).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('Non-admin users', () => {
|
|
it('should return 403 for non-admin user', () => {
|
|
req.user = {
|
|
id: 1,
|
|
email: 'user@test.com',
|
|
role: 'user'
|
|
};
|
|
|
|
requireAdmin(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(403);
|
|
expect(res.json).toHaveBeenCalledWith({
|
|
error: 'Admin access required',
|
|
code: 'INSUFFICIENT_PERMISSIONS'
|
|
});
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should return 403 for host role', () => {
|
|
req.user = {
|
|
id: 1,
|
|
email: 'host@test.com',
|
|
role: 'host'
|
|
};
|
|
|
|
requireAdmin(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(403);
|
|
expect(res.json).toHaveBeenCalledWith({
|
|
error: 'Admin access required',
|
|
code: 'INSUFFICIENT_PERMISSIONS'
|
|
});
|
|
});
|
|
|
|
it('should return 403 for user with no role property', () => {
|
|
req.user = {
|
|
id: 1,
|
|
email: 'user@test.com'
|
|
// role is missing
|
|
};
|
|
|
|
requireAdmin(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(403);
|
|
expect(res.json).toHaveBeenCalledWith({
|
|
error: 'Admin access required',
|
|
code: 'INSUFFICIENT_PERMISSIONS'
|
|
});
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should return 403 for user with empty string role', () => {
|
|
req.user = {
|
|
id: 1,
|
|
email: 'user@test.com',
|
|
role: ''
|
|
};
|
|
|
|
requireAdmin(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(403);
|
|
});
|
|
});
|
|
|
|
describe('No user', () => {
|
|
it('should return 401 when user is null', () => {
|
|
req.user = null;
|
|
|
|
requireAdmin(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(401);
|
|
expect(res.json).toHaveBeenCalledWith({
|
|
error: 'Authentication required',
|
|
code: 'NO_AUTH'
|
|
});
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should return 401 when user is undefined', () => {
|
|
req.user = undefined;
|
|
|
|
requireAdmin(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(401);
|
|
expect(res.json).toHaveBeenCalledWith({
|
|
error: 'Authentication required',
|
|
code: 'NO_AUTH'
|
|
});
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('Edge cases', () => {
|
|
it('should handle case-sensitive role comparison', () => {
|
|
req.user = {
|
|
id: 1,
|
|
email: 'user@test.com',
|
|
role: 'Admin' // Capital A
|
|
};
|
|
|
|
requireAdmin(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(403);
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should handle role with whitespace', () => {
|
|
req.user = {
|
|
id: 1,
|
|
email: 'user@test.com',
|
|
role: ' admin ' // With spaces
|
|
};
|
|
|
|
requireAdmin(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(403);
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('authenticateToken - Additional Tests', () => {
|
|
let req, res, next;
|
|
|
|
beforeEach(() => {
|
|
req = {
|
|
cookies: {},
|
|
id: 'request-123'
|
|
};
|
|
res = {
|
|
status: jest.fn().mockReturnThis(),
|
|
json: jest.fn()
|
|
};
|
|
next = jest.fn();
|
|
jest.clearAllMocks();
|
|
process.env.JWT_ACCESS_SECRET = 'test-secret';
|
|
});
|
|
|
|
describe('Banned user', () => {
|
|
it('should return 403 USER_BANNED for banned user', async () => {
|
|
const mockUser = { id: 1, email: 'banned@test.com', isBanned: true, jwtVersion: 1 };
|
|
req.cookies.accessToken = 'validtoken';
|
|
jwt.verify.mockReturnValue({ id: 1, jwtVersion: 1 });
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
|
|
await authenticateToken(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(403);
|
|
expect(res.json).toHaveBeenCalledWith({
|
|
error: 'Your account has been suspended. Please contact support for more information.',
|
|
code: 'USER_BANNED'
|
|
});
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('JWT version mismatch', () => {
|
|
it('should return 401 JWT_VERSION_MISMATCH for version mismatch', async () => {
|
|
const mockUser = { id: 1, email: 'test@test.com', jwtVersion: 2 };
|
|
req.cookies.accessToken = 'validtoken';
|
|
jwt.verify.mockReturnValue({ id: 1, jwtVersion: 1 }); // Old version in token
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
|
|
await authenticateToken(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(401);
|
|
expect(res.json).toHaveBeenCalledWith({
|
|
error: 'Session expired due to password change. Please log in again.',
|
|
code: 'JWT_VERSION_MISMATCH'
|
|
});
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should pass when JWT version matches', async () => {
|
|
const mockUser = { id: 1, email: 'test@test.com', jwtVersion: 5 };
|
|
req.cookies.accessToken = 'validtoken';
|
|
jwt.verify.mockReturnValue({ id: 1, jwtVersion: 5 });
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
|
|
await authenticateToken(req, res, next);
|
|
|
|
expect(next).toHaveBeenCalled();
|
|
expect(req.user).toEqual(mockUser);
|
|
});
|
|
});
|
|
}); |