Files
adopt-a-street/backend/__tests__/routes/auth.test.js
William Valentin 56c2292797 fix: add CouchDB mocking to all route tests
- Add comprehensive CouchDB service mocks to all route test files
- Include all required service methods (find, create, update, etc.)
- Add beforeEach cleanup to ensure mock state is reset
- Consistent mocking pattern across all route tests

🤖 Generated with [AI Assistant]

Co-Authored-By: AI Assistant <noreply@ai-assistant.com>
2025-11-01 13:54:54 -07:00

333 lines
9.4 KiB
JavaScript

const request = require('supertest');
const express = require('express');
// Mock CouchDB service before importing routes
jest.mock('../../services/couchdbService', () => ({
initialize: jest.fn().mockResolvedValue(true),
create: jest.fn(),
getById: jest.fn(),
find: jest.fn(),
createDocument: jest.fn(),
updateDocument: jest.fn(),
deleteDocument: jest.fn(),
findByType: jest.fn(),
findUserById: jest.fn(),
update: jest.fn(),
}));
const authRoutes = require('../../routes/auth');
const User = require('../../models/User');
const couchdbService = require('../../services/couchdbService');
const { createTestUser } = require('../utils/testHelpers');
// Mock User.findOne method for login tests
jest.spyOn(User, 'findOne');
// 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 existingUserData = {
_id: 'user_123',
_rev: '1-abc',
type: 'user',
email: 'existing@example.com',
name: 'Existing User',
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'
};
const existingUser = new User(existingUserData);
couchdbService.findUserByEmail.mockResolvedValue(existingUser.toJSON());
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(400);
expect(response.body).toBeDefined();
expect(response.body.success).toBe(false);
expect(response.body.errors).toBeDefined();
});
});
describe('POST /api/auth/login', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should login with valid credentials and return a token', async () => {
const mockUserData = {
_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'
};
const mockUser = new User(mockUserData);
jest.spyOn(mockUser, 'comparePassword').mockResolvedValue(true);
User.findOne.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 () => {
User.findOne.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 mockUserData = {
_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'
};
const mockUser = new User(mockUserData);
jest.spyOn(mockUser, 'comparePassword').mockResolvedValue(false);
User.findOne.mockResolvedValue(mockUser);
const loginData = {
email: 'login@example.com',
password: 'WrongPassword123',
};
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(400);
expect(response.body).toBeDefined();
expect(response.body.success).toBe(false);
expect(response.body.errors).toBeDefined();
});
});
describe('GET /api/auth', () => {
it('should get authenticated user with valid token', async () => {
const mockUserData = {
_id: 'user_123',
_rev: '1-abc',
type: 'user',
name: 'Test User',
email: 'test@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'
};
const mockUser = new User(mockUserData);
couchdbService.findUserById.mockResolvedValue(mockUser.toJSON());
// 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');
});
});
});