backend unit tests
This commit is contained in:
194
backend/tests/unit/middleware/auth.test.js
Normal file
194
backend/tests/unit/middleware/auth.test.js
Normal file
@@ -0,0 +1,194 @@
|
||||
const { authenticateToken } = 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_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' };
|
||||
req.cookies.accessToken = 'validtoken';
|
||||
jwt.verify.mockReturnValue({ id: 1 });
|
||||
User.findByPk.mockResolvedValue(mockUser);
|
||||
|
||||
await authenticateToken(req, res, next);
|
||||
|
||||
expect(jwt.verify).toHaveBeenCalledWith('validtoken', process.env.JWT_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' };
|
||||
req.cookies.accessToken = 'validtoken2';
|
||||
jwt.verify.mockReturnValue({ id: 2 });
|
||||
User.findByPk.mockResolvedValue(mockUser);
|
||||
|
||||
await authenticateToken(req, res, next);
|
||||
|
||||
expect(jwt.verify).toHaveBeenCalledWith('validtoken2', process.env.JWT_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'
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user