Xcode7 | Xcode Interface Tests | How to deal with location alerts?

I am writing test cases for one of my applications using XCUIApplication, XCUIElement and XCUIElementQuery introduced in Xcode7 / iOS 9.

I hit the road block. One of the screens in the test case requires the iOS location service. As expected, the user will be asked to allow the use of the location service with a warning under the heading: Allow "App name" to access your location while you use the app? with the Allow and Don't Allow buttons.

The problem is that since the warning is presented by the OS itself, it is not in the subtree of the application element.

I registered as follows:

 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 

Even the entry in the user interface generated similar code:

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

I have not found an API that can make me get past this problem. For example:

  • Click in position on screen
  • Get alerts outside the app

So how can I get past this? Is there a way to set up test goals to not allow the authorization of the geographic service.

+31
xcode ios9 xcode-ui-testing xctest xcode7-beta4
Jul 31 '15 at 12:28
source share
8 answers

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 



Note that this is slightly different, as the method name is now addUIInterruptionMonitor and takes withDescription as an argument

Xcode 7.1

Xcode 7.1 has finally fixed the system alert issue. There are, however, two small errors.

First, you need to set up a "user interface interrupt handler" before presenting a warning. This is our way to tell the framework how to handle an alert when it appears.

Secondly, after giving a warning you should interact with the interface. A simple click on the application works just fine, but it is necessary.

 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 

The "location dialog" is just a line that helps the developer determine which handler was accessed; it does not belong to the type of alert.

Xcode 7.0

The following will reject the only "system warning" in Xcode 7 Beta 6:

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

Beta 6 introduced many fixes for UI Testing, and I believe this was one of them.

Also note that I'm calling -element directly on -alerts . Calling -element for XCUIElementQuery forces the platform to select the "one and only" corresponding element on the screen. This works great for alerts when you can only see one image at a time. However, if you try this for a label and you have two labels, the framework will throw an exception.

+32
Aug 26 '15 at
source share

This is the only thing that worked for me. Using Xcode 9 fwiw.

It is also possible that I have already used addUIInterruptionMonitor for another alert. I tried reordering them, and that did not change the situation. Maybe this is a problem in 9 when you have two, or I may use them incorrectly. Anyway, the code below worked. :)

 let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard") let allowBtn = springboard.buttons["Allow"] if allowBtn.exists { allowBtn.tap() } 
+7
Nov 02 '17 at 21:53 on
source share

If you want to check if a warning is displayed, just check for the button:

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

he checks if a warning is displayed, and if he shows it, he touches it

+3
Nov 02 '15 at 16:38
source share

I made it work with this on Xcode 9.4.1 , the trick was to wait for the popup to appear.

 // 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() } 
+3
Aug 07 '18 at 6:08
source share

In xcode 9.1, warnings are only processed if the test device has iOS 11 . Does not work on older versions of iOS, e.g. 10.3, etc. Link: https://forums.developer.apple.com/thread/86989

To handle alerts, use this:

 //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 
+2
Dec 20 '17 at 13:30
source share

This works for all languages:

 let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard") let allowBtn = springboard.buttons.element(boundBy: 1) if allowBtn.exists { allowBtn.tap() } 
+1
Aug 18 '18 at 8:49
source share

To allow access to a location alert, you can call element.tap (), where an element is any element on your screen. Thus, after the call, click, access will click "Allow warning", and then touch your item

0
Oct 27 '15 at 18:48
source share

Here's what I did to accept the notification of permission to notify in any language by clicking the second button in the dialog box (two buttons). The Allow button is on the right, so the index is 1.

 let handler = addUIInterruptionMonitor(withDescription: "System Dialog") { (alert) -> Bool in alert.buttons.element(boundBy: 1).tap() return true } app.tap() 
0
Jun 22 '19 at 23:59
source share



All Articles