MotorSignal-App/website/tests/operations-speedtest.test.tsx

265 lines
9.5 KiB
TypeScript

import React from 'react';
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { OperationsInfrastructure } from '../components/ops/operations-infrastructure';
describe('OperationsInfrastructure Speedtest Options Component Tests', () => {
const originalFetch = global.fetch;
beforeEach(() => {
vi.restoreAllMocks();
});
afterEach(() => {
global.fetch = originalFetch;
});
const mockInfraResponse = {
resources: {
cpu_percent: 12.0,
load_avg: [0.1, 0.2, 0.15],
memory: { total: 16000000000, used: 4000000000, available: 12000000000, percent: 25.0 },
swap: { total: 4000000000, used: 0, percent: 0.0 },
disk: { total: 100000000000, used: 20000000000, available: 80000000000, percent: 20.0 },
uptime_seconds: 50000,
uptime_formatted: '13h 53m',
},
services: [
{ name: 'motorsignal-website', status: 'active' },
{ name: 'motorsignal-api', status: 'active' },
{ name: 'nginx', status: 'active' },
{ name: 'postgresql', status: 'active' },
],
network: {
bytes_received: 1048576,
bytes_transmitted: 2097152,
label: 'Cumulative Total Since Boot',
},
deployment: {
git_revision: 'abcdef1234567890abcdef1234567890abcdef12',
short_revision: 'abcdef1',
revision_status: 'known',
website_health: 'available',
api_health: 'available',
},
};
it('renders both speedtest option tabs with intuitive labels', async () => {
global.fetch = vi.fn().mockImplementation((url: string) => {
if (url.includes('/api/ops/infrastructure') && !url.includes('/speedtest')) {
return Promise.resolve({
ok: true,
status: 200,
json: async () => mockInfraResponse,
});
}
return Promise.reject(new Error('Unknown URL'));
});
render(<OperationsInfrastructure role="operator" />);
// Wait for initial data load
await waitFor(() => {
expect(screen.getByText('Network Cumulative Totals')).toBeDefined();
});
// Check option 1 tab: My Connection -> MotorSignal
const clientTab = screen.getByRole('button', { name: /My Connection → MotorSignal/i });
expect(clientTab).toBeDefined();
// Check option 2 tab: MotorSignal -> Upstream Server
const serverTab = screen.getByRole('button', { name: /MotorSignal → Upstream Server/i });
expect(serverTab).toBeDefined();
// Check action button reflects client mode initially
expect(screen.getByRole('button', { name: /Run Client Speedtest/i })).toBeDefined();
// Check description mentions client to server
expect(screen.getByText(/Measures latency, download, and upload between your operator browser/i)).toBeDefined();
});
it('switches between Client to Server and Server to External tabs', async () => {
global.fetch = vi.fn().mockImplementation((url: string) => {
if (url.includes('/api/ops/infrastructure') && !url.includes('/speedtest')) {
return Promise.resolve({
ok: true,
status: 200,
json: async () => mockInfraResponse,
});
}
return Promise.reject(new Error('Unknown URL'));
});
render(<OperationsInfrastructure role="operator" />);
await waitFor(() => {
expect(screen.getByText('Network Cumulative Totals')).toBeDefined();
});
// Click Server to External tab
const serverTab = screen.getByRole('button', { name: /MotorSignal → Upstream Server/i });
fireEvent.click(serverTab);
// Check button updates to server speedtest
expect(screen.getByRole('button', { name: /Run Server Speedtest/i })).toBeDefined();
// Check description mentions upstream Cloudflare edge
expect(screen.getByText(/Measures server-side network performance from MotorSignal production host to upstream/i)).toBeDefined();
// Click back to Client to Server tab
const clientTab = screen.getByRole('button', { name: /My Connection → MotorSignal/i });
fireEvent.click(clientTab);
expect(screen.getByRole('button', { name: /Run Client Speedtest/i })).toBeDefined();
});
it('runs Server to External upstream speedtest and displays results with directional labels', async () => {
global.fetch = vi.fn().mockImplementation((url: string, opts?: RequestInit) => {
if (url.includes('/api/ops/infrastructure/speedtest')) {
return Promise.resolve({
ok: true,
status: 200,
json: async () => ({
status: 'completed',
tested_at: new Date().toISOString(),
latency_ms: 12.4,
download_mbps: 345.67,
upload_mbps: 189.23,
server_target: 'Cloudflare Edge (1.1.1.1)',
client_ip: '198.51.100.24',
mode: 'server_to_external',
direction_label: 'MotorSignal Server ➔ Upstream Edge (1.1.1.1)',
}),
});
}
if (url.includes('/api/ops/infrastructure')) {
return Promise.resolve({
ok: true,
status: 200,
json: async () => mockInfraResponse,
});
}
return Promise.reject(new Error('Unknown URL'));
});
render(<OperationsInfrastructure role="operator" />);
await waitFor(() => {
expect(screen.getByText('Network Cumulative Totals')).toBeDefined();
});
// Switch to Server to External
fireEvent.click(screen.getByRole('button', { name: /MotorSignal → Upstream Server/i }));
const runBtn = screen.getByRole('button', { name: /Run Server Speedtest/i });
fireEvent.click(runBtn);
// Verify results render
await waitFor(() => {
expect(screen.getByText('Server to External Result (MotorSignal → Upstream Server)')).toBeDefined();
expect(screen.getByText('12.4 ms')).toBeDefined();
expect(screen.getByText('345.67 Mbps')).toBeDefined();
expect(screen.getByText('189.23 Mbps')).toBeDefined();
expect(screen.getByText(/Target: Cloudflare Edge \(1.1.1.1\)/i)).toBeDefined();
expect(screen.getByText(/IP: 198.51.100.24/i)).toBeDefined();
});
});
it('runs Client to Server speedtest with ping, download, and upload phases', async () => {
global.fetch = vi.fn().mockImplementation((url: string, opts?: RequestInit) => {
if (url.includes('/api/ops/infrastructure/speedtest')) {
if (url.includes('action=ping')) {
return Promise.resolve({
ok: true,
status: 200,
json: async () => ({ status: 'ok', client_ip: '203.0.113.88' }),
});
}
if (url.includes('action=download')) {
const testBuffer = new Uint8Array(2500000);
return Promise.resolve({
ok: true,
status: 200,
headers: new Headers({ 'X-Client-IP': '203.0.113.88' }),
arrayBuffer: async () => testBuffer.buffer,
blob: async () => new Blob([testBuffer]),
});
}
if (url.includes('action=upload')) {
return Promise.resolve({
ok: true,
status: 200,
json: async () => ({ status: 'completed', received_bytes: 1500000, client_ip: '203.0.113.88' }),
});
}
if (url.includes('action=record_client_result')) {
return Promise.resolve({
ok: true,
status: 200,
json: async () => ({ status: 'completed' }),
});
}
}
if (url.includes('/api/ops/infrastructure')) {
return Promise.resolve({
ok: true,
status: 200,
json: async () => mockInfraResponse,
});
}
return Promise.reject(new Error('Unknown URL'));
});
render(<OperationsInfrastructure role="operator" />);
await waitFor(() => {
expect(screen.getByText('Network Cumulative Totals')).toBeDefined();
});
const runBtn = screen.getByRole('button', { name: /Run Client Speedtest/i });
fireEvent.click(runBtn);
// Verify results render
await waitFor(() => {
expect(screen.getByText('Client to Server Result (My Connection → MotorSignal)')).toBeDefined();
expect(screen.getByText(/Target: MotorSignal Host Edge/i)).toBeDefined();
expect(screen.getByText(/IP: 203.0.113.88/i)).toBeDefined();
expect(screen.getByText(/Route: Operator Browser ➔ MotorSignal Server/i)).toBeDefined();
});
});
it('displays error banner gracefully when speedtest fails', async () => {
global.fetch = vi.fn().mockImplementation((url: string) => {
if (url.includes('/api/ops/infrastructure/speedtest')) {
return Promise.resolve({
ok: false,
status: 503,
json: async () => ({ detail: 'Operations speedtest service temporarily unavailable.' }),
});
}
if (url.includes('/api/ops/infrastructure')) {
return Promise.resolve({
ok: true,
status: 200,
json: async () => mockInfraResponse,
});
}
return Promise.reject(new Error('Unknown URL'));
});
render(<OperationsInfrastructure role="operator" />);
await waitFor(() => {
expect(screen.getByText('Network Cumulative Totals')).toBeDefined();
});
// Run in server mode to test error
fireEvent.click(screen.getByRole('button', { name: /MotorSignal → Upstream Server/i }));
fireEvent.click(screen.getByRole('button', { name: /Run Server Speedtest/i }));
await waitFor(() => {
expect(screen.getByText(/Operations speedtest service temporarily unavailable/i)).toBeDefined();
});
});
});