Skip to main content
Glama
sigaihealth

RealVest Real Estate MCP Server

airbnb-str.test.js12 kB
import { test } from 'node:test'; import assert from 'node:assert'; import { AirbnbSTRCalculator } from '../src/calculators/airbnb-str.js'; test('AirbnbSTRCalculator - Basic STR Analysis', () => { const calc = new AirbnbSTRCalculator(); const result = calc.calculate({ property_info: { purchase_price: 400000, property_type: 'single_family', bedrooms: 3, bathrooms: 2, max_guests: 6, location_type: 'urban' }, rental_assumptions: { average_nightly_rate: 180, occupancy_rate: 70, cleaning_fee: 100, average_stay_length: 3 }, operating_expenses: { platform_fees: 15, cleaning_cost: 80, management_fee: 10, supplies_monthly: 200, utilities_monthly: 250, insurance_annual: 2400, property_tax_annual: 4800, maintenance_monthly: 400 }, financing: { down_payment_percent: 25, interest_rate: 7.5, loan_term_years: 30 } }); // Test structure assert(result.investment_summary, 'Should have investment summary'); assert(result.revenue_analysis, 'Should have revenue analysis'); assert(result.expense_analysis, 'Should have expense analysis'); assert(result.cash_flow_analysis, 'Should have cash flow analysis'); assert(result.performance_metrics, 'Should have performance metrics'); assert(result.traditional_rental_comparison, 'Should have traditional rental comparison'); assert(result.risk_analysis, 'Should have risk analysis'); assert(result.breakeven_analysis, 'Should have breakeven analysis'); assert(result.recommendations, 'Should have recommendations'); // Test calculations assert(result.investment_summary.total_investment > 100000, 'Should calculate total investment'); assert(result.revenue_analysis.annual_gross_revenue > 0, 'Should calculate gross revenue'); assert(result.cash_flow_analysis.annual_cash_flow !== undefined, 'Should calculate cash flow'); assert(result.performance_metrics.cash_on_cash_return !== undefined, 'Should calculate CoC return'); assert(result.performance_metrics.cap_rate > 0, 'Should calculate cap rate'); }); test('AirbnbSTRCalculator - Seasonal Variation Analysis', () => { const calc = new AirbnbSTRCalculator(); const result = calc.calculate({ property_info: { purchase_price: 350000, bedrooms: 2, bathrooms: 1, max_guests: 4, location_type: 'beach' }, rental_assumptions: { average_nightly_rate: 200, occupancy_rate: 65, seasonal_variation: { peak_months: 4, peak_rate_multiplier: 1.8, low_season_discount: 30 }, cleaning_fee: 120, average_stay_length: 4 } }); // Test seasonal analysis assert(result.seasonal_analysis, 'Should have seasonal analysis'); assert(result.seasonal_analysis.peak_season, 'Should have peak season data'); assert(result.seasonal_analysis.low_season, 'Should have low season data'); assert(result.seasonal_analysis.peak_season.nightly_rate > 200, 'Peak season rate should be higher than base rate'); assert(result.seasonal_analysis.low_season.nightly_rate < 200, 'Low season rate should be lower than base rate'); // Test weighted average rate calculation assert(result.revenue_analysis.average_nightly_rate !== 200, 'Average rate should be adjusted for seasonal variation'); }); test('AirbnbSTRCalculator - High-End Property Analysis', () => { const calc = new AirbnbSTRCalculator(); const result = calc.calculate({ property_info: { purchase_price: 800000, property_type: 'single_family', bedrooms: 5, bathrooms: 4, max_guests: 10, location_type: 'tourist_destination' }, rental_assumptions: { average_nightly_rate: 450, occupancy_rate: 60, cleaning_fee: 200, average_stay_length: 5 }, operating_expenses: { platform_fees: 12, cleaning_cost: 150, management_fee: 15, supplies_monthly: 500, utilities_monthly: 400, marketing_monthly: 300 }, startup_costs: { furniture_budget: 50000, renovation_budget: 25000, initial_supplies: 5000, technology_setup: 3000 } }); // Test high-end property specifics assert(result.investment_summary.startup_costs > 75000, 'Should include significant startup costs'); assert(result.performance_metrics.revenue_per_available_room > 100, 'High-end property should have high RevPAR'); // Test risk analysis for tourist destination const touristRisk = result.risk_analysis.key_risks.find(risk => risk.includes('Tourism-dependent')); assert(touristRisk, 'Should identify tourism dependency risk'); }); test('AirbnbSTRCalculator - Traditional Rental Comparison', () => { const calc = new AirbnbSTRCalculator(); const result = calc.calculate({ property_info: { purchase_price: 300000, property_type: 'condo', bedrooms: 2, bathrooms: 2, max_guests: 4 }, rental_assumptions: { average_nightly_rate: 120, occupancy_rate: 75 }, financing: { down_payment_percent: 20, interest_rate: 7.0 } }); // Test traditional rental comparison assert(result.traditional_rental_comparison, 'Should have traditional rental comparison'); assert(result.traditional_rental_comparison.estimated_monthly_rent > 0, 'Should estimate traditional rental income'); assert(result.traditional_rental_comparison.cash_on_cash_return !== undefined, 'Should calculate traditional rental CoC return'); // Verify comparison makes sense assert(result.traditional_rental_comparison.annual_rental_income > 0, 'Traditional rental should have positive income'); }); test('AirbnbSTRCalculator - Low Occupancy Scenario', () => { const calc = new AirbnbSTRCalculator(); const result = calc.calculate({ property_info: { purchase_price: 250000, bedrooms: 1, bathrooms: 1, max_guests: 2, location_type: 'rural' }, rental_assumptions: { average_nightly_rate: 90, occupancy_rate: 45 // Low occupancy }, analysis_options: { vacancy_buffer: 10 // Additional vacancy buffer } }); // Test low occupancy impact assert(result.revenue_analysis.effective_occupancy < 45, 'Effective occupancy should be reduced by vacancy buffer'); assert(result.risk_analysis.risk_level === 'Medium' || result.risk_analysis.risk_level === 'High', 'Low occupancy should increase risk level'); const occupancyRisk = result.risk_analysis.key_risks.find(risk => risk.includes('Low occupancy')); assert(occupancyRisk, 'Should identify low occupancy risk'); // Test break-even analysis assert(result.breakeven_analysis.breakeven_occupancy_rate > 0, 'Should calculate break-even occupancy'); assert(result.breakeven_analysis.margin_of_safety_percent < 50, 'Low occupancy should result in lower margin of safety'); }); test('AirbnbSTRCalculator - Multi-Year Projections', () => { const calc = new AirbnbSTRCalculator(); const result = calc.calculate({ property_info: { purchase_price: 400000, bedrooms: 3, bathrooms: 2, max_guests: 6 }, rental_assumptions: { average_nightly_rate: 175, occupancy_rate: 68 }, analysis_options: { analysis_period_years: 5, annual_rate_increase: 4, annual_expense_increase: 3 } }); // Test projections assert(result.projections, 'Should have projections'); assert(result.projections.length === 5, 'Should have 5-year projections'); // Test growth assumptions const year1 = result.projections[0]; const year5 = result.projections[4]; assert(year5.gross_revenue > year1.gross_revenue, 'Revenue should grow over time'); assert(year5.operating_expenses > year1.operating_expenses, 'Expenses should grow over time'); assert(year5.cumulative_cash_flow !== undefined, 'Should track cumulative cash flow'); }); test('AirbnbSTRCalculator - Cash Purchase Analysis', () => { const calc = new AirbnbSTRCalculator(); const result = calc.calculate({ property_info: { purchase_price: 300000, bedrooms: 2, bathrooms: 2, max_guests: 4 }, rental_assumptions: { average_nightly_rate: 150, occupancy_rate: 70 }, financing: { down_payment_percent: 100 // Cash purchase } }); // Test cash purchase assert(result.investment_summary.loan_amount === 0, 'Cash purchase should have no loan'); assert(result.investment_summary.monthly_debt_service === 0, 'Cash purchase should have no debt service'); assert(result.cash_flow_analysis.annual_debt_service === 0, 'No annual debt service for cash purchase'); // Cash flow should equal NOI assert(Math.abs(result.cash_flow_analysis.annual_cash_flow - result.cash_flow_analysis.annual_net_operating_income) < 1, 'Cash flow should equal NOI for cash purchase'); }); test('AirbnbSTRCalculator - High Management Fee Scenario', () => { const calc = new AirbnbSTRCalculator(); const result = calc.calculate({ property_info: { purchase_price: 350000, bedrooms: 3, bathrooms: 2, max_guests: 6 }, rental_assumptions: { average_nightly_rate: 160, occupancy_rate: 72 }, operating_expenses: { platform_fees: 18, // High platform fees management_fee: 25, // High management fee cleaning_cost: 100 } }); // Test high fee impact assert(result.expense_analysis.expense_ratio > 40, 'High fees should result in high expense ratio'); // Verify variable expenses are calculated correctly assert(result.expense_analysis.variable_expenses.platform_fees > 0, 'Should calculate platform fees'); assert(result.expense_analysis.variable_expenses.management_fees > 0, 'Should calculate management fees'); // The recommendation system focuses on performance vs traditional rental // rather than just expense ratios, so this test is more flexible assert(result.recommendations.length > 0, 'Should have recommendations'); }); test('AirbnbSTRCalculator - Stress Test Scenarios', () => { const calc = new AirbnbSTRCalculator(); const result = calc.calculate({ property_info: { purchase_price: 400000, bedrooms: 3, bathrooms: 2, max_guests: 6 }, rental_assumptions: { average_nightly_rate: 180, occupancy_rate: 70 } }); // Test stress scenarios assert(result.risk_analysis.stress_scenarios, 'Should have stress scenarios'); assert(result.risk_analysis.stress_scenarios.occupancy_drop_20pct, 'Should test occupancy drop scenario'); assert(result.risk_analysis.stress_scenarios.rate_drop_15pct, 'Should test rate drop scenario'); assert(result.risk_analysis.stress_scenarios.expense_increase_25pct, 'Should test expense increase scenario'); // Stress scenarios should show negative impact const occupancyStress = result.risk_analysis.stress_scenarios.occupancy_drop_20pct; assert(occupancyStress.annual_cash_flow < result.cash_flow_analysis.annual_cash_flow, 'Occupancy drop should reduce cash flow'); }); test('AirbnbSTRCalculator - Schema Validation', () => { const calc = new AirbnbSTRCalculator(); const schema = calc.getSchema(); assert(schema.type === 'object', 'Schema should be an object'); assert(schema.properties.property_info, 'Should have property_info'); assert(schema.properties.rental_assumptions, 'Should have rental_assumptions'); assert(schema.properties.operating_expenses, 'Should have operating_expenses'); assert(schema.properties.financing, 'Should have financing'); assert(schema.properties.startup_costs, 'Should have startup_costs'); assert(schema.required.includes('property_info'), 'property_info should be required'); assert(schema.required.includes('rental_assumptions'), 'rental_assumptions 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