Q15 of 26 · Mobile QA
How do you test deep links and universal links on iOS and Android?
Short answer
Short answer: Trigger deep links programmatically — via ADB intent on Android or xcrun simctl openurl on iOS Simulator — and assert the app opens the correct screen. In Appium, use the mobile: deepLink execute command for real devices. Test valid, invalid, and expired link parameters.
Detail
Android: deep links are fired as explicit intents. From the terminal: adb shell am start -a android.intent.action.VIEW -d "myapp://product/123". In Appium: driver.execute('mobile: deepLink', { url: 'myapp://product/123', package: 'com.example.myapp' }). Universal links (App Links) require the assetlinks.json file to be served correctly — test by triggering the HTTPS URL from a browser and asserting the app opens rather than the website.
iOS: for the Simulator: xcrun simctl openurl booted "myapp://product/123". For real devices via Appium: driver.execute('mobile: deepLink', { url: 'myapp://product/123' }). Universal Links (associated domains) require HTTPS and an apple-app-site-association file — test that tapping the URL from Safari or Messages opens the app, not the browser.
What to verify: the correct screen opens with the correct data loaded, back navigation returns to the expected place (not a blank stack), and the app handles invalid URLs gracefully (unknown path → home screen, not a crash). Also test deep links when the app is closed — the cold-start deep link path is commonly different from the warm-start path.
// EXAMPLE
deep-link.test.ts
// Android via Appium
await driver.execute('mobile: deepLink', {
url: 'myapp://product/abc-123',
package: 'com.example.myapp',
});
await expect(productScreen.title).toHaveText('Product abc-123');
// Invalid deep link — should redirect to home, not crash
await driver.execute('mobile: deepLink', {
url: 'myapp://product/INVALID-ID',
package: 'com.example.myapp',
});
await expect(homeScreen.searchBar).toBeDisplayed();