/** * DrizzleInitiativeRepository Tests * * Tests for the Initiative repository adapter. */ import { describe, it, expect, beforeEach } from 'vitest'; import { DrizzleInitiativeRepository } from './initiative.js'; import { createTestDatabase } from './test-helpers.js'; import type { DrizzleDatabase } from '../../index.js'; describe('DrizzleInitiativeRepository', () => { let db: DrizzleDatabase; let repo: DrizzleInitiativeRepository; beforeEach(() => { db = createTestDatabase(); repo = new DrizzleInitiativeRepository(db); }); describe('create', () => { it('should create an initiative with generated id and timestamps', async () => { const initiative = await repo.create({ name: 'Test Initiative', }); expect(initiative.id).toBeDefined(); expect(initiative.id.length).toBeGreaterThan(0); expect(initiative.name).toBe('Test Initiative'); expect(initiative.status).toBe('active'); expect(initiative.createdAt).toBeInstanceOf(Date); expect(initiative.updatedAt).toBeInstanceOf(Date); }); it('should use provided status', async () => { const initiative = await repo.create({ name: 'Completed Initiative', status: 'completed', }); expect(initiative.status).toBe('completed'); }); }); describe('findById', () => { it('should return null for non-existent initiative', async () => { const result = await repo.findById('non-existent-id'); expect(result).toBeNull(); }); it('should find an existing initiative', async () => { const created = await repo.create({ name: 'Find Me', }); const found = await repo.findById(created.id); expect(found).not.toBeNull(); expect(found!.id).toBe(created.id); expect(found!.name).toBe('Find Me'); }); }); describe('findAll', () => { it('should return empty array initially', async () => { const all = await repo.findAll(); expect(all).toEqual([]); }); it('should return all initiatives', async () => { await repo.create({ name: 'Initiative 1' }); await repo.create({ name: 'Initiative 2' }); await repo.create({ name: 'Initiative 3' }); const all = await repo.findAll(); expect(all.length).toBe(3); }); }); describe('update', () => { it('should update fields and updatedAt', async () => { const created = await repo.create({ name: 'Original Name', status: 'active', }); // Small delay to ensure updatedAt differs await new Promise((resolve) => setTimeout(resolve, 10)); const updated = await repo.update(created.id, { name: 'Updated Name', status: 'completed', }); expect(updated.name).toBe('Updated Name'); expect(updated.status).toBe('completed'); expect(updated.updatedAt.getTime()).toBeGreaterThanOrEqual(created.updatedAt.getTime()); }); it('should throw for non-existent initiative', async () => { await expect( repo.update('non-existent-id', { name: 'New Name' }) ).rejects.toThrow('Initiative not found'); }); }); describe('delete', () => { it('should delete an existing initiative', async () => { const created = await repo.create({ name: 'To Delete' }); await repo.delete(created.id); const found = await repo.findById(created.id); expect(found).toBeNull(); }); it('should throw for non-existent initiative', async () => { await expect(repo.delete('non-existent-id')).rejects.toThrow( 'Initiative not found' ); }); }); describe('findByStatus', () => { it('should return empty array for no matches', async () => { await repo.create({ name: 'Active 1', status: 'active' }); const completed = await repo.findByStatus('completed'); expect(completed).toEqual([]); }); it('should filter by status', async () => { await repo.create({ name: 'Active 1', status: 'active' }); await repo.create({ name: 'Active 2', status: 'active' }); await repo.create({ name: 'Completed', status: 'completed' }); await repo.create({ name: 'Archived', status: 'archived' }); const active = await repo.findByStatus('active'); expect(active).toHaveLength(2); expect(active.every((i) => i.status === 'active')).toBe(true); const completed = await repo.findByStatus('completed'); expect(completed).toHaveLength(1); expect(completed[0].name).toBe('Completed'); const archived = await repo.findByStatus('archived'); expect(archived).toHaveLength(1); expect(archived[0].name).toBe('Archived'); }); }); describe('qualityReview', () => { it('defaults to false on create', async () => { const initiative = await repo.create({ name: 'QR Test' }); expect(initiative.qualityReview).toBe(false); }); it('can be set to true via update', async () => { const created = await repo.create({ name: 'QR Toggle' }); const updated = await repo.update(created.id, { qualityReview: true }); expect(updated.qualityReview).toBe(true); }); it('round-trips through findById', async () => { const created = await repo.create({ name: 'QR Round-trip' }); await repo.update(created.id, { qualityReview: true }); const found = await repo.findById(created.id); expect(found!.qualityReview).toBe(true); }); it('round-trips false value', async () => { const created = await repo.create({ name: 'QR False' }); await repo.update(created.id, { qualityReview: true }); await repo.update(created.id, { qualityReview: false }); const found = await repo.findById(created.id); expect(found!.qualityReview).toBe(false); }); }); });