const jwt = require('jsonwebtoken'); const bcrypt = require('bcryptjs'); const User = require('../../models/User'); const Street = require('../../models/Street'); const Task = require('../../models/Task'); const Post = require('../../models/Post'); const Event = require('../../models/Event'); const Reward = require('../../models/Reward'); const Report = require('../../models/Report'); /** * Create a test user and return user object with token */ async function createTestUser(overrides = {}) { const defaultUser = { name: 'Test User', email: 'test@example.com', password: 'password123', }; const userData = { ...defaultUser, ...overrides }; // Generate a test ID that matches CouchDB ID pattern const userId = '507f1f77bcf86cd7994390' + Math.floor(Math.random() * 10); // Create mock user object directly (bypass User.create to avoid mock issues) const user = { _id: userId, _rev: '1-abc', type: 'user', ...userData, password: '$2a$10$hashedpassword', // Mock hashed password 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 token = jwt.sign( { user: { id: user._id } }, process.env.JWT_SECRET, { expiresIn: 3600 } ); return { user, token }; } /** * Create multiple test users */ async function createTestUsers(count = 2) { const users = []; for (let i = 0; i < count; i++) { const { user, token } = await createTestUser({ name: `Test User ${i + 1}`, email: `test${i + 1}@example.com`, }); users.push({ user, token }); } return users; } /** * Create a test street */ async function createTestStreet(userId, overrides = {}) { const defaultStreet = { name: 'Test Street', location: { type: 'Point', coordinates: [-73.935242, 40.730610], }, city: 'Test City', state: 'TS', }; // Add adoptedBy if userId is provided if (userId) { defaultStreet.adoptedBy = { userId: userId, name: 'Test User', profilePicture: '' }; defaultStreet.status = 'adopted'; } // Generate a test ID that matches CouchDB ID pattern const streetId = '507f1f77bcf86cd7994390' + Math.floor(Math.random() * 10); // Apply overrides to defaultStreet const finalStreetData = { ...defaultStreet, ...overrides }; const street = { _id: streetId, id: streetId, // Add id property for compatibility _rev: '1-abc', type: 'street', ...finalStreetData, status: finalStreetData.status || 'available', adoptedBy: finalStreetData.adoptedBy || null, createdAt: '2023-01-01T00:00:00.000Z', updatedAt: '2023-01-01T00:00:00.000Z' }; return street; } /** * Create a test task */ async function createTestTask(userId, streetId, overrides = {}) { const streetData = { streetId: streetId, name: 'Test Street', location: { type: 'Point', coordinates: [-73.935242, 40.730610], } }; const defaultTask = { street: streetData, description: 'Test task description', type: 'cleaning', status: 'pending', }; // Add completedBy if userId is provided if (userId) { defaultTask.completedBy = { userId: userId, name: 'Test User', profilePicture: '' }; defaultTask.status = 'completed'; } // Generate a test ID that matches CouchDB ID pattern const taskId = '507f1f77bcf86cd7994390' + Math.floor(Math.random() * 10); const task = { _id: taskId, _rev: '1-abc', type: 'task', ...defaultTask, pointsAwarded: 10, createdAt: '2023-01-01T00:00:00.000Z', updatedAt: '2023-01-01T00:00:00.000Z' }; return task; } /** * Create a test post */ async function createTestPost(userId, overrides = {}) { const defaultPost = { user: userId, content: 'Test post content', type: 'text', }; // Generate a test ID that matches CouchDB ID pattern const postId = '507f1f77bcf86cd7994390' + Math.floor(Math.random() * 10); const post = { _id: postId, _rev: '1-abc', type: 'post', ...defaultPost, likes: [], comments: [], commentsCount: 0, createdAt: '2023-01-01T00:00:00.000Z', updatedAt: '2023-01-01T00:00:00.000Z' }; return post; } /** * Create a test event */ async function createTestEvent(userId, overrides = {}) { const defaultEvent = { title: 'Test Event', description: 'Test event description', date: new Date(Date.now() + 86400000).toISOString(), // Tomorrow location: 'Test Location', }; // Generate a test ID that matches validator pattern const eventId = `event_${Math.random().toString(36).substr(2, 9)}`; const event = { _id: eventId, id: eventId, // Add id property for compatibility _rev: '1-abc', type: 'event', ...defaultEvent, participants: [], participantsCount: 0, status: 'upcoming', createdAt: '2023-01-01T00:00:00.000Z', updatedAt: '2023-01-01T00:00:00.000Z' }; // Add participant if userId is provided if (userId) { event.participants.push({ userId: userId, name: 'Test User', profilePicture: '', joinedAt: new Date().toISOString() }); event.participantsCount = 1; } return event; } /** * Create a test reward */ async function createTestReward(overrides = {}) { const defaultReward = { name: 'Test Reward', description: 'Test reward description', cost: 100, }; // Handle legacy field name mapping const rewardData = { ...defaultReward, ...overrides }; if (rewardData.pointsCost && !rewardData.cost) { rewardData.cost = rewardData.pointsCost; delete rewardData.pointsCost; } // Generate a test ID that matches validator pattern const rewardId = `reward_${Math.random().toString(36).substr(2, 9)}`; const reward = { _id: rewardId, _rev: '1-abc', type: 'reward', ...rewardData, isActive: true, isPremium: rewardData.isPremium || false, createdAt: '2023-01-01T00:00:00.000Z', updatedAt: '2023-01-01T00:00:00.000Z' }; return reward; } /** * Create a test report */ async function createTestReport(userId, streetId, overrides = {}) { const defaultReport = { street: streetId, reporter: userId, type: 'pothole', description: 'Test report description', status: 'pending', }; // Generate a test ID that matches validator pattern const reportId = `report_${Math.random().toString(36).substr(2, 9)}`; const report = { _id: reportId, _rev: '1-abc', type: 'report', ...defaultReport, createdAt: '2023-01-01T00:00:00.000Z', updatedAt: '2023-01-01T00:00:00.000Z' }; return report; } /** * Clean up all test data */ async function cleanupDatabase() { const couchdbService = require('../../services/couchdbService'); await couchdbService.initialize(); // Delete all documents by type const types = ['user', 'street', 'task', 'post', 'event', 'reward', 'report', 'badge', 'user_badge', 'point_transaction']; for (const type of types) { try { const docs = await couchdbService.findByType(type); for (const doc of docs) { await couchdbService.deleteDocument(doc._id, doc._rev); } } catch (error) { console.error(`Error cleaning up ${type}s:`, error.message); } } } module.exports = { createTestUser, createTestUsers, createTestStreet, createTestTask, createTestPost, createTestEvent, createTestReward, createTestReport, cleanupDatabase, };