Test ownership and action separately
Install a release-like app on a fresh device and open a URL from the verified test domain. Then break the association file in staging, reset the test verification state where supported, and try again. Record whether the app or browser opens. Next, change the payment ID in a valid link to a record owned by another test account. The app must fetch and authorize that record on the server before any approval. Domain ownership only decides which app can handle the URL; it does not grant access to the object inside it.
Test cases and proof
| Case | Expected result | Proof to keep |
|---|---|---|
| Verified domain file removed | Check actual handler after re-verification; safe browser page if selected | Open result |
| Unknown action in link | Show safe error | App route |
| Link carries another customer ID | Recheck server access | API response |
Use an ownership matrix
For each supported link domain, list the Android package or iOS app that should handle it, the route pattern, and the browser fallback. Test each row after a fresh install and an app update. Include the release signing certificate fingerprint for Android and the app identifier for iOS. Compare staging and production association files; a debug certificate entry cannot prove the release build is associated. Keep secrets out of link URLs because they can enter history and analytics. Save the association file version beside the device result so a link failure can be traced.
On iOS, verify each subdomain that the app claims; one working domain does not prove a second one is associated.
Test a link from outside the app
Send a fake transfer link from browser, SMS, and QR scan to the installed app. Use a valid link, a lookalike host, an unexpected path, and an encoded redirect. Test percent-encoded separators and a redirect to an unlisted host; the parsed destination must remain inside the route allowlist. Confirm Android App Links or iOS Universal Links use the verified domain and the app validates every parameter after opening. Do not perform the transfer merely because a link opened the screen. Save association-file response, chosen handler, parsed fields, user confirmation, and final request. (Android App Links verification).
Reset verification state for the broken-file test
Removing a domain file does not instantly erase a device’s saved association or user choice. For Android 12 and later, reset the test package’s App Links state, request re-verification, and inspect the resulting host state before opening the URL. Record the commands and wait for verification to finish. Test a fresh install separately. On iOS, record install state and user preference; test the browser path directly as well as Universal Link handling. The pass condition is a safe result for the actual handler chosen. Do not declare browser fallback merely because the file is absent on the server.
Keep pending link state tied to sign-in
Open a synthetic statement link while signed out. The app can retain the route for after login, but it must not retain an authorization decision from another session. Sign in as account B while the route names account A’s statement. Expect a denial with no statement bytes, title, or cached preview. Then sign out and sign in as A: the valid route should work under the current session. Repeat with an expired one-time link. A login redirect must preserve only validated route data and reject an outside return URL. This catches a separate failure from domain association: the app opens correctly but restores a route under the wrong identity.