Issue #48

Continue my post https://github.com/onmyway133/blog/issues/45. When you work with features, like map view, you mostly need permissions, and in UITests you need to test for system alerts.

Add interruption monitor

This is the code. Note that you need to call app.tap() to interact with the app again, in order for interruption monitor to work

addUIInterruptionMonitor(withDescription: "Location permission", handler: { alert in
  alert.buttons["Allow"].tap()
  return true
})

app.tap()

Note that you don’t always need to handle the returned value of addUIInterruptionMonitor

Only tap when needed

One problem with this approach is that when there is no system alert (you already touched to allow before), then app.tap() will tap on your main screen. In my app which uses map view, it will tap on some pins, which will present another screen, which is not correct.

Since app.alerts does not work, my 2nd attempt is to check for app.windows.count. Unfortunately, it always shows 5 windows whether alert is showing or not. I know 1 is for main window, 1 is for status bar, the other 3 windows I have no idea.

The 3rd attempt is to check that underlying elements (behind alert) can’t be touched, which is to use isHittable. This property does not work, it always returns true

Check the content

This uses the assumption that we only tests for when user hits Allow button. So only if alert is answered with Allow, then we have permission to display our content. For my map view, I check that there are some pins on the map. See https://github.com/onmyway133/blog/issues/45 on how to mock location and identify the pins

if app.otherElements.matching(identifier: "myPin").count == 0 {
  app.tap()
}

When there is no permission

So how can we test that user has denied your request? In my map view, if user does not allow location permission, I show a popup asking user to go to Settings and change it, otherwise, they can’t interact with the map.

I don’t know how to toggle location in Privacy in Settings, maybe XCUISiriService can help. But 1 thing we can do is to mock the application

Before you launch the app in UITests, add some arguments

app.launchArguments.append("--UITests-mockNoLocationPermission")

and in the app, we need to check for this arguments

func checkLocationPermission() {
  if CommandLine.arguments.contains("--UITests-mockNoLocationPermission") {
    showNoLocationPopupAndAskUserToEnableInSettings()
  }
}

That’s it. In UITests, we can test whether that no location permission popup appears or not

Updated at 2020-06-02 02:12:36