91 lines
4.0 KiB
TypeScript
91 lines
4.0 KiB
TypeScript
// @vitest-environment jsdom
|
||
import { beforeEach, afterEach, describe, expect, it, vi } from 'vitest';
|
||
import { render, screen } from '@testing-library/react';
|
||
import { AlertFeed } from './AlertFeed';
|
||
|
||
describe('AlertFeed DOM behavior', () => {
|
||
beforeEach(() => {
|
||
vi.useFakeTimers();
|
||
vi.setSystemTime(new Date('2026-02-17T12:00:00Z'));
|
||
});
|
||
|
||
afterEach(() => {
|
||
vi.useRealTimers();
|
||
});
|
||
|
||
it('renders recent activity header', () => {
|
||
render(<AlertFeed alerts={[]} />);
|
||
expect(screen.getByText('Recent Activity')).toBeInTheDocument();
|
||
});
|
||
|
||
it('renders different alert types with correct icons', () => {
|
||
const alerts: any[] = [
|
||
{ timestamp: Date.now(), type: 'signal', symbol: 'BTC', message: 'Signal Alert' },
|
||
{ timestamp: Date.now(), type: 'pulse', symbol: 'ETH', message: 'Pulse Alert' },
|
||
{ timestamp: Date.now(), type: 'error', symbol: 'SOL', message: 'Error Alert' },
|
||
{ timestamp: Date.now(), type: 'info', symbol: 'ADA', message: 'Info Alert' }
|
||
];
|
||
|
||
render(<AlertFeed alerts={alerts} />);
|
||
|
||
expect(screen.getByText('🚀')).toBeInTheDocument();
|
||
expect(screen.getByText('⏰')).toBeInTheDocument();
|
||
expect(screen.getByText('⚠️')).toBeInTheDocument();
|
||
expect(screen.getByText('ℹ️')).toBeInTheDocument();
|
||
|
||
expect(screen.getByText('Signal Alert')).toBeInTheDocument();
|
||
expect(screen.getByText('Pulse Alert')).toBeInTheDocument();
|
||
expect(screen.getByText('Error Alert')).toBeInTheDocument();
|
||
expect(screen.getByText('Info Alert')).toBeInTheDocument();
|
||
});
|
||
|
||
it('displays relative time correctly (just now)', () => {
|
||
const alerts: any[] = [{ timestamp: Date.now(), type: 'info', symbol: 'BTC', message: 'test' }];
|
||
render(<AlertFeed alerts={alerts} />);
|
||
expect(screen.getByText('just now')).toBeInTheDocument();
|
||
});
|
||
|
||
it('displays relative time correctly (minutes ago)', () => {
|
||
const alerts: any[] = [{ timestamp: Date.now() - 5 * 60000, type: 'info', symbol: 'BTC', message: 'test' }];
|
||
render(<AlertFeed alerts={alerts} />);
|
||
expect(screen.getByText('5m ago')).toBeInTheDocument();
|
||
});
|
||
|
||
it('displays relative time correctly (hours ago)', () => {
|
||
const alerts: any[] = [{ timestamp: Date.now() - 3 * 3600000, type: 'info', symbol: 'BTC', message: 'test' }];
|
||
render(<AlertFeed alerts={alerts} />);
|
||
expect(screen.getByText('3h ago')).toBeInTheDocument();
|
||
});
|
||
|
||
it('displays relative time correctly (days ago)', () => {
|
||
const alerts: any[] = [{ timestamp: Date.now() - 2 * 86400000, type: 'info', symbol: 'BTC', message: 'test' }];
|
||
render(<AlertFeed alerts={alerts} />);
|
||
expect(screen.getByText('2d ago')).toBeInTheDocument();
|
||
});
|
||
|
||
it('limits alerts to 50 items and reverses order', () => {
|
||
// Since AlertFeed does .reverse().slice(0, 50),
|
||
// if we want SYM0 to be the first one visible (most recent),
|
||
// it should be at the END of the input array.
|
||
const alerts = Array.from({ length: 60 }, (_, i) => ({
|
||
timestamp: Date.now() - (60 - i) * 1000,
|
||
type: 'info' as const,
|
||
symbol: `SYM${i}`,
|
||
message: `Msg ${i}`
|
||
}));
|
||
|
||
const { container } = render(<AlertFeed alerts={alerts} />);
|
||
|
||
// Should only show 50 items
|
||
const alertItems = container.querySelectorAll('.alert-item');
|
||
expect(alertItems.length).toBe(50);
|
||
|
||
// After reverse, SYM59 should be first (it was at the end and has largest timestamp in this mock data)
|
||
expect(screen.getByText('SYM59')).toBeInTheDocument();
|
||
// SYM10 should be the last visible one (50th item)
|
||
expect(screen.getByText('SYM10')).toBeInTheDocument();
|
||
// SYM9 should not be visible (it's at index 9, so it would be at index 50 after reverse)
|
||
expect(screen.queryByText('SYM9')).not.toBeInTheDocument();
|
||
});
|
||
});
|