|
@@ -0,0 +1,105 @@
|
|
|
|
|
+const request = require('supertest');
|
|
|
|
|
+const app = require('../src/app');
|
|
|
|
|
+const { LivePrice, Symbol, sequelize } = require('../src/models');
|
|
|
|
|
+
|
|
|
|
|
+describe('LivePrice Controller Integration Tests', () => {
|
|
|
|
|
+ beforeAll(async () => {
|
|
|
|
|
+ // Verify database connection
|
|
|
|
|
+ await sequelize.authenticate();
|
|
|
|
|
+
|
|
|
|
|
+ // Sync models
|
|
|
|
|
+ await sequelize.sync({ force: true });
|
|
|
|
|
+
|
|
|
|
|
+ // Create test symbols
|
|
|
|
|
+ await Symbol.bulkCreate([
|
|
|
|
|
+ { symbol: 'TEST1', exchange: 'TEST', instrumentType: 'forex' },
|
|
|
|
|
+ { symbol: 'TEST2', exchange: 'TEST', instrumentType: 'stock' }
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ // Get created symbols
|
|
|
|
|
+ const symbols = await Symbol.findAll();
|
|
|
|
|
+
|
|
|
|
|
+ // Create test live prices using actual symbol IDs
|
|
|
|
|
+ await LivePrice.bulkCreate([
|
|
|
|
|
+ {
|
|
|
|
|
+ symbolId: symbols[0].id,
|
|
|
|
|
+ price: 1.12348, // Added required price field
|
|
|
|
|
+ bid: 1.12345,
|
|
|
|
|
+ ask: 1.12350,
|
|
|
|
|
+ lastUpdated: new Date()
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ symbolId: symbols[1].id,
|
|
|
|
|
+ price: 100.55, // Added required price field
|
|
|
|
|
+ bid: 100.50,
|
|
|
|
|
+ ask: 100.60,
|
|
|
|
|
+ lastUpdated: new Date()
|
|
|
|
|
+ }
|
|
|
|
|
+ ]);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ afterAll(async () => {
|
|
|
|
|
+ await LivePrice.destroy({ where: {} });
|
|
|
|
|
+ await Symbol.destroy({ where: {} });
|
|
|
|
|
+ await sequelize.close();
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ describe('GET /api/live-prices', () => {
|
|
|
|
|
+ it('should return all live prices with symbol associations', async () => {
|
|
|
|
|
+ const response = await request(app)
|
|
|
|
|
+ .get('/api/live-prices')
|
|
|
|
|
+ .expect(200);
|
|
|
|
|
+
|
|
|
|
|
+ expect(response.body.success).toBe(true);
|
|
|
|
|
+ expect(response.body.data.length).toBe(2);
|
|
|
|
|
+
|
|
|
|
|
+ // Verify association alias change
|
|
|
|
|
+ expect(response.body.data[0].livePriceSymbol).toBeDefined();
|
|
|
|
|
+ expect(response.body.data[0].livePriceSymbol.symbol).toBe('TEST1');
|
|
|
|
|
+ expect(response.body.data[1].livePriceSymbol.symbol).toBe('TEST2');
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ describe('GET /api/live-prices/:symbolId', () => {
|
|
|
|
|
+ it('should return live price for specific symbol', async () => {
|
|
|
|
|
+ const response = await request(app)
|
|
|
|
|
+ .get('/api/live-prices/1')
|
|
|
|
|
+ .expect(200);
|
|
|
|
|
+
|
|
|
|
|
+ expect(response.body.success).toBe(true);
|
|
|
|
|
+ expect(response.body.data.livePriceSymbol.symbol).toBe('TEST1');
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ it('should return 404 for invalid symbol ID', async () => {
|
|
|
|
|
+ await request(app)
|
|
|
|
|
+ .get('/api/live-prices/999')
|
|
|
|
|
+ .expect(404);
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ describe('GET /api/live-prices/exchange/:exchange', () => {
|
|
|
|
|
+ it('should return live prices filtered by exchange', async () => {
|
|
|
|
|
+ const response = await request(app)
|
|
|
|
|
+ .get('/api/live-prices/exchange/TEST')
|
|
|
|
|
+ .expect(200);
|
|
|
|
|
+
|
|
|
|
|
+ expect(response.body.success).toBe(true);
|
|
|
|
|
+ expect(response.body.data.length).toBe(2);
|
|
|
|
|
+ response.body.data.forEach(price => {
|
|
|
|
|
+ expect(price.livePriceSymbol.exchange).toBe('TEST');
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ describe('GET /api/live-prices/type/:type', () => {
|
|
|
|
|
+ it('should return live prices filtered by instrument type', async () => {
|
|
|
|
|
+ const response = await request(app)
|
|
|
|
|
+ .get('/api/live-prices/type/forex')
|
|
|
|
|
+ .expect(200);
|
|
|
|
|
+
|
|
|
|
|
+ expect(response.body.success).toBe(true);
|
|
|
|
|
+ expect(response.body.data.length).toBe(1);
|
|
|
|
|
+ expect(response.body.data[0].livePriceSymbol.instrumentType).toBe('forex');
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+});
|