aprs.me/test/assets/js/map_helpers_test.ts

186 lines
No EOL
5.5 KiB
TypeScript

import { describe, test, expect, beforeEach, afterEach, vi } from 'vitest';
import {
parseTimestamp,
getTrailId,
saveMapState,
safePushEvent,
isLiveViewConnected,
getLiveSocket
} from '../../../assets/js/map_helpers';
describe('map_helpers', () => {
describe('parseTimestamp', () => {
test('returns current time for null/undefined', () => {
const before = Date.now();
const result = parseTimestamp(null);
const after = Date.now();
expect(result).toBeGreaterThanOrEqual(before);
expect(result).toBeLessThanOrEqual(after);
});
test('returns number timestamp as-is', () => {
const timestamp = 1234567890;
expect(parseTimestamp(timestamp)).toBe(timestamp);
});
test('parses string timestamp', () => {
const dateStr = '2024-01-01T00:00:00Z';
const expected = new Date(dateStr).getTime();
expect(parseTimestamp(dateStr)).toBe(expected);
});
test('returns current time for invalid input', () => {
const before = Date.now();
const result = parseTimestamp({});
const after = Date.now();
expect(result).toBeGreaterThanOrEqual(before);
expect(result).toBeLessThanOrEqual(after);
});
});
describe('getTrailId', () => {
test('prioritizes callsign_group', () => {
const data = {
callsign_group: 'GROUP-1',
callsign: 'CALL-1',
id: 'ID-1'
};
expect(getTrailId(data)).toBe('GROUP-1');
});
test('falls back to callsign when no callsign_group', () => {
const data = {
callsign: 'CALL-1',
id: 'ID-1'
};
expect(getTrailId(data)).toBe('CALL-1');
});
test('falls back to id when no callsign_group or callsign', () => {
const data = {
id: 'ID-1'
};
expect(getTrailId(data)).toBe('ID-1');
});
});
describe('saveMapState', () => {
let mockMap: any;
let mockPushEvent: any;
beforeEach(() => {
// Mock localStorage
const localStorageMock = {
setItem: vi.fn()
};
Object.defineProperty(window, 'localStorage', {
value: localStorageMock,
writable: true
});
// Mock map object
mockMap = {
getCenter: vi.fn().mockReturnValue({ lat: 40.7128, lng: -74.0060 }),
getZoom: vi.fn().mockReturnValue(10),
getBounds: vi.fn().mockReturnValue({
getNorth: vi.fn().mockReturnValue(41.0),
getSouth: vi.fn().mockReturnValue(40.0),
getEast: vi.fn().mockReturnValue(-73.0),
getWest: vi.fn().mockReturnValue(-75.0)
})
};
mockPushEvent = vi.fn();
});
test('saves truncated coordinates to localStorage', () => {
saveMapState(mockMap, mockPushEvent);
expect(localStorage.setItem).toHaveBeenCalledWith(
'aprs_map_state',
JSON.stringify({ lat: 40.7128, lng: -74.006, zoom: 10 })
);
});
test('pushes event with map state and bounds', () => {
saveMapState(mockMap, mockPushEvent);
expect(mockPushEvent).toHaveBeenCalledWith('update_map_state', {
center: { lat: 40.7128, lng: -74.006 },
zoom: 10,
bounds: {
north: 41.0,
south: 40.0,
east: -73.0,
west: -75.0
}
});
});
test('truncates coordinates to 5 decimal places', () => {
mockMap.getCenter.mockReturnValue({ lat: 40.71281234567, lng: -74.00601234567 });
saveMapState(mockMap, mockPushEvent);
const call = mockPushEvent.mock.calls[0][1];
expect(call.center.lat).toBe(40.71281);
expect(call.center.lng).toBe(-74.00601);
});
});
describe('safePushEvent', () => {
test('calls pushEvent and returns true on success', () => {
const mockPushEvent = vi.fn();
const result = safePushEvent(mockPushEvent, 'test_event', { data: 'test' });
expect(mockPushEvent).toHaveBeenCalledWith('test_event', { data: 'test' });
expect(result).toBe(true);
});
test('returns false when pushEvent is undefined', () => {
const result = safePushEvent(undefined, 'test_event', { data: 'test' });
expect(result).toBe(false);
});
test('catches error and returns false', () => {
const mockPushEvent = vi.fn().mockImplementation(() => {
throw new Error('LiveView not connected');
});
const consoleSpy = vi.spyOn(console, 'debug').mockImplementation(() => {});
const result = safePushEvent(mockPushEvent, 'test_event', { data: 'test' });
expect(result).toBe(false);
expect(consoleSpy).toHaveBeenCalledWith('Unable to send test_event event - LiveView disconnected');
consoleSpy.mockRestore();
});
});
describe('LiveView socket helpers', () => {
afterEach(() => {
// Clean up window.liveSocket
delete (window as any).liveSocket;
});
test('isLiveViewConnected returns true when socket exists', () => {
(window as any).liveSocket = { connected: true };
expect(isLiveViewConnected()).toBe(true);
});
test('isLiveViewConnected returns false when socket missing', () => {
expect(isLiveViewConnected()).toBe(false);
});
test('getLiveSocket returns the socket', () => {
const mockSocket = { connected: true, pushHistoryPatch: vi.fn() };
(window as any).liveSocket = mockSocket;
expect(getLiveSocket()).toBe(mockSocket);
});
test('getLiveSocket returns undefined when missing', () => {
expect(getLiveSocket()).toBeUndefined();
});
});
});