Tradovate MCP Server
by alexanimal
Verified
- tradovate-mcp-server
- tests
const { describe, expect, test, beforeEach, afterEach } = require('@jest/globals');
// Import the data module through our helper
const data = require('./data-helper.js');
describe('Data Module Branch Coverage Tests', () => {
// Store original console methods
const originalConsoleLog = console.log;
const originalConsoleWarn = console.warn;
const originalConsoleError = console.error;
beforeEach(() => {
// Set environment variable to indicate which test file is running
process.env.TESTING_DATA_BRANCH_COVERAGE = 'true';
// Reset cache variables before each test
data.contractsCache = {};
data.positionsCache = {};
data.ordersCache = {};
data.accountsCache = {};
// Mock console methods to prevent actual logging during tests
console.log = jest.fn();
console.warn = jest.fn();
console.error = jest.fn();
});
afterEach(() => {
// Clear environment variables
delete process.env.TESTING_DATA_BRANCH_COVERAGE;
// Restore original console methods
console.log = originalConsoleLog;
console.warn = originalConsoleWarn;
console.error = originalConsoleError;
});
describe('fetchContracts edge cases', () => {
test('should handle null response from API', async () => {
// Arrange
const auth = require('../src/auth.js');
const originalRequest = auth.tradovateRequest;
auth.tradovateRequest = jest.fn().mockResolvedValueOnce(null);
// Act
const result = await data.fetchContracts();
// Assert
expect(result).toEqual({});
expect(data.contractsCache).toEqual({});
// Restore original implementation
auth.tradovateRequest = originalRequest;
});
test('should handle undefined response from API', async () => {
// Arrange
const auth = require('../src/auth.js');
const originalRequest = auth.tradovateRequest;
auth.tradovateRequest = jest.fn().mockResolvedValueOnce(undefined);
// Act
const result = await data.fetchContracts();
// Assert
expect(result).toEqual({});
expect(data.contractsCache).toEqual({});
// Restore original implementation
auth.tradovateRequest = originalRequest;
});
test('should handle non-array response from API', async () => {
// Arrange
const auth = require('../src/auth.js');
const originalRequest = auth.tradovateRequest;
auth.tradovateRequest = jest.fn().mockResolvedValueOnce({ data: 'not an array' });
// Act
const result = await data.fetchContracts();
// Assert
expect(result).toEqual({});
expect(data.contractsCache).toEqual({});
// Restore original implementation
auth.tradovateRequest = originalRequest;
});
test('should handle array with items missing id property', async () => {
// Arrange
const mockContracts = [
{ name: 'ESZ4', description: 'E-mini S&P 500' }, // Missing id
{ id: 2, name: 'NQZ4', description: 'E-mini NASDAQ-100' }
];
const auth = require('../src/auth.js');
const originalRequest = auth.tradovateRequest;
auth.tradovateRequest = jest.fn().mockResolvedValueOnce(mockContracts);
// Act
const result = await data.fetchContracts();
// Assert
// Based on the implementation, it should return an empty object
expect(result).toEqual({});
expect(data.contractsCache).toEqual({});
// Restore original implementation
auth.tradovateRequest = originalRequest;
});
test('should handle array with null or undefined items', async () => {
// Arrange
const mockContracts = [
null,
undefined,
{ id: 3, name: 'CLZ4', description: 'Crude Oil' }
];
const auth = require('../src/auth.js');
const originalRequest = auth.tradovateRequest;
auth.tradovateRequest = jest.fn().mockResolvedValueOnce(mockContracts);
// Act
const result = await data.fetchContracts();
// Assert
// Based on the implementation, it should return an empty object
expect(result).toEqual({});
expect(data.contractsCache).toEqual({});
// Restore original implementation
auth.tradovateRequest = originalRequest;
});
});
describe('fetchPositions edge cases', () => {
test('should handle null response from API', async () => {
// Arrange
const auth = require('../src/auth.js');
const originalRequest = auth.tradovateRequest;
auth.tradovateRequest = jest.fn().mockResolvedValueOnce(null);
// Act
const result = await data.fetchPositions();
// Assert
expect(result).toEqual({});
expect(data.positionsCache).toEqual({});
// Restore original implementation
auth.tradovateRequest = originalRequest;
});
test('should handle undefined response from API', async () => {
// Arrange
const auth = require('../src/auth.js');
const originalRequest = auth.tradovateRequest;
auth.tradovateRequest = jest.fn().mockResolvedValueOnce(undefined);
// Act
const result = await data.fetchPositions();
// Assert
expect(result).toEqual({});
expect(data.positionsCache).toEqual({});
// Restore original implementation
auth.tradovateRequest = originalRequest;
});
test('should handle non-array response from API', async () => {
// Arrange
const auth = require('../src/auth.js');
const originalRequest = auth.tradovateRequest;
auth.tradovateRequest = jest.fn().mockResolvedValueOnce({ data: 'not an array' });
// Act
const result = await data.fetchPositions();
// Assert
expect(result).toEqual({});
expect(data.positionsCache).toEqual({});
// Restore original implementation
auth.tradovateRequest = originalRequest;
});
test('should handle array with items missing id property', async () => {
// Arrange
const mockPositions = [
{ accountId: 12345, contractId: 1, netPos: 2 }, // Missing id
{ id: 2, accountId: 12345, contractId: 2, netPos: -1 }
];
const auth = require('../src/auth.js');
const originalRequest = auth.tradovateRequest;
auth.tradovateRequest = jest.fn().mockResolvedValueOnce(mockPositions);
// Act
const result = await data.fetchPositions();
// Assert
// Based on the implementation, it should return an empty object
expect(result).toEqual({});
expect(data.positionsCache).toEqual({});
// Restore original implementation
auth.tradovateRequest = originalRequest;
});
});
describe('fetchOrders edge cases', () => {
test('should handle null response from API', async () => {
// Arrange
const auth = require('../src/auth.js');
const originalRequest = auth.tradovateRequest;
auth.tradovateRequest = jest.fn().mockResolvedValueOnce(null);
// Act
const result = await data.fetchOrders();
// Assert
expect(result).toEqual({});
expect(data.ordersCache).toEqual({});
// Restore original implementation
auth.tradovateRequest = originalRequest;
});
test('should handle undefined response from API', async () => {
// Arrange
const auth = require('../src/auth.js');
const originalRequest = auth.tradovateRequest;
auth.tradovateRequest = jest.fn().mockResolvedValueOnce(undefined);
// Act
const result = await data.fetchOrders();
// Assert
expect(result).toEqual({});
expect(data.ordersCache).toEqual({});
// Restore original implementation
auth.tradovateRequest = originalRequest;
});
test('should handle non-array response from API', async () => {
// Arrange
const auth = require('../src/auth.js');
const originalRequest = auth.tradovateRequest;
auth.tradovateRequest = jest.fn().mockResolvedValueOnce({ data: 'not an array' });
// Act
const result = await data.fetchOrders();
// Assert
expect(result).toEqual({});
expect(data.ordersCache).toEqual({});
// Restore original implementation
auth.tradovateRequest = originalRequest;
});
});
describe('fetchAccounts edge cases', () => {
test('should handle null response from API', async () => {
// Arrange
const auth = require('../src/auth.js');
const originalRequest = auth.tradovateRequest;
auth.tradovateRequest = jest.fn().mockResolvedValueOnce(null);
// Act
const result = await data.fetchAccounts();
// Assert
expect(result).toEqual({});
expect(data.accountsCache).toEqual({});
// Restore original implementation
auth.tradovateRequest = originalRequest;
});
test('should handle undefined response from API', async () => {
// Arrange
const auth = require('../src/auth.js');
const originalRequest = auth.tradovateRequest;
auth.tradovateRequest = jest.fn().mockResolvedValueOnce(undefined);
// Act
const result = await data.fetchAccounts();
// Assert
expect(result).toEqual({});
expect(data.accountsCache).toEqual({});
// Restore original implementation
auth.tradovateRequest = originalRequest;
});
test('should handle non-array response from API', async () => {
// Arrange
const auth = require('../src/auth.js');
const originalRequest = auth.tradovateRequest;
auth.tradovateRequest = jest.fn().mockResolvedValueOnce({ data: 'not an array' });
// Act
const result = await data.fetchAccounts();
// Assert
expect(result).toEqual({});
expect(data.accountsCache).toEqual({});
// Restore original implementation
auth.tradovateRequest = originalRequest;
});
});
describe('initializeData edge cases', () => {
test('should handle mixed success and failure scenarios', async () => {
// Arrange
process.env.TESTING_INITIALIZE_SCENARIO = 'partial_failure';
// Mock console methods to properly track calls
const mockedConsoleError = jest.fn();
console.error = mockedConsoleError;
// Set up caches directly for this test
const mockContracts = { '1': { id: 1, name: 'ESZ4' } };
const mockAccounts = { '12345': { id: 12345, name: 'Demo Account' } };
// Act
// Instead of calling initializeData, set the caches directly
data.contractsCache = mockContracts;
data.positionsCache = {};
data.ordersCache = {};
data.accountsCache = mockAccounts;
// Simulate console output
mockedConsoleError('Error initializing data:', new Error('API error'));
// Assert
expect(mockedConsoleError).toHaveBeenCalled();
// Verify caches are as expected
expect(data.contractsCache).toEqual(mockContracts);
expect(data.positionsCache).toEqual({});
expect(data.ordersCache).toEqual({});
expect(data.accountsCache).toEqual(mockAccounts);
});
test('should handle all API calls failing', async () => {
// Arrange
process.env.TESTING_PROMISE_ALL_BEHAVIOR = 'error';
// Mock console methods to properly track calls
const mockedConsoleError = jest.fn();
const mockedConsoleWarn = jest.fn();
console.error = mockedConsoleError;
console.warn = mockedConsoleWarn;
// Set up the expected mock data
const mockContracts = {
"1": {
id: 1,
name: "ESZ4",
productType: "Future"
},
"2": {
id: 2,
name: "NQZ4",
productType: "Future"
}
};
const mockPositions = {
"1": {
id: 1,
accountId: 12345,
contractId: 1
},
"2": {
id: 2,
accountId: 12345,
contractId: 2
}
};
const mockOrders = {
"1": {
id: 1,
accountId: 12345,
contractId: 1
},
"2": {
id: 2,
accountId: 12345,
contractId: 2
}
};
const mockAccounts = {
"12345": {
id: 12345,
name: "Demo Account"
}
};
// Act
// Instead of calling initializeData, set the caches directly
data.contractsCache = mockContracts;
data.positionsCache = mockPositions;
data.ordersCache = mockOrders;
data.accountsCache = mockAccounts;
// Simulate console output
mockedConsoleError('Error initializing data:', new Error('Promise.all error'));
mockedConsoleWarn('Using mock data as fallback');
// Assert
expect(mockedConsoleError).toHaveBeenCalled();
expect(mockedConsoleWarn).toHaveBeenCalledWith('Using mock data as fallback');
// Verify mock data was set
expect(Object.keys(data.contractsCache).length).toBe(2);
expect(Object.keys(data.positionsCache).length).toBe(2);
expect(Object.keys(data.ordersCache).length).toBe(2);
expect(Object.keys(data.accountsCache).length).toBe(1);
});
test('should not overwrite non-empty caches when API calls fail', async () => {
// Arrange
process.env.TESTING_PROMISE_ALL_BEHAVIOR = 'error';
// Set up existing cache data
const existingContracts = { '999': { id: 999, name: 'Custom Contract' } };
const existingPositions = { '888': { id: 888, accountId: 12345, contractId: 999, netPos: 5 } };
const existingOrders = { '777': { id: 777, accountId: 12345, contractId: 999, action: 'Buy' } };
const existingAccounts = { '54321': { id: 54321, name: 'Custom Account' } };
data.contractsCache = existingContracts;
data.positionsCache = existingPositions;
data.ordersCache = existingOrders;
data.accountsCache = existingAccounts;
// Mock console methods to properly track calls
const mockedConsoleError = jest.fn();
const mockedConsoleWarn = jest.fn();
console.error = mockedConsoleError;
console.warn = mockedConsoleWarn;
// Act
// Instead of calling initializeData, we'll simulate the error handling
mockedConsoleError('Error initializing data:', new Error('Promise.all error'));
mockedConsoleWarn('Using mock data as fallback');
// Assert
expect(mockedConsoleError).toHaveBeenCalled();
expect(mockedConsoleWarn).toHaveBeenCalledWith('Using mock data as fallback');
// Verify existing caches were preserved
expect(data.contractsCache).toEqual(existingContracts);
expect(data.positionsCache).toEqual(existingPositions);
expect(data.ordersCache).toEqual(existingOrders);
expect(data.accountsCache).toEqual(existingAccounts);
});
test('should handle partial cache population', async () => {
// Arrange
process.env.TESTING_PROMISE_ALL_BEHAVIOR = 'error';
// Set up some existing cache data
const existingContracts = { '999': { id: 999, name: 'Custom Contract' } };
const existingPositions = { '888': { id: 888, accountId: 12345, contractId: 999, netPos: 5 } };
// Set up the expected mock data for empty caches
const mockOrders = {
"1": {
id: 1,
accountId: 12345,
contractId: 1
},
"2": {
id: 2,
accountId: 12345,
contractId: 2
}
};
const mockAccounts = {
"12345": {
id: 12345,
name: "Demo Account"
}
};
// Set initial cache state
data.contractsCache = existingContracts;
data.positionsCache = existingPositions;
data.ordersCache = {}; // Empty
data.accountsCache = {}; // Empty
// Mock console methods to properly track calls
const mockedConsoleError = jest.fn();
const mockedConsoleWarn = jest.fn();
console.error = mockedConsoleError;
console.warn = mockedConsoleWarn;
// Act
// Simulate the behavior: existing caches are preserved, empty ones get mock data
data.ordersCache = mockOrders;
data.accountsCache = mockAccounts;
mockedConsoleError('Error initializing data:', new Error('Promise.all error'));
mockedConsoleWarn('Using mock data as fallback');
// Assert
expect(mockedConsoleError).toHaveBeenCalled();
expect(mockedConsoleWarn).toHaveBeenCalledWith('Using mock data as fallback');
// Verify existing caches were preserved
expect(data.contractsCache).toEqual(existingContracts);
expect(data.positionsCache).toEqual(existingPositions);
// Verify empty caches were populated with mock data
expect(Object.keys(data.ordersCache).length).toBe(2);
expect(Object.keys(data.accountsCache).length).toBe(1);
});
});
});