UNPKG

alnilam-cli

Version:

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

334 lines (333 loc) 14.5 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); // Mock Supabase client const mockSupabaseClient = { functions: { invoke: jest.fn(), }, from: jest.fn(), auth: { getSession: jest.fn().mockResolvedValue({ data: { session: { access_token: 'mock-token', user: { id: 'mock-user-id' } } } }) } }; // Mock fetch API global.fetch = jest.fn(); // Mock config module jest.mock('../config.js', () => ({ getConfig: jest.fn(() => ({ supabaseUrl: 'https://mock-project.supabase.co', supabaseAnonKey: 'mock-anon-key' })) })); // Mock auth module jest.mock('../auth.js', () => ({ createAuthenticatedSupabaseClient: jest.fn(() => mockSupabaseClient), })); const api_js_1 = require("../api.js"); const auth_js_1 = require("../auth.js"); describe('API Layer', () => { beforeEach(() => { jest.clearAllMocks(); }); describe('Client Setup', () => { it('should return authenticated Supabase client', () => { const client = (0, api_js_1.getAPIClient)(); expect(auth_js_1.createAuthenticatedSupabaseClient).toHaveBeenCalled(); expect(client).toBe(mockSupabaseClient); }); it('should return database client', () => { const database = (0, api_js_1.getDatabase)(); expect(database).toBe(mockSupabaseClient); }); }); describe('Function Invocation', () => { it('should call Edge Function successfully', async () => { const mockResponse = { data: { success: true }, error: null }; mockSupabaseClient.functions.invoke.mockResolvedValue(mockResponse); const result = await (0, api_js_1.callFunction)('test_function', { test: 'data' }); expect(mockSupabaseClient.functions.invoke).toHaveBeenCalledWith('test_function', { body: { test: 'data' } }); expect(result).toEqual({ success: true }); }); it('should handle function errors', async () => { const mockResponse = { data: null, error: { message: 'Function failed' } }; mockSupabaseClient.functions.invoke.mockResolvedValue(mockResponse); await expect((0, api_js_1.callFunction)('failing_function', {})) .rejects.toThrow('Function failing_function failed: Function failed'); }); it('should call function without data', async () => { const mockResponse = { data: { result: 'success' }, error: null }; mockSupabaseClient.functions.invoke.mockResolvedValue(mockResponse); const result = await (0, api_js_1.callFunction)('simple_function'); expect(mockSupabaseClient.functions.invoke).toHaveBeenCalledWith('simple_function', { body: undefined }); expect(result).toEqual({ result: 'success' }); }); }); describe('Goal API Functions', () => { it('should create goal via Edge Function', async () => { const mockGoal = { id: 'goal-123', title: 'Test Goal', horizon: 'weekly', created_at: '2025-07-02T10:00:00Z' }; mockSupabaseClient.functions.invoke.mockResolvedValue({ data: mockGoal, error: null }); const goalData = { title: 'Test Goal', horizon: 'weekly', description: 'Test description' }; const result = await (0, api_js_1.createGoal)(goalData); expect(mockSupabaseClient.functions.invoke).toHaveBeenCalledWith('create_goal', { body: goalData }); expect(result).toEqual(mockGoal); }); it('should list goals via Edge Function', async () => { const mockGoals = [ { id: 'goal-1', title: 'Goal 1', horizon: 'weekly' }, { id: 'goal-2', title: 'Goal 2', horizon: 'quarterly' } ]; const mockResponse = { ok: true, json: jest.fn().mockResolvedValue({ goals: mockGoals }) }; global.fetch.mockResolvedValue(mockResponse); const params = { horizon: 'weekly' }; const result = await (0, api_js_1.listGoals)(params); expect(global.fetch).toHaveBeenCalledWith('https://mock-project.supabase.co/functions/v1/list_goals?horizon=weekly', { method: 'GET', headers: { 'Authorization': 'Bearer mock-token', 'Content-Type': 'application/json' } }); expect(result).toEqual(mockGoals); }); it('should handle goal creation errors', async () => { mockSupabaseClient.functions.invoke.mockResolvedValue({ data: null, error: { message: 'Validation failed' } }); const goalData = { title: 'Invalid Goal', horizon: 'invalid' }; await expect((0, api_js_1.createGoal)(goalData)) .rejects.toThrow('Function create_goal failed: Validation failed'); }); }); describe('Evidence API Functions', () => { it('should add evidence via Edge Function', async () => { const mockEvidence = { id: 'evidence-123', type: 'commit', message: 'Test commit', created_at: '2025-07-02T10:00:00Z' }; mockSupabaseClient.functions.invoke.mockResolvedValue({ data: mockEvidence, error: null }); const evidenceData = { type: 'commit', message: 'Test commit', source: 'feature/test' }; const result = await (0, api_js_1.addEvidence)(evidenceData); expect(mockSupabaseClient.functions.invoke).toHaveBeenCalledWith('add_evidence', { body: evidenceData }); expect(result).toEqual(mockEvidence); }); it('should handle evidence creation errors', async () => { mockSupabaseClient.functions.invoke.mockResolvedValue({ data: null, error: { message: 'Invalid evidence type' } }); const evidenceData = { type: 'invalid', message: 'Test evidence' }; await expect((0, api_js_1.addEvidence)(evidenceData)) .rejects.toThrow('Function add_evidence failed: Invalid evidence type'); }); }); describe('Legacy API Client', () => { it('should handle POST requests', async () => { const mockResponse = { success: true }; mockSupabaseClient.functions.invoke.mockResolvedValue({ data: mockResponse, error: null }); // Import the legacy client const { apiClient } = await Promise.resolve().then(() => __importStar(require('../api.js'))); const result = await apiClient.post('/functions/v1/create_goal', { title: 'Test' }); expect(mockSupabaseClient.functions.invoke).toHaveBeenCalledWith('create_goal', { body: { title: 'Test' } }); expect(result.data).toEqual(mockResponse); }); it('should handle GET requests', async () => { const mockResponse = [{ id: 'goal-1' }]; mockSupabaseClient.functions.invoke.mockResolvedValue({ data: mockResponse, error: null }); const { apiClient } = await Promise.resolve().then(() => __importStar(require('../api.js'))); const result = await apiClient.get('/functions/v1/list_goals', { horizon: 'weekly' }); expect(mockSupabaseClient.functions.invoke).toHaveBeenCalledWith('list_goals', { body: { horizon: 'weekly' } }); expect(result.data).toEqual(mockResponse); }); it('should handle invalid function paths', async () => { const { apiClient } = await Promise.resolve().then(() => __importStar(require('../api.js'))); await expect(apiClient.post('/', {})) .rejects.toThrow('Invalid function path'); }); }); describe('REST Client', () => { it('should handle direct database queries', async () => { const mockData = [{ id: 'goal-1', title: 'Test Goal' }]; const mockQuery = { select: jest.fn().mockReturnThis(), }; mockSupabaseClient.from.mockReturnValue(mockQuery); mockQuery.select.mockResolvedValue({ data: mockData, error: null }); const { restClient } = await Promise.resolve().then(() => __importStar(require('../api.js'))); const result = await restClient.get('/goals'); expect(mockSupabaseClient.from).toHaveBeenCalledWith('goals'); expect(mockQuery.select).toHaveBeenCalledWith('*'); expect(result.data).toEqual(mockData); }); it('should handle database update operations', async () => { const mockData = [{ id: 'goal-1', title: 'Updated Goal' }]; const mockQuery = { update: jest.fn().mockReturnThis(), eq: jest.fn().mockReturnThis(), select: jest.fn().mockReturnThis(), }; mockSupabaseClient.from.mockReturnValue(mockQuery); mockQuery.select.mockResolvedValue({ data: mockData, error: null }); const { restClient } = await Promise.resolve().then(() => __importStar(require('../api.js'))); const result = await restClient.patch('/goals/goal-1', { title: 'Updated Goal' }); expect(mockSupabaseClient.from).toHaveBeenCalledWith('goals'); expect(mockQuery.update).toHaveBeenCalledWith({ title: 'Updated Goal' }); expect(mockQuery.eq).toHaveBeenCalledWith('id', 'goal-1'); expect(result.data).toEqual(mockData); }); it('should handle database errors', async () => { const mockQuery = { select: jest.fn().mockReturnThis(), }; mockSupabaseClient.from.mockReturnValue(mockQuery); mockQuery.select.mockResolvedValue({ data: null, error: { message: 'Database error' } }); const { restClient } = await Promise.resolve().then(() => __importStar(require('../api.js'))); await expect(restClient.get('/goals')) .rejects.toEqual({ message: 'Database error' }); }); it('should handle invalid REST paths', async () => { const { restClient } = await Promise.resolve().then(() => __importStar(require('../api.js'))); await expect(restClient.get('/')) .rejects.toThrow('Invalid table path'); await expect(restClient.patch('/invalid', {})) .rejects.toThrow('Invalid path for patch operation'); }); }); describe('Type Definitions', () => { it('should validate Goal interface structure', () => { const goal = { id: 'goal-123', title: 'Test Goal', horizon: 'weekly', target_date: '2025-12-31', description: 'Test description', created_at: '2025-07-02T10:00:00Z', updated_at: '2025-07-02T10:00:00Z' }; // TypeScript will validate at compile time expect(goal).toMatchObject({ id: expect.any(String), title: expect.any(String), horizon: expect.stringMatching(/^(multi-year|annual|quarterly|weekly)$/), target_date: expect.any(String), description: expect.any(String), created_at: expect.any(String), updated_at: expect.any(String) }); }); it('should validate Evidence interface structure', () => { const evidence = { id: 'evidence-123', type: 'commit', message: 'Test commit', goal_id: 'goal-123', source: 'feature/test', metadata: { lines_added: 10 }, created_at: '2025-07-02T10:00:00Z' }; expect(evidence).toMatchObject({ id: expect.any(String), type: expect.stringMatching(/^(commit|pr|time|note)$/), message: expect.any(String), goal_id: expect.any(String), source: expect.any(String), metadata: expect.any(Object), created_at: expect.any(String) }); }); }); });