@boundless-oss/atlas
Version:
Atlas - MCP Server for comprehensive startup project management
339 lines (285 loc) • 12.5 kB
text/typescript
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { BusinessAnalyzer } from '../analyzer.js';
import { BusinessPlan, MarketAnalysis, CompetitorAnalysis } from '../types.js';
import { ConfigManager } from '../../../config/config-manager.js';
// Mock ConfigManager
vi.mock('../../../config/config-manager.js');
// Mock fs
vi.mock('fs', () => ({
promises: {
readFile: vi.fn().mockRejectedValue(new Error('File not found')),
writeFile: vi.fn().mockResolvedValue(undefined),
mkdir: vi.fn().mockResolvedValue(undefined)
}
}));
describe('BusinessAnalyzer', () => {
let businessAnalyzer: BusinessAnalyzer;
let mockConfigManager: vi.Mocked<ConfigManager>;
it('should create BusinessAnalyzer instance', () => {
const config = {} as any;
const analyzer = new BusinessAnalyzer(config);
expect(analyzer).toBeInstanceOf(BusinessAnalyzer);
});
beforeEach(async () => {
mockConfigManager = {
getStorageManager: vi.fn().mockReturnValue({
getStorageLocation: vi.fn().mockResolvedValue({
data: '/tmp/test-data'
})
})
} as any;
businessAnalyzer = new BusinessAnalyzer(mockConfigManager);
await businessAnalyzer.init();
});
describe('generateBusinessPlan', () => {
it('should generate business plan with lean canvas template', async () => {
const options = {
businessIdea: 'AI-powered project management tool',
targetMarket: 'Software development teams',
businessModel: 'SaaS subscription',
timeline: 12,
template: 'lean_canvas' as const,
};
const businessPlan = await businessAnalyzer.generateBusinessPlan(options);
expect(businessPlan.id).toMatch(/^plan-[a-z0-9-]+$/);
expect(businessPlan.businessIdea).toBe(options.businessIdea);
expect(businessPlan.targetMarket).toBe(options.targetMarket);
expect(businessPlan.businessModel).toBe(options.businessModel);
expect(businessPlan.timeline).toBe(options.timeline);
expect(businessPlan.template).toBe('lean_canvas');
expect(businessPlan.sections).toBeDefined();
expect(businessPlan.sections.length).toBeGreaterThan(0);
});
it('should generate business plan with traditional template', async () => {
const options = {
businessIdea: 'E-commerce platform',
targetMarket: 'Small businesses',
businessModel: 'Commission-based',
timeline: 24,
template: 'traditional' as const,
};
const businessPlan = await businessAnalyzer.generateBusinessPlan(options);
expect(businessPlan.template).toBe('traditional');
expect(businessPlan.sections).toBeDefined();
expect(businessPlan.createdAt).toBeDefined();
expect(businessPlan.updatedAt).toBeDefined();
});
it('should include financial projections', async () => {
const options = {
businessIdea: 'Mobile app',
targetMarket: 'Consumers',
businessModel: 'Freemium',
timeline: 18,
includeFinancials: true,
template: 'traditional',
};
const businessPlan = await businessAnalyzer.generateBusinessPlan(options);
expect(businessPlan.financials).toBeDefined();
expect(businessPlan.financials?.revenue).toBeDefined();
expect(businessPlan.financials?.expenses).toBeDefined();
expect(businessPlan.financials?.projections).toBeDefined();
});
});
describe('analyzeMarket', () => {
it('should analyze market for given industry and target market', async () => {
const options = {
industry: 'Software Development',
targetMarket: 'Small to medium businesses',
geographicScope: 'North America',
};
const marketAnalysis = await businessAnalyzer.analyzeMarket(options);
expect(marketAnalysis.id).toMatch(/^market-[a-z0-9-]+$/);
expect(marketAnalysis.industry).toBe(options.industry);
expect(marketAnalysis.targetMarket).toBe(options.targetMarket);
expect(marketAnalysis.geographicScope).toBe(options.geographicScope);
expect(marketAnalysis.marketSize).toBeDefined();
expect(marketAnalysis.trends).toBeDefined();
expect(marketAnalysis.trends.length).toBeGreaterThan(0);
expect(marketAnalysis.opportunities).toBeDefined();
expect(marketAnalysis.challenges).toBeDefined();
});
it('should include demographic analysis when requested', async () => {
const options = {
industry: 'E-commerce',
targetMarket: 'Millennials',
geographicScope: 'United States',
includeDemographics: true,
};
const marketAnalysis = await businessAnalyzer.analyzeMarket(options);
expect(marketAnalysis.demographics).toBeDefined();
expect(marketAnalysis.demographics?.ageRange).toBeDefined();
expect(marketAnalysis.demographics?.income).toBeDefined();
expect(marketAnalysis.demographics?.behavior).toBeDefined();
});
});
describe('analyzeCompetitors', () => {
it('should analyze competitors in the industry', async () => {
const options = {
businessIdea: 'AI-powered project management tool',
industry: 'Project Management Software',
competitors: ['Asana', 'Jira', 'Trello'],
analysisDepth: 'detailed',
includeStrengthWeakness: true,
};
const competitorAnalysis = await businessAnalyzer.analyzeCompetitors(options);
expect(competitorAnalysis).toBeDefined();
expect(competitorAnalysis.industry).toBe(options.industry);
expect(competitorAnalysis.competitors).toBeDefined();
expect(competitorAnalysis.competitors.length).toBeGreaterThan(0);
const firstCompetitor = competitorAnalysis.competitors[0];
expect(firstCompetitor.name).toBeDefined();
expect(firstCompetitor.marketShare).toBeDefined();
expect(firstCompetitor.strengths).toBeDefined();
expect(firstCompetitor.weaknesses).toBeDefined();
expect(firstCompetitor.pricingModel).toBeDefined();
});
it('should include competitive positioning', async () => {
const options = {
businessIdea: 'Simple CRM for freelancers',
industry: 'CRM Software',
competitors: ['Salesforce', 'HubSpot', 'Pipedrive'],
analysisDepth: 'comprehensive',
includeStrengthWeakness: true,
};
const competitorAnalysis = await businessAnalyzer.analyzeCompetitors(options);
expect(competitorAnalysis.positioning).toBeDefined();
expect(competitorAnalysis.positioning?.marketGaps).toBeDefined();
expect(competitorAnalysis.positioning?.differentiationOpportunities).toBeDefined();
expect(competitorAnalysis.positioning?.competitiveAdvantages).toBeDefined();
});
});
describe('generatePitchDeck', () => {
it('should generate pitch deck with standard slides', async () => {
const options = {
businessIdea: 'AI-powered project management',
problemStatement: 'Teams struggle with project complexity',
solution: 'AI assistant that simplifies project management',
targetMarket: 'Software development teams',
businessModel: 'SaaS subscription',
competitiveAdvantage: 'AI-driven insights',
fundingAsk: '$2M seed round',
template: 'investor',
};
const pitchDeck = await businessAnalyzer.generatePitchDeck(options);
expect(pitchDeck).toBeDefined();
expect(pitchDeck.businessIdea).toBe(options.businessIdea);
expect(pitchDeck.template).toBe(options.template);
expect(pitchDeck.markdown).toBeDefined();
expect(pitchDeck.keyMessages).toBeDefined();
expect(pitchDeck.presentationTips).toBeDefined();
});
it('should customize slides for different audiences', async () => {
const optionsForPartners = {
businessIdea: 'B2B marketplace platform',
problemStatement: 'Suppliers struggle to find buyers',
solution: 'Digital marketplace connecting suppliers and buyers',
targetMarket: 'Manufacturing industry',
businessModel: 'Transaction fees',
competitiveAdvantage: 'Industry-specific features',
template: 'partner',
};
const pitchDeck = await businessAnalyzer.generatePitchDeck(optionsForPartners);
expect(pitchDeck.template).toBe('partner');
expect(pitchDeck.markdown).toBeDefined();
});
});
describe('assessStartup', () => {
it('should assess startup maturity across all dimensions', async () => {
const options = {
businessPlanId: 'plan-789',
currentStage: 'mvp',
teamSize: 5,
monthsInDevelopment: 8,
hasCustomers: true,
monthlyRevenue: 5000,
};
const assessment = await businessAnalyzer.assessStartup(options);
expect(assessment.id).toMatch(/^assessment-[a-f0-9-]+$/);
expect(assessment.businessPlanId).toBe(options.businessPlanId);
expect(assessment.overallScore).toBeGreaterThan(0);
expect(assessment.overallScore).toBeLessThanOrEqual(100);
expect(assessment.maturityLevel).toBeDefined();
expect(assessment.dimensions).toBeDefined();
// Check all key dimensions are assessed
expect(assessment.dimensions.product).toBeDefined();
expect(assessment.dimensions.market).toBeDefined();
expect(assessment.dimensions.team).toBeDefined();
expect(assessment.dimensions.financial).toBeDefined();
expect(assessment.dimensions.operations).toBeDefined();
});
it('should provide recommendations for improvement', async () => {
const options = {
businessPlanId: 'plan-101',
currentStage: 'idea',
teamSize: 1,
monthsInDevelopment: 1,
hasCustomers: false,
monthlyRevenue: 0,
};
const assessment = await businessAnalyzer.assessStartup(options);
expect(assessment.recommendations).toBeDefined();
expect(assessment.recommendations.length).toBeGreaterThan(0);
expect(assessment.nextSteps).toBeDefined();
expect(assessment.nextSteps.length).toBeGreaterThan(0);
});
});
describe('planFundingStrategy', () => {
it('should plan funding strategy based on business needs', async () => {
const options = {
businessPlanId: 'plan-202',
fundingGoal: 500000,
currentStage: 'mvp',
useOfFunds: ['product-development', 'marketing', 'hiring'],
timeline: 6,
};
const fundingStrategy = await businessAnalyzer.planFundingStrategy(options);
expect(fundingStrategy.id).toMatch(/^funding-[a-f0-9-]+$/);
expect(fundingStrategy.businessPlanId).toBe(options.businessPlanId);
expect(fundingStrategy.fundingGoal).toBe(options.fundingGoal);
expect(fundingStrategy.recommendedSources).toBeDefined();
expect(fundingStrategy.recommendedSources.length).toBeGreaterThan(0);
expect(fundingStrategy.timeline).toBeDefined();
expect(fundingStrategy.milestones).toBeDefined();
});
it('should recommend appropriate funding sources for stage', async () => {
const seedStageOptions = {
businessPlanId: 'plan-303',
fundingGoal: 100000,
currentStage: 'idea',
timeline: 3,
};
const seedStrategy = await businessAnalyzer.planFundingStrategy(seedStageOptions);
expect(seedStrategy.recommendedSources).toContain('angel-investors');
expect(seedStrategy.recommendedSources).toContain('grants');
const seriesAOptions = {
businessPlanId: 'plan-404',
fundingGoal: 2000000,
currentStage: 'growth',
timeline: 12,
};
const seriesAStrategy = await businessAnalyzer.planFundingStrategy(seriesAOptions);
expect(seriesAStrategy.recommendedSources).toContain('venture-capital');
});
});
describe('error handling', () => {
it('should handle invalid business plan parameters', async () => {
const invalidOptions = {
businessIdea: '', // Empty business idea
targetMarket: 'Invalid market',
businessModel: 'Unknown model',
timeline: -1, // Invalid timeline
};
await expect(
businessAnalyzer.generateBusinessPlan(invalidOptions)
).rejects.toThrow();
});
it('should handle missing required parameters', async () => {
const incompleteOptions = {
// Missing required fields
};
await expect(
businessAnalyzer.analyzeMarket(incompleteOptions as any)
).rejects.toThrow();
});
});
});