feat: Migrate Street and Task models from MongoDB to CouchDB
- Replace Street model with CouchDB-based implementation - Replace Task model with CouchDB-based implementation - Update routes to use new model interfaces - Handle geospatial queries with CouchDB design documents - Maintain adoption functionality and middleware - Use denormalized document structure with embedded data - Update test files to work with new models - Ensure API compatibility while using CouchDB underneath 🤖 Generated with [AI Assistant] Co-Authored-By: AI Assistant <noreply@ai-assistant.com>
This commit is contained in:
@@ -2,14 +2,22 @@ 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 = {
|
||||
@@ -18,6 +26,35 @@ describe('Auth Routes', () => {
|
||||
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)
|
||||
@@ -25,18 +62,21 @@ describe('Auth Routes', () => {
|
||||
|
||||
expect(response.body).toHaveProperty('token');
|
||||
expect(typeof response.body.token).toBe('string');
|
||||
expect(response.body.success).toBe(true);
|
||||
|
||||
// Verify user was created in database
|
||||
const user = await User.findOne({ email: userData.email });
|
||||
expect(user).toBeTruthy();
|
||||
expect(user.name).toBe(userData.name);
|
||||
expect(user.email).toBe(userData.email);
|
||||
expect(user.password).not.toBe(userData.password); // Password should be hashed
|
||||
// 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 () => {
|
||||
// Create a user first
|
||||
await createTestUser({ email: 'existing@example.com' });
|
||||
const existingUser = {
|
||||
_id: 'user_123',
|
||||
email: 'existing@example.com',
|
||||
name: 'Existing User'
|
||||
};
|
||||
|
||||
couchdbService.findUserByEmail.mockResolvedValue(existingUser);
|
||||
|
||||
const userData = {
|
||||
name: 'Jane Doe',
|
||||
@@ -50,6 +90,7 @@ describe('Auth Routes', () => {
|
||||
.expect(400);
|
||||
|
||||
expect(response.body).toHaveProperty('msg', 'User already exists');
|
||||
expect(response.body.success).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle missing required fields', async () => {
|
||||
@@ -63,15 +104,39 @@ describe('Auth Routes', () => {
|
||||
});
|
||||
|
||||
describe('POST /api/auth/login', () => {
|
||||
beforeEach(async () => {
|
||||
// Create a test user before each login test
|
||||
await createTestUser({
|
||||
email: 'login@example.com',
|
||||
password: 'password123',
|
||||
});
|
||||
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',
|
||||
@@ -84,9 +149,12 @@ describe('Auth Routes', () => {
|
||||
|
||||
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',
|
||||
@@ -98,9 +166,19 @@ describe('Auth Routes', () => {
|
||||
.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',
|
||||
@@ -112,6 +190,7 @@ describe('Auth Routes', () => {
|
||||
.expect(400);
|
||||
|
||||
expect(response.body).toHaveProperty('msg', 'Invalid credentials');
|
||||
expect(response.body.success).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle missing email or password', async () => {
|
||||
@@ -126,16 +205,55 @@ describe('Auth Routes', () => {
|
||||
|
||||
describe('GET /api/auth', () => {
|
||||
it('should get authenticated user with valid token', async () => {
|
||||
const { user, token } = await createTestUser();
|
||||
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.id);
|
||||
expect(response.body).toHaveProperty('name', user.name);
|
||||
expect(response.body).toHaveProperty('email', user.email);
|
||||
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');
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user