Skip to main content
Glama
decision-service.test.ts5.84 kB
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals'; import { DecisionService } from '../../src/domain/services/decision-service.js'; import { PlanService } from '../../src/domain/services/plan-service.js'; import { FileStorage } from '../../src/infrastructure/file-storage.js'; import * as fs from 'fs/promises'; import * as path from 'path'; import * as os from 'os'; describe('DecisionService', () => { let service: DecisionService; let planService: PlanService; let storage: FileStorage; let testDir: string; let planId: string; beforeEach(async () => { testDir = path.join(os.tmpdir(), `mcp-dec-test-${Date.now()}`); storage = new FileStorage(testDir); await storage.initialize(); planService = new PlanService(storage); service = new DecisionService(storage, planService); const plan = await planService.createPlan({ name: 'Test Plan', description: 'For testing decisions', }); planId = plan.planId; }); afterEach(async () => { await fs.rm(testDir, { recursive: true, force: true }); }); describe('record_decision', () => { it('should record a new decision', async () => { const result = await service.recordDecision({ planId, decision: { title: 'JWT Library Selection', question: 'Which JWT library should we use?', context: 'Need secure JWT handling', decision: 'Use jsonwebtoken', alternativesConsidered: [ { option: 'jose', reasoning: 'Modern', whyNotChosen: 'Less mature' }, ], }, }); expect(result.decisionId).toBeDefined(); expect(result.decision.title).toBe('JWT Library Selection'); expect(result.decision.status).toBe('active'); }); it('should store alternatives considered', async () => { const result = await service.recordDecision({ planId, decision: { title: 'Database Choice', question: 'Which database?', context: 'Need ACID', decision: 'PostgreSQL', alternativesConsidered: [ { option: 'MySQL', reasoning: 'Popular', whyNotChosen: 'Less features' }, { option: 'MongoDB', reasoning: 'Flexible', whyNotChosen: 'No ACID' }, ], }, }); expect(result.decision.alternativesConsidered).toHaveLength(2); }); }); describe('get_decision_history', () => { beforeEach(async () => { await service.recordDecision({ planId, decision: { title: 'First Decision', question: 'Q1', context: 'C1', decision: 'D1', alternativesConsidered: [], }, }); await service.recordDecision({ planId, decision: { title: 'Second Decision', question: 'Q2', context: 'C2', decision: 'D2', alternativesConsidered: [], }, }); }); it('should return decision history', async () => { const result = await service.getDecisionHistory({ planId }); expect(result.decisions).toHaveLength(2); }); it('should search in decision text', async () => { const result = await service.getDecisionHistory({ planId, filters: { search: 'First' }, }); expect(result.decisions).toHaveLength(1); expect(result.decisions[0].title).toBe('First Decision'); }); }); describe('update_decision (supersede)', () => { it('should supersede a decision', async () => { const original = await service.recordDecision({ planId, decision: { title: 'JWT Choice', question: 'Which JWT lib?', context: 'Auth', decision: 'jsonwebtoken', alternativesConsidered: [], }, }); const result = await service.updateDecision({ planId, decisionId: original.decisionId, supersede: { newDecision: 'jose', reason: 'Performance issues found', }, }); expect(result.decision.decision).toBe('jose'); expect(result.decision.status).toBe('active'); expect(result.superseded?.status).toBe('superseded'); expect(result.decision.supersedes).toBe(original.decisionId); }); it('should add old decision to alternatives', async () => { const original = await service.recordDecision({ planId, decision: { title: 'Choice', question: 'Q', context: 'C', decision: 'Option A', alternativesConsidered: [], }, }); const result = await service.updateDecision({ planId, decisionId: original.decisionId, supersede: { newDecision: 'Option B', reason: 'Better performance', }, }); const oldInAlternatives = result.decision.alternativesConsidered.find( (a) => a.option === 'Option A' ); expect(oldInAlternatives).toBeDefined(); expect(oldInAlternatives?.whyNotChosen).toBe('Better performance'); }); }); describe('list_decisions', () => { it('should filter by status', async () => { const d1 = await service.recordDecision({ planId, decision: { title: 'D1', question: 'Q', context: 'C', decision: 'A', alternativesConsidered: [], }, }); await service.updateDecision({ planId, decisionId: d1.decisionId, supersede: { newDecision: 'B', reason: 'Test' }, }); const activeOnly = await service.listDecisions({ planId, filters: { status: 'active' }, }); expect(activeOnly.decisions).toHaveLength(1); expect(activeOnly.decisions[0].decision).toBe('B'); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/cppmyjob/cpp-mcp-planner'

If you have feedback or need assistance with the MCP directory API, please join our Discord server