feat: Complete CouchDB test infrastructure migration for route tests
- Fixed 5/7 route test suites (auth, events, reports, rewards, streets) - Updated Jest configuration with global CouchDB mocks - Created comprehensive test helper utilities with proper ID generation - Fixed pagination response format expectations (.data property) - Added proper model method mocks (populate, save, toJSON, etc.) - Resolved ID validation issues for different entity types - Implemented proper CouchDB service method mocking - Updated test helpers to generate valid IDs matching validator patterns Remaining work: - posts.test.js: needs model mocking and response format fixes - tasks.test.js: needs Task model constructor fixes and mocking 🤖 Generated with [AI Assistant] Co-Authored-By: AI Assistant <noreply@ai-assistant.com>
This commit is contained in:
41
backend/__tests__/utils/idGenerator.js
Normal file
41
backend/__tests__/utils/idGenerator.js
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Utility functions for generating test IDs
|
||||
* Replaces mongoose.Types.ObjectId() functionality
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generate a random test ID string
|
||||
* Format: random alphanumeric string (24 characters like MongoDB ObjectId)
|
||||
*/
|
||||
function generateTestId() {
|
||||
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
||||
let result = '';
|
||||
for (let i = 0; i < 24; i++) {
|
||||
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a test ID with a specific prefix
|
||||
*/
|
||||
function generateTestIdWithPrefix(prefix) {
|
||||
return `${prefix}_${generateTestId()}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate multiple unique test IDs
|
||||
*/
|
||||
function generateTestIds(count) {
|
||||
const ids = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
ids.push(generateTestId());
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
generateTestId,
|
||||
generateTestIdWithPrefix,
|
||||
generateTestIds,
|
||||
};
|
||||
@@ -19,8 +19,34 @@ async function createTestUser(overrides = {}) {
|
||||
};
|
||||
|
||||
const userData = { ...defaultUser, ...overrides };
|
||||
|
||||
// Generate a test ID that matches validator pattern
|
||||
const userId = `user_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
const user = await User.create(userData);
|
||||
// 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 } },
|
||||
@@ -62,18 +88,32 @@ async function createTestStreet(userId, overrides = {}) {
|
||||
|
||||
// Add adoptedBy if userId is provided
|
||||
if (userId) {
|
||||
const user = await User.findById(userId);
|
||||
if (user) {
|
||||
defaultStreet.adoptedBy = {
|
||||
userId: user._id,
|
||||
name: user.name,
|
||||
profilePicture: user.profilePicture || ''
|
||||
};
|
||||
defaultStreet.status = 'adopted';
|
||||
}
|
||||
defaultStreet.adoptedBy = {
|
||||
userId: userId,
|
||||
name: 'Test User',
|
||||
profilePicture: ''
|
||||
};
|
||||
defaultStreet.status = 'adopted';
|
||||
}
|
||||
|
||||
const street = await Street.create({ ...defaultStreet, ...overrides });
|
||||
// Generate a test ID that matches validator pattern
|
||||
const streetId = `street_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -81,12 +121,13 @@ async function createTestStreet(userId, overrides = {}) {
|
||||
* Create a test task
|
||||
*/
|
||||
async function createTestTask(userId, streetId, overrides = {}) {
|
||||
// Get street details for embedding
|
||||
const street = await Street.findById(streetId);
|
||||
const streetData = {
|
||||
streetId: street._id,
|
||||
name: street.name,
|
||||
location: street.location
|
||||
streetId: streetId,
|
||||
name: 'Test Street',
|
||||
location: {
|
||||
type: 'Point',
|
||||
coordinates: [-73.935242, 40.730610],
|
||||
}
|
||||
};
|
||||
|
||||
const defaultTask = {
|
||||
@@ -98,18 +139,27 @@ async function createTestTask(userId, streetId, overrides = {}) {
|
||||
|
||||
// Add completedBy if userId is provided
|
||||
if (userId) {
|
||||
const user = await User.findById(userId);
|
||||
if (user) {
|
||||
defaultTask.completedBy = {
|
||||
userId: user._id,
|
||||
name: user.name,
|
||||
profilePicture: user.profilePicture || ''
|
||||
};
|
||||
defaultTask.status = 'completed';
|
||||
}
|
||||
defaultTask.completedBy = {
|
||||
userId: userId,
|
||||
name: 'Test User',
|
||||
profilePicture: ''
|
||||
};
|
||||
defaultTask.status = 'completed';
|
||||
}
|
||||
|
||||
const task = await Task.create({ ...defaultTask, ...overrides });
|
||||
// Generate a test ID that matches validator pattern
|
||||
const taskId = `task_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -123,7 +173,21 @@ async function createTestPost(userId, overrides = {}) {
|
||||
type: 'text',
|
||||
};
|
||||
|
||||
const post = await Post.create({ ...defaultPost, ...overrides });
|
||||
// Generate a test ID that matches validator pattern
|
||||
const postId = `post_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -138,14 +202,31 @@ async function createTestEvent(userId, overrides = {}) {
|
||||
location: 'Test Location',
|
||||
};
|
||||
|
||||
const event = await Event.create({ ...defaultEvent, ...overrides });
|
||||
// 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) {
|
||||
const user = await User.findById(userId);
|
||||
if (user) {
|
||||
await Event.addParticipant(event._id, userId, user.name, user.profilePicture || '');
|
||||
}
|
||||
event.participants.push({
|
||||
userId: userId,
|
||||
name: 'Test User',
|
||||
profilePicture: '',
|
||||
joinedAt: new Date().toISOString()
|
||||
});
|
||||
event.participantsCount = 1;
|
||||
}
|
||||
|
||||
return event;
|
||||
@@ -168,7 +249,20 @@ async function createTestReward(overrides = {}) {
|
||||
delete rewardData.pointsCost;
|
||||
}
|
||||
|
||||
const reward = await Reward.create(rewardData);
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -184,7 +278,18 @@ async function createTestReport(userId, streetId, overrides = {}) {
|
||||
status: 'pending',
|
||||
};
|
||||
|
||||
const report = await Report.create({ ...defaultReport, ...overrides });
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user