Skip to main content
Glama
sigaihealth

RealVest Real Estate MCP Server

additional-calculators.test.js17.7 kB
import { test } from 'node:test'; import assert from 'node:assert'; import { NPVCalculator } from '../src/calculators/npv.js'; import { COCRCalculator } from '../src/calculators/cocr.js'; import { DSCRCalculator } from '../src/calculators/dscr.js'; import { BreakevenCalculator } from '../src/calculators/breakeven.js'; // ========== NPV CALCULATOR TESTS ========== test('NPVCalculator - Basic Calculation', () => { const calc = new NPVCalculator(); const result = calc.calculate({ initial_investment: -100000, cash_flows: [ { period: 1, amount: 20000 }, { period: 2, amount: 25000 }, { period: 3, amount: 30000 }, { period: 4, amount: 35000 }, { period: 5, amount: 40000 } ], discount_rate: 10 }); // Test structure assert(result.npv_analysis, 'Should have NPV analysis'); assert(result.investment_metrics, 'Should have investment metrics'); assert(result.payback_analysis, 'Should have payback analysis'); assert(result.decision_criteria, 'Should have decision criteria'); assert(result.sensitivity_analysis, 'Should have sensitivity analysis'); assert(result.cash_flow_schedule, 'Should have cash flow schedule'); assert(result.recommendations, 'Should have recommendations'); // Test calculations assert(result.npv_analysis.nominal_npv !== 0, 'Should calculate NPV'); assert(result.investment_metrics.total_cash_inflows === 150000, 'Should sum cash inflows correctly'); assert(result.payback_analysis.simple_payback_period > 0, 'Should calculate payback period'); assert(result.cash_flow_schedule.length === 6, 'Should have 6 entries (initial + 5 periods)'); }); test('NPVCalculator - Terminal Value', () => { const calc = new NPVCalculator(); const result = calc.calculate({ initial_investment: -200000, cash_flows: [ { period: 1, amount: 15000 }, { period: 2, amount: 18000 }, { period: 3, amount: 22000 } ], discount_rate: 12, terminal_value: 250000, terminal_period: 3 }); // Terminal value should be added to period 3 const period3 = result.cash_flow_schedule.find(cf => cf.period === 3); assert(period3.cash_flow === 272000, 'Should include terminal value in period 3'); assert(result.npv_analysis.nominal_npv > 0, 'Should have positive NPV with terminal value'); }); test('NPVCalculator - Inflation Adjustment', () => { const calc = new NPVCalculator(); const result = calc.calculate({ initial_investment: -50000, cash_flows: [ { period: 1, amount: 15000 }, { period: 2, amount: 15000 }, { period: 3, amount: 15000 } ], discount_rate: 10, inflation_rate: 3 }); assert(result.npv_analysis.real_npv !== null, 'Should calculate real NPV'); assert(result.npv_analysis.real_discount_rate !== null, 'Should calculate real discount rate'); assert(result.npv_analysis.real_npv > result.npv_analysis.nominal_npv, 'Real NPV should be greater than nominal NPV when inflation is positive'); }); test('NPVCalculator - Sensitivity Analysis', () => { const calc = new NPVCalculator(); const result = calc.calculate({ initial_investment: -75000, cash_flows: [ { period: 1, amount: 25000 }, { period: 2, amount: 30000 }, { period: 3, amount: 35000 } ], discount_rate: 8 }); const sensitivity = result.sensitivity_analysis; assert(sensitivity.scenarios.length >= 10, 'Should have multiple scenarios'); assert(sensitivity.break_even_discount_rate > 0, 'Should find break-even rate'); assert(sensitivity.most_sensitive_to, 'Should identify most sensitive variable'); // Check that different discount rates produce different NPVs const discountScenarios = sensitivity.scenarios.filter(s => s.variable === 'Discount Rate'); const npvs = discountScenarios.map(s => s.npv); assert(new Set(npvs).size === npvs.length, 'Different rates should produce different NPVs'); }); test('NPVCalculator - Schema Validation', () => { const calc = new NPVCalculator(); const schema = calc.getSchema(); assert(schema.type === 'object', 'Schema should be an object'); assert(schema.properties.initial_investment, 'Should have initial_investment'); assert(schema.properties.cash_flows, 'Should have cash_flows array'); assert(schema.properties.discount_rate, 'Should have discount_rate'); assert(schema.required.includes('initial_investment'), 'initial_investment should be required'); assert(schema.required.includes('cash_flows'), 'cash_flows should be required'); }); // ========== COCR CALCULATOR TESTS ========== test('COCRCalculator - Basic Calculation', () => { const calc = new COCRCalculator(); const result = calc.calculate({ purchase_price: 300000, down_payment: 60000, closing_costs: 5000, annual_rental_income: 36000, annual_expenses: { property_tax: 3600, insurance: 1200, maintenance: 1800 }, loan_details: { interest_rate: 6.5, loan_term_years: 30 } }); // Test structure assert(result.investment_summary, 'Should have investment summary'); assert(result.income_analysis, 'Should have income analysis'); assert(result.expense_analysis, 'Should have expense analysis'); assert(result.cash_flow_analysis, 'Should have cash flow analysis'); assert(result.return_metrics, 'Should have return metrics'); assert(result.performance_rating, 'Should have performance rating'); assert(result.monthly_breakdown, 'Should have monthly breakdown'); assert(result.scenario_analysis, 'Should have scenario analysis'); assert(result.five_year_projection, 'Should have 5-year projection'); assert(result.recommendations, 'Should have recommendations'); // Test calculations assert(result.investment_summary.total_cash_invested === 65000, 'Should calculate total cash correctly'); assert(result.return_metrics.cash_on_cash_return > 0, 'Should calculate positive COCR'); assert(result.five_year_projection.length === 5, 'Should have 5-year projection'); }); test('COCRCalculator - Vacancy Impact', () => { const calc = new COCRCalculator(); const result = calc.calculate({ purchase_price: 200000, down_payment: 40000, annual_rental_income: 24000, vacancy_rate: 10, // 10% vacancy loan_details: { interest_rate: 7.0, loan_term_years: 30 } }); // Check vacancy impact assert(result.income_analysis.vacancy_loss === 2400, 'Should calculate 10% vacancy loss'); assert(result.income_analysis.effective_annual_income === 21600, 'Should reduce income by vacancy'); }); test('COCRCalculator - Cash Purchase', () => { const calc = new COCRCalculator(); const result = calc.calculate({ purchase_price: 150000, down_payment: 150000, // Full cash purchase annual_rental_income: 18000, annual_expenses: { property_tax: 2000, insurance: 800 } }); // No loan details provided = cash purchase assert(result.cash_flow_analysis.annual_debt_service === 0, 'Should have no debt service'); assert(result.return_metrics.debt_coverage_ratio === null, 'Should have no DSCR for cash purchase'); }); test('COCRCalculator - Performance Rating', () => { const calc = new COCRCalculator(); // Excellent performance scenario const excellentResult = calc.calculate({ purchase_price: 100000, down_payment: 20000, annual_rental_income: 18000, annual_expenses: { property_tax: 1200, insurance: 600 }, loan_details: { interest_rate: 5.5, loan_term_years: 30 } }); assert(excellentResult.performance_rating.overall_rating.includes('Excellent') || excellentResult.performance_rating.overall_rating.includes('Good'), 'Should rate high-return property positively'); // Poor performance scenario const poorResult = calc.calculate({ purchase_price: 400000, down_payment: 80000, annual_rental_income: 24000, annual_expenses: { property_tax: 6000, insurance: 2400, hoa_fees: 3600 }, loan_details: { interest_rate: 7.5, loan_term_years: 30 } }); assert(poorResult.return_metrics.cash_on_cash_return < 5, 'Should have low COCR'); }); test('COCRCalculator - Schema Validation', () => { const calc = new COCRCalculator(); const schema = calc.getSchema(); assert(schema.type === 'object', 'Schema should be an object'); assert(schema.properties.purchase_price, 'Should have purchase_price'); assert(schema.properties.annual_rental_income, 'Should have annual_rental_income'); assert(schema.properties.annual_expenses, 'Should have annual_expenses object'); assert(schema.required.includes('purchase_price'), 'purchase_price should be required'); assert(schema.required.includes('down_payment'), 'down_payment should be required'); }); // ========== DSCR CALCULATOR TESTS ========== test('DSCRCalculator - Basic Calculation', () => { const calc = new DSCRCalculator(); const result = calc.calculate({ property_income: { monthly_rent: 3000, vacancy_rate: 5 }, property_expenses: { property_tax: 300, insurance: 150, maintenance_reserve: 200 }, loan_details: { loan_amount: 250000, interest_rate: 6.75, loan_term_years: 30 } }); // Test structure assert(result.income_analysis, 'Should have income analysis'); assert(result.expense_analysis, 'Should have expense analysis'); assert(result.noi_analysis, 'Should have NOI analysis'); assert(result.debt_service, 'Should have debt service'); assert(result.dscr_analysis, 'Should have DSCR analysis'); assert(result.qualification_analysis, 'Should have qualification analysis'); assert(result.maximum_loan_analysis, 'Should have maximum loan analysis'); assert(result.stress_test_results, 'Should have stress test results'); assert(result.break_even_analysis, 'Should have break-even analysis'); assert(result.recommendations, 'Should have recommendations'); // Test calculations assert(result.dscr_analysis.dscr_ratio > 0, 'Should calculate DSCR'); assert(result.noi_analysis.annual_noi > 0, 'Should calculate positive NOI'); assert(result.debt_service.annual_debt_service > 0, 'Should calculate debt service'); }); test('DSCRCalculator - Loan Qualification', () => { const calc = new DSCRCalculator(); // Good DSCR scenario const goodResult = calc.calculate({ property_income: { monthly_rent: 4000, vacancy_rate: 5 }, property_expenses: { property_tax: 400, insurance: 200 }, loan_details: { loan_amount: 300000, interest_rate: 6.5, loan_type: 'dscr' } }); assert(goodResult.qualification_analysis.qualifies === true, 'Should qualify with good DSCR'); // Poor DSCR scenario const poorResult = calc.calculate({ property_income: { monthly_rent: 2000, vacancy_rate: 10 }, property_expenses: { property_tax: 400, insurance: 200, hoa: 300 }, loan_details: { loan_amount: 300000, interest_rate: 7.5, loan_type: 'conventional' } }); assert(poorResult.dscr_analysis.dscr_ratio < 1.25, 'Should have low DSCR'); assert(poorResult.qualification_analysis.qualifies === false, 'Should not qualify with poor DSCR'); }); test('DSCRCalculator - Stress Testing', () => { const calc = new DSCRCalculator(); const result = calc.calculate({ property_income: { monthly_rent: 3500, vacancy_rate: 5 }, property_expenses: { property_tax: 350, insurance: 175, maintenance_reserve: 150 }, loan_details: { loan_amount: 280000, interest_rate: 6.85 } }); const stressTests = result.stress_test_results; assert(stressTests.scenarios.length > 0, 'Should have stress test scenarios'); assert(stressTests.worst_case, 'Should identify worst case scenario'); assert(stressTests.resilience_score, 'Should calculate resilience score'); // Verify different scenarios produce different DSCRs const dscrs = stressTests.scenarios.map(s => s.dscr); assert(new Set(dscrs).size > 1, 'Different scenarios should produce different DSCRs'); }); test('DSCRCalculator - Maximum Loan Calculation', () => { const calc = new DSCRCalculator(); const result = calc.calculate({ property_income: { monthly_rent: 3000, vacancy_rate: 5 }, property_expenses: { property_tax: 250, insurance: 125 }, loan_details: { loan_amount: 200000, interest_rate: 6.5, loan_type: 'dscr' } }); const maxLoan = result.maximum_loan_analysis; assert(maxLoan.maximum_loan_amount > 0, 'Should calculate maximum loan amount'); assert(maxLoan.required_dscr >= 1.0, 'Should show required DSCR'); assert(maxLoan.max_monthly_payment > 0, 'Should calculate max payment'); }); test('DSCRCalculator - Schema Validation', () => { const calc = new DSCRCalculator(); const schema = calc.getSchema(); assert(schema.type === 'object', 'Schema should be an object'); assert(schema.properties.property_income, 'Should have property_income'); assert(schema.properties.property_expenses, 'Should have property_expenses'); assert(schema.properties.loan_details, 'Should have loan_details'); assert(schema.required.includes('property_income'), 'property_income should be required'); assert(schema.required.includes('loan_details'), 'loan_details should be required'); }); // ========== BREAKEVEN CALCULATOR TESTS ========== test('BreakevenCalculator - Basic Calculation', () => { const calc = new BreakevenCalculator(); const result = calc.calculate({ property_costs: { purchase_price: 250000, down_payment: 50000, closing_costs: 5000 }, fixed_costs: { mortgage_payment: 1200, property_tax: 300, insurance: 150 }, revenue_streams: { monthly_rent_per_unit: 2000, total_units: 1 } }); // Test structure assert(result.initial_investment, 'Should have initial investment'); assert(result.cost_analysis, 'Should have cost analysis'); assert(result.breakeven_analysis, 'Should have breakeven analysis'); assert(result.current_performance, 'Should have current performance'); assert(result.sensitivity_analysis, 'Should have sensitivity analysis'); assert(result.multi_year_projection, 'Should have multi-year projection'); assert(result.risk_assessment, 'Should have risk assessment'); assert(result.recommendations, 'Should have recommendations'); // Test calculations assert(result.initial_investment.total_cash_required === 55000, 'Should calculate total cash'); assert(result.breakeven_analysis.occupancy_breakeven.occupancy_rate > 0, 'Should calculate breakeven occupancy'); assert(result.multi_year_projection.length > 0, 'Should have projection data'); }); test('BreakevenCalculator - Multi-Unit Property', () => { const calc = new BreakevenCalculator(); const result = calc.calculate({ property_costs: { purchase_price: 400000, down_payment: 80000 }, fixed_costs: { mortgage_payment: 2000, property_tax: 500, insurance: 300 }, revenue_streams: { monthly_rent_per_unit: 1200, total_units: 4 } }); const breakeven = result.breakeven_analysis.occupancy_breakeven; assert(breakeven.total_units === 4, 'Should track 4 units'); assert(breakeven.occupancy_rate < 100, 'Should have achievable breakeven'); assert(breakeven.units_needed < 4, 'Should need less than all units to break even'); }); test('BreakevenCalculator - Target Cash Flow Analysis', () => { const calc = new BreakevenCalculator(); const result = calc.calculate({ property_costs: { purchase_price: 200000, down_payment: 40000 }, fixed_costs: { mortgage_payment: 1000, property_tax: 250, insurance: 125 }, revenue_streams: { monthly_rent_per_unit: 1800 }, analysis_parameters: { target_cash_flow: 500 } }); const target = result.target_analysis; assert(target !== null, 'Should have target analysis'); if (!target.target_achieved) { assert(target.rent_increase_needed > 0 || target.expense_reduction_needed > 0, 'Should show path to target'); } }); test('BreakevenCalculator - Sensitivity Analysis', () => { const calc = new BreakevenCalculator(); const result = calc.calculate({ property_costs: { purchase_price: 300000, down_payment: 60000 }, fixed_costs: { mortgage_payment: 1500, property_tax: 400 }, revenue_streams: { monthly_rent_per_unit: 2200 } }); const sensitivity = result.sensitivity_analysis; assert(sensitivity.scenarios.length > 0, 'Should have sensitivity scenarios'); assert(sensitivity.most_sensitive_to, 'Should identify most sensitive factor'); assert(sensitivity.rent_elasticity >= 0, 'Should calculate rent elasticity'); assert(sensitivity.cost_elasticity >= 0, 'Should calculate cost elasticity'); }); test('BreakevenCalculator - Schema Validation', () => { const calc = new BreakevenCalculator(); const schema = calc.getSchema(); assert(schema.type === 'object', 'Schema should be an object'); assert(schema.properties.property_costs, 'Should have property_costs'); assert(schema.properties.revenue_streams, 'Should have revenue_streams'); assert(schema.properties.fixed_costs, 'Should have fixed_costs'); assert(schema.properties.variable_costs, 'Should have variable_costs'); assert(schema.required.includes('property_costs'), 'property_costs should be required'); assert(schema.required.includes('revenue_streams'), 'revenue_streams should be required'); });

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/sigaihealth/realvestmcp'

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