Q15 of 26 · Mobile QA

How do you test deep links and universal links on iOS and Android?

Mobile QAMidmobiledeep-linksuniversal-linksappiumadbiosandroid

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();

// WHAT INTERVIEWERS LOOK FOR

Knows the ADB/xcrun and Appium approaches. Tests both the happy path and invalid parameters. Calls out cold-start vs warm-start as a distinct scenario.