Skip to main content
Glama
WindowCommandCLITests.swift8.3 kB
import Foundation import Testing @testable import PeekabooCLI @testable import PeekabooCore #if !PEEKABOO_SKIP_AUTOMATION @Suite("Window Command CLI Tests", .serialized, .tags(.automation), .enabled(if: CLITestEnvironment.runAutomationRead)) struct WindowCommandCLITests { @Test("Window help output") func windowHelpOutput() async throws { let result = try await runCommand(["window", "--help"]) #expect(result.status == 0) #expect(result.output.contains("Manipulate application windows")) #expect(result.output.contains("close")) #expect(result.output.contains("minimize")) #expect(result.output.contains("maximize")) #expect(result.output.contains("move")) #expect(result.output.contains("resize")) #expect(result.output.contains("set-bounds")) #expect(result.output.contains("focus")) #expect(result.output.contains("list")) } @Test("Window close help") func windowCloseHelp() async throws { let result = try await runCommand(["window", "close", "--help"]) #expect(result.status == 0) #expect(result.output.contains("Close a window")) #expect(result.output.contains("--app")) #expect(result.output.contains("--window-title")) #expect(result.output.contains("--window-index")) } @Test("Window move help") func windowMoveHelp() async throws { let result = try await runCommand(["window", "move", "--help"]) #expect(result.status == 0) #expect(result.output.contains("Move a window")) #expect(result.output.contains("--x")) #expect(result.output.contains("--y")) } @Test("Window resize help") func windowResizeHelp() async throws { let result = try await runCommand(["window", "resize", "--help"]) #expect(result.status == 0) #expect(result.output.contains("Resize a window")) #expect(result.output.contains("--width")) #expect(result.output.contains("--height")) } @Test("Window list delegates to list windows") func windowListDelegation() async throws { let result = try await runCommand(["window", "list", "--app", "NonExistentApp", "--json-output"]) #expect(result.status != 0) // Should get JSON output #expect(result.output.contains("{")) #expect(result.output.contains("}")) // Parse and verify structure if let data = result.output.data(using: .utf8) { let response = try JSONDecoder().decode(JSONResponse.self, from: data) #expect(response.success == false) #expect(response.error?.code == "APP_NOT_FOUND") } } @Test("Missing required app parameter") func missingAppParameter() async throws { let result = try await self.runCommand(["window", "close", "--json-output"]) #expect(result.status != 0) } @Test("Invalid window index") func invalidWindowIndex() async throws { let result = try await runCommand([ "window", "close", "--app", "Finder", "--window-index", "999", "--json-output", ]) #expect(result.status != 0) if let data = result.output.data(using: .utf8) { let response = try JSONDecoder().decode(JSONResponse.self, from: data) #expect(response.success == false) #expect(response.error != nil) } } @Test("Window operation with non-existent app") func nonExistentApp() async throws { let operations = ["close", "minimize", "maximize", "focus"] for operation in operations { let result = try await runCommand(["window", operation, "--app", "NonExistentApp123", "--json-output"]) #expect(result.status != 0) if let data = result.output.data(using: .utf8) { let response = try JSONDecoder().decode(JSONResponse.self, from: data) #expect(response.success == false) #expect(response.error?.code == "APP_NOT_FOUND") } } } // Helper to run commands private struct CommandResult { let output: String let status: Int32 } private func runCommand(_ arguments: [String]) async throws -> CommandResult { let services = await self.makeTestServices() let result = try await InProcessCommandRunner.run(arguments, services: services) let output = result.stdout.isEmpty ? result.stderr : result.stdout return CommandResult(output: output, status: result.exitStatus) } @MainActor private func makeTestServices() -> PeekabooServices { let applications: [ServiceApplicationInfo] = [ ServiceApplicationInfo( processIdentifier: 101, bundleIdentifier: "com.apple.finder", name: "Finder", bundlePath: "/System/Library/CoreServices/Finder.app", isActive: true, isHidden: false, windowCount: 1 ), ServiceApplicationInfo( processIdentifier: 202, bundleIdentifier: "com.apple.TextEdit", name: "TextEdit", bundlePath: "/System/Applications/TextEdit.app", isActive: false, isHidden: false, windowCount: 1 ), ] let finderWindow = ServiceWindowInfo( windowID: 1, title: "Finder Window", bounds: CGRect(x: 0, y: 0, width: 1024, height: 768), isMinimized: false, isMainWindow: true, windowLevel: 0, alpha: 1.0, index: 0, spaceID: 1, spaceName: "Desktop 1", screenIndex: 0, screenName: "Built-in" ) let windowsByApp: [String: [ServiceWindowInfo]] = [ "Finder": [finderWindow], ] return TestServicesFactory.makePeekabooServices( applications: StubApplicationService(applications: applications, windowsByApp: windowsByApp), windows: StubWindowService(windowsByApp: windowsByApp), menu: StubMenuService(menusByApp: [:]), dialogs: StubDialogService() ) } } @Suite( "Window Command Integration Tests", .serialized, .enabled(if: CLITestEnvironment.runAutomationActions) ) struct WindowCommandLocalTests { @Test("Window operations with TextEdit") func textEditWindowOperations() async throws { // Ensure TextEdit is running _ = try? await self.runBuiltCommand(["image", "--app", "TextEdit", "--json-output"]) // Try to focus TextEdit let focusOutput = try await runBuiltCommand(["window", "focus", "--app", "TextEdit", "--json-output"]) let focusResponse = try JSONDecoder().decode(JSONResponse.self, from: Data(focusOutput.utf8)) if focusResponse.error?.code == "PERMISSION_ERROR_ACCESSIBILITY" { Issue.record("Accessibility permission required") return } if focusResponse.success { // Try moving the window let moveOutput = try await runBuiltCommand([ "window", "move", "--app", "TextEdit", "--x", "200", "--y", "200", "--json-output", ]) let moveResponse = try JSONDecoder().decode(JSONResponse.self, from: Data(moveOutput.utf8)) if moveResponse.success, let data = moveResponse.data as? [String: Any], let bounds = data["new_bounds"] as? [String: Any] { #expect(bounds["x"] as? Int == 200) #expect(bounds["y"] as? Int == 200) } } } // Helper for local tests using built binary private func runBuiltCommand( _ arguments: [String], allowedExitStatuses: Set<Int32> = [0, 64] ) async throws -> String { let result = try await InProcessCommandRunner.runShared( arguments, allowedExitCodes: allowedExitStatuses ) return result.combinedOutput } } #endif

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

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