Skip to main content
Glama

Peekaboo MCP

by steipete
ClickCommandFocusTests.swiftβ€’8.08 kB
import Foundation import Testing @testable import peekaboo @Suite("Click Command Focus Tests", .serialized) struct ClickCommandFocusTests { // Helper function to run peekaboo commands private func runPeekabooCommand(_ arguments: [String]) async throws -> String { let projectRoot = URL(fileURLWithPath: #file) .deletingLastPathComponent() .deletingLastPathComponent() .deletingLastPathComponent() .deletingLastPathComponent() .deletingLastPathComponent() let process = Process() process.executableURL = URL(fileURLWithPath: "/usr/bin/swift") process.currentDirectoryURL = projectRoot process.arguments = ["run", "peekaboo"] + arguments let pipe = Pipe() process.standardOutput = pipe process.standardError = pipe try process.run() process.waitUntilExit() let data = pipe.fileHandleForReading.readDataToEndOfFile() guard let output = String(data: data, encoding: .utf8) else { throw ProcessError(message: "Failed to decode output") } guard process.terminationStatus == 0 else { throw ProcessError(message: "Process failed with exit code: \(process.terminationStatus)\nOutput: \(output)" ) } return output } // MARK: - Focus Options in Click Command @Test("click command accepts all focus options") func clickAcceptsFocusOptions() async throws { // Test that all focus options are accepted without error let focusOptions = [ "--no-auto-focus", "--focus-timeout", "3.0", "--focus-retry-count", "5", "--space-switch", "--bring-to-current-space" ] // Create a basic click command with all options var args = ["click", "100", "100", "--json-output"] args.append(contentsOf: focusOptions.flatMap { [$0] }.compactMap { arg in // Add values for options that need them if arg == "--focus-timeout" { return ["--focus-timeout", "3.0"] } if arg == "--focus-retry-count" { return ["--focus-retry-count", "5"] } return [arg] }.flatMap(\.self)) let output = try await runPeekabooCommand(args) let data = try JSONDecoder().decode(JSONResponse.self, from: output.data(using: .utf8)!) // Command should be valid (may fail due to no element at position) #expect(data.success == true || data.error != nil) } @Test("click with session uses window focus") func clickWithSessionFocus() async throws { // Create session let seeOutput = try await runPeekabooCommand([ "see", "--app", "Finder", "--json-output" ]) let seeData = try JSONDecoder().decode(SeeResponse.self, from: seeOutput.data(using: .utf8)!) guard seeData.success, let sessionId = seeData.data?.session_id, let elements = seeData.data?.elements, !elements.isEmpty else { // Skip test if no Finder windows return } // Find a clickable element let clickableRoles = ["AXButton", "AXCheckBox", "AXRadioButton"] guard let clickable = elements.first(where: { clickableRoles.contains($0.role) }) else { // No clickable elements found return } // Click with session should auto-focus let clickOutput = try await runPeekabooCommand([ "click", clickable.role.lowercased().replacingOccurrences(of: "ax", with: ""), "--session", sessionId, "--json-output" ]) let clickData = try JSONDecoder().decode(ClickResponse.self, from: clickOutput.data(using: .utf8)!) #expect(clickData.success == true || clickData.error != nil) } @Test("click with Space switch option") func clickWithSpaceSwitch() async throws { // Test click with Space switching enabled let output = try await runPeekabooCommand([ "click", "button", "--space-switch", "--json-output" ]) let data = try JSONDecoder().decode(ClickResponse.self, from: output.data(using: .utf8)!) // Should handle Space switch option #expect(data.success == true || data.error != nil) } @Test("click with bring to current Space") func clickBringToCurrentSpace() async throws { // Test click with bring-to-current-space option let output = try await runPeekabooCommand([ "click", "100", "200", "--bring-to-current-space", "--json-output" ]) let data = try JSONDecoder().decode(ClickResponse.self, from: output.data(using: .utf8)!) // Should handle bring-to-current-space option #expect(data.success == true || data.error != nil) } // MARK: - Performance Tests @Test("click with session is faster than without") func clickSessionPerformance() async throws { // Create session let seeOutput = try await runPeekabooCommand([ "see", "--app", "Finder", "--json-output" ]) let seeData = try JSONDecoder().decode(SeeResponse.self, from: seeOutput.data(using: .utf8)!) guard seeData.success, let sessionId = seeData.data?.session_id else { return } // Time click with session let sessionStart = Date() _ = try await self.runPeekabooCommand([ "click", "100", "100", "--session", sessionId, "--json-output" ]) let sessionDuration = Date().timeIntervalSince(sessionStart) // Time click without session let noSessionStart = Date() _ = try await self.runPeekabooCommand([ "click", "100", "100", "--json-output" ]) let noSessionDuration = Date().timeIntervalSince(noSessionStart) // Session-based click should generally be faster // But we can't guarantee this in all test environments print("Click with session: \(sessionDuration)s, without: \(noSessionDuration)s") } // MARK: - Error Cases @Test("click with invalid session ID") func clickInvalidSession() async throws { let output = try await runPeekabooCommand([ "click", "button", "--session", "invalid-session-id", "--json-output" ]) let data = try JSONDecoder().decode(ClickResponse.self, from: output.data(using: .utf8)!) #expect(data.success == false) #expect(data.error?.contains("session") == true || data.error?.contains("not found") == true ) } @Test("click with conflicting focus options") func clickConflictingFocusOptions() async throws { // Test mutually exclusive options let output = try await runPeekabooCommand([ "click", "100", "100", "--space-switch", "--bring-to-current-space", "--json-output" ]) let data = try JSONDecoder().decode(ClickResponse.self, from: output.data(using: .utf8)!) // Should handle conflicting options gracefully #expect(data.success == true || data.error != nil) } } // MARK: - Response Types private struct JSONResponse: Codable { let success: Bool let error: String? } private struct SeeResponse: Codable { let success: Bool let data: SeeData? let error: String? } private struct SeeData: Codable { let session_id: String let elements: [ElementData]? } private struct ElementData: Codable { let role: String let title: String? let label: String? } private struct ClickResponse: Codable { let success: Bool let data: ClickData? let error: String? } private struct ClickData: Codable { let action: String let success: Bool } private struct ProcessError: Error { let message: String }

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/steipete/Peekaboo'

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