- 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>
333 lines
9.4 KiB
JavaScript
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');
|
|
});
|
|
});
|
|
});
|