Reputation: 565
My App uses Location Services and I have code that alerts the user if Location Services are disabled. This has a button that allows them to switch to the Settings app and enable it. This works fine but I want to write a UI Test that detects it, if possible.
Currently, my UI Tests work correctly checking for the alert appearing and that it has a Settings button. I can confirm the app switches to settings through either the simulator or physical device when the button is tapped.
I'm not sure I can tell that the Settings app itself appears through the UITest (that would be nice!) but I could check that the app under test entered the background (that would be good enough!)
In my AppDelegate I have print statements that confirm the app is going through applicationWillResignActive(...) and applicationDidEnterBackground(...)
I tried the following:
let predicate = NSPredicate(format: "self.state = XCUIApplication.State.runningBackground", argumentArray: nil)
_ = self.expectation(for: predicate, evaluatedWith: app, handler: nil)
waitForExpectations(timeout: 10.0, handler: nil)
XCTAssertTrue(app.state == .runningBackground, "Doesn't look like the Settings App was launched")
and the console is flagging up that it is waiting on the expectation - it logs every second. Note that 'app' is the instance of XCUIApplication() that I use in the test. Eventually, the expectation times out and the test terminates because it wasn't fulfilled. At that point, my two print statements (resigning active, entered background) appear on the console.
It would seem that my app is working as expected but that the expectation isn't determining the change in app state. I've tried setting the wait period to 60 secs but the result is the same so it isn't a case of not waiting long enough.
Without the expectation, i.e. the code goes straight from pressing the settings button to checking the assert, the assert fails because the app state is .runningForeground. I thought that execution was happening too fast, hence the attempt to wait for the state change. In this case, the assert fails, the test finishes and then "Resigning active" appears in the console, but not "Entered background".
This is ios11 on Xcode 9 and behaviour is the same in the simulator and physical device.
To sum up, the question is: what's the best way to programmatically test that the Settings app has launched?
Upvotes: 0
Views: 675
Reputation: 565
So it would seem I'm overcomplicating it! Whilst waiting for an answer I thought I'd see if I could check for a UI Element becoming inactive, or similar. That's when I discovered:
app.wait(for: .runningBackground, timeout: 10)
Which returns true when that state is achieved! And it works. Obviously, I don't know whether the app now running is Settings but it's good enough as the only reason for that state to be achieved in that UI Test is if the settings URL activated.
Upvotes: 5