const request = require('supertest'); const express = require('express'); const authRoutes = require('../../routes/auth'); const User = require('../../models/User'); const couchdbService = require('../../services/couchdbService'); const { createTestUser } = require('../utils/testHelpers'); // Mock CouchDB service for testing jest.mock('../../services/couchdbService'); // Create Express app for testing const app = express(); app.use(express.json()); app.use('/api/auth', authRoutes); describe('Auth Routes', () => { beforeEach(() => { jest.clearAllMocks(); }); describe('POST /api/auth/register', () => { it('should register a new user and return a token', async () => { const userData = { name: 'John Doe', email: 'john@example.com', password: 'password123', }; // Mock CouchDB responses couchdbService.findUserByEmail.mockResolvedValue(null); const mockCreatedUser = { _id: 'user_123', _rev: '1-abc', type: 'user', ...userData, password: '$2a$10$hashedpassword', isPremium: false, points: 0, adoptedStreets: [], completedTasks: [], posts: [], events: [], earnedBadges: [], stats: { streetsAdopted: 0, tasksCompleted: 0, postsCreated: 0, eventsParticipated: 0, badgesEarned: 0 }, createdAt: '2023-01-01T00:00:00.000Z', updatedAt: '2023-01-01T00:00:00.000Z' }; couchdbService.createDocument.mockResolvedValue(mockCreatedUser); const response = await request(app) .post('/api/auth/register') .send(userData) .expect(200); expect(response.body).toHaveProperty('token'); expect(typeof response.body.token).toBe('string'); expect(response.body.success).toBe(true); // Verify CouchDB service was called correctly expect(couchdbService.findUserByEmail).toHaveBeenCalledWith(userData.email); expect(couchdbService.createDocument).toHaveBeenCalled(); }); it('should not register a user with an existing email', async () => { const existingUser = { _id: 'user_123', email: 'existing@example.com', name: 'Existing User' }; couchdbService.findUserByEmail.mockResolvedValue(existingUser); const userData = { name: 'Jane Doe', email: 'existing@example.com', password: 'password123', }; const response = await request(app) .post('/api/auth/register') .send(userData) .expect(400); expect(response.body).toHaveProperty('msg', 'User already exists'); expect(response.body.success).toBe(false); }); it('should handle missing required fields', async () => { const response = await request(app) .post('/api/auth/register') .send({ email: 'test@example.com' }) .expect(500); expect(response.body).toBeDefined(); }); }); describe('POST /api/auth/login', () => { beforeEach(() => { jest.clearAllMocks(); }); it('should login with valid credentials and return a token', async () => { const mockUser = { _id: 'user_123', _rev: '1-abc', type: 'user', name: 'Test User', email: 'login@example.com', password: '$2a$10$hashedpassword', isPremium: false, points: 0, adoptedStreets: [], completedTasks: [], posts: [], events: [], earnedBadges: [], stats: { streetsAdopted: 0, tasksCompleted: 0, postsCreated: 0, eventsParticipated: 0, badgesEarned: 0 }, createdAt: '2023-01-01T00:00:00.000Z', updatedAt: '2023-01-01T00:00:00.000Z', comparePassword: jest.fn().mockResolvedValue(true) }; couchdbService.findUserByEmail.mockResolvedValue(mockUser); const loginData = { email: 'login@example.com', password: 'password123', }; const response = await request(app) .post('/api/auth/login') .send(loginData) .expect(200); expect(response.body).toHaveProperty('token'); expect(typeof response.body.token).toBe('string'); expect(response.body.success).toBe(true); }); it('should not login with invalid email', async () => { couchdbService.findUserByEmail.mockResolvedValue(null); const loginData = { email: 'nonexistent@example.com', password: 'password123', }; const response = await request(app) .post('/api/auth/login') .send(loginData) .expect(400); expect(response.body).toHaveProperty('msg', 'Invalid credentials'); expect(response.body.success).toBe(false); }); it('should not login with invalid password', async () => { const mockUser = { _id: 'user_123', email: 'login@example.com', password: '$2a$10$hashedpassword', comparePassword: jest.fn().mockResolvedValue(false) }; couchdbService.findUserByEmail.mockResolvedValue(mockUser); const loginData = { email: 'login@example.com', password: 'wrongpassword', }; const response = await request(app) .post('/api/auth/login') .send(loginData) .expect(400); expect(response.body).toHaveProperty('msg', 'Invalid credentials'); expect(response.body.success).toBe(false); }); it('should handle missing email or password', async () => { const response = await request(app) .post('/api/auth/login') .send({ email: 'test@example.com' }) .expect(500); expect(response.body).toBeDefined(); }); }); describe('GET /api/auth', () => { it('should get authenticated user with valid token', async () => { const mockUser = { _id: 'user_123', _rev: '1-abc', type: 'user', name: 'Test User', email: 'test@example.com', isPremium: false, points: 0, adoptedStreets: [], completedTasks: [], posts: [], events: [], earnedBadges: [], stats: { streetsAdopted: 0, tasksCompleted: 0, postsCreated: 0, eventsParticipated: 0, badgesEarned: 0 }, createdAt: '2023-01-01T00:00:00.000Z', updatedAt: '2023-01-01T00:00:00.000Z', toSafeObject: jest.fn().mockReturnValue({ _id: 'user_123', name: 'Test User', email: 'test@example.com', isPremium: false, points: 0 }) }; couchdbService.findUserById.mockResolvedValue(mockUser); // Create a valid token const jwt = require('jsonwebtoken'); const token = jwt.sign( { user: { id: 'user_123' } }, process.env.JWT_SECRET, { expiresIn: 3600 } ); const response = await request(app) .get('/api/auth') .set('x-auth-token', token) .expect(200); expect(response.body).toHaveProperty('_id', 'user_123'); expect(response.body).toHaveProperty('name', 'Test User'); expect(response.body).toHaveProperty('email', 'test@example.com'); expect(response.body).not.toHaveProperty('password'); }); it('should reject request without token', async () => { const response = await request(app) .get('/api/auth') .expect(401); expect(response.body).toHaveProperty('msg', 'No token, authorization denied'); }); it('should reject request with invalid token', async () => { const response = await request(app) .get('/api/auth') .set('x-auth-token', 'invalid-token') .expect(401); expect(response.body).toHaveProperty('msg', 'Token is not valid'); }); }); });