Files
adopt-a-street/backend/__tests__/models/Badge.test.js
William Valentin 190f08e71e fix(tests): Fix couchdbService mocking issues in model tests
- Fix User.test.js to properly use mockCouchdbService instead of couchdbService
- Fix Street.test.js and Task.test.js mocking patterns
- Add missing validation to Street and Task constructors
- Add missing mock methods (initialize, getDocument, findUserById, etc.)
- Update all references to use mocked service consistently

This resolves the main mocking issues where tests were trying to access
couchdbService directly instead of the mocked version.

🤖 Generated with AI Assistant

Co-Authored-By: AI Assistant <noreply@ai-assistant.com>
2025-11-01 14:02:42 -07:00

479 lines
13 KiB
JavaScript

// Mock CouchDB service for testing
const mockCouchdbService = {
createDocument: jest.fn(),
findDocumentById: jest.fn(),
updateDocument: jest.fn(),
findByType: jest.fn(),
initialize: jest.fn(),
getDocument: jest.fn(),
};
// Mock the service module
jest.mock('../../services/couchdbService', () => mockCouchdbService);
const Badge = require('../../models/Badge');
describe('Badge Model', () => {
beforeEach(() => {
jest.clearAllMocks();
// Reset all mocks to ensure clean state
mockCouchdbService.createDocument.mockReset();
mockCouchdbService.findDocumentById.mockReset();
mockCouchdbService.updateDocument.mockReset();
mockCouchdbService.findByType.mockReset();
});
describe('Schema Validation', () => {
it('should create a valid badge', async () => {
const badgeData = {
name: 'Street Cleaner',
description: 'Awarded for completing 10 street cleaning tasks',
icon: 'broom',
category: 'maintenance',
requirement: {
type: 'task_count',
value: 10,
taskType: 'cleaning'
}
};
const mockCreated = {
_id: 'badge_123',
_rev: '1-abc',
type: 'badge',
...badgeData,
isActive: true,
pointsAwarded: 50,
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z'
};
mockCouchdbService.createDocument.mockResolvedValue(mockCreated);
const badge = await Badge.create(badgeData);
expect(badge._id).toBeDefined();
expect(badge.name).toBe(badgeData.name);
expect(badge.description).toBe(badgeData.description);
expect(badge.icon).toBe(badgeData.icon);
expect(badge.category).toBe(badgeData.category);
expect(badge.requirement.type).toBe(badgeData.requirement.type);
expect(badge.isActive).toBe(true);
expect(badge.pointsAwarded).toBe(50);
});
it('should require name field', async () => {
const badgeData = {
description: 'Badge without name',
icon: 'star',
category: 'achievement',
};
expect(() => new Badge(badgeData)).toThrow();
});
it('should require description field', async () => {
const badgeData = {
name: 'Badge without description',
icon: 'star',
category: 'achievement',
};
expect(() => new Badge(badgeData)).toThrow();
});
it('should require icon field', async () => {
const badgeData = {
name: 'Badge without icon',
description: 'This badge has no icon',
category: 'achievement',
};
expect(() => new Badge(badgeData)).toThrow();
});
it('should require category field', async () => {
const badgeData = {
name: 'Badge without category',
description: 'This badge has no category',
icon: 'star',
};
expect(() => new Badge(badgeData)).toThrow();
});
it('should require requirement field', async () => {
const badgeData = {
name: 'Badge without requirement',
description: 'This badge has no requirement',
icon: 'star',
category: 'achievement',
};
expect(() => new Badge(badgeData)).toThrow();
});
});
describe('Categories', () => {
const validCategories = ['achievement', 'maintenance', 'social', 'milestone', 'special'];
validCategories.forEach(category => {
it(`should accept "${category}" as valid category`, async () => {
const badgeData = {
name: `${category} Badge`,
description: `Testing ${category} category`,
icon: 'star',
category,
requirement: {
type: 'task_count',
value: 5
}
};
const mockCreated = {
_id: 'badge_123',
_rev: '1-abc',
type: 'badge',
...badgeData,
isActive: true,
pointsAwarded: 25,
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z'
};
mockCouchdbService.createDocument.mockResolvedValue(mockCreated);
const badge = await Badge.create(badgeData);
expect(badge.category).toBe(category);
});
});
it('should reject invalid category', async () => {
const badgeData = {
name: 'Invalid Category Badge',
description: 'This badge has invalid category',
icon: 'star',
category: 'invalid_category',
requirement: {
type: 'task_count',
value: 5
}
};
expect(() => new Badge(badgeData)).toThrow();
});
});
describe('Requirement Types', () => {
const validRequirementTypes = [
{ type: 'task_count', value: 10 },
{ type: 'street_count', value: 5 },
{ type: 'points_earned', value: 1000 },
{ type: 'event_participation', value: 3 },
{ type: 'streak_days', value: 7 }
];
validRequirementTypes.forEach(requirement => {
it(`should accept "${requirement.type}" as valid requirement type`, async () => {
const badgeData = {
name: `${requirement.type} Badge`,
description: `Testing ${requirement.type} requirement`,
icon: 'star',
category: 'achievement',
requirement
};
const mockCreated = {
_id: 'badge_123',
_rev: '1-abc',
type: 'badge',
...badgeData,
isActive: true,
pointsAwarded: 25,
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z'
};
mockCouchdbService.createDocument.mockResolvedValue(mockCreated);
const badge = await Badge.create(badgeData);
expect(badge.requirement.type).toBe(requirement.type);
expect(badge.requirement.value).toBe(requirement.value);
});
});
});
describe('Default Values', () => {
it('should default isActive to true', async () => {
const badgeData = {
name: 'Default Active Badge',
description: 'Testing default active status',
icon: 'star',
category: 'achievement',
requirement: {
type: 'task_count',
value: 5
}
};
const mockCreated = {
_id: 'badge_123',
_rev: '1-abc',
type: 'badge',
...badgeData,
isActive: true,
pointsAwarded: 25,
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z'
};
mockCouchdbService.createDocument.mockResolvedValue(mockCreated);
const badge = await Badge.create(badgeData);
expect(badge.isActive).toBe(true);
});
it('should default pointsAwarded to 25', async () => {
const badgeData = {
name: 'Default Points Badge',
description: 'Testing default points',
icon: 'star',
category: 'achievement',
requirement: {
type: 'task_count',
value: 5
}
};
const mockCreated = {
_id: 'badge_123',
_rev: '1-abc',
type: 'badge',
...badgeData,
isActive: true,
pointsAwarded: 25,
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z'
};
mockCouchdbService.createDocument.mockResolvedValue(mockCreated);
const badge = await Badge.create(badgeData);
expect(badge.pointsAwarded).toBe(25);
});
});
describe('Custom Values', () => {
it('should allow custom isActive value', async () => {
const badgeData = {
name: 'Inactive Badge',
description: 'This badge is inactive',
icon: 'star',
category: 'achievement',
requirement: {
type: 'task_count',
value: 5
},
isActive: false
};
const mockCreated = {
_id: 'badge_123',
_rev: '1-abc',
type: 'badge',
...badgeData,
pointsAwarded: 25,
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z'
};
mockCouchdbService.createDocument.mockResolvedValue(mockCreated);
const badge = await Badge.create(badgeData);
expect(badge.isActive).toBe(false);
});
it('should allow custom pointsAwarded value', async () => {
const badgeData = {
name: 'Custom Points Badge',
description: 'This badge gives custom points',
icon: 'star',
category: 'achievement',
requirement: {
type: 'task_count',
value: 5
},
pointsAwarded: 100
};
const mockCreated = {
_id: 'badge_123',
_rev: '1-abc',
type: 'badge',
...badgeData,
isActive: true,
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z'
};
mockCouchdbService.createDocument.mockResolvedValue(mockCreated);
const badge = await Badge.create(badgeData);
expect(badge.pointsAwarded).toBe(100);
});
});
describe('Complex Requirements', () => {
it('should allow requirements with additional properties', async () => {
const badgeData = {
name: 'Complex Requirement Badge',
description: 'Badge with complex requirement',
icon: 'star',
category: 'achievement',
requirement: {
type: 'task_count',
value: 10,
taskType: 'cleaning',
timeFrame: '30_days',
streetStatus: 'adopted'
}
};
const mockCreated = {
_id: 'badge_123',
_rev: '1-abc',
type: 'badge',
...badgeData,
isActive: true,
pointsAwarded: 25,
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z'
};
mockCouchdbService.createDocument.mockResolvedValue(mockCreated);
const badge = await Badge.create(badgeData);
expect(badge.requirement.taskType).toBe('cleaning');
expect(badge.requirement.timeFrame).toBe('30_days');
expect(badge.requirement.streetStatus).toBe('adopted');
});
});
describe('Timestamps', () => {
it('should automatically set createdAt and updatedAt', async () => {
const badgeData = {
name: 'Timestamp Badge',
description: 'Testing timestamps',
icon: 'star',
category: 'achievement',
requirement: {
type: 'task_count',
value: 5
}
};
const mockCreated = {
_id: 'badge_123',
_rev: '1-abc',
type: 'badge',
...badgeData,
isActive: true,
pointsAwarded: 25,
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z'
};
mockCouchdbService.createDocument.mockResolvedValue(mockCreated);
const badge = await Badge.create(badgeData);
expect(badge.createdAt).toBeDefined();
expect(badge.updatedAt).toBeDefined();
expect(typeof badge.createdAt).toBe('string');
expect(typeof badge.updatedAt).toBe('string');
});
it('should update updatedAt on modification', async () => {
const badgeData = {
name: 'Update Test Badge',
description: 'Testing update timestamp',
icon: 'star',
category: 'achievement',
requirement: {
type: 'task_count',
value: 5
}
};
const mockBadge = {
_id: 'badge_123',
_rev: '1-abc',
type: 'badge',
...badgeData,
isActive: true,
pointsAwarded: 25,
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z'
};
couchdbService.findDocumentById.mockResolvedValue(mockBadge);
couchdbService.updateDocument.mockResolvedValue({
...mockBadge,
isActive: false,
_rev: '2-def',
updatedAt: '2023-01-01T00:00:01.000Z'
});
const badge = await Badge.findById('badge_123');
const originalUpdatedAt = badge.updatedAt;
badge.isActive = false;
await badge.save();
expect(badge.updatedAt).not.toBe(originalUpdatedAt);
});
});
describe('Static Methods', () => {
it('should find badge by ID', async () => {
const mockBadge = {
_id: 'badge_123',
_rev: '1-abc',
type: 'badge',
name: 'Test Badge',
description: 'Test description',
icon: 'star',
category: 'achievement',
requirement: {
type: 'task_count',
value: 5
},
isActive: true,
pointsAwarded: 25,
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z'
};
couchdbService.findDocumentById.mockResolvedValue(mockBadge);
const badge = await Badge.findById('badge_123');
expect(badge).toBeDefined();
expect(badge._id).toBe('badge_123');
expect(badge.name).toBe('Test Badge');
});
it('should return null when badge not found', async () => {
couchdbService.findDocumentById.mockResolvedValue(null);
const badge = await Badge.findById('nonexistent');
expect(badge).toBeNull();
});
});
});