// Integration tests for MCP server
import { DatabaseClient } from '../src/database.js';
// import { ValidationError, QueryError } from '../src/error-handler.js';
describe('MCP Server Integration Tests', () => {
let dbClient: DatabaseClient;
beforeAll(() => {
dbClient = new DatabaseClient();
});
describe('Banking Query Scenarios', () => {
it('should handle accounts query for all providers', async () => {
const accounts = await dbClient.getAccountBalances();
expect(Array.isArray(accounts)).toBe(true);
// Should have data from multiple providers
const providers = new Set(accounts.map(acc => acc.provider_id));
expect(providers.size).toBeGreaterThan(0);
});
it('should handle transactions query with date filtering', async () => {
const dateFrom = '2025-01-01';
const dateTo = '2025-12-31';
const transactions = await dbClient.getTransactions({
dateFrom,
dateTo,
limit: 50,
});
expect(Array.isArray(transactions)).toBe(true);
expect(transactions.length).toBeLessThanOrEqual(50);
// Verify date filtering
transactions.forEach(transaction => {
const transactionDate = new Date(transaction.date);
expect(transactionDate.getTime()).toBeGreaterThanOrEqual(
new Date(dateFrom).getTime()
);
expect(transactionDate.getTime()).toBeLessThanOrEqual(
new Date(dateTo).getTime()
);
});
});
it('should handle balance query with provider filtering', async () => {
const providers = await dbClient.getProviders();
if (providers.length > 0) {
const firstProvider = providers[0].provider_id;
const balances = await dbClient.getAccountBalances({
providerId: firstProvider,
});
expect(Array.isArray(balances)).toBe(true);
// All balances should be from the specified provider
balances.forEach(balance => {
expect(balance.provider_id).toBe(firstProvider);
});
}
});
it('should handle spending analysis with category filtering', async () => {
const spending = await dbClient.getSpendingAnalysis({ months: 6 });
expect(Array.isArray(spending)).toBe(true);
// Should have positive amounts (expenses are stored as positive values in spending analysis)
spending.forEach(item => {
expect(Number(item.total_amount)).toBeGreaterThan(0);
expect(Number(item.transaction_count)).toBeGreaterThan(0);
expect(Number(item.average_amount)).toBeGreaterThan(0);
});
});
it('should handle cashflow analysis with monthly data', async () => {
const monthlyData = await dbClient.getMonthlyData({ months: 12 });
expect(Array.isArray(monthlyData)).toBe(true);
expect(monthlyData.length).toBeLessThanOrEqual(12);
// Should have valid financial data
monthlyData.forEach(month => {
expect(typeof Number(month.total_income)).toBe('number');
expect(typeof Number(month.total_expenses)).toBe('number');
expect(typeof Number(month.net_flow)).toBe('number');
expect(typeof Number(month.transaction_count)).toBe('number');
});
});
it('should handle financial overview', async () => {
const overview = await dbClient.getFinancialOverview();
expect(typeof Number(overview.total_income)).toBe('number');
expect(typeof Number(overview.total_expenses)).toBe('number');
expect(typeof Number(overview.net_cash_flow)).toBe('number');
expect(typeof Number(overview.transaction_count)).toBe('number');
expect(Array.isArray(overview.providers)).toBe(true);
// Net cash flow should equal income minus expenses
expect(Number(overview.net_cash_flow)).toBeCloseTo(
Number(overview.total_income) - Number(overview.total_expenses),
2
);
});
});
describe('Data Query Scenarios', () => {
it('should provide database statistics', async () => {
const providers = await dbClient.getProviders();
const totalTransactions = providers.reduce(
(sum, p) => sum + Number(p.transaction_count),
0
);
expect(providers.length).toBeGreaterThan(0);
expect(totalTransactions).toBeGreaterThan(0);
// Should have a largest provider
const largestProvider = providers[0];
expect(Number(largestProvider.transaction_count)).toBeGreaterThan(0);
});
it('should validate data integrity', async () => {
const transactions = await dbClient.getTransactions({ limit: 10 });
const monthlyData = await dbClient.getMonthlyData({ months: 1 });
expect(Array.isArray(transactions)).toBe(true);
expect(Array.isArray(monthlyData)).toBe(true);
// Basic data validation
transactions.forEach(transaction => {
expect(transaction.id).toBeDefined();
expect(transaction.date).toBeDefined();
expect(transaction.amount).toBeDefined();
expect(transaction.description).toBeDefined();
});
});
});
describe('Error Handling Scenarios', () => {
it('should handle invalid date ranges gracefully', () => {
expect(() => {
// This would be caught by validation before reaching database
// const invalidDateFrom = 'invalid-date';
// const invalidDateTo = '2025-12-31';
// In real scenario, this would be caught by validateDateRange
}).not.toThrow();
});
it('should handle large limit requests efficiently', async () => {
const startTime = Date.now();
const transactions = await dbClient.getTransactions({ limit: 1000 });
const endTime = Date.now();
expect(transactions.length).toBeLessThanOrEqual(1000);
expect(endTime - startTime).toBeLessThan(5000); // Should complete within 5 seconds
});
it('should handle provider filtering with non-existent provider', async () => {
const nonExistentProvider = 'non-existent-provider-12345';
const transactions = await dbClient.getTransactions({
providerId: nonExistentProvider,
});
// Should return empty array, not throw error
expect(Array.isArray(transactions)).toBe(true);
expect(transactions.length).toBe(0);
});
});
describe('Performance Tests', () => {
it('should handle concurrent requests', async () => {
const promises = [
dbClient.getTransactions({ limit: 100 }),
dbClient.getMonthlyData({ months: 3 }),
dbClient.getAccountBalances(),
dbClient.getSpendingAnalysis({ months: 3 }),
dbClient.getFinancialOverview(),
];
const results = await Promise.all(promises);
expect(results).toHaveLength(5);
results.forEach(result => {
expect(result).toBeDefined();
});
});
it('should handle large date range queries efficiently', async () => {
const startTime = Date.now();
const transactions = await dbClient.getTransactions({
dateFrom: '2020-01-01',
dateTo: '2025-12-31',
limit: 5000,
});
const endTime = Date.now();
expect(transactions.length).toBeLessThanOrEqual(5000);
expect(endTime - startTime).toBeLessThan(10000); // Should complete within 10 seconds
});
});
});