Spaces:
Sleeping
Sleeping
/** | |
* Tests for Video Client - equivalent to Python's test_video_client.py | |
*/ | |
import { test, expect, describe, beforeEach, afterEach } from "bun:test"; | |
import { video } from "../src/index"; | |
import { TEST_SERVER_URL, TestRoomManager, mockFrameSource } from "./setup"; | |
const { VideoProducer, VideoConsumer, createProducerClient, createConsumerClient } = video; | |
describe("Video Types", () => { | |
test("resolution creation", () => { | |
const resolution = { width: 1920, height: 1080 }; | |
expect(resolution.width).toBe(1920); | |
expect(resolution.height).toBe(1080); | |
}); | |
test("video config creation", () => { | |
const config = { | |
encoding: "vp8" as video.VideoEncoding, | |
resolution: { width: 640, height: 480 }, | |
framerate: 30, | |
bitrate: 1000000 | |
}; | |
expect(config.encoding).toBe("vp8"); | |
expect(config.resolution?.width).toBe(640); | |
expect(config.framerate).toBe(30); | |
}); | |
test("participant role enum", () => { | |
const producerRole = "producer"; | |
const consumerRole = "consumer"; | |
expect(producerRole).toBe("producer"); | |
expect(consumerRole).toBe("consumer"); | |
}); | |
}); | |
describe("Video Core", () => { | |
let roomManager: TestRoomManager; | |
beforeEach(() => { | |
roomManager = new TestRoomManager(); | |
}); | |
afterEach(async () => { | |
await roomManager.cleanup(new VideoProducer(TEST_SERVER_URL)); | |
}); | |
test("video producer creation", () => { | |
const producer = new VideoProducer(TEST_SERVER_URL); | |
expect(producer.getConnectionInfo().base_url).toBe(TEST_SERVER_URL); | |
expect(producer.isConnected()).toBe(false); | |
expect(producer.getConnectionInfo().room_id).toBeNull(); | |
}); | |
test("video consumer creation", () => { | |
const consumer = new VideoConsumer(TEST_SERVER_URL); | |
expect(consumer.getConnectionInfo().base_url).toBe(TEST_SERVER_URL); | |
expect(consumer.isConnected()).toBe(false); | |
expect(consumer.getConnectionInfo().room_id).toBeNull(); | |
}); | |
test("producer room creation", async () => { | |
try { | |
const producer = new VideoProducer(TEST_SERVER_URL); | |
const { workspaceId, roomId } = await producer.createRoom(); | |
roomManager.addRoom(workspaceId, roomId); | |
expect(typeof roomId).toBe("string"); | |
expect(roomId.length).toBeGreaterThan(0); | |
console.log(`β Created room: ${roomId}`); | |
} catch (error) { | |
console.warn(`β οΈ Server not available: ${error}`); | |
// Skip test if server not available | |
} | |
}, { timeout: 5000 }); | |
test("consumer list rooms", async () => { | |
try { | |
const consumer = new VideoConsumer(TEST_SERVER_URL); | |
const workspaceId = "test-workspace-id"; | |
const rooms = await consumer.listRooms(workspaceId); | |
expect(Array.isArray(rooms)).toBe(true); | |
console.log(`β Listed ${rooms.length} rooms`); | |
} catch (error) { | |
console.warn(`β οΈ Server not available: ${error}`); | |
// Skip test if server not available | |
} | |
}, { timeout: 5000 }); | |
}); | |
describe("Video Client Integration", () => { | |
let roomManager: TestRoomManager; | |
beforeEach(() => { | |
roomManager = new TestRoomManager(); | |
}); | |
afterEach(async () => { | |
await roomManager.cleanup(new VideoProducer(TEST_SERVER_URL)); | |
}); | |
test("producer consumer setup", () => { | |
// Test producer setup | |
const producer = new VideoProducer(TEST_SERVER_URL); | |
expect(producer.getLocalStream()).toBeNull(); | |
// Test consumer setup | |
const consumer = new VideoConsumer(TEST_SERVER_URL); | |
expect(consumer.getRemoteStream()).toBeNull(); | |
console.log("β Producer/Consumer setup test passed"); | |
}); | |
test("custom stream setup validation", async () => { | |
const producer = new VideoProducer(TEST_SERVER_URL); | |
// This will fail because we're not connected, but it tests the setup | |
try { | |
// Simulate starting a custom stream when not connected | |
await producer.startCamera(); | |
expect(true).toBe(false); // Should not reach here | |
} catch (error: any) { | |
expect(error.message).toContain("Must be connected"); | |
console.log("β Custom stream setup validation passed"); | |
} | |
}); | |
test("factory functions", async () => { | |
// Test that factory functions create the right types | |
// (We can't actually connect without a server) | |
try { | |
await createProducerClient(TEST_SERVER_URL); | |
} catch (error) { | |
// Expected to fail without server | |
console.log("β Producer factory function exists"); | |
} | |
try { | |
await createConsumerClient("test-workspace", "test-room", TEST_SERVER_URL); | |
} catch (error) { | |
// Expected to fail without server | |
console.log("β Consumer factory function exists"); | |
} | |
console.log("β Factory functions test passed"); | |
}); | |
test("mock frame source", async () => { | |
const frameData = await mockFrameSource(); | |
expect(frameData).not.toBeNull(); | |
expect(frameData).toBeInstanceOf(ArrayBuffer); | |
if (frameData) { | |
expect(frameData.byteLength).toBe(320 * 240 * 4); // RGBA | |
console.log("β Mock frame source test passed"); | |
} | |
}); | |
test("video config types", () => { | |
const config: video.VideoConfig = { | |
encoding: "h264", | |
resolution: { width: 1280, height: 720 }, | |
framerate: 60, | |
bitrate: 2000000, | |
quality: 90 | |
}; | |
expect(config.encoding).toBe("h264"); | |
expect(config.resolution?.width).toBe(1280); | |
expect(config.resolution?.height).toBe(720); | |
expect(config.framerate).toBe(60); | |
expect(config.bitrate).toBe(2000000); | |
expect(config.quality).toBe(90); | |
console.log("β Video config types test passed"); | |
}); | |
test("recovery config types", () => { | |
const recoveryConfig: video.RecoveryConfig = { | |
frame_timeout_ms: 200, | |
max_frame_reuse_count: 5, | |
recovery_policy: "freeze_last_frame", | |
fallback_policy: "connection_info", | |
show_hold_indicators: true, | |
fade_intensity: 0.8 | |
}; | |
expect(recoveryConfig.frame_timeout_ms).toBe(200); | |
expect(recoveryConfig.recovery_policy).toBe("freeze_last_frame"); | |
expect(recoveryConfig.fallback_policy).toBe("connection_info"); | |
console.log("β Recovery config types test passed"); | |
}); | |
test("participant info types", () => { | |
const participantInfo: video.ParticipantInfo = { | |
producer: "producer-123", | |
consumers: ["consumer-1", "consumer-2"], | |
total: 3 | |
}; | |
expect(participantInfo.producer).toBe("producer-123"); | |
expect(participantInfo.consumers).toHaveLength(2); | |
expect(participantInfo.total).toBe(3); | |
console.log("β Participant info types test passed"); | |
}); | |
test("room info types", () => { | |
const roomInfo: video.RoomInfo = { | |
id: "room-123", | |
workspace_id: "workspace-456", | |
participants: { | |
producer: "producer-1", | |
consumers: ["consumer-1"], | |
total: 2 | |
}, | |
frame_count: 1000, | |
config: { | |
encoding: "vp8", | |
resolution: { width: 640, height: 480 }, | |
framerate: 30 | |
}, | |
has_producer: true, | |
active_consumers: 1 | |
}; | |
expect(roomInfo.id).toBe("room-123"); | |
expect(roomInfo.workspace_id).toBe("workspace-456"); | |
expect(roomInfo.has_producer).toBe(true); | |
expect(roomInfo.active_consumers).toBe(1); | |
console.log("β Room info types test passed"); | |
}); | |
test("stream stats types", () => { | |
const streamStats: video.StreamStats = { | |
stream_id: "stream-123", | |
duration_seconds: 120.5, | |
frame_count: 3615, | |
total_bytes: 1048576, | |
average_fps: 30.0, | |
average_bitrate: 1000000 | |
}; | |
expect(streamStats.stream_id).toBe("stream-123"); | |
expect(streamStats.duration_seconds).toBe(120.5); | |
expect(streamStats.frame_count).toBe(3615); | |
expect(streamStats.average_fps).toBe(30.0); | |
console.log("β Stream stats types test passed"); | |
}); | |
}); |