fixed tests
This commit is contained in:
233
tests/integration.test.ts
Normal file
233
tests/integration.test.ts
Normal file
@@ -0,0 +1,233 @@
|
||||
import { test, expect, describe, beforeEach, afterEach } from "bun:test";
|
||||
import { ClientManager } from "../src/services/ClientManager.ts";
|
||||
import { SignalingService } from "../src/services/SignalingService.ts";
|
||||
|
||||
interface MockWebSocketMessage {
|
||||
type: string;
|
||||
data?: any;
|
||||
senderId?: string;
|
||||
}
|
||||
|
||||
class MockWebSocket {
|
||||
private messageHandler: ((event: { data: string }) => void) | null = null;
|
||||
private openHandler: (() => void) | null = null;
|
||||
private closeHandler: (() => void) | null = null;
|
||||
|
||||
public sentMessages: string[] = [];
|
||||
public readyState = WebSocket.OPEN;
|
||||
public url: string;
|
||||
|
||||
constructor(url: string) {
|
||||
this.url = url;
|
||||
// Simulate connection opening
|
||||
setTimeout(() => {
|
||||
if (this.openHandler) {
|
||||
this.openHandler();
|
||||
}
|
||||
}, 10);
|
||||
}
|
||||
|
||||
send(data: string) {
|
||||
this.sentMessages.push(data);
|
||||
}
|
||||
|
||||
close() {
|
||||
this.readyState = WebSocket.CLOSED;
|
||||
if (this.closeHandler) {
|
||||
this.closeHandler();
|
||||
}
|
||||
}
|
||||
|
||||
set onmessage(handler: (event: { data: string }) => void) {
|
||||
this.messageHandler = handler;
|
||||
}
|
||||
|
||||
set onopen(handler: () => void) {
|
||||
this.openHandler = handler;
|
||||
}
|
||||
|
||||
set onclose(handler: () => void) {
|
||||
this.closeHandler = handler;
|
||||
}
|
||||
|
||||
set onerror(handler: (error: any) => void) {
|
||||
// Mock implementation
|
||||
}
|
||||
|
||||
simulateMessage(message: MockWebSocketMessage) {
|
||||
if (this.messageHandler) {
|
||||
this.messageHandler({ data: JSON.stringify(message) });
|
||||
}
|
||||
}
|
||||
|
||||
getLastMessage(): MockWebSocketMessage | null {
|
||||
if (this.sentMessages.length === 0) return null;
|
||||
return JSON.parse(this.sentMessages[this.sentMessages.length - 1]);
|
||||
}
|
||||
|
||||
getAllMessages(): MockWebSocketMessage[] {
|
||||
return this.sentMessages.map(msg => JSON.parse(msg));
|
||||
}
|
||||
}
|
||||
|
||||
describe("WebSocket Signaling Integration", () => {
|
||||
let clientManager: ClientManager;
|
||||
let signalingService: SignalingService;
|
||||
|
||||
beforeEach(() => {
|
||||
clientManager = new ClientManager();
|
||||
signalingService = new SignalingService(clientManager);
|
||||
});
|
||||
|
||||
test("should handle complete publisher-subscriber flow", () => {
|
||||
// Setup subscribers first
|
||||
const subscriber1Ws = new MockWebSocket("ws://test?role=subscriber");
|
||||
const subscriber1Id = signalingService.handleConnection(subscriber1Ws, "subscriber");
|
||||
|
||||
const subscriber2Ws = new MockWebSocket("ws://test?role=subscriber");
|
||||
const subscriber2Id = signalingService.handleConnection(subscriber2Ws, "subscriber");
|
||||
|
||||
// Setup publisher (this should notify existing subscribers)
|
||||
const publisherWs = new MockWebSocket("ws://test?role=publisher");
|
||||
const publisherId = signalingService.handleConnection(publisherWs, "publisher");
|
||||
|
||||
// Verify initial connections
|
||||
expect(publisherWs.getLastMessage()).toEqual({
|
||||
type: 'join',
|
||||
data: { clientId: publisherId, role: 'publisher' }
|
||||
});
|
||||
|
||||
// Verify subscribers get notified about publisher joining
|
||||
const sub1Messages = subscriber1Ws.getAllMessages();
|
||||
const sub2Messages = subscriber2Ws.getAllMessages();
|
||||
|
||||
expect(sub1Messages).toHaveLength(2); // join + publisher-joined
|
||||
expect(sub1Messages.some(msg => msg.type === 'publisher-joined')).toBe(true);
|
||||
expect(sub2Messages).toHaveLength(2); // join + publisher-joined
|
||||
expect(sub2Messages.some(msg => msg.type === 'publisher-joined')).toBe(true);
|
||||
|
||||
// Test offer flow
|
||||
const offerMessage = {
|
||||
type: "offer" as const,
|
||||
data: { sdp: "fake-offer-sdp", type: "offer" }
|
||||
};
|
||||
|
||||
signalingService.handleMessage(publisherId, offerMessage);
|
||||
|
||||
// Verify subscribers received the offer
|
||||
const sub1LastMessage = subscriber1Ws.getLastMessage();
|
||||
const sub2LastMessage = subscriber2Ws.getLastMessage();
|
||||
|
||||
expect(sub1LastMessage).toEqual({
|
||||
...offerMessage,
|
||||
senderId: publisherId
|
||||
});
|
||||
expect(sub2LastMessage).toEqual({
|
||||
...offerMessage,
|
||||
senderId: publisherId
|
||||
});
|
||||
|
||||
// Test answer flow
|
||||
const answerMessage = {
|
||||
type: "answer" as const,
|
||||
data: { sdp: "fake-answer-sdp", type: "answer" }
|
||||
};
|
||||
|
||||
signalingService.handleMessage(subscriber1Id, answerMessage);
|
||||
|
||||
// Verify publisher received the answer
|
||||
const publisherLastMessage = publisherWs.getLastMessage();
|
||||
expect(publisherLastMessage).toEqual({
|
||||
...answerMessage,
|
||||
senderId: subscriber1Id
|
||||
});
|
||||
|
||||
// Test ICE candidate exchange
|
||||
const iceCandidateMessage = {
|
||||
type: "ice-candidate" as const,
|
||||
data: { candidate: "fake-ice-candidate" }
|
||||
};
|
||||
|
||||
// Publisher to subscribers
|
||||
signalingService.handleMessage(publisherId, iceCandidateMessage);
|
||||
|
||||
expect(subscriber1Ws.getLastMessage()).toEqual({
|
||||
...iceCandidateMessage,
|
||||
senderId: publisherId
|
||||
});
|
||||
expect(subscriber2Ws.getLastMessage()).toEqual({
|
||||
...iceCandidateMessage,
|
||||
senderId: publisherId
|
||||
});
|
||||
|
||||
// Subscriber to publisher
|
||||
signalingService.handleMessage(subscriber1Id, iceCandidateMessage);
|
||||
|
||||
expect(publisherWs.getLastMessage()).toEqual({
|
||||
...iceCandidateMessage,
|
||||
senderId: subscriber1Id
|
||||
});
|
||||
});
|
||||
|
||||
test("should handle publisher disconnect gracefully", () => {
|
||||
// Setup
|
||||
const publisherWs = new MockWebSocket("ws://test?role=publisher");
|
||||
const publisherId = signalingService.handleConnection(publisherWs, "publisher");
|
||||
|
||||
const subscriberWs = new MockWebSocket("ws://test?role=subscriber");
|
||||
signalingService.handleConnection(subscriberWs, "subscriber");
|
||||
|
||||
// Disconnect publisher
|
||||
signalingService.handleDisconnection(publisherId);
|
||||
|
||||
// Verify subscriber gets publisher-left notification
|
||||
const subscriberMessages = subscriberWs.getAllMessages();
|
||||
expect(subscriberMessages).toHaveLength(2); // join + publisher-left
|
||||
expect(subscriberMessages.some(msg => msg.type === 'publisher-left')).toBe(true);
|
||||
|
||||
// Verify publisher is removed
|
||||
expect(clientManager.getPublisher()).toBeNull();
|
||||
});
|
||||
|
||||
test("should handle subscriber disconnect gracefully", () => {
|
||||
const publisherWs = new MockWebSocket("ws://test?role=publisher");
|
||||
signalingService.handleConnection(publisherWs, "publisher");
|
||||
|
||||
const subscriberWs = new MockWebSocket("ws://test?role=subscriber");
|
||||
const subscriberId = signalingService.handleConnection(subscriberWs, "subscriber");
|
||||
|
||||
// Verify subscriber was added
|
||||
expect(clientManager.getSubscribers()).toHaveLength(1);
|
||||
|
||||
// Disconnect subscriber
|
||||
signalingService.handleDisconnection(subscriberId);
|
||||
|
||||
// Verify subscriber was removed
|
||||
expect(clientManager.getSubscribers()).toHaveLength(0);
|
||||
expect(clientManager.getClient(subscriberId)).toBeUndefined();
|
||||
});
|
||||
|
||||
test("should handle multiple subscribers connecting and disconnecting", () => {
|
||||
const publisherWs = new MockWebSocket("ws://test?role=publisher");
|
||||
signalingService.handleConnection(publisherWs, "publisher");
|
||||
|
||||
// Add 3 subscribers
|
||||
const subscribers = [];
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const ws = new MockWebSocket(`ws://test?role=subscriber&id=${i}`);
|
||||
const id = signalingService.handleConnection(ws, "subscriber");
|
||||
subscribers.push({ ws, id });
|
||||
}
|
||||
|
||||
expect(clientManager.getSubscribers()).toHaveLength(3);
|
||||
|
||||
// Disconnect middle subscriber
|
||||
signalingService.handleDisconnection(subscribers[1].id);
|
||||
expect(clientManager.getSubscribers()).toHaveLength(2);
|
||||
|
||||
// Verify remaining subscribers are still connected
|
||||
expect(clientManager.getClient(subscribers[0].id)).toBeDefined();
|
||||
expect(clientManager.getClient(subscribers[2].id)).toBeDefined();
|
||||
expect(clientManager.getClient(subscribers[1].id)).toBeUndefined();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user