Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -118,15 +118,23 @@ extension RunnerTests {
return windows
}

func elementQueries(app: XCUIApplication, matching type: XCUIElement.ElementType) throws -> [XCUIElementQuery] {
try elementQueries(root: app, matching: type, litDisplayID: requestLitPanel?.displayID)
/// One walk of the roots for every type, so a multi-type read walks the lit windows once.
func elementQueries(app: XCUIApplication, matching types: XCUIElement.ElementType...) throws -> [XCUIElementQuery] {
queries(matching: types, in: try elementSearchRoots(root: app, litDisplayID: requestLitPanel?.displayID))
}

func elementQueries(
root: XCUIElement,
matching type: XCUIElement.ElementType,
matching types: XCUIElement.ElementType...,
litDisplayID: UInt?
) throws -> [XCUIElementQuery] {
try elementSearchRoots(root: root, litDisplayID: litDisplayID).map { $0.descendants(matching: type) }
queries(matching: types, in: try elementSearchRoots(root: root, litDisplayID: litDisplayID))
}

private func queries(
matching types: [XCUIElement.ElementType],
in roots: [XCUIElement]
) -> [XCUIElementQuery] {
types.flatMap { type in roots.map { $0.descendants(matching: type) } }
}
Comment thread
thymikee marked this conversation as resolved.
Resolved
}
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,7 @@ extension RunnerTests {

/// Resolved before the probe's issue containment, so a lit-panel refusal is not read as no input.
private func textInputQueries(app: XCUIApplication) throws -> [XCUIElementQuery] {
let inputTypes: [XCUIElement.ElementType] = [.textField, .secureTextField, .searchField, .textView]
return try inputTypes.flatMap { try elementQueries(app: app, matching: $0) }
try elementQueries(app: app, matching: .textField, .secureTextField, .searchField, .textView)
}

private func queryTextInputs(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,16 @@ extension RunnerTests {
try assertions(response)
}

/// Runs `body` with the app's window probed as the only window on lit display 3 at `frame`,
/// handing it the count of window-list reads.
@MainActor
func withLitPanelWindow(frame: CGRect, _ body: (_ windowListReads: () -> Int) throws -> Void) throws {
try withLitPanelBookingProbe { _ in
LitPanelBookingProbe.windowFrame = frame
try body { LitPanelBookingProbe.windowListReads }
}
}

@MainActor
private func withLitPanelBookingProbe(composed: Bool = false, _ body: (XCUIElement) throws -> Void) throws {
app.launch()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ import AgentDeviceSnapshotPresentation
#if AGENT_DEVICE_RUNNER_UNIT_TESTS
extension RunnerTests {
#if os(iOS)
/// Keyboard reads stay application-wide on a lit-panel request, so a failed lit-window walk
/// cannot turn `keyboard dismiss` into a refusal.
@MainActor
func testKeyboardDismissIgnoresAFailedLitPanelWindowWalk() throws {
try withLitPanelWindow(frame: CGRect(x: 0, y: 0, width: 669, height: 951)) { _ in
litPanelWindowWalkIssueForTesting = true
defer { litPanelWindowWalkIssueForTesting = false }
let command = try runnerCommandFixture(#"{"command":"keyboardDismiss","litPanel":{"displayId":3,"widthPt":669,"heightPt":951}}"#)
setRequestLitPanel(from: command)
let response = try executeOnMainPrepared(command: command, activeApp: app)
XCTAssertTrue(response.ok, String(describing: response.error))
}
}

@MainActor
func testCapturedKeyboardBandIncludesTheInputAssistantOutsideTheKeyboard() {
let keyboard = ElementAttributesFixture(.keyboard, CGRect(x: 0, y: 600, width: 390, height: 244))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ private struct AlertCommandTraitsFixture: Decodable {
}

extension RunnerTests {
#if os(iOS)
/// A frame sample resolves the lit panel without booking it, so it never replaces the request's booking.
@MainActor
func testFrameSamplingResolvesTheLitPanelWithoutBookingIt() throws {
try withLitPanelWindow(frame: CGRect(x: 0, y: 0, width: 669, height: 951)) { _ in
setRequestLitPanel(from: try runnerCommandFixture(#"{"command":"snapshot","litPanel":{"displayId":3,"widthPt":669,"heightPt":951}}"#))
_ = captureRunnerFrame(app: app)
XCTAssertNil(litPanelState.surface)
}
}
#endif

func testAlertRetryFactMatchesTheSharedGoldenTable() throws {
let fixtureURL = URL(fileURLWithPath: #filePath)
.deletingLastPathComponent()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,30 @@ import XCTest

extension RunnerTests {
#if AGENT_DEVICE_RUNNER_UNIT_TESTS && os(iOS)
/// One text-input lookup walks the lit windows once, however many input types it queries.
@MainActor
func testTextInputProbeWalksTheLitWindowsOnce() throws {
try withLitPanelWindow(frame: CGRect(x: 0, y: 0, width: 669, height: 951)) { windowListReads in
setRequestLitPanel(from: try runnerCommandFixture(
#"{"command":"type","litPanel":{"displayId":3,"widthPt":669,"heightPt":951}}"#
))
_ = try probeTextInputs(app: app, point: CGPoint(x: 10, y: 10), contentTranslation: .none)
XCTAssertEqual(windowListReads(), 1)
}
}

/// A content-vector read on a lit-panel request that nothing booked yet books the request's
/// window and answers its origin, instead of refusing for want of an earlier booking.
@MainActor
func testUnbookedLitPanelContentTranslationBooksTheRequestWindow() throws {
try withLitPanelWindow(frame: CGRect(x: 0, y: 80, width: 669, height: 871)) { _ in
setRequestLitPanel(from: try runnerCommandFixture(#"{"command":"type","litPanel":{"displayId":3,"widthPt":669,"heightPt":951}}"#))
guard case .known(let vector) = liveContentTranslation(app: app) else { return XCTFail("no vector") }
XCTAssertEqual(vector, CGSize(width: 0, height: 80))
XCTAssertNotNil(litPanelState.surface)
}
}

func testTextInputProbePreservesEnclosingRunnerWait() {
app.launchArguments = ["--agent-device-text-entry-regression"]
app.launch()
Expand Down
Loading