Skip to main content
Glama
useControlHandler.test.ts8.91 kB
/// <reference types="jest" /> import { useControlHandler } from "../useControlHandler"; import { ControlClient } from "../../lib/types"; import { renderHook, act } from "@testing-library/react"; // Mock ControlClient class MockControlClient implements ControlClient { public keyEvents: Array<{ keycode: number; action: string; metaState: number; }> = []; public isMouseDragging: boolean = false; // ControlClient interface implementation connect( _deviceSerial: string, _apiUrl: string, _wsUrl?: string ): Promise<void> { return Promise.resolve(); } disconnect(): void { // Mock implementation } isControlConnected(): boolean { return true; } sendKeyEvent( keycode: number, action: "down" | "up", metaState: number = 0 ): void { this.keyEvents.push({ keycode, action, metaState }); } sendTouchEvent( _x: number, _y: number, _action: "down" | "up" | "move", _pressure: number = 1.0 ): void { // Mock implementation } sendControlAction(_action: string, _params?: unknown): void { // Mock implementation } sendClipboardSet(_text: string, _paste?: boolean): void { // Mock implementation } requestKeyframe(): void { // Mock implementation } handleMouseEvent(_event: MouseEvent, _action: "down" | "up" | "move"): void { // Mock implementation } handleTouchEvent(_event: TouchEvent, _action: "down" | "up" | "move"): void { // Mock implementation } } describe("useControlHandler", () => { let mockClient: MockControlClient; beforeEach(() => { mockClient = new MockControlClient(); jest.clearAllMocks(); }); it("should provide control handlers", () => { const { result } = renderHook(() => useControlHandler({ client: mockClient, enabled: true, isConnected: true, }) ); expect(result.current.handleControlAction).toBeDefined(); expect(result.current.handleIMESwitch).toBeDefined(); expect(typeof result.current.handleControlAction).toBe("function"); expect(typeof result.current.handleIMESwitch).toBe("function"); }); it("should handle control actions correctly", async () => { const { result } = renderHook(() => useControlHandler({ client: mockClient, enabled: true, isConnected: true, }) ); act(() => { result.current.handleControlAction("power"); }); // Wait for the async up event await new Promise((resolve) => setTimeout(resolve, 150)); expect(mockClient.keyEvents).toHaveLength(2); // down + up expect(mockClient.keyEvents[0]).toEqual({ keycode: 26, // power keycode action: "down", metaState: 0, }); expect(mockClient.keyEvents[1]).toEqual({ keycode: 26, action: "up", metaState: 0, }); }); it("should handle volume up action", async () => { const { result } = renderHook(() => useControlHandler({ client: mockClient, enabled: true, isConnected: true, }) ); act(() => { result.current.handleControlAction("volume_up"); }); // Wait for the async up event await new Promise((resolve) => setTimeout(resolve, 150)); expect(mockClient.keyEvents).toHaveLength(2); expect(mockClient.keyEvents[0].keycode).toBe(24); // volume up }); it("should handle volume down action", async () => { const { result } = renderHook(() => useControlHandler({ client: mockClient, enabled: true, isConnected: true, }) ); act(() => { result.current.handleControlAction("volume_down"); }); // Wait for the async up event await new Promise((resolve) => setTimeout(resolve, 150)); expect(mockClient.keyEvents).toHaveLength(2); expect(mockClient.keyEvents[0].keycode).toBe(25); // volume down }); it("should handle back action", async () => { const { result } = renderHook(() => useControlHandler({ client: mockClient, enabled: true, isConnected: true, }) ); act(() => { result.current.handleControlAction("back"); }); // Wait for the async up event await new Promise((resolve) => setTimeout(resolve, 150)); expect(mockClient.keyEvents).toHaveLength(2); expect(mockClient.keyEvents[0].keycode).toBe(4); // back }); it("should handle home action", async () => { const { result } = renderHook(() => useControlHandler({ client: mockClient, enabled: true, isConnected: true, }) ); act(() => { result.current.handleControlAction("home"); }); // Wait for the async up event await new Promise((resolve) => setTimeout(resolve, 150)); expect(mockClient.keyEvents).toHaveLength(2); expect(mockClient.keyEvents[0].keycode).toBe(3); // home }); it("should handle app switch action", async () => { const { result } = renderHook(() => useControlHandler({ client: mockClient, enabled: true, isConnected: true, }) ); act(() => { result.current.handleControlAction("app_switch"); }); // Wait for the async up event await new Promise((resolve) => setTimeout(resolve, 150)); expect(mockClient.keyEvents).toHaveLength(2); expect(mockClient.keyEvents[0].keycode).toBe(187); // app switch }); it("should handle menu action", async () => { const { result } = renderHook(() => useControlHandler({ client: mockClient, enabled: true, isConnected: true, }) ); act(() => { result.current.handleControlAction("menu"); }); // Wait for the async up event await new Promise((resolve) => setTimeout(resolve, 150)); expect(mockClient.keyEvents).toHaveLength(2); expect(mockClient.keyEvents[0].keycode).toBe(82); // menu }); it("should handle unknown action gracefully", () => { const consoleSpy = jest.spyOn(console, "warn").mockImplementation(() => {}); const { result } = renderHook(() => useControlHandler({ client: mockClient, enabled: true, isConnected: true, }) ); act(() => { result.current.handleControlAction("unknown_action"); }); expect(mockClient.keyEvents).toHaveLength(0); expect(consoleSpy).toHaveBeenCalledWith( "[ControlHandler] No keycode found for action: unknown_action" ); consoleSpy.mockRestore(); }); it("should handle IME switch correctly", async () => { const { result } = renderHook(() => useControlHandler({ client: mockClient, enabled: true, isConnected: true, }) ); act(() => { result.current.handleIMESwitch(); }); // Wait for the async up event await new Promise((resolve) => setTimeout(resolve, 100)); expect(mockClient.keyEvents).toHaveLength(2); expect(mockClient.keyEvents[0]).toEqual({ keycode: 204, // KEYCODE_LANGUAGE_SWITCH action: "down", metaState: 0, }); expect(mockClient.keyEvents[1]).toEqual({ keycode: 204, action: "up", metaState: 0, }); }); it("should not handle actions when disabled", () => { const { result } = renderHook(() => useControlHandler({ client: mockClient, enabled: false, isConnected: true, }) ); act(() => { result.current.handleControlAction("power"); result.current.handleIMESwitch(); }); expect(mockClient.keyEvents).toHaveLength(0); }); it("should not handle actions when not connected", () => { const { result } = renderHook(() => useControlHandler({ client: mockClient, enabled: true, isConnected: false, }) ); act(() => { result.current.handleControlAction("power"); result.current.handleIMESwitch(); }); expect(mockClient.keyEvents).toHaveLength(0); }); it("should not handle actions when client is null", () => { const { result } = renderHook(() => useControlHandler({ client: null, enabled: true, isConnected: true, }) ); act(() => { result.current.handleControlAction("power"); result.current.handleIMESwitch(); }); expect(mockClient.keyEvents).toHaveLength(0); }); it("should handle case insensitive actions", async () => { const { result } = renderHook(() => useControlHandler({ client: mockClient, enabled: true, isConnected: true, }) ); act(() => { result.current.handleControlAction("POWER"); }); // Wait for the async up event await new Promise((resolve) => setTimeout(resolve, 150)); expect(mockClient.keyEvents).toHaveLength(2); expect(mockClient.keyEvents[0].keycode).toBe(26); // power keycode }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/babelcloud/gru-sandbox'

If you have feedback or need assistance with the MCP directory API, please join our Discord server