198 lines
5.8 KiB
TypeScript
198 lines
5.8 KiB
TypeScript
import { test, expect, describe, beforeEach } from "bun:test";
|
|
|
|
// Simple mock function for tests
|
|
function mockFn() {
|
|
let callCount = 0;
|
|
const fn = () => { callCount++; };
|
|
|
|
Object.defineProperty(fn, 'toHaveBeenCalledTimes', {
|
|
value: (expected: number) => {
|
|
if (callCount !== expected) {
|
|
throw new Error(`Expected ${expected} calls, got ${callCount}`);
|
|
}
|
|
return true;
|
|
}
|
|
});
|
|
|
|
return fn;
|
|
}
|
|
|
|
// Mock HTML elements
|
|
class MockHTMLElement {
|
|
public textContent: string = '';
|
|
public className: string = '';
|
|
public disabled: boolean = false;
|
|
private eventListeners: { [key: string]: (() => void)[] } = {};
|
|
|
|
addEventListener(event: string, handler: () => void) {
|
|
if (!this.eventListeners[event]) {
|
|
this.eventListeners[event] = [];
|
|
}
|
|
this.eventListeners[event].push(handler);
|
|
}
|
|
|
|
click() {
|
|
const handlers = this.eventListeners['click'] || [];
|
|
handlers.forEach(handler => handler());
|
|
}
|
|
}
|
|
|
|
// Mock document.getElementById
|
|
const mockElements: { [id: string]: MockHTMLElement } = {};
|
|
const getElementByIdCalls: string[] = [];
|
|
(global as any).document = {
|
|
getElementById: (id: string) => {
|
|
getElementByIdCalls.push(id);
|
|
return mockElements[id] || null;
|
|
}
|
|
};
|
|
|
|
// Import after mocking
|
|
import { UIController } from "../../public/js/services/UIController.ts";
|
|
|
|
describe("UIController", () => {
|
|
let uiController: UIController;
|
|
let statusElement: MockHTMLElement;
|
|
let subscribersElement: MockHTMLElement;
|
|
let startButton: MockHTMLElement;
|
|
let stopButton: MockHTMLElement;
|
|
|
|
beforeEach(() => {
|
|
// Reset mock elements
|
|
statusElement = new MockHTMLElement();
|
|
subscribersElement = new MockHTMLElement();
|
|
startButton = new MockHTMLElement();
|
|
stopButton = new MockHTMLElement();
|
|
|
|
mockElements['status'] = statusElement;
|
|
mockElements['subscribers'] = subscribersElement;
|
|
mockElements['startBtn'] = startButton;
|
|
mockElements['stopBtn'] = stopButton;
|
|
|
|
// Clear call history
|
|
getElementByIdCalls.length = 0;
|
|
|
|
uiController = new UIController('status', 'subscribers', 'startBtn', 'stopBtn');
|
|
});
|
|
|
|
test("should initialize with all elements", () => {
|
|
expect(getElementByIdCalls).toContain('status');
|
|
expect(getElementByIdCalls).toContain('subscribers');
|
|
expect(getElementByIdCalls).toContain('startBtn');
|
|
expect(getElementByIdCalls).toContain('stopBtn');
|
|
});
|
|
|
|
test("should initialize with minimal elements", () => {
|
|
getElementByIdCalls.length = 0; // Clear previous calls
|
|
const minimalController = new UIController('status');
|
|
expect(getElementByIdCalls).toContain('status');
|
|
});
|
|
|
|
test("should update status correctly", () => {
|
|
uiController.updateStatus('Connected', 'connected');
|
|
|
|
expect(statusElement.textContent).toBe('Connected');
|
|
expect(statusElement.className).toBe('status connected');
|
|
});
|
|
|
|
test("should update subscribers count", () => {
|
|
uiController.updateSubscribersCount(5);
|
|
|
|
expect(subscribersElement.textContent).toBe('Subscribers: 5');
|
|
});
|
|
|
|
test("should handle missing subscribers element", () => {
|
|
const controllerWithoutSubs = new UIController('status');
|
|
|
|
expect(() => {
|
|
controllerWithoutSubs.updateSubscribersCount(5);
|
|
}).not.toThrow();
|
|
});
|
|
|
|
test("should set button states", () => {
|
|
uiController.setButtonStates(false, true);
|
|
|
|
expect(startButton.disabled).toBe(true);
|
|
expect(stopButton.disabled).toBe(false);
|
|
|
|
uiController.setButtonStates(true, false);
|
|
|
|
expect(startButton.disabled).toBe(false);
|
|
expect(stopButton.disabled).toBe(true);
|
|
});
|
|
|
|
test("should handle missing buttons", () => {
|
|
const controllerWithoutButtons = new UIController('status');
|
|
|
|
expect(() => {
|
|
controllerWithoutButtons.setButtonStates(true, false);
|
|
}).not.toThrow();
|
|
});
|
|
|
|
test("should add button click handlers", () => {
|
|
const startHandler = mockFn();
|
|
const stopHandler = mockFn();
|
|
|
|
uiController.onButtonClick('startBtn', startHandler);
|
|
uiController.onButtonClick('stopBtn', stopHandler);
|
|
|
|
startButton.click();
|
|
expect(startHandler.toHaveBeenCalledTimes(1)).toBe(true);
|
|
|
|
stopButton.click();
|
|
expect(stopHandler.toHaveBeenCalledTimes(1)).toBe(true);
|
|
});
|
|
|
|
test("should handle non-existent button click handlers", () => {
|
|
const handler = mockFn();
|
|
|
|
expect(() => {
|
|
uiController.onButtonClick('nonExistentBtn', handler);
|
|
}).not.toThrow();
|
|
});
|
|
|
|
test("should handle multiple clicks", () => {
|
|
const handler = mockFn();
|
|
uiController.onButtonClick('startBtn', handler);
|
|
|
|
startButton.click();
|
|
startButton.click();
|
|
startButton.click();
|
|
|
|
expect(handler.toHaveBeenCalledTimes(3)).toBe(true);
|
|
});
|
|
|
|
test("should support multiple handlers on same button", () => {
|
|
const handler1 = mockFn();
|
|
const handler2 = mockFn();
|
|
|
|
uiController.onButtonClick('startBtn', handler1);
|
|
uiController.onButtonClick('startBtn', handler2);
|
|
|
|
startButton.click();
|
|
|
|
expect(handler1.toHaveBeenCalledTimes(1)).toBe(true);
|
|
expect(handler2.toHaveBeenCalledTimes(1)).toBe(true);
|
|
});
|
|
|
|
test("should update status with different classes", () => {
|
|
uiController.updateStatus('Connecting...', 'waiting');
|
|
expect(statusElement.className).toBe('status waiting');
|
|
|
|
uiController.updateStatus('Connected', 'connected');
|
|
expect(statusElement.className).toBe('status connected');
|
|
|
|
uiController.updateStatus('Error occurred', 'error');
|
|
expect(statusElement.className).toBe('status error');
|
|
});
|
|
|
|
test("should update subscribers count with zero", () => {
|
|
uiController.updateSubscribersCount(0);
|
|
expect(subscribersElement.textContent).toBe('Subscribers: 0');
|
|
});
|
|
|
|
test("should update subscribers count with large numbers", () => {
|
|
uiController.updateSubscribersCount(1000);
|
|
expect(subscribersElement.textContent).toBe('Subscribers: 1000');
|
|
});
|
|
}); |