xcode xctest ios9 xcode7-beta4 xcode-ui-testing

Xcode7 | Pruebas Xcode UI | ¿Cómo manejar la alerta de servicio de ubicación?



xctest ios9 (7)

Xcode 9

let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard") let allowBtn = springboard.buttons["Allow"] if allowBtn.exists { allowBtn.tap() }

Xcode 8.3.3

_ = addUIInterruptionMonitor(withDescription: "Location Dialog") { (alert) -> Bool in alert.buttons["Allow"].tap() return true } app.buttons["Request Location"].tap() app.tap() // need to interact with the app for the handler to fire

Tenga en cuenta que es un poco diferente, ya que el nombre del método ahora es addUIInterruptionMonitor y toma withDescription como argumento

Xcode 7.1

Xcode 7.1 finalmente ha solucionado un problema con las alertas del sistema. Hay, sin embargo, dos pequeños errores.

Primero, debe configurar un "Controlador de Interrupción de UI" antes de presentar la alerta. Esta es nuestra manera de decirle al marco cómo manejar una alerta cuando aparece.

Segundo, luego de presentar la alerta debes interactuar con la interfaz. Simplemente tocando la aplicación funciona bien, pero es necesario.

addUIInterruptionMonitorWithDescription("Location Dialog") { (alert) -> Bool in alert.buttons["Allow"].tap() return true } app.buttons["Request Location"].tap() app.tap() // need to interact with the app for the handler to fire

El "Cuadro de diálogo de ubicación" es solo una cadena para ayudar al desarrollador a identificar a qué controlador se accedió, no es específico del tipo de alerta.

Xcode 7.0

Lo siguiente descartará una sola "alerta del sistema" en Xcode 7 Beta 6:

let app = XCUIApplication() app.launch() // trigger location permission dialog app.alerts.element.collectionViews.buttons["Allow"].tap()

Beta 6 introdujo una serie de correcciones para las pruebas de UI y creo que esta fue una de ellas.

También tenga en cuenta que estoy llamando a -element directamente en las -alerts . Al llamar a -element en una XCUIElementQuery , el marco debe elegir el elemento "único y único" en la pantalla. Esto funciona muy bien para alertas donde solo puede tener una visible a la vez. Sin embargo, si intenta esto para una etiqueta y tiene dos etiquetas, el marco generará una excepción.

Estoy escribiendo Casos de prueba de UI para una de mis aplicaciones utilizando XCUIApplication, XCUIElement y XCUIElementQuery introducidas en Xcode7 / iOS 9.

He golpeado un bloqueo de carretera. Una de las pantallas en caso de prueba requiere los Servicios de Localización de iOS. Como era de esperar, se le solicita al usuario que permita el uso del servicio de ubicación con una alerta titulada: ¿ Allow “App name” to access your location while you use the app? con los botones Allow y Don''t Allow .

Parece que el problema es que, dado que la alerta es presentada por el propio sistema operativo, no está presente en el subárbol de elementos de la aplicación.

He registrado los siguientes

print("XYZ:/(app.alerts.count)")//0 var existence = app.staticTexts["Allow “App Name” to access your location while you use the app?"].exists print("XYZ:/(existence)")//false existence = app.buttons["Allow"].exists print("XYZ:/(existence)") //false

Incluso la grabación de UI generó un código similar:

XCUIApplication().alerts["Allow “App Name” to access your location while you use the app?"].collectionViews.buttons["Allow"].tap()

No he encontrado ninguna API que me permita superar este problema. Por ejemplo:

  • Toque en una posición en la pantalla
  • Recibe alertas fuera de la aplicación

Entonces, ¿cómo puedo pasar esto? ¿Hay alguna forma de configurar los objetivos de prueba para que no se requiera la autorización del servicio de ubicación?


Conseguí que funcionara con esto en Xcode 9.4.1 , el truco era esperar a que aparezca la ventana emergente.

// wait for location service popup to appear let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard") let allowBtn = springboard.buttons["Allow"] expectation(for: NSPredicate(format: "exists == true"), evaluatedWith: allowBtn, handler: nil) waitForExpectations(timeout: 10, handler: nil) //allow location service if allowBtn.exists { allowBtn.tap() }


Esto fue lo único que funcionó para mí. Utilizando Xcode 9 fwiw.

También es probable que addUIInterruptionMonitor en addUIInterruptionMonitor ya estaba usando addUIInterruptionMonitor para una alerta diferente. Intenté reordenarlos y no hizo una diferencia. Podría ser que es un problema en 9 cuando tienes dos, o podría ser que los estaba usando mal. En cualquier caso, el siguiente código funcionó. :)

let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard") let allowBtn = springboard.buttons["Allow"] if allowBtn.exists { allowBtn.tap() }


Esto funciona para todos los idiomas:

let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard") let allowBtn = springboard.buttons.element(boundBy: 2) if allowBtn.exists { allowBtn.tap() }


Para tocar en alerta de ubicación, puede llamar a element.tap () donde elemento es cualquier elemento en su pantalla. Entonces, después de llamar a tap, la accesibilidad tocará Permitir alerta y luego tocará tu elemento


Si desea verificar si la alerta se está mostrando, solo verifique la existencia del botón:

if (app.alerts.element.collectionViews.buttons["Dismiss"].exists) { app.alerts.element.collectionViews.buttons["Dismiss"].tap() }

comprueba si la alerta se muestra y si la muestra la tocará


En xcode 9.1, las alertas solo se manejan si el dispositivo de prueba tiene iOS 11 . No funciona en versiones anteriores de iOS, por ejemplo, 10.3, etc. Referencia: https://forums.developer.apple.com/thread/86989

Para manejar alertas usa esto:

//Use this before the alerts appear. I am doing it before app.launch() let allowButtonPredicate = NSPredicate(format: "label == ''Always Allow'' || label == ''Allow''") //1st alert _ = addUIInterruptionMonitor(withDescription: "Allow to access your location?") { (alert) -> Bool in let alwaysAllowButton = alert.buttons.matching(allowButtonPredicate).element.firstMatch if alwaysAllowButton.exists { alwaysAllowButton.tap() return true } return false } //Copy paste if there are more than one alerts to handle in the app