BREAKING CHANGE(stocks): Unify stock provider API to discriminated IStockDataRequest and add company name/fullname enrichment
This commit is contained in:
@@ -151,7 +151,7 @@ tap.test('should handle invalid ticker gracefully', async () => {
|
||||
await stockService.getPrice({ ticker: invalidTicker });
|
||||
throw new Error('Should have thrown an error for invalid ticker');
|
||||
} catch (error) {
|
||||
expect(error.message).toInclude('Failed to fetch price');
|
||||
expect(error.message).toInclude('Failed to fetch');
|
||||
console.log('✓ Invalid ticker handled correctly');
|
||||
}
|
||||
});
|
||||
@@ -215,19 +215,20 @@ tap.test('should test direct provider methods', async () => {
|
||||
expect(available).toEqual(true);
|
||||
console.log(' ✓ isAvailable() returned true');
|
||||
|
||||
// Test fetchPrice directly
|
||||
const price = await marketstackProvider.fetchPrice({ ticker: 'MSFT' });
|
||||
// Test fetchData for single ticker
|
||||
const price = await marketstackProvider.fetchData({ type: 'current', ticker: 'MSFT' }) as opendata.IStockPrice;
|
||||
expect(price.ticker).toEqual('MSFT');
|
||||
expect(price.provider).toEqual('Marketstack');
|
||||
expect(price.price).toBeGreaterThan(0);
|
||||
console.log(` ✓ fetchPrice() for MSFT: $${price.price}`);
|
||||
console.log(` ✓ fetchData (current) for MSFT: $${price.price}`);
|
||||
|
||||
// Test fetchPrices directly
|
||||
const prices = await marketstackProvider.fetchPrices({
|
||||
// Test fetchData for batch
|
||||
const prices = await marketstackProvider.fetchData({
|
||||
type: 'batch',
|
||||
tickers: ['AAPL', 'GOOGL']
|
||||
});
|
||||
}) as opendata.IStockPrice[];
|
||||
expect(prices.length).toBeGreaterThan(0);
|
||||
console.log(` ✓ fetchPrices() returned ${prices.length} prices`);
|
||||
console.log(` ✓ fetchData (batch) returned ${prices.length} prices`);
|
||||
|
||||
for (const p of prices) {
|
||||
console.log(` ${p.ticker}: $${p.price}`);
|
||||
@@ -252,9 +253,10 @@ tap.test('should fetch sample EOD data', async () => {
|
||||
];
|
||||
|
||||
try {
|
||||
const prices = await marketstackProvider.fetchPrices({
|
||||
const prices = await marketstackProvider.fetchData({
|
||||
type: 'batch',
|
||||
tickers: sampleTickers.map(t => t.ticker)
|
||||
});
|
||||
}) as opendata.IStockPrice[];
|
||||
|
||||
const priceMap = new Map(prices.map(p => [p.ticker, p]));
|
||||
|
||||
@@ -452,4 +454,119 @@ tap.test('should verify smart caching with historical data', async () => {
|
||||
console.log(`✓ Speed improvement: ${Math.round((duration1 / duration2) * 10) / 10}x faster`);
|
||||
});
|
||||
|
||||
// Company Name Feature Tests
|
||||
|
||||
tap.test('should include company name in single price request', async () => {
|
||||
if (!marketstackProvider) {
|
||||
console.log('⚠️ Skipping - Marketstack provider not initialized');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('\n🏢 Testing Company Name Feature: Single Request');
|
||||
|
||||
const price = await stockService.getPrice({ ticker: 'AAPL' });
|
||||
|
||||
expect(price.companyName).not.toEqual(undefined);
|
||||
expect(typeof price.companyName).toEqual('string');
|
||||
expect(price.companyName).toInclude('Apple');
|
||||
|
||||
console.log(`✓ Company name retrieved: "${price.companyName}"`);
|
||||
console.log(` Ticker: ${price.ticker}`);
|
||||
console.log(` Price: $${price.price}`);
|
||||
console.log(` Company: ${price.companyName}`);
|
||||
});
|
||||
|
||||
tap.test('should include company names in batch price request', async () => {
|
||||
if (!marketstackProvider) {
|
||||
console.log('⚠️ Skipping - Marketstack provider not initialized');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('\n🏢 Testing Company Name Feature: Batch Request');
|
||||
|
||||
const prices = await stockService.getPrices({
|
||||
tickers: ['AAPL', 'MSFT', 'GOOGL']
|
||||
});
|
||||
|
||||
expect(prices).toBeArray();
|
||||
expect(prices.length).toBeGreaterThan(0);
|
||||
|
||||
console.log(`✓ Fetched ${prices.length} prices with company names:`);
|
||||
|
||||
for (const price of prices) {
|
||||
expect(price.companyName).not.toEqual(undefined);
|
||||
expect(typeof price.companyName).toEqual('string');
|
||||
console.log(` ${price.ticker.padEnd(6)} - ${price.companyName}`);
|
||||
}
|
||||
});
|
||||
|
||||
tap.test('should include company name in historical data', async () => {
|
||||
if (!marketstackProvider) {
|
||||
console.log('⚠️ Skipping - Marketstack provider not initialized');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('\n🏢 Testing Company Name Feature: Historical Data');
|
||||
|
||||
const prices = await stockService.getData({
|
||||
type: 'historical',
|
||||
ticker: 'TSLA',
|
||||
from: new Date('2025-10-01'),
|
||||
to: new Date('2025-10-05')
|
||||
});
|
||||
|
||||
expect(prices).toBeArray();
|
||||
const historicalPrices = prices as opendata.IStockPrice[];
|
||||
expect(historicalPrices.length).toBeGreaterThan(0);
|
||||
|
||||
// All historical records should have the same company name
|
||||
for (const price of historicalPrices) {
|
||||
expect(price.companyName).not.toEqual(undefined);
|
||||
expect(typeof price.companyName).toEqual('string');
|
||||
}
|
||||
|
||||
const firstPrice = historicalPrices[0];
|
||||
console.log(`✓ Historical records include company name: "${firstPrice.companyName}"`);
|
||||
console.log(` Ticker: ${firstPrice.ticker}`);
|
||||
console.log(` Records: ${historicalPrices.length}`);
|
||||
console.log(` Date range: ${historicalPrices[historicalPrices.length - 1].timestamp.toISOString().split('T')[0]} to ${firstPrice.timestamp.toISOString().split('T')[0]}`);
|
||||
});
|
||||
|
||||
tap.test('should verify company name is included with zero extra API calls', async () => {
|
||||
if (!marketstackProvider) {
|
||||
console.log('⚠️ Skipping - Marketstack provider not initialized');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('\n⚡ Testing Company Name Efficiency: Zero Extra API Calls');
|
||||
|
||||
// Clear cache to ensure we're making fresh API calls
|
||||
stockService.clearCache();
|
||||
|
||||
// Single request timing
|
||||
const start1 = Date.now();
|
||||
const singlePrice = await stockService.getPrice({ ticker: 'AMZN' });
|
||||
const duration1 = Date.now() - start1;
|
||||
|
||||
expect(singlePrice.companyName).not.toEqual(undefined);
|
||||
|
||||
// Batch request timing
|
||||
stockService.clearCache();
|
||||
const start2 = Date.now();
|
||||
const batchPrices = await stockService.getPrices({ tickers: ['NVDA', 'AMD', 'INTC'] });
|
||||
const duration2 = Date.now() - start2;
|
||||
|
||||
for (const price of batchPrices) {
|
||||
expect(price.companyName).not.toEqual(undefined);
|
||||
}
|
||||
|
||||
console.log(`✓ Single request (with company name): ${duration1}ms`);
|
||||
console.log(`✓ Batch request (with company names): ${duration2}ms`);
|
||||
console.log(`✓ Company names included in standard EOD response - zero extra calls!`);
|
||||
console.log(` Single: ${singlePrice.ticker} - "${singlePrice.companyName}"`);
|
||||
for (const price of batchPrices) {
|
||||
console.log(` Batch: ${price.ticker} - "${price.companyName}"`);
|
||||
}
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
|
||||
Reference in New Issue
Block a user