updating unit and integration tests

This commit is contained in:
jackiettran
2025-12-20 14:59:09 -05:00
parent 4e0a4ef019
commit bd1bd5014c
14 changed files with 2424 additions and 100 deletions

View File

@@ -45,10 +45,15 @@ jest.mock('../../../middleware/rateLimiter', () => ({
loginLimiter: (req, res, next) => next(),
registerLimiter: (req, res, next) => next(),
passwordResetLimiter: (req, res, next) => next(),
emailVerificationLimiter: (req, res, next) => next(),
}));
jest.mock('../../../middleware/auth', () => ({
optionalAuth: (req, res, next) => next(),
authenticateToken: (req, res, next) => {
req.user = { id: 'user-123' };
next();
},
}));
jest.mock('../../../services/email', () => ({
@@ -290,7 +295,7 @@ describe('Auth Routes', () => {
});
expect(response.status).toBe(401);
expect(response.body.error).toBe('Invalid credentials');
expect(response.body.error).toBe('Unable to log in. Please check your email and password, or create an account.');
});
it('should reject login with invalid password', async () => {
@@ -311,7 +316,7 @@ describe('Auth Routes', () => {
});
expect(response.status).toBe(401);
expect(response.body.error).toBe('Invalid credentials');
expect(response.body.error).toBe('Unable to log in. Please check your email and password, or create an account.');
expect(mockUser.incLoginAttempts).toHaveBeenCalled();
});
@@ -536,95 +541,147 @@ describe('Auth Routes', () => {
});
describe('POST /auth/verify-email', () => {
it('should verify email with valid token', async () => {
it('should verify email with valid 6-digit code', async () => {
const mockUser = {
id: 1,
id: 'user-123',
email: 'test@example.com',
isVerified: false,
verificationToken: 'valid-token',
verificationToken: '123456',
verificationTokenExpiry: new Date(Date.now() + 3600000), // 1 hour from now
verificationAttempts: 0,
isVerificationLocked: jest.fn().mockReturnValue(false),
isVerificationTokenValid: jest.fn().mockReturnValue(true),
verifyEmail: jest.fn().mockResolvedValue()
};
User.findOne.mockResolvedValue(mockUser);
User.findByPk.mockResolvedValue(mockUser);
const response = await request(app)
.post('/auth/verify-email')
.send({ token: 'valid-token' });
.send({ code: '123456' });
expect(response.status).toBe(200);
expect(response.body.message).toBe('Email verified successfully');
expect(response.body.user).toMatchObject({
id: 1,
id: 'user-123',
email: 'test@example.com',
isVerified: true
});
expect(mockUser.verifyEmail).toHaveBeenCalled();
});
it('should reject missing token', async () => {
it('should reject missing code', async () => {
const response = await request(app)
.post('/auth/verify-email')
.send({});
expect(response.status).toBe(400);
expect(response.body.error).toBe('Verification token required');
expect(response.body.code).toBe('TOKEN_REQUIRED');
expect(response.body.error).toBe('Verification code required');
expect(response.body.code).toBe('CODE_REQUIRED');
});
it('should reject invalid token', async () => {
User.findOne.mockResolvedValue(null);
it('should reject invalid code format (not 6 digits)', async () => {
const response = await request(app)
.post('/auth/verify-email')
.send({ code: '12345' }); // Only 5 digits
expect(response.status).toBe(400);
expect(response.body.error).toBe('Verification code must be 6 digits');
expect(response.body.code).toBe('INVALID_CODE_FORMAT');
});
it('should reject when user not found', async () => {
User.findByPk.mockResolvedValue(null);
const response = await request(app)
.post('/auth/verify-email')
.send({ token: 'invalid-token' });
.send({ code: '123456' });
expect(response.status).toBe(400);
expect(response.body.error).toBe('Invalid verification token');
expect(response.body.code).toBe('VERIFICATION_TOKEN_INVALID');
expect(response.status).toBe(404);
expect(response.body.error).toBe('User not found');
expect(response.body.code).toBe('USER_NOT_FOUND');
});
it('should reject already verified user', async () => {
const mockUser = {
id: 1,
id: 'user-123',
isVerified: true
};
User.findOne.mockResolvedValue(mockUser);
User.findByPk.mockResolvedValue(mockUser);
const response = await request(app)
.post('/auth/verify-email')
.send({ token: 'some-token' });
.send({ code: '123456' });
expect(response.status).toBe(400);
expect(response.body.error).toBe('Email already verified');
expect(response.body.code).toBe('ALREADY_VERIFIED');
});
it('should reject expired token', async () => {
it('should reject when too many verification attempts', async () => {
const mockUser = {
id: 1,
id: 'user-123',
isVerified: false,
isVerificationTokenValid: jest.fn().mockReturnValue(false)
isVerificationLocked: jest.fn().mockReturnValue(true)
};
User.findOne.mockResolvedValue(mockUser);
User.findByPk.mockResolvedValue(mockUser);
const response = await request(app)
.post('/auth/verify-email')
.send({ token: 'expired-token' });
.send({ code: '123456' });
expect(response.status).toBe(429);
expect(response.body.error).toContain('Too many verification attempts');
expect(response.body.code).toBe('TOO_MANY_ATTEMPTS');
});
it('should reject when no verification code exists', async () => {
const mockUser = {
id: 'user-123',
isVerified: false,
verificationToken: null,
isVerificationLocked: jest.fn().mockReturnValue(false)
};
User.findByPk.mockResolvedValue(mockUser);
const response = await request(app)
.post('/auth/verify-email')
.send({ code: '123456' });
expect(response.status).toBe(400);
expect(response.body.error).toContain('No verification code found');
expect(response.body.code).toBe('NO_CODE');
});
it('should reject expired verification code', async () => {
const mockUser = {
id: 'user-123',
isVerified: false,
verificationToken: '123456',
verificationTokenExpiry: new Date(Date.now() - 3600000), // 1 hour ago (expired)
isVerificationLocked: jest.fn().mockReturnValue(false)
};
User.findByPk.mockResolvedValue(mockUser);
const response = await request(app)
.post('/auth/verify-email')
.send({ code: '123456' });
expect(response.status).toBe(400);
expect(response.body.error).toContain('expired');
expect(response.body.code).toBe('VERIFICATION_TOKEN_EXPIRED');
expect(response.body.code).toBe('VERIFICATION_EXPIRED');
});
it('should handle verification errors', async () => {
User.findOne.mockRejectedValue(new Error('Database error'));
User.findByPk.mockRejectedValue(new Error('Database error'));
const response = await request(app)
.post('/auth/verify-email')
.send({ token: 'some-token' });
.send({ code: '123456' });
expect(response.status).toBe(500);
expect(response.body.error).toBe('Email verification failed. Please try again.');
@@ -835,6 +892,48 @@ describe('Auth Routes', () => {
});
});
describe('GET /auth/status', () => {
it('should return authenticated true when user is logged in', async () => {
// The optionalAuth middleware sets req.user if authenticated
// We need to modify the mock for this specific test
const mockUser = {
id: 1,
email: 'test@example.com',
firstName: 'Test',
lastName: 'User',
isVerified: true
};
// Create a custom app for this test with user set
const statusApp = express();
statusApp.use(express.json());
statusApp.use((req, res, next) => {
req.user = mockUser;
next();
});
statusApp.use('/auth', authRoutes);
const response = await request(statusApp)
.get('/auth/status');
expect(response.status).toBe(200);
expect(response.body.authenticated).toBe(true);
expect(response.body.user).toMatchObject({
id: 1,
email: 'test@example.com'
});
});
it('should return authenticated false when user is not logged in', async () => {
const response = await request(app)
.get('/auth/status');
expect(response.status).toBe(200);
expect(response.body.authenticated).toBe(false);
expect(response.body.user).toBeUndefined();
});
});
describe('POST /auth/forgot-password', () => {
it('should send password reset email for existing user', async () => {
const mockUser = {