alnilam-cli
Version:
Git-native AI career coach that converts multi-year ambitions into weekly execution
334 lines (333 loc) • 14.5 kB
JavaScript
"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)
});
});
});
});