blanchon's picture
Update
116a27a
/**
* Tests for Factory Functions - equivalent to Python's test_factory_functions.py
*/
import { test, expect, describe, beforeEach, afterEach } from "bun:test";
import { robotics } from "../src/index";
import { TEST_SERVER_URL, TestRoomManager, MessageCollector, sleep } from "./setup";
const { RoboticsProducer, RoboticsConsumer, createClient, createProducerClient, createConsumerClient } = robotics;
describe("Factory Functions", () => {
let roomManager: TestRoomManager;
beforeEach(() => {
roomManager = new TestRoomManager();
});
afterEach(async () => {
// Cleanup will be handled by individual tests
});
test("create client producer", () => {
const client = createClient("producer", TEST_SERVER_URL);
expect(client).toBeInstanceOf(RoboticsProducer);
expect(client.isConnected()).toBe(false);
expect(client.getConnectionInfo().base_url).toBe("http://localhost:8000");
});
test("create client consumer", () => {
const client = createClient("consumer", TEST_SERVER_URL);
expect(client).toBeInstanceOf(RoboticsConsumer);
expect(client.isConnected()).toBe(false);
expect(client.getConnectionInfo().base_url).toBe("http://localhost:8000");
});
test("create client invalid role", () => {
expect(() => createClient("invalid_role" as any, TEST_SERVER_URL)).toThrow("Invalid role");
});
test("create client default url", () => {
const client = createClient("producer", TEST_SERVER_URL);
expect(client.getConnectionInfo().base_url).toBe("http://localhost:8000");
});
test("create producer client auto room", async () => {
const producer = await createProducerClient(TEST_SERVER_URL);
try {
expect(producer).toBeInstanceOf(RoboticsProducer);
expect(producer.isConnected()).toBe(true);
const info = producer.getConnectionInfo();
expect(info.room_id).toBeTruthy();
expect(info.workspace_id).toBeTruthy();
expect(info.role).toBe("producer");
// Should be able to send commands immediately
await producer.sendStateSync({ test: 123.0 });
// Track for cleanup
roomManager.addRoom(info.workspace_id!, info.room_id!);
} finally {
await producer.disconnect();
await roomManager.cleanup(producer);
}
});
test("create producer client specific room", async () => {
// First create a room
const tempProducer = new RoboticsProducer(TEST_SERVER_URL);
const { workspaceId, roomId } = await tempProducer.createRoom();
roomManager.addRoom(workspaceId, roomId);
try {
const producer = await createProducerClient(TEST_SERVER_URL, workspaceId, roomId);
expect(producer).toBeInstanceOf(RoboticsProducer);
expect(producer.isConnected()).toBe(true);
const info = producer.getConnectionInfo();
expect(info.room_id).toBe(roomId);
expect(info.workspace_id).toBe(workspaceId);
expect(info.role).toBe("producer");
await producer.disconnect();
} finally {
await roomManager.cleanup(tempProducer);
}
});
test("create consumer client", async () => {
// First create a room
const tempProducer = new RoboticsProducer(TEST_SERVER_URL);
const { workspaceId, roomId } = await tempProducer.createRoom();
roomManager.addRoom(workspaceId, roomId);
try {
const consumer = await createConsumerClient(workspaceId, roomId, TEST_SERVER_URL);
expect(consumer).toBeInstanceOf(RoboticsConsumer);
expect(consumer.isConnected()).toBe(true);
const info = consumer.getConnectionInfo();
expect(info.room_id).toBe(roomId);
expect(info.workspace_id).toBe(workspaceId);
expect(info.role).toBe("consumer");
// Should be able to get state immediately
const state = await consumer.getStateSyncAsync();
expect(typeof state).toBe("object");
await consumer.disconnect();
} finally {
await roomManager.cleanup(tempProducer);
}
});
test("create producer consumer pair", async () => {
const producer = await createProducerClient(TEST_SERVER_URL);
const producerInfo = producer.getConnectionInfo();
const workspaceId = producerInfo.workspace_id!;
const roomId = producerInfo.room_id!;
roomManager.addRoom(workspaceId, roomId);
try {
const consumer = await createConsumerClient(workspaceId, roomId, TEST_SERVER_URL);
// Both should be connected to same room
const consumerInfo = consumer.getConnectionInfo();
expect(producerInfo.room_id).toBe(consumerInfo.room_id);
expect(producerInfo.workspace_id).toBe(consumerInfo.workspace_id);
expect(producer.isConnected()).toBe(true);
expect(consumer.isConnected()).toBe(true);
// Test communication
const updateCollector = new MessageCollector(1);
consumer.onJointUpdate(updateCollector.collect);
// Give some time for connection to stabilize
await sleep(100);
// Send update from producer
await producer.sendStateSync({ test_joint: 42.0 });
// Wait for message
const receivedUpdates = await updateCollector.waitForMessages(2000);
// Consumer should have received update
expect(receivedUpdates.length).toBeGreaterThanOrEqual(1);
await consumer.disconnect();
} finally {
await producer.disconnect();
await roomManager.cleanup(producer);
}
});
test("convenience functions with default url", async () => {
const producer = await createProducerClient(TEST_SERVER_URL);
const producerInfo = producer.getConnectionInfo();
const workspaceId = producerInfo.workspace_id!;
const roomId = producerInfo.room_id!;
roomManager.addRoom(workspaceId, roomId);
try {
expect(producerInfo.base_url).toBe("http://localhost:8000");
expect(producer.isConnected()).toBe(true);
const consumer = await createConsumerClient(workspaceId, roomId, TEST_SERVER_URL);
try {
const consumerInfo = consumer.getConnectionInfo();
expect(consumerInfo.base_url).toBe("http://localhost:8000");
expect(consumer.isConnected()).toBe(true);
} finally {
await consumer.disconnect();
}
} finally {
await producer.disconnect();
await roomManager.cleanup(producer);
}
});
test("multiple convenience producers", async () => {
const producer1 = await createProducerClient(TEST_SERVER_URL);
const producer2 = await createProducerClient(TEST_SERVER_URL);
try {
const info1 = producer1.getConnectionInfo();
const info2 = producer2.getConnectionInfo();
// Both should be connected to different rooms
expect(info1.room_id).not.toBe(info2.room_id);
expect(producer1.isConnected()).toBe(true);
expect(producer2.isConnected()).toBe(true);
// Track for cleanup
roomManager.addRoom(info1.workspace_id!, info1.room_id!);
roomManager.addRoom(info2.workspace_id!, info2.room_id!);
// Both should work independently
await producer1.sendStateSync({ joint1: 10.0 });
await producer2.sendStateSync({ joint2: 20.0 });
} finally {
await producer1.disconnect();
await producer2.disconnect();
await roomManager.cleanup(producer1);
}
});
test("create consumer nonexistent room", async () => {
const fakeWorkspaceId = "00000000-0000-0000-0000-000000000000";
const fakeRoomId = "00000000-0000-0000-0000-000000000000";
const consumer = new RoboticsConsumer(TEST_SERVER_URL);
const success = await consumer.connect(fakeWorkspaceId, fakeRoomId);
// Should fail to connect to non-existent room
expect(success).toBe(false);
expect(consumer.isConnected()).toBe(false);
});
});