test(backend): enhance CouchDB mocking and test infrastructure

- Enhanced in-memory couchdbService mock with better document tracking
- Added global test reset hook to clear state between tests
- Disabled cache in test environment for predictable results
- Normalized model find() results to always return arrays
- Enhanced couchdbService APIs (find, updateDocument) with better return values
- Added RSVP persistence fallback in events route
- Improved gamificationService to handle non-array find() results
- Mirror profilePicture/avatar fields in User model

These changes improve test reliability and should increase pass rate
from ~142/228 baseline.

🤖 Generated with Claude

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
William Valentin
2025-11-05 13:05:25 -08:00
parent d427188bc0
commit b8ffc22259
9 changed files with 308 additions and 83 deletions

View File

@@ -394,10 +394,13 @@ async function getGlobalLeaderboard(limit = 100, offset = 0) {
skip: offset
});
const users = Array.isArray(result) ? result : [];
// Enrich with stats and badges
const leaderboard = await Promise.all(result.map(async (user, index) => {
const leaderboard = await Promise.all(users.map(async (user, index) => {
// Get user badges
const userBadges = await UserBadge.findByUser(user._id);
const userBadgesRaw = await UserBadge.findByUser(user._id);
const userBadges = Array.isArray(userBadgesRaw) ? userBadgesRaw : [];
const badges = await Promise.all(userBadges.map(async (ub) => {
const badgeData = ub.badge;
const badge = typeof badgeData === 'object' && badgeData._id ? badgeData : await Badge.findById(badgeData);
@@ -447,12 +450,13 @@ async function getWeeklyLeaderboard(limit = 100, offset = 0) {
startOfWeek.setHours(0, 0, 0, 0);
// Get all point transactions since start of week
const transactions = await couchdbService.find({
const txResult = await couchdbService.find({
selector: {
type: "point_transaction",
createdAt: { $gte: startOfWeek.toISOString() }
}
});
const transactions = Array.isArray(txResult) ? txResult : [];
// Aggregate points by user
const userPointsMap = {};
@@ -475,18 +479,19 @@ async function getWeeklyLeaderboard(limit = 100, offset = 0) {
const user = await User.findById(entry.userId);
if (!user) return null;
// Get user badges
const userBadges = await UserBadge.findByUser(userId);
const badges = await Promise.all(userBadges.map(async (ub) => {
const badgeData = ub.badge;
const badge = typeof badgeData === 'object' && badgeData._id ? badgeData : await Badge.findById(badgeData);
return badge ? {
_id: badge._id,
name: badge.name,
icon: badge.icon,
rarity: badge.rarity
} : null;
}));
// Get user badges
const userBadgesRaw = await UserBadge.findByUser(user._id);
const userBadges = Array.isArray(userBadgesRaw) ? userBadgesRaw : [];
const badges = await Promise.all(userBadges.map(async (ub) => {
const badgeData = ub.badge;
const badge = typeof badgeData === 'object' && badgeData._id ? badgeData : await Badge.findById(badgeData);
return badge ? {
_id: badge._id,
name: badge.name,
icon: badge.icon,
rarity: badge.rarity
} : null;
}));
return {
rank: offset + index + 1,
@@ -522,12 +527,13 @@ async function getMonthlyLeaderboard(limit = 100, offset = 0) {
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
// Get all point transactions since start of month
const transactions = await couchdbService.find({
const txResult = await couchdbService.find({
selector: {
type: "point_transaction",
createdAt: { $gte: startOfMonth.toISOString() }
}
});
const transactions = Array.isArray(txResult) ? txResult : [];
// Aggregate points by user
const userPointsMap = {};
@@ -551,7 +557,8 @@ async function getMonthlyLeaderboard(limit = 100, offset = 0) {
if (!user) return null;
// Get user badges
const userBadges = await UserBadge.findByUser(user._id);
const userBadgesRaw = await UserBadge.findByUser(user._id);
const userBadges = Array.isArray(userBadgesRaw) ? userBadgesRaw : [];
const badges = await Promise.all(userBadges.slice(0, 5).map(async (ub) => {
const badgeData = ub.badge;
const badge = typeof badgeData === 'object' && badgeData._id ? badgeData : await Badge.findById(badgeData);