test(api): align market data contract checks

This commit is contained in:
root 2026-05-06 07:08:18 +00:00
parent 3d505db8d8
commit f57f0fc205

View File

@ -64,7 +64,7 @@ function testChartBarsContract() {
'/api/chart/bars must reject missing symbols',
);
assertSourceMatches(
/this\.app\.get\('\/api\/chart\/bars'[\s\S]*Alpaca credentials not configured/,
/this\.app\.get\('\/api\/chart\/bars'[\s\S]*getUserMarketDataAlpacaCredentials\(authUserId\)[\s\S]*if \(error instanceof MissingServiceConfigError\)[\s\S]*status\(503\)\.json\(\{ error: error\.message \}\)/,
'/api/chart/bars must fail closed when Alpaca credentials are absent',
);
@ -156,26 +156,18 @@ function testFmpProxyContracts() {
"import { fetchFmpJson, FmpFetchError } from './fmpCache.js';",
'FMP routes must use the shared cache helper and typed upstream error',
);
assertConfigIncludes(
"FMP_API_KEY: process.env.FMP_API_KEY || '',",
'FMP config must not silently default to the shared demo key',
);
assertSourceIncludes(
"apiKey.toLowerCase() === 'demo'",
'FMP routes must reject the shared demo key explicitly',
);
assertSourceIncludes(
'FMP_API_KEY is required for research and screener endpoints',
'FMP routes must surface an explicit missing-key error',
'User FMP API key is required for research and screener endpoints',
'FMP routes must surface an explicit per-user missing-key error',
);
const fetchFmpCalls = apiServerSource.match(/fetchFmpJson\(url\)/g) ?? [];
assert.equal(fetchFmpCalls.length, 4, 'each FMP route must fetch through fetchFmpJson(url)');
for (const [route, endpoint, errorMessage] of [
['/api/research/profile', '/api/v3/profile/${symbol}?apikey=${apiKey}', 'FMP profile fetch failed'],
['/api/research/metrics', '/api/v3/key-metrics/${symbol}?limit=4&apikey=${apiKey}', 'FMP metrics fetch failed'],
['/api/research/earnings', '/api/v3/historical/earning_calendar/${symbol}?limit=8&apikey=${apiKey}', 'FMP earnings fetch failed'],
['/api/research/profile', 'https://financialmodelingprep.com/stable/profile?symbol=${encodeURIComponent(symbol)}&apikey=${apiKey}', 'FMP profile fetch failed'],
['/api/research/metrics', 'https://financialmodelingprep.com/stable/key-metrics?symbol=${encodeURIComponent(symbol)}&limit=4&apikey=${apiKey}', 'FMP metrics fetch failed'],
['/api/research/earnings', 'https://financialmodelingprep.com/stable/earnings-calendar?symbol=${encodeURIComponent(symbol)}&limit=8&apikey=${apiKey}', 'FMP earnings fetch failed'],
]) {
assertSourceMatches(
new RegExp(`this\\.app\\.get\\('${escapeRegExp(route)}'[\\s\\S]*if \\(!symbol\\)[\\s\\S]*status\\(400\\)\\.json\\(\\{ error: 'symbol required' \\}\\)`),
@ -194,8 +186,8 @@ function testFmpProxyContracts() {
'/api/research/earnings must normalize to an earnings array wrapper',
);
assertSourceIncludes(
'https://financialmodelingprep.com/api/v3/stock-screener?${qs.toString()}',
'/api/screener must call FMP stock-screener',
'https://financialmodelingprep.com/stable/company-screener?${qs.toString()}',
'/api/screener must call FMP stable company-screener',
);
assertSourceIncludes(
'const ALLOWED_SCREENER_SECTORS = new Set([',