-
-
Save cornr/46e14d1e8b160f981dc0fae53ba68b09 to your computer and use it in GitHub Desktop.
import Foundation | |
import XCTest | |
//This is based on https://blog.branch.io/ui-testing-universal-links-in-xcode-9/ | |
final class iMessage { | |
static func launch() -> XCUIApplication { | |
// Open iMessage App | |
let messageApp = XCUIApplication(bundleIdentifier: "com.apple.MobileSMS") | |
// Launch iMessage app | |
messageApp.launch() | |
// Wait some seconds for launch | |
XCTAssertTrue(messageApp.waitForExistence(timeout: 10)) | |
// Continues "Whats new" if present | |
let continueButton = messageApp.buttons["Continue"] | |
if (continueButton.exists) { | |
continueButton.tap() | |
} | |
// Removes New Messages Sheet on iOS 13 | |
let cancelButton = messageApp.navigationBars.buttons["Cancel"] | |
if cancelButton.exists { | |
cancelButton.tap() | |
} | |
// Return application handle | |
return messageApp | |
} | |
static func open(URLString urlString: String, inMessageApp app: XCUIApplication) { | |
XCTContext.runActivity(named: "Open URL \(urlString) in iMessage") { _ in | |
// Find Simulator Message | |
let kateBell = app.cells.staticTexts["Kate Bell"] | |
XCTAssertTrue(kateBell.waitForExistence(timeout: 10)) | |
kateBell.tap() | |
// Tap message field | |
app.textFields["iMessage"].tap() | |
// Continues "Swipe to Text" Sheet | |
let continueButton = app.buttons["Continue"] | |
if continueButton.exists { | |
continueButton.tap() | |
} | |
// Enter the URL string | |
app.typeText("Open Link:\n") | |
app.typeText(urlString) | |
// Simulate sending link | |
app.buttons["sendButton"].tap() | |
//Wait for Main App to finish launching | |
sleep(2) | |
// The first link on the page | |
let messageBubble = app.cells.links["com.apple.messages.URLBalloonProvider"] | |
XCTAssertTrue(messageBubble.waitForExistence(timeout: 10)) | |
messageBubble.tap() | |
} | |
} | |
static func openFromPasteboard(inMessageApp app: XCUIApplication) { | |
XCTContext.runActivity(named: "Open URL from Pasetboard in iMessage") { _ in | |
// Find Simulator Message | |
let kateBell = app.cells.staticTexts["Kate Bell"] | |
XCTAssertTrue(kateBell.waitForExistence(timeout: 10)) | |
kateBell.tap() | |
// Add dummy text to workaround issue with link-only bubbles in iOS 12.4+ | |
app.textFields["iMessage"].tap() | |
app.typeText("Open Link:\n") | |
// Tap message field to open paste menu | |
app.textFields["iMessage"].tap() | |
sleep(1) | |
app.menuItems["Paste"].tap() | |
// Simulate sending link | |
sleep(1) | |
app.buttons["sendButton"].tap() | |
//Wait for Main App to finish launching | |
sleep(3) | |
// The first link on the page | |
let messageBubble = app.cells.links["com.apple.messages.URLBalloonProvider"] | |
XCTAssertTrue(messageBubble.waitForExistence(timeout: 10)) | |
messageBubble.tap() | |
} | |
} | |
} |
import XCTest | |
class UniversialLinktTest: XCTestCase { | |
var app: XCUIApplication! | |
override func setUp() { | |
super.setUp() | |
continueAfterFailure = false | |
app = XCUIApplication() | |
app.launch() | |
} | |
func testItDeepLinksIntoApp() { | |
// Open App via iMessage | |
let messageApp = iMessage.launch() | |
iMessage.open(URLString: "https://mydomain.com/verify/12345", inMessageApp: messageApp) | |
// Do test here... | |
let isInVerifyScreen = app.staticTexts["12345"].waitForExistence(timeout: 10) | |
XCTAssertTrue(isInVerifyScreen) | |
// For reliability terminate iMessage after test | |
messageApp.terminate() | |
} | |
} |
I tried this approach manually with HTTP(S) URL. But it did not open the app, instead opened the web browser.
Looks like it's not working anymore with Xcode 12.2 / iOS 14.2 :(
Can confirm, iOS 14.2 Simulator completely breaks links being sent through iMessage.
Found a good way to launch links in UI tests: https://github.com/mattstanford/GhostHand
Obviously this doesn't help with testing aspects of iMessage, but it will let you launch a specific URL to test universal links or an app schema.
As of iOS 16.4, macOS 13.3, and Xcode 14.3, new XCTest UI Testing API's are available which let you do this in an even easier way.
You can open your application with a specific URL: https://developer.apple.com/documentation/xctest/xcuiapplication/4108226-open
Or, open any URL in the default application for it: https://developer.apple.com/documentation/xctest/xcuisystem/4108234-open
Thanks @harlynkingm for mentioning (and maybe even implementing 😀) that. I guess this workaround is obsolete now. ❤️
As of iOS 16.4, macOS 13.3, and Xcode 14.3, new XCTest UI Testing API's are available which let you do this in an even easier way.
You can open your application with a specific URL: https://developer.apple.com/documentation/xctest/xcuiapplication/4108226-open
Or, open any URL in the default application for it: https://developer.apple.com/documentation/xctest/xcuisystem/4108234-open
Have you been able to use the XCUIApplication open (_ url:)? I'm trying to replace UITests that were using Safari, but this just opens the app like XCUIApplication launch, ignoring the URL completely.
XCUIDevice.shared.system.open(url)
works, but only if the app is already installed :( Otherwise, it fails Failed to open the default app for a URL: The operation couldn’t be completed. (OSStatus error -10814.)
. I was thinking about a workaround to do app.launch / app.terminate before calling XCUIDevice.shared.system.open(url)
, but it would slow down tests and reduce benefits of directly opening urls.
Thanks!
There seem to be two known problems with the released APIs that are being investigated.
The first shows an un-skippable popup on the first call to XCUISystem.open when using a custom URL scheme. This might be able to be worked-around by calling XCUISystem.open from inside an async thread, then tapping the "Open" button from SpringBoard as described here:
https://developer.apple.com/forums/thread/25355
The second is that XCUIApplication().open() seems to be more flaky than XCUIApplication(bundleIdentifier:).open()
Hopefully, fixes for these issues will be available soon.
Yeah, I saw this thread just after I posted here. Seems we need to wait some more for a non-workaround (native) solution.
@cornr I tried open deeplink manual in messages (simulator) but it not works. It works well on devices.