I have an App with Today Widget. So I would like to perform some UI testing on it.
I found a way to open Today/Notifications panel. It seems easy:
let statusBar = XCUIApplication().statusBars.elementBoundByIndex(0)
statusBar.swipeDown()
But then I can't find a way to do something useful. It is possible to record UI interactions in Today/Notifications panel, but such code can't reproduce my actions.
First you need to open Today View, you can use this way:
let app = XCUIApplication()
// Open Notification Center
let bottomPoint = app.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 2))
app.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 0)).press(forDuration: 0.1, thenDragTo: bottomPoint)
// Open Today View
let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
springboard.scrollViews.firstMatch.swipeRight()
Then, to access everything you need, just use springboard
, for example:
let editButton = springboard.buttons["Edit"]
There's a similar problem testing extensions. I've found that what you must do is tap the element at where it is on the screen rather than the element itself in order to drive the interaction. I haven't tested this with your scenario, but I haven't found anything un-tappable via this method yet.
Here is a Swift example of tapping the "X" button on the Springboard for an app icon, which similarly cannot be tapped via typical interaction:
let iconFrame = icon.frame // App icon on the springboard
let springboardFrame = springboard.frame // The springboard (homescreen)
icon.pressForDuration(1.3) // tap and hold
// Tap the little "X" button at approximately where it is. The X is not exposed directly
springboard.coordinateWithNormalizedOffset(CGVectorMake((iconFrame.minX + 3) / springboardFrame.maxX, (iconFrame.minY + 3) / springboardFrame.maxY)).tap()
By getting the frame of the superview and the subview, you can calculate where on the screen the element should be. Note that coordinateWithNormalizedOffset
takes a vector in the range [0,1], not a frame or pixel offset. Tapping the element itself at a coordinate doesn't work, either, so you must tap at the superview / XCUIApplication() layer.
More generalized example:
let myElementFrame = myElement.frame
let appFrame = XCUIApplication().frame
let middleOfElementVector = CGVectorMake(iconFrame.midX / appFrame.maxX, iconFrame.midY / appFrame.maxY)
// Tap element from the app-level at the given coordinate
XCUIApplication().coordinateWithNormalizedOffset(middleOfElementVector).tap()
If you need to access the Springboard layer and go outside your application, you can do so with:
let springboard = XCUIApplication(privateWithPath: nil, bundleID: "com.apple.springboard")
springboard.resolve()
But you'll need to expose some private XCUITest methods with Objective-C:
@interface XCUIApplication (Private) {
- (id)initPrivateWithPath:(id)arg1 bundleID:(id)arg2;
}
@interface XCUIElement (Private) {
- (void) resolve;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With