/** * Campaign Repository Tests * * Tests for CampaignRepository database operations * Uses REAL PostgreSQL database - NO mocks */ const { CampaignRepository } = require('../../repositories'); const VotingTestHelper = require('../helpers/testHelper'); describe('CampaignRepository', () => { let campaignRepo; let testHelper; let testSite; let testUserId; beforeAll(async () => { campaignRepo = new CampaignRepository(); testHelper = new VotingTestHelper(); testSite = await testHelper.createTestSite(); const testUser = await testHelper.createTestUser(testSite.id); testUserId = testUser.id; }); afterAll(async () => { // Cleanup handled by global schema manager }); describe('create', () => { it('should create a new campaign', async () => { const formData = await testHelper.createTestForm(testSite.id); const campaignData = { site_id: testSite.id, title: 'Board Elections 2025', description: 'Annual board elections', campaign_type: 'board_election', form_id: formData.id, status: 'draft', overall_sharing_results: 'detailed', public_access: 'restrict', start_date: new Date().toISOString(), end_date: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(), recipient_type: 'all_owners', send_email: true, send_text: true, send_owner_app: true, created_by: testUserId }; const campaign = await campaignRepo.create(campaignData); expect(campaign).toBeDefined(); expect(campaign.id).toBeDefined(); expect(campaign.title).toBe('Board Elections 2025'); expect(campaign.campaign_type).toBe('board_election'); expect(campaign.status).toBe('draft'); }); }); describe('findOne', () => { it('should find a campaign by ID', async () => { const formData = await testHelper.createTestForm(testSite.id); const campaign = await testHelper.createTestCampaign(testSite.id, formData.id); const found = await campaignRepo.findOne({ id: campaign.id }); expect(found).toBeDefined(); expect(found.id).toBe(campaign.id); expect(found.title).toBe(campaign.title); }); it('should return null if campaign not found', async () => { const found = await campaignRepo.findOne({ id: '00000000-0000-0000-0000-000000000000' }); expect(found).toBeUndefined(); }); }); describe('findAll', () => { it('should find all campaigns for a site', async () => { const formData = await testHelper.createTestForm(testSite.id); // Create multiple campaigns await testHelper.createTestCampaign(testSite.id, formData.id, 'board_election'); await testHelper.createTestCampaign(testSite.id, formData.id, 'decision'); await testHelper.createTestCampaign(testSite.id, formData.id, 'survey'); const campaigns = await campaignRepo.findAll( { site_id: testSite.id }, { orderBy: 'created_at', orderDirection: 'desc' } ); expect(campaigns).toBeInstanceOf(Array); expect(campaigns.length).toBeGreaterThanOrEqual(3); }); it('should filter campaigns by type', async () => { const formData = await testHelper.createTestForm(testSite.id); await testHelper.createTestCampaign(testSite.id, formData.id, 'board_election'); await testHelper.createTestCampaign(testSite.id, formData.id, 'decision'); const elections = await campaignRepo.findAll( { site_id: testSite.id, campaign_type: 'board_election' }, { orderBy: 'created_at', orderDirection: 'desc' } ); elections.forEach(campaign => { expect(campaign.campaign_type).toBe('board_election'); }); }); it('should filter campaigns by status', async () => { const formData = await testHelper.createTestForm(testSite.id); const campaign = await testHelper.createTestCampaign(testSite.id, formData.id); // Update status await campaignRepo.updateById(campaign.id, { status: 'active' }); const activeCampaigns = await campaignRepo.findAll( { site_id: testSite.id, status: 'active' } ); expect(activeCampaigns.length).toBeGreaterThanOrEqual(1); activeCampaigns.forEach(c => { expect(c.status).toBe('active'); }); }); }); describe('updateById', () => { it('should update campaign details', async () => { const formData = await testHelper.createTestForm(testSite.id); const campaign = await testHelper.createTestCampaign(testSite.id, formData.id); const updated = await campaignRepo.updateById(campaign.id, { title: 'Updated Campaign Title', status: 'active' }); expect(updated).toBeDefined(); expect(updated.title).toBe('Updated Campaign Title'); expect(updated.status).toBe('active'); }); }); describe('deleteById', () => { it('should delete a campaign', async () => { const formData = await testHelper.createTestForm(testSite.id); const campaign = await testHelper.createTestCampaign(testSite.id, formData.id); const deleted = await campaignRepo.deleteById(campaign.id); expect(deleted).toBe(true); const found = await campaignRepo.findOne({ id: campaign.id }); expect(found).toBeUndefined(); }); }); describe('findByIdWithDetails', () => { it('should return campaign with participation statistics', async () => { const formData = await testHelper.createTestForm(testSite.id); const campaign = await testHelper.createTestCampaign(testSite.id, formData.id); const details = await campaignRepo.findByIdWithDetails(campaign.id); expect(details).toBeDefined(); expect(details.participation_count).toBeDefined(); expect(details.total_invited).toBeDefined(); expect(details.participation_percentage).toBeDefined(); }); }); describe('updateStatus', () => { it('should update campaign status to active', async () => { const formData = await testHelper.createTestForm(testSite.id); const campaign = await testHelper.createTestCampaign(testSite.id, formData.id); const updated = await campaignRepo.updateStatus(campaign.id, 'active'); expect(updated).toBeDefined(); expect(updated.status).toBe('active'); }); it('should update campaign status to completed', async () => { const formData = await testHelper.createTestForm(testSite.id); const campaign = await testHelper.createTestCampaign(testSite.id, formData.id); const updated = await campaignRepo.updateStatus(campaign.id, 'completed'); expect(updated).toBeDefined(); expect(updated.status).toBe('completed'); }); it('should throw error for invalid status', async () => { const formData = await testHelper.createTestForm(testSite.id); const campaign = await testHelper.createTestCampaign(testSite.id, formData.id); await expect( campaignRepo.updateStatus(campaign.id, 'invalid_status') ).rejects.toThrow('Invalid status: invalid_status'); }); }); });