PressCommandTests.swift•4.43 kB
import Foundation
import PeekabooCore
import PeekabooFoundation
import Testing
@testable import PeekabooCLI
#if !PEEKABOO_SKIP_AUTOMATION
@Suite(
"PressCommand Tests",
.serialized,
.tags(.safe),
.enabled(if: CLITestEnvironment.runAutomationRead)
)
struct PressCommandTests {
@Test("press --help documents command")
func pressHelp() async throws {
let context = await self.makeContext()
let result = try await self.runPress(arguments: ["--help"], context: context)
#expect(result.exitStatus == 0)
#expect(self.output(from: result).contains("Press individual keys or key sequences"))
}
@Test("Press command forwards keys to automation service")
func forwardsKeys() async throws {
let context = await self.makeContext()
let result = try await self.runPress(arguments: ["return", "--json-output"], context: context)
#expect(result.exitStatus == 0)
let calls = await self.automationState(context) { $0.typeActionsCalls }
let call = try #require(calls.first)
#expect(call.actions.count == 1)
let payloadData = try #require(self.output(from: result).data(using: .utf8))
let payload = try JSONDecoder().decode(PressResult.self, from: payloadData)
#expect(payload.success)
#expect(payload.keys == ["return"])
#expect(payload.totalPresses == 1)
}
@Test("Repeat count multiplies key actions")
func repeatCount() async throws {
let context = await self.makeContext()
let result = try await self.runPress(arguments: ["tab", "--count", "3"], context: context)
#expect(result.exitStatus == 0)
let calls = await self.automationState(context) { $0.typeActionsCalls }
let call = try #require(calls.first)
#expect(call.actions.count == 3)
#expect(call.cadence == .fixed(milliseconds: 100))
}
@Test("Press command supports multiple keys in sequence")
func multipleKeysSequence() async throws {
let context = await self.makeContext()
let result = try await self.runPress(arguments: ["up", "down", "left", "right"], context: context)
#expect(result.exitStatus == 0)
let calls = await self.automationState(context) { $0.typeActionsCalls }
let call = try #require(calls.first)
#expect(call.actions.count == 4)
#expect(call.actions.allSatisfy {
if case .key = $0 { true } else { false }
})
}
@Test("Session argument is forwarded")
func forwardsSession() async throws {
let context = await self.makeContext()
let result = try await self.runPress(arguments: ["escape", "--session", "session-42"], context: context)
#expect(result.exitStatus == 0)
let calls = await self.automationState(context) { $0.typeActionsCalls }
let call = try #require(calls.first)
#expect(call.sessionId == "session-42")
}
@Test("Invalid key results in failure")
func invalidKey() async throws {
let context = await self.makeContext()
let result = try await self.runPress(arguments: ["notakey"], context: context)
#expect(result.exitStatus != 0)
let calls = await self.automationState(context) { $0.typeActionsCalls }
#expect(calls.isEmpty)
}
// MARK: - Helpers
private func runPress(
arguments: [String],
context: TestServicesFactory.AutomationTestContext
) async throws -> CommandRunResult {
try await InProcessCommandRunner.run(["press"] + arguments, services: context.services)
}
private func output(from result: CommandRunResult) -> String {
result.stdout.isEmpty ? result.stderr : result.stdout
}
private func makeContext(
configure: (@MainActor (StubAutomationService, StubSessionManager) -> Void)? = nil
) async -> TestServicesFactory.AutomationTestContext {
await MainActor.run {
let context = TestServicesFactory.makeAutomationTestContext()
configure?(context.automation, context.sessions)
return context
}
}
private func automationState<T: Sendable>(
_ context: TestServicesFactory.AutomationTestContext,
_ operation: @MainActor (StubAutomationService) -> T
) async -> T {
await MainActor.run {
operation(context.automation)
}
}
}
#endif