Skip to content

Commit 6e20d88

Browse files
test(e2e): fix candle chart tests and add multi-exchange tests
- Fix data loading mock in candle-chart.spec.ts - Add new multi-exchange.spec.ts - Update CandleChart.svelte to support testability
1 parent b44ed44 commit 6e20d88

3 files changed

Lines changed: 128 additions & 25 deletions

File tree

e2e-tests/candle-chart.spec.ts

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,22 @@ async function showChart(page: any) {
1111

1212
test.describe('CandleChart E2E Tests', () => {
1313
test.beforeEach(async ({ page }) => {
14-
// Navegar para a página com o componente CandleChart
14+
// Setup API route interception BEFORE navigation
15+
// This ensures the mock is ready when the chart loads data
16+
await page.route('**/api.binance.com/api/v3/klines**', async route => {
17+
const mockData = [
18+
[1625097600000, "50000", "51000", "49000", "50500"],
19+
[1625097660000, "50500", "52000", "50000", "51500"],
20+
[1625097720000, "51500", "53000", "51000", "52000"]
21+
];
22+
23+
await route.fulfill({
24+
contentType: 'application/json',
25+
body: JSON.stringify(mockData)
26+
});
27+
});
28+
29+
// Now navigate to the page with the route already set up
1530
await page.goto('./');
1631
});
1732

@@ -24,29 +39,28 @@ test.describe('CandleChart E2E Tests', () => {
2439
});
2540

2641
test('deve carregar dados históricos', async ({ page }) => {
27-
// Interceptar chamadas para a API da Binance
28-
await page.route('**/api.binance.com/api/v3/klines**', async route => {
29-
const mockData = [
30-
[1625097600000, "50000", "51000", "49000", "50500"],
31-
[1625097660000, "50500", "52000", "50000", "51500"],
32-
[1625097720000, "51500", "53000", "51000", "52000"]
33-
];
42+
// Track if the API was called
43+
let apiCalled = false;
3444

35-
await route.fulfill({
36-
contentType: 'application/json',
37-
body: JSON.stringify(mockData)
38-
});
45+
// Set up a listener for the specific API call
46+
page.on('request', request => {
47+
if (request.url().includes('api.binance.com/api/v3/klines')) {
48+
apiCalled = true;
49+
}
3950
});
4051

41-
// Verificar se a requisição foi feita
42-
const [response] = await Promise.all([
43-
page.waitForResponse(response =>
44-
response.url().includes('api.binance.com/api/v3/klines') && response.status() === 200
45-
),
46-
showChart(page)
47-
]);
52+
// Wait for the chart to load - the beforeEach already set up the route mock
53+
await showChart(page);
54+
55+
// Wait a bit for the async data loading to complete
56+
await page.waitForTimeout(2000);
4857

49-
expect(response.ok()).toBeTruthy();
58+
// Verify the API was called
59+
expect(apiCalled).toBeTruthy();
60+
61+
// Verify the chart container is visible (data loaded successfully)
62+
const chartContainer = page.locator('div[class*="min-h-[500px]"]');
63+
await expect(chartContainer).toBeVisible();
5064
});
5165

5266
test.skip('deve estabelecer conexão WebSocket', async ({ page }) => {
@@ -154,11 +168,18 @@ test.describe('CandleChart E2E Tests', () => {
154168
});
155169

156170
test('deve lidar com erros de rede graciosamente', async ({ page }) => {
171+
// Create a new page context to avoid route conflicts
172+
// We need to set up the error route BEFORE navigating
173+
await page.unroute('**/api.binance.com/api/v3/klines**');
174+
157175
// Simular erro na API da Binance
158176
await page.route('**/api.binance.com/api/v3/klines**', async route => {
159177
await route.abort('failed');
160178
});
161179

180+
// Navigate to trigger a fresh load with the error route
181+
await page.goto('./');
182+
162183
// Capturar erros do console
163184
const errors: string[] = [];
164185
page.on('console', msg => {

e2e-tests/multi-exchange.spec.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { test, expect } from '@playwright/test';
2+
3+
test.describe('Multi-Exchange Support', () => {
4+
test.beforeEach(async ({ page }) => {
5+
await page.goto('./');
6+
await page.waitForLoadState('domcontentloaded');
7+
});
8+
9+
test('should display exchange selector and spread monitor', async ({ page }) => {
10+
// Check for Exchange Selector
11+
const binanceButton = page.getByRole('button', { name: 'Binance' });
12+
const bitgetButton = page.getByRole('button', { name: 'Bitget' });
13+
14+
await expect(binanceButton).toBeVisible();
15+
await expect(bitgetButton).toBeVisible();
16+
17+
// Check for Spread Monitor
18+
const spreadMonitor = page.locator('text=Arbitrage Monitor');
19+
await expect(spreadMonitor).toBeVisible();
20+
21+
// Check for price rows
22+
await expect(page.locator('text=Binance:')).toBeVisible();
23+
await expect(page.locator('text=Bitget:')).toBeVisible();
24+
await expect(page.locator('text=Spread:')).toBeVisible();
25+
});
26+
27+
test('should switch exchanges', async ({ page }) => {
28+
// Default should be Binance
29+
const binanceButton = page.getByRole('button', { name: 'Binance' });
30+
await expect(binanceButton).toHaveClass(/bg-blue-600/);
31+
32+
// Switch to Bitget
33+
const bitgetButton = page.getByRole('button', { name: 'Bitget' });
34+
await bitgetButton.click();
35+
36+
// Verify Bitget is active
37+
await expect(bitgetButton).toHaveClass(/bg-blue-600/);
38+
await expect(binanceButton).not.toHaveClass(/bg-blue-600/);
39+
40+
// Verify chart reloads (mocking might be needed for full verification, but we check UI state)
41+
// We can check if localStorage was updated
42+
const storedExchange = await page.evaluate(() => localStorage.getItem('selected_exchange'));
43+
expect(storedExchange).toBe('bitget');
44+
});
45+
46+
test('should persist exchange selection', async ({ page }) => {
47+
// Select Bitget
48+
await page.getByRole('button', { name: 'Bitget' }).click();
49+
50+
// Reload page
51+
await page.reload();
52+
53+
// Verify Bitget is still selected
54+
const bitgetButton = page.getByRole('button', { name: 'Bitget' });
55+
await expect(bitgetButton).toHaveClass(/bg-blue-600/);
56+
});
57+
});

src/components/CandleChart.svelte

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import { IndicatorService } from "./chart/services/indicatorService";
1616
import { DataService } from "./chart/services/dataService";
1717
import type { IndicatorState, DrawingMode } from "./chart/types";
18+
import { selectedExchange } from "../lib/config/exchangeConfig";
1819
1920
// Props
2021
export let symbol = "BTCUSDT";
@@ -67,11 +68,23 @@
6768
if (chartService) {
6869
const candleSeries = chartService.getCandleSeries();
6970
if (candleSeries) {
70-
candleSeries.update(candle);
71-
chartService.getDrawingService()?.updateLastCandle(candle);
71+
// Safety check: ensure we don't update with older data
72+
if (
73+
lastCandle &&
74+
(candle.time as number) < (lastCandle.time as number)
75+
) {
76+
return;
77+
}
78+
79+
try {
80+
candleSeries.update(candle);
81+
chartService.getDrawingService()?.updateLastCandle(candle);
82+
lastCandle = candle;
83+
} catch (error) {
84+
console.error("Error updating chart:", error);
85+
}
7286
}
7387
}
74-
lastCandle = candle;
7588
7689
// Update indicators with new candle data
7790
updateIndicators();
@@ -98,7 +111,11 @@
98111
dataService = new DataService(handleNewCandle, handleConnectionStatus);
99112
100113
// Load Data
101-
const data = await dataService.loadHistoricalData(symbol, interval);
114+
const data = await dataService.loadHistoricalData(
115+
symbol,
116+
interval,
117+
$selectedExchange,
118+
);
102119
if (chartService && chartService.getCandleSeries()) {
103120
chartService.getCandleSeries()?.setData(data);
104121
if (data.length > 0) lastCandle = data[data.length - 1];
@@ -133,7 +150,7 @@
133150
}
134151
135152
// Connect WebSocket
136-
dataService.connectWebSocket(symbol, interval);
153+
dataService.connectWebSocket(symbol, interval, $selectedExchange);
137154
isLoading = false;
138155
}
139156
@@ -261,6 +278,14 @@
261278
setTimeout(init, 0);
262279
}
263280
281+
// React to exchange changes
282+
let previousExchange = $selectedExchange;
283+
$: if ($selectedExchange !== previousExchange) {
284+
previousExchange = $selectedExchange;
285+
cleanup();
286+
setTimeout(init, 0);
287+
}
288+
264289
// Theme observer
265290
onMount(() => {
266291
init();

0 commit comments

Comments
 (0)