UNPKG

alnilam-cli

Version:

Git-native AI career coach that converts multi-year ambitions into weekly execution

326 lines (325 loc) 13.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); // Mock the API module before importing jest.mock('../api.js', () => ({ addEvidence: jest.fn(), })); const api_js_1 = require("../api.js"); describe('Evidence Management', () => { beforeEach(() => { jest.clearAllMocks(); // Reset console methods jest.spyOn(console, 'log').mockImplementation(() => { }); jest.spyOn(console, 'error').mockImplementation(() => { }); jest.spyOn(process, 'exit').mockImplementation(() => { throw new Error('process.exit called'); }); }); afterEach(() => { jest.restoreAllMocks(); }); describe('Evidence Type Validation', () => { it('should validate evidence types', () => { const validTypes = ['commit', 'pr', 'time', 'note']; validTypes.forEach(type => { expect(validTypes.includes(type)).toBe(true); }); const invalidTypes = ['task', 'meeting', 'invalid']; invalidTypes.forEach(type => { expect(validTypes.includes(type)).toBe(false); }); }); }); describe('Evidence Creation', () => { it('should create evidence with required fields only', async () => { const mockEvidence = { id: 'evidence-1', type: 'note', message: 'Test note', created_at: '2025-07-02T10:00:00Z' }; api_js_1.addEvidence.mockResolvedValue(mockEvidence); const evidenceData = { type: 'note', message: 'Test note', goal_id: undefined, source: undefined, metadata: undefined, }; const result = await (0, api_js_1.addEvidence)(evidenceData); expect(api_js_1.addEvidence).toHaveBeenCalledWith(evidenceData); expect(result).toEqual(mockEvidence); }); it('should create evidence with all optional fields', async () => { const mockEvidence = { id: 'evidence-2', type: 'commit', message: 'Add new feature', goal_id: 'goal-123', source: 'feature/new-feature', metadata: { lines_added: 100, lines_deleted: 20 }, created_at: '2025-07-02T10:00:00Z' }; api_js_1.addEvidence.mockResolvedValue(mockEvidence); const evidenceData = { type: 'commit', message: 'Add new feature', goal_id: 'goal-123', source: 'feature/new-feature', metadata: { lines_added: 100, lines_deleted: 20 }, }; const result = await (0, api_js_1.addEvidence)(evidenceData); expect(api_js_1.addEvidence).toHaveBeenCalledWith(evidenceData); expect(result).toEqual(mockEvidence); }); it('should handle addEvidence API errors', async () => { const errorMessage = 'Failed to add evidence'; api_js_1.addEvidence.mockRejectedValue(new Error(errorMessage)); const evidenceData = { type: 'note', message: 'Test note', goal_id: undefined, source: undefined, metadata: undefined, }; await expect((0, api_js_1.addEvidence)(evidenceData)).rejects.toThrow(errorMessage); }); }); describe('Time Evidence Validation', () => { it('should accept valid time entries', async () => { const mockEvidence = { id: 'time-evidence', type: 'time', message: 'Development work', metadata: { minutes: 120 }, created_at: '2025-07-02T10:00:00Z' }; api_js_1.addEvidence.mockResolvedValue(mockEvidence); const evidenceData = { type: 'time', message: 'Development work', goal_id: undefined, source: undefined, metadata: { minutes: 120 }, }; const result = await (0, api_js_1.addEvidence)(evidenceData); expect(result.metadata?.minutes).toBe(120); expect(result.type).toBe('time'); }); it('should validate positive minutes for time entries', () => { const validMinutes = [1, 30, 60, 120, 480]; validMinutes.forEach(minutes => { expect(minutes).toBeGreaterThan(0); }); const invalidMinutes = [0, -1, -30]; invalidMinutes.forEach(minutes => { expect(minutes).toBeLessThanOrEqual(0); }); }); it('should handle time entries with goal linking', async () => { const mockEvidence = { id: 'time-evidence-with-goal', type: 'time', message: 'Feature development', goal_id: 'goal-456', metadata: { minutes: 180 }, created_at: '2025-07-02T10:00:00Z' }; api_js_1.addEvidence.mockResolvedValue(mockEvidence); const evidenceData = { type: 'time', message: 'Feature development', goal_id: 'goal-456', source: undefined, metadata: { minutes: 180 }, }; const result = await (0, api_js_1.addEvidence)(evidenceData); expect(result.goal_id).toBe('goal-456'); expect(result.metadata?.minutes).toBe(180); }); }); describe('Commit Evidence', () => { it('should handle commit evidence with code changes', async () => { const mockEvidence = { id: 'commit-evidence', type: 'commit', message: 'Fix authentication bug', source: 'fix/auth-issue', metadata: { lines_added: 15, lines_deleted: 8, files_changed: 3, commit_hash: 'abc123' }, created_at: '2025-07-02T10:00:00Z' }; api_js_1.addEvidence.mockResolvedValue(mockEvidence); const evidenceData = { type: 'commit', message: 'Fix authentication bug', goal_id: undefined, source: 'fix/auth-issue', metadata: { lines_added: 15, lines_deleted: 8, files_changed: 3, commit_hash: 'abc123' }, }; const result = await (0, api_js_1.addEvidence)(evidenceData); expect(result.type).toBe('commit'); expect(result.source).toBe('fix/auth-issue'); expect(result.metadata?.lines_added).toBe(15); expect(result.metadata?.lines_deleted).toBe(8); }); }); describe('PR Evidence', () => { it('should handle PR evidence with review metadata', async () => { const mockEvidence = { id: 'pr-evidence', type: 'pr', message: 'Add comprehensive testing strategy', source: 'https://github.com/user/repo/pull/15', metadata: { pr_number: 15, status: 'merged', reviews_received: 2, files_changed: 8 }, created_at: '2025-07-02T10:00:00Z' }; api_js_1.addEvidence.mockResolvedValue(mockEvidence); const evidenceData = { type: 'pr', message: 'Add comprehensive testing strategy', goal_id: undefined, source: 'https://github.com/user/repo/pull/15', metadata: { pr_number: 15, status: 'merged', reviews_received: 2, files_changed: 8 }, }; const result = await (0, api_js_1.addEvidence)(evidenceData); expect(result.type).toBe('pr'); expect(result.source).toBe('https://github.com/user/repo/pull/15'); expect(result.metadata?.pr_number).toBe(15); }); }); describe('Note Evidence', () => { it('should handle note evidence with custom metadata', async () => { const mockEvidence = { id: 'note-evidence', type: 'note', message: 'Planning session for Q4 goals', metadata: { location: 'team meeting', attendees: ['alice', 'bob'], duration_minutes: 45 }, created_at: '2025-07-02T10:00:00Z' }; api_js_1.addEvidence.mockResolvedValue(mockEvidence); const evidenceData = { type: 'note', message: 'Planning session for Q4 goals', goal_id: undefined, source: undefined, metadata: { location: 'team meeting', attendees: ['alice', 'bob'], duration_minutes: 45 }, }; const result = await (0, api_js_1.addEvidence)(evidenceData); expect(result.type).toBe('note'); expect(result.metadata?.location).toBe('team meeting'); expect(result.metadata?.attendees).toEqual(['alice', 'bob']); }); }); describe('Metadata Handling', () => { it('should handle empty metadata gracefully', async () => { const mockEvidence = { id: 'minimal-evidence', type: 'note', message: 'Simple note', created_at: '2025-07-02T10:00:00Z' }; api_js_1.addEvidence.mockResolvedValue(mockEvidence); const evidenceData = { type: 'note', message: 'Simple note', goal_id: undefined, source: undefined, metadata: undefined, }; const result = await (0, api_js_1.addEvidence)(evidenceData); expect(result.metadata).toBeUndefined(); }); it('should merge minutes with additional metadata', () => { const baseMetadata = { minutes: 60 }; const additionalMetadata = { category: 'development', priority: 'high' }; const mergedMetadata = { ...baseMetadata, ...additionalMetadata }; expect(mergedMetadata).toEqual({ minutes: 60, category: 'development', priority: 'high' }); }); it('should handle JSON metadata parsing errors', () => { const invalidJson = '{ invalid json }'; expect(() => { JSON.parse(invalidJson); }).toThrow(); }); it('should handle valid JSON metadata', () => { const validJson = '{"key": "value", "number": 42, "array": [1, 2, 3]}'; const parsed = JSON.parse(validJson); expect(parsed).toEqual({ key: 'value', number: 42, array: [1, 2, 3] }); }); }); describe('Goal Linking', () => { it('should handle evidence linked to goals', async () => { const mockEvidence = { id: 'linked-evidence', type: 'commit', message: 'Work towards weekly goal', goal_id: 'weekly-goal-123', created_at: '2025-07-02T10:00:00Z' }; api_js_1.addEvidence.mockResolvedValue(mockEvidence); const evidenceData = { type: 'commit', message: 'Work towards weekly goal', goal_id: 'weekly-goal-123', source: undefined, metadata: undefined, }; const result = await (0, api_js_1.addEvidence)(evidenceData); expect(result.goal_id).toBe('weekly-goal-123'); }); it('should handle evidence without goal linking', async () => { const mockEvidence = { id: 'unlinked-evidence', type: 'note', message: 'General research notes', created_at: '2025-07-02T10:00:00Z' }; api_js_1.addEvidence.mockResolvedValue(mockEvidence); const evidenceData = { type: 'note', message: 'General research notes', goal_id: undefined, source: undefined, metadata: undefined, }; const result = await (0, api_js_1.addEvidence)(evidenceData); expect(result.goal_id).toBeUndefined(); }); }); });