add changes
This commit is contained in:
316
backend/__tests__/auth.test.js
Normal file
316
backend/__tests__/auth.test.js
Normal file
@@ -0,0 +1,316 @@
|
||||
const request = require('supertest');
|
||||
const express = require('express');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
const authRoutes = require('../routes/auth.routes');
|
||||
const { User, GuestSession, QuizSession, sequelize } = require('../models');
|
||||
|
||||
// Create Express app for testing
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
app.use('/api/auth', authRoutes);
|
||||
|
||||
describe('Authentication Endpoints', () => {
|
||||
let testUser;
|
||||
let authToken;
|
||||
|
||||
beforeAll(async () => {
|
||||
// Sync database
|
||||
await sequelize.sync({ force: true });
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
// Clean up
|
||||
await User.destroy({ where: {}, force: true });
|
||||
await sequelize.close();
|
||||
});
|
||||
|
||||
describe('POST /api/auth/register', () => {
|
||||
it('should register a new user successfully', async () => {
|
||||
const userData = {
|
||||
username: 'testuser',
|
||||
email: 'test@example.com',
|
||||
password: 'Test@123'
|
||||
};
|
||||
|
||||
const response = await request(app)
|
||||
.post('/api/auth/register')
|
||||
.send(userData)
|
||||
.expect(201);
|
||||
|
||||
expect(response.body.success).toBe(true);
|
||||
expect(response.body.message).toBe('User registered successfully');
|
||||
expect(response.body.data).toHaveProperty('user');
|
||||
expect(response.body.data).toHaveProperty('token');
|
||||
expect(response.body.data.user.email).toBe(userData.email);
|
||||
expect(response.body.data.user.username).toBe(userData.username);
|
||||
expect(response.body.data.user).not.toHaveProperty('password');
|
||||
|
||||
testUser = response.body.data.user;
|
||||
authToken = response.body.data.token;
|
||||
});
|
||||
|
||||
it('should reject registration with duplicate email', async () => {
|
||||
const userData = {
|
||||
username: 'anotheruser',
|
||||
email: 'test@example.com', // Same email
|
||||
password: 'Test@123'
|
||||
};
|
||||
|
||||
const response = await request(app)
|
||||
.post('/api/auth/register')
|
||||
.send(userData)
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.success).toBe(false);
|
||||
expect(response.body.message).toBe('Email already registered');
|
||||
});
|
||||
|
||||
it('should reject registration with duplicate username', async () => {
|
||||
const userData = {
|
||||
username: 'testuser', // Same username
|
||||
email: 'another@example.com',
|
||||
password: 'Test@123'
|
||||
};
|
||||
|
||||
const response = await request(app)
|
||||
.post('/api/auth/register')
|
||||
.send(userData)
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.success).toBe(false);
|
||||
expect(response.body.message).toBe('Username already taken');
|
||||
});
|
||||
|
||||
it('should reject registration with invalid email', async () => {
|
||||
const userData = {
|
||||
username: 'newuser',
|
||||
email: 'invalid-email',
|
||||
password: 'Test@123'
|
||||
};
|
||||
|
||||
const response = await request(app)
|
||||
.post('/api/auth/register')
|
||||
.send(userData)
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.success).toBe(false);
|
||||
expect(response.body.message).toBe('Validation failed');
|
||||
});
|
||||
|
||||
it('should reject registration with weak password', async () => {
|
||||
const userData = {
|
||||
username: 'newuser',
|
||||
email: 'new@example.com',
|
||||
password: 'weak'
|
||||
};
|
||||
|
||||
const response = await request(app)
|
||||
.post('/api/auth/register')
|
||||
.send(userData)
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.success).toBe(false);
|
||||
expect(response.body.message).toBe('Validation failed');
|
||||
});
|
||||
|
||||
it('should reject registration with username too short', async () => {
|
||||
const userData = {
|
||||
username: 'ab', // Only 2 characters
|
||||
email: 'new@example.com',
|
||||
password: 'Test@123'
|
||||
};
|
||||
|
||||
const response = await request(app)
|
||||
.post('/api/auth/register')
|
||||
.send(userData)
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.success).toBe(false);
|
||||
expect(response.body.message).toBe('Validation failed');
|
||||
});
|
||||
|
||||
it('should reject registration with invalid username characters', async () => {
|
||||
const userData = {
|
||||
username: 'test-user!', // Contains invalid characters
|
||||
email: 'new@example.com',
|
||||
password: 'Test@123'
|
||||
};
|
||||
|
||||
const response = await request(app)
|
||||
.post('/api/auth/register')
|
||||
.send(userData)
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.success).toBe(false);
|
||||
expect(response.body.message).toBe('Validation failed');
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST /api/auth/register with guest migration', () => {
|
||||
let guestSession;
|
||||
|
||||
beforeAll(async () => {
|
||||
// Create a guest session with quiz data
|
||||
guestSession = await GuestSession.create({
|
||||
id: uuidv4(),
|
||||
guest_id: `guest_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
||||
session_token: 'test-guest-token',
|
||||
expires_at: new Date(Date.now() + 24 * 60 * 60 * 1000),
|
||||
max_quizzes: 3,
|
||||
quizzes_attempted: 2,
|
||||
is_converted: false
|
||||
});
|
||||
|
||||
// Create quiz sessions for the guest
|
||||
await QuizSession.create({
|
||||
id: uuidv4(),
|
||||
guest_session_id: guestSession.id,
|
||||
category_id: uuidv4(),
|
||||
quiz_type: 'practice',
|
||||
difficulty: 'easy',
|
||||
status: 'completed',
|
||||
questions_count: 5,
|
||||
questions_answered: 5,
|
||||
correct_answers: 4,
|
||||
score: 40,
|
||||
percentage: 80,
|
||||
is_passed: true,
|
||||
started_at: new Date(),
|
||||
completed_at: new Date()
|
||||
});
|
||||
});
|
||||
|
||||
it('should register user and migrate guest data', async () => {
|
||||
const userData = {
|
||||
username: 'guestconvert',
|
||||
email: 'guestconvert@example.com',
|
||||
password: 'Test@123',
|
||||
guestSessionId: guestSession.guest_id
|
||||
};
|
||||
|
||||
const response = await request(app)
|
||||
.post('/api/auth/register')
|
||||
.send(userData)
|
||||
.expect(201);
|
||||
|
||||
expect(response.body.success).toBe(true);
|
||||
expect(response.body.data).toHaveProperty('migratedData');
|
||||
expect(response.body.data.migratedData).toHaveProperty('quizzes');
|
||||
expect(response.body.data.migratedData).toHaveProperty('stats');
|
||||
|
||||
// Verify guest session is marked as converted
|
||||
await guestSession.reload();
|
||||
expect(guestSession.is_converted).toBe(true);
|
||||
expect(guestSession.converted_user_id).toBe(response.body.data.user.id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST /api/auth/login', () => {
|
||||
it('should login with valid credentials', async () => {
|
||||
const credentials = {
|
||||
email: 'test@example.com',
|
||||
password: 'Test@123'
|
||||
};
|
||||
|
||||
const response = await request(app)
|
||||
.post('/api/auth/login')
|
||||
.send(credentials)
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.success).toBe(true);
|
||||
expect(response.body.message).toBe('Login successful');
|
||||
expect(response.body.data).toHaveProperty('user');
|
||||
expect(response.body.data).toHaveProperty('token');
|
||||
expect(response.body.data.user).not.toHaveProperty('password');
|
||||
});
|
||||
|
||||
it('should reject login with invalid email', async () => {
|
||||
const credentials = {
|
||||
email: 'nonexistent@example.com',
|
||||
password: 'Test@123'
|
||||
};
|
||||
|
||||
const response = await request(app)
|
||||
.post('/api/auth/login')
|
||||
.send(credentials)
|
||||
.expect(401);
|
||||
|
||||
expect(response.body.success).toBe(false);
|
||||
expect(response.body.message).toBe('Invalid email or password');
|
||||
});
|
||||
|
||||
it('should reject login with invalid password', async () => {
|
||||
const credentials = {
|
||||
email: 'test@example.com',
|
||||
password: 'WrongPassword123'
|
||||
};
|
||||
|
||||
const response = await request(app)
|
||||
.post('/api/auth/login')
|
||||
.send(credentials)
|
||||
.expect(401);
|
||||
|
||||
expect(response.body.success).toBe(false);
|
||||
expect(response.body.message).toBe('Invalid email or password');
|
||||
});
|
||||
|
||||
it('should reject login with missing fields', async () => {
|
||||
const credentials = {
|
||||
email: 'test@example.com'
|
||||
// Missing password
|
||||
};
|
||||
|
||||
const response = await request(app)
|
||||
.post('/api/auth/login')
|
||||
.send(credentials)
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.success).toBe(false);
|
||||
expect(response.body.message).toBe('Validation failed');
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /api/auth/verify', () => {
|
||||
it('should verify valid token', async () => {
|
||||
const response = await request(app)
|
||||
.get('/api/auth/verify')
|
||||
.set('Authorization', `Bearer ${authToken}`)
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.success).toBe(true);
|
||||
expect(response.body.message).toBe('Token valid');
|
||||
expect(response.body.data).toHaveProperty('user');
|
||||
expect(response.body.data.user.email).toBe('test@example.com');
|
||||
});
|
||||
|
||||
it('should reject request without token', async () => {
|
||||
const response = await request(app)
|
||||
.get('/api/auth/verify')
|
||||
.expect(401);
|
||||
|
||||
expect(response.body.success).toBe(false);
|
||||
expect(response.body.message).toContain('No token provided');
|
||||
});
|
||||
|
||||
it('should reject request with invalid token', async () => {
|
||||
const response = await request(app)
|
||||
.get('/api/auth/verify')
|
||||
.set('Authorization', 'Bearer invalid-token')
|
||||
.expect(401);
|
||||
|
||||
expect(response.body.success).toBe(false);
|
||||
expect(response.body.message).toContain('Invalid token');
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST /api/auth/logout', () => {
|
||||
it('should logout successfully', async () => {
|
||||
const response = await request(app)
|
||||
.post('/api/auth/logout')
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.success).toBe(true);
|
||||
expect(response.body.message).toContain('Logout successful');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user