Skip to content

Commit

Permalink
Revert keyboard change that throws error if keyboard is not shown (#2222
Browse files Browse the repository at this point in the history
)
  • Loading branch information
amanjeetsingh150 authored Dec 31, 2024
1 parent c07184d commit 266c9a8
Show file tree
Hide file tree
Showing 16 changed files with 24 additions and 80 deletions.
4 changes: 3 additions & 1 deletion maestro-client/src/main/java/maestro/Errors.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ sealed class MaestroException(override val message: String) : RuntimeException(m

class UnableToClearState(message: String) : MaestroException(message)

class UnableToProcessCommand(message: String, val command: String): MaestroException(message)
class UnableToPullState(message: String) : MaestroException(message)

class UnableToPushState(message: String) : MaestroException(message)

class AppCrash(message: String): MaestroException(message)

Expand Down
6 changes: 1 addition & 5 deletions maestro-client/src/main/java/maestro/drivers/IOSDriver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,13 @@ package maestro.drivers
import com.github.michaelbull.result.expect
import com.github.michaelbull.result.getOrThrow
import com.github.michaelbull.result.onSuccess
import com.github.michaelbull.result.runCatching
import hierarchy.AXElement
import ios.IOSDevice
import ios.IOSDeviceErrors
import maestro.*
import maestro.UiElement.Companion.toUiElement
import maestro.UiElement.Companion.toUiElementOrNull
import maestro.utils.*
import maestro.utils.network.XCUITestServerError
import okio.Sink
import okio.source
import org.slf4j.LoggerFactory
Expand Down Expand Up @@ -531,10 +529,8 @@ class IOSDriver(
} catch (socketTimeoutException: SocketTimeoutException) {
LOGGER.error("Got socket timeout processing $callName command", socketTimeoutException)
throw socketTimeoutException
} catch (badRequest: XCUITestServerError.BadRequest) {
LOGGER.error("Bad request for $callName, reason: ${badRequest.errorResponse}")
throw MaestroException.UnableToProcessCommand(command = callName, message = badRequest.error.errorMessage)
} catch (appCrashException: IOSDeviceErrors.AppCrash) {
LOGGER.error("Detected app crash during $callName command", appCrashException)
throw MaestroException.AppCrash(appCrashException.errorMessage)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import maestro.ios.MockXCTestInstaller
import maestro.utils.network.XCUITestServerError
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import maestro.utils.network.Error
import okhttp3.mockwebserver.SocketPolicy
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
import xcuitest.XCTestClient
import xcuitest.XCTestDriverClient
import xcuitest.api.DeviceInfo
import xcuitest.api.Error
import java.net.InetAddress

class XCTestDriverClientTest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ object XCRunnerCLIUtils {
val mapper = jacksonObjectMapper()
val appsMap = mapper.readValue(json, Map::class.java) as Map<String, Any>

return appsMap.keys + runningApps(deviceId).keys
return appsMap.keys
}

fun setProxy(host: String, port: Int) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package xcuitest
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import hierarchy.ViewHierarchy
import maestro.utils.HttpClient
import maestro.utils.network.Error
import maestro.utils.network.XCUITestServerError
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
Expand Down Expand Up @@ -255,7 +254,7 @@ class XCTestDriverClient(
logger.error("Request for $pathString failed with bad request ${code}, body: $responseBodyAsString")
throw XCUITestServerError.BadRequest(
"Request for $pathString failed with bad request ${code}, body: $responseBodyAsString",
error
responseBodyAsString
)
}
error.errorMessage.contains("Lost connection to the application.*".toRegex()) -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package maestro.utils.network
package xcuitest.api

import com.fasterxml.jackson.annotation.JsonProperty

Expand Down
Binary file modified maestro-ios-driver/src/main/resources/maestro-driver-ios.zip
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ struct EraseTextHandler: HTTPHandler {
do {
let start = Date()

if let errorResponse = await waitUntilKeyboardIsPresented(appIds: requestBody.appIds) {
return errorResponse
}
let appId = RunningApp.getForegroundAppId(requestBody.appIds)
await waitUntilKeyboardIsPresented(appId: appId)

let deleteText = String(repeating: XCUIKeyboardKey.delete.rawValue, count: requestBody.charactersToErase)

Expand All @@ -36,20 +35,11 @@ struct EraseTextHandler: HTTPHandler {
}
}

private func waitUntilKeyboardIsPresented(appIds: [String]) async -> HTTPResponse? {
let foregroundAppIds = RunningApp.getForegroundAppIds(appIds)
logger.info("Foreground apps \(foregroundAppIds)")

let isKeyboardPresented: Bool = (try? await TimeoutHelper.repeatUntil(timeout: 1, delta: 0.2) {
return foregroundAppIds.contains { appId in
XCUIApplication(bundleIdentifier: appId).keyboards.firstMatch.exists
}
}) ?? false
private func waitUntilKeyboardIsPresented(appId: String?) async {
try? await TimeoutHelper.repeatUntil(timeout: 1, delta: 0.2) {
guard let appId = appId else { return true }

// Return an error response if the keyboard is not presented
if !isKeyboardPresented {
return AppError(type: .timeout, message: "Keyboard not presented within 1 second timeout for erase command").httpResponse
return XCUIApplication(bundleIdentifier: appId).keyboards.firstMatch.exists
}
return nil
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@ struct InputTextRouteHandler : HTTPHandler {
do {
let start = Date()

if let errorResponse = await waitUntilKeyboardIsPresented(appIds: requestBody.appIds) {
return errorResponse
}
let appId = RunningApp.getForegroundAppId(requestBody.appIds)
await waitUntilKeyboardIsPresented(appId: appId)

try await TextInputHelper.inputText(requestBody.text)

Expand All @@ -31,20 +30,11 @@ struct InputTextRouteHandler : HTTPHandler {
}
}

private func waitUntilKeyboardIsPresented(appIds: [String]) async -> HTTPResponse? {
let foregroundAppIds = RunningApp.getForegroundAppIds(appIds)
logger.info("Foreground apps \(foregroundAppIds)")

let isKeyboardPresented: Bool = (try? await TimeoutHelper.repeatUntil(timeout: 1, delta: 0.2) {
return foregroundAppIds.contains { appId in
XCUIApplication(bundleIdentifier: appId).keyboards.firstMatch.exists
}
}) ?? false
private func waitUntilKeyboardIsPresented(appId: String?) async {
try? await TimeoutHelper.repeatUntil(timeout: 1, delta: 0.2) {
guard let appId = appId else { return true }

// Return an error response if the keyboard is not presented
if !isKeyboardPresented {
return AppError(type: .timeout, message: "Keyboard not presented within 1 second timeout for input command").httpResponse
return XCUIApplication(bundleIdentifier: appId).keyboards.firstMatch.exists
}
return nil
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import FlyingFox
enum AppErrorType: String, Codable {
case `internal`
case precondition
case timeout
}

struct AppError: Error, Codable {
Expand All @@ -16,7 +15,6 @@ struct AppError: Error, Codable {
switch type {
case .internal: return .internalServerError
case .precondition: return .badRequest
case .timeout: return .badRequest
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,4 @@ struct TimeoutHelper {
}
}
}

static func repeatUntil(timeout: TimeInterval, delta: TimeInterval, block: () -> Bool) async throws -> Bool {
guard delta >= 0 else {
throw NSError(domain: "Invalid value", code: 1, userInfo: [NSLocalizedDescriptionKey: "Delta cannot be negative"])
}

let timeout = Date().addingTimeInterval(timeout)

while Date() < timeout {
do {
try await Task.sleep(nanoseconds: UInt64(1_000_000_000 * delta))
} catch {
throw NSError(domain: "Failed to sleep task", code: 2, userInfo: [NSLocalizedDescriptionKey: "Task could not be put to sleep"])
}

if (block()) {
return true
}
}
return false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,5 @@ struct RunningApp {
} ?? RunningApp.springboardBundleId
}

static func getForegroundAppIds(_ appIds: [String]) -> [String] {
// springboard is always on foreground
let allAppIds = appIds + ["com.apple.springboard"]


return allAppIds.filter { appId in
let app = XCUIApplication(bundleIdentifier: appId)
return app.state == .runningForeground
}
}

}
1 change: 0 additions & 1 deletion maestro-utils/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ dependencies {
api(libs.square.okio)
implementation(libs.square.okhttp)
implementation(libs.micrometer.core)
api(libs.jackson.module.kotlin)
implementation(libs.micrometer.observation)

testImplementation(libs.mockk)
Expand Down
2 changes: 1 addition & 1 deletion maestro-utils/src/main/kotlin/network/Errors.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ sealed class XCUITestServerError: Throwable() {
data class UnknownFailure(val errorResponse: String) : XCUITestServerError()
data class NetworkError(val errorResponse: String): XCUITestServerError()
data class AppCrash(val errorResponse: String): XCUITestServerError()
data class BadRequest(val errorResponse: String, val error: Error): XCUITestServerError()
data class BadRequest(val errorResponse: String, val clientMessage: String): XCUITestServerError()
}
3 changes: 1 addition & 2 deletions maestro-utils/src/test/kotlin/network/ErrorsTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,9 @@ class ErrorsTest {
fun `XCUITestServerError BadRequest should have correct messages`() {
val errorMessage = "Bad request"
val clientMessage = "Client error"
val error = Error(errorMessage = clientMessage, errorCode = "bad-request-precondition")

assertThrows<XCUITestServerError.BadRequest>(errorMessage) {
throw XCUITestServerError.BadRequest(errorMessage, error)
throw XCUITestServerError.BadRequest(errorMessage, clientMessage)
}
}
}

0 comments on commit 266c9a8

Please sign in to comment.