XCTest – Handling camera/photos/location permissions alerts when running UX tests

When running UX tests, we are often interrupted by alerts as shown below. Whats a good way to handle this ?

Alert asking user permission access to the photo library

There are two ways you can handle these alerts. You can either use addUIInterruptionMonitor or waitForExistence APIs to handle the alerts. You can use the below diagram to determine what you should be using.

Diagram showing when to use interruption APIs

Let’s consider your app always asks for the photos library permission when it opens up. I would handle this using a addUIInterruptionMonitor API as shown below.

func testAccessToPhotosLibrary() throws {
	var alertPressed: Bool = false
	handler = addUIInterruptionMonitor(withDescription: "Asking for photos library permission") { [self] element -> Bool in
	alertPressed = clickButtons(element: element, text: "Allow Access to All Photos")
		return alertPressed
	}
	wait {
		app.tap()
	}
	waitAndCheck {
		alertPressed
	}
	var textQuery = app.staticTexts["Hello Tap Test"]
	XCTAssertFalse(textQuery.exists)
}

func clickButtons(element: XCUIElement, text: String) -> Bool {
	let allowButton = element.buttons[text]
	if allowButton.exists {
		allowButton.tap()
		return true
	}
	return false
}
extension XCTestCase {
	func waitAndCheck(_ description: String = "", _ timeout: Double = 0.5, callback: () -> Bool) {
		let exp = self.expectation(description: description)
		let result = XCTWaiter.wait(for: [exp], timeout: timeout)
		if result == XCTWaiter.Result.timedOut {
			XCTAssertTrue(callback())
		}
		else {
			XCTFail("Timeout waiting \(timeout) for \(description)")
		}
	}

	func wait(_ description: String = "", _ timeout: Double = 0.5, callback: () -> Void) {
		let exp = self.expectation(description: description)
		let result = XCTWaiter.wait(for: [exp], timeout: timeout)
		if result == XCTWaiter.Result.timedOut {
			callback()
		}
		else {
			XCTFail("Timeout waiting \(timeout) for \(description)")
		}
	}
}

In the above code snippet, we are clicking the Allow access to all Photos button. You can alter the above snippet to also click the “Don’t Allow” button. Notice the allowButton.tap() call. This is very important.

The second way to handle alerts is to use the waitForExistence APIs. I would prefer to use this when I am throwing an alert knowingly. This is how it can be used.

XCUIApplication().alerts.scrollViews.otherElements.buttons["OK"].waitForExistence(timeout: 2.0)

To learn more about testing, you can refer to this WWDC video: https://developer.apple.com/videos/play/wwdc2020/10220/

Leave a Reply

Your email address will not be published. Required fields are marked *