iOS deep linking with Xcode UI testing

I want to test parts of my app UI in isolation, so avoid having to drill down from the splash screen to the pages in question. My app implements deep linking, but I can't figure out how to configure XCUIApplication in the setUp() to trigger the page transition.


I have a method in the app delegate called openURL() which handles this for the production app. It works great, but when I call it (below), nothing happens. If I put a breakpoint in openURL() it never even gets hit.


    override func setUp() {
        super.setUp()
        continueAfterFailure = false

        XCUIApplication().launch()
      
        guard let url = NSURL(string: "fooapp://page/3") else {
            fatalError("Couldn't create URL")
        }


        UIApplication.sharedApplication().openURL(url)
    }


What I really want is to set UIApplicationLaunchOptionsURLKey in launchOptions and just let the app behave as if it received an external URL. I see launchArguments and launchEnvironment are available on XCUIApplication, but then I have to write something special to extract those values out and manually call openURL somewhere in the app delegate. What's the right way to do this?

Hello,

The openURL still does not work correctly. I am using Xcode 15.0.1 with an iOS 17 simulator. Application launches by openURL API but the app doesn't receive this in onOpenURL.

Isn't the purpose of this XCUIApplication.open(_:) function to launch the app by link like deep links?

  • If yes, I can say that it still not working on the latest Xcode and iOS. If I can't receive the URL by onOpenURL I can't test deep links, URL schemes, and Universal links. The app also can't receive the link on launchOptions which is provided to the app through didFinishLaunchingWithOptions.

  • If not, I am truly questioning the purpose of this API. It seems to me it works exactly the same as launch().

Just posting this here in case it helps someone in the future. The code here came in handy for us:

http://emndeniz.medium.com/ios-ui-testing-with-deep-links-7c33e9f9b7f1

Here's the relevant code. After starting a UI test in your app, then you start up Safari and open a deep link, which sends the data back to your app, and since the UI test is running for your app, you can now receive the incoming data in onOpenURL.

import XCTest

final class UITestHelpers {

    // Singleton instance
    static let shared = UITestHelpers()
    private init() {}

    // Safari app by its identifier
    private let safari: XCUIApplication = XCUIApplication(bundleIdentifier: "com.apple.mobilesafari")

    /// Opens safari with given url
    /// - Parameter url: URL of the deeplink.
    func openWithSafari(app: XCUIApplication, url: String) {
        if safari.state != .notRunning {
            // Safari can get in to bugs depending on too many tests.
            // Better to kill at at the beginning.
            safari.terminate()
            _ = safari.wait(for: .notRunning, timeout: 5)
        }

        safari.launch()

        // Ensure that safari is running
        _ = safari.wait(for: .runningForeground, timeout: 30)

        // Access the search bar of the safari
        // Note: 'Address' needs to be localized if the simulator language is not english
        let searchBar = safari.descendants(matching: .any).matching(identifier: "Address").firstMatch
        searchBar.tap()

        // Enter the URL
        safari.typeText(url)

        // Simulate "Return" key tap
        safari.typeText("\n")

        // Tap "Open" on confirmation dialog
        // Note: 'Open' needs to be localized if the simulator language is not english
        safari.buttons["Open"].tap()

        // Wait for the app to start
        _ = app.wait(for: .runningForeground, timeout: 5)
    }

    func waitFor(element: XCUIElement,
                 failIfNotExist: Bool = true,
                         timeOut: TimeInterval = 15.0) {
        if !element.waitForExistence(timeout: timeOut) {
            if failIfNotExist {
                XCTFail("Could not find \(element.description) within \(timeOut) seconds")
            }
        }
    }

}
iOS deep linking with Xcode UI testing
 
 
Q