@Tags(['alpaca']) library; import 'package:cyberhybridhub_server/alpaca/alpaca_env.dart'; import 'package:cyberhybridhub_server/alpaca/alpaca_models.dart'; import 'package:cyberhybridhub_server/alpaca/alpaca_trading_client.dart'; import 'package:dotenv/dotenv.dart'; import 'package:test/test.dart'; void main() { late AlpacaEnv env; AlpacaTradingClient? client; setUpAll(() { final DotEnv dotenv = DotEnv(includePlatformEnvironment: true) ..load(['.env']); const List alpacaKeys = [ 'ALPACA_API_KEY_ID', 'ALPACA_API_SECRET_KEY', 'ALPACA_TRADING_BASE_URL', 'ALPACA_DATA_BASE_URL', 'ALPACA_DATA_FEED', 'ALPACA_ALLOW_LIVE', ]; final Map envMap = { for (final String key in alpacaKeys) if (dotenv[key] != null && dotenv[key]!.isNotEmpty) key: dotenv[key]!, }; env = AlpacaEnv.fromMap(envMap); if (env.hasCredentials) { client = AlpacaTradingClient(env: env); } }); tearDownAll(() { client?.close(); }); test('paper submitOrder + getOrderByClientOrderId roundtrip', () async { if (!env.hasCredentials) { markTestSkipped( 'Set ALPACA_API_KEY_ID and ALPACA_API_SECRET_KEY in server/.env', ); return; } // Refuse only on the *exact* live host. Substring matching breaks for // paper-api.alpaca.markets (which includes "api.alpaca.markets"). final Uri tradingUri = Uri.parse(env.tradingBaseUrl); if (tradingUri.host == AlpacaEnv.liveTradingHost && !env.allowLive) { markTestSkipped( 'Refusing to run live test on live trading host ' '(${tradingUri.host}) without ALPACA_ALLOW_LIVE=true', ); return; } final String clientOrderId = 'live-test-${DateTime.now().toUtc().millisecondsSinceEpoch}'; final AlpacaOrderResponse submitted = await client!.submitOrder( AlpacaOrderRequest( symbol: 'SPY', side: 'buy', type: 'market', timeInForce: 'day', clientOrderId: clientOrderId, notional: 1, ), ); expect(submitted.id, isNotEmpty); expect(submitted.clientOrderId, clientOrderId); final AlpacaOrderResponse? fetched = await client!.getOrderByClientOrderId(clientOrderId); expect(fetched, isNotNull); expect(fetched!.id, submitted.id); }, timeout: const Timeout(Duration(seconds: 30))); }