Skip to main content
Glama

MCPControl

screen.test.ts9.41 kB
import { describe, it, expect, vi, beforeEach } from 'vitest'; import { KeysenderScreenAutomation } from './screen.js'; // Properly mock keysender without any hoisting issues vi.mock('keysender', async () => { // This empty import() is important to make Vitest properly track the module await vi.importActual('vitest'); // Define mocks inline within this function to avoid hoisting problems const mockCapture = vi.fn().mockImplementation((part, _format) => { return part && typeof part === 'object' ? { data: Buffer.from('region-screenshot-data'), width: part.width, height: part.height } : { data: Buffer.from('full-screenshot-data'), width: 1920, height: 1080 }; }); const mockGet = vi.fn().mockReturnValue({ title: 'Test Window', className: 'TestClass', handle: 12345, }); const mockGetView = vi.fn().mockReturnValue({ x: 100, y: 200, width: 800, height: 600, }); const mockSet = vi.fn().mockReturnValue(true); const mockSetForeground = vi.fn(); const mockSetView = vi.fn(); // Create the mock object with all the required functions const mockObject = { Hardware: vi.fn().mockImplementation(() => ({ workwindow: { capture: mockCapture, get: mockGet, set: mockSet, getView: mockGetView, setForeground: mockSetForeground, setView: mockSetView, isForeground: vi.fn().mockReturnValue(true), isOpen: vi.fn().mockReturnValue(true), }, })), getScreenSize: vi.fn().mockReturnValue({ width: 1920, height: 1080, }), getAllWindows: vi .fn() .mockReturnValue([{ title: 'Test Window', className: 'TestClass', handle: 12345 }]), getWindowChildren: vi.fn().mockReturnValue([]), }; // Return both default export and named exports return { default: mockObject, // Add default export to match 'import pkg from 'keysender'' ...mockObject, // Spread the same object as named exports }; }); describe('KeysenderScreenAutomation', () => { let screenAutomation: KeysenderScreenAutomation; let keysender: any; let mockCapture: any; let mockGet: any; let mockGetView: any; let mockSet: any; let mockSetForeground: any; let mockSetView: any; let mockGetScreenSize: any; let mockGetAllWindows: any; beforeEach(async () => { // Reset all mocks before each test vi.clearAllMocks(); // Import the mocked module to get access to the mock functions // Using dynamic import to get the mocked module keysender = await import('keysender'); // Get references to mocks from the hardware instance const hardware = keysender.Hardware(); mockCapture = hardware.workwindow.capture; mockGet = hardware.workwindow.get; mockGetView = hardware.workwindow.getView; mockSet = hardware.workwindow.set; mockSetForeground = hardware.workwindow.setForeground; mockSetView = hardware.workwindow.setView; // Get references to other mocks mockGetScreenSize = keysender.getScreenSize; mockGetAllWindows = keysender.getAllWindows; // Create a new instance for each test screenAutomation = new KeysenderScreenAutomation(); }); describe('getScreenSize', () => { it('should return screen dimensions from keysender', () => { const result = screenAutomation.getScreenSize(); expect(mockGetScreenSize).toHaveBeenCalled(); expect(result.success).toBe(true); expect(result.data).toEqual({ width: 1920, height: 1080, }); }); it('should handle errors gracefully', () => { // Mock getScreenSize to throw an error mockGetScreenSize.mockImplementationOnce(() => { throw new Error('Test error'); }); const result = screenAutomation.getScreenSize(); expect(result.success).toBe(false); expect(result.message).toContain('Test error'); }); }); describe('getScreenshot', () => { it('should capture full screen when no region is specified', async () => { const result = await screenAutomation.getScreenshot(); // Check that workwindow.capture was called with the right parameters expect(mockCapture).toHaveBeenCalledWith('rgba'); expect(result.success).toBe(true); // Using 1280 as the standard width for HD Ready resolution // This is a common standard for digital imagery and display scaling expect(result.data).toEqual({ width: 1280, height: 720, }); expect(result.screenshot).toBeDefined(); expect(result.encoding).toBe('base64'); expect(result.content?.[0].type).toBe('image'); }); it('should capture a specific region when region is specified', async () => { const region = { x: 100, y: 200, width: 300, height: 400 }; const result = await screenAutomation.getScreenshot({ region }); // Check that workwindow.capture was called with the right parameters expect(mockCapture).toHaveBeenCalledWith(region, 'rgba'); expect(result.success).toBe(true); expect(result.data).toEqual({ width: 300, height: 400, }); }); it('should handle errors gracefully', async () => { // Mock workwindow.capture to throw an error mockCapture.mockImplementationOnce(() => { throw new Error('Capture error'); }); const result = await screenAutomation.getScreenshot(); expect(result.success).toBe(false); expect(result.message).toContain('Capture error'); }); }); describe('getActiveWindow', () => { it('should return information about the active window', () => { // Mock a successful window detection mockGetAllWindows.mockReturnValueOnce([ { title: 'Test Window', className: 'TestClass', handle: 12345, }, ]); // Create hardware instance to ensure get and getView are called const mockHardware = { workwindow: { set: mockSet, get: mockGet, getView: mockGetView, isForeground: vi.fn().mockReturnValue(true), }, }; // Replace hardware instance creation in the class vi.spyOn(keysender, 'Hardware').mockReturnValueOnce(mockHardware as any); const result = screenAutomation.getActiveWindow(); expect(mockGetAllWindows).toHaveBeenCalled(); // These will be called through the findSuitableWindow method expect(mockGet).toHaveBeenCalled(); expect(mockGetView).toHaveBeenCalled(); expect(result.success).toBe(true); expect(result.data).toEqual( expect.objectContaining({ title: 'Test Window', className: 'TestClass', handle: 12345, position: { x: 100, y: 200, }, size: { width: 800, height: 600, }, }), ); }); it('should handle missing window information gracefully', () => { // Mock getAllWindows to return empty array mockGetAllWindows.mockReturnValueOnce([]); const result = screenAutomation.getActiveWindow(); expect(result.success).toBe(true); expect(result.data).toEqual({ title: 'Unknown', className: 'Unknown', handle: 0, position: { x: 0, y: 0, }, size: { width: 0, height: 0, }, }); }); }); describe('focusWindow', () => { it('should focus a window by title', () => { const result = screenAutomation.focusWindow('Test Window'); expect(mockGetAllWindows).toHaveBeenCalled(); expect(mockSet).toHaveBeenCalled(); expect(mockSetForeground).toHaveBeenCalled(); expect(result.success).toBe(true); expect(result.message).toContain('Focused window'); }); it('should handle window not found', () => { // Mock getAllWindows to return empty array mockGetAllWindows.mockReturnValueOnce([]); const result = screenAutomation.focusWindow('Nonexistent Window'); expect(result.success).toBe(false); expect(result.message).toContain('Could not find window'); }); }); describe('resizeWindow', () => { it('should resize a window to specified dimensions', async () => { const result = await screenAutomation.resizeWindow('Test Window', 1024, 768); expect(mockGetAllWindows).toHaveBeenCalled(); expect(mockSet).toHaveBeenCalled(); expect(mockSetForeground).toHaveBeenCalled(); expect(mockSetView).toHaveBeenCalledWith( expect.objectContaining({ width: 1024, height: 768, }), ); expect(result.success).toBe(true); expect(result.message).toContain('Resized window'); }); }); describe('repositionWindow', () => { it('should reposition a window to specified coordinates', async () => { const result = await screenAutomation.repositionWindow('Test Window', 50, 100); expect(mockGetAllWindows).toHaveBeenCalled(); expect(mockSet).toHaveBeenCalled(); expect(mockSetForeground).toHaveBeenCalled(); expect(mockSetView).toHaveBeenCalledWith( expect.objectContaining({ x: 50, y: 100, }), ); expect(result.success).toBe(true); expect(result.message).toContain('Repositioned window'); }); }); });

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/claude-did-this/MCPControl'

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