Check the position of the XCUIElement on screen while testing iOS Application using XCTest
XCUIElement
has a property frame
which you can use to find the coordinates of the element in question.
let button = XCUIApplication().buttons["someButton"]
let frame = button.frame
let xPosition = frame.origin.x
let yPosition = frame.origin.y
There are other ways of retrieving different points relative to the frame, which is a CGRect
, such as midX
and midY
, depending on how you want to assert the position of the element.
You should be aware that XCTest is a functional UI testing framework, and if you are using it for asserting the position of an element, the position will probably be different per device/simulator which may make your tests brittle.
UITesting Xcode 7: How to tell if XCUIElement is visible?
Looks like this is a known bug :-(
https://forums.developer.apple.com/thread/9934
Xcode7 | Xcode UI Tests | How to handle location service alert?
Xcode 9
let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
let allowBtn = springboard.buttons["Allow"]
if allowBtn.exists {
allowBtn.tap()
}
Xcode 8.3.3
_ = addUIInterruptionMonitor(withDescription: "Location Dialog") { (alert) -> Bool in
alert.buttons["Allow"].tap()
return true
}
app.buttons["Request Location"].tap()
app.tap() // need to interact with the app for the handler to fire
Note that it is a bit different as the method name now is addUIInterruptionMonitor and takes withDescription as an argument
Xcode 7.1
Xcode 7.1 has finally fixed a issue with system alerts. There are, however, two small gotchas.
First, you need to set up a "UI Interuption Handler" before presenting the alert. This is our way of telling the framework how to handle an alert when it appears.
Second, after presenting the alert you must interact with the interface. Simply tapping the app works just fine, but is required.
addUIInterruptionMonitorWithDescription("Location Dialog") { (alert) -> Bool in
alert.buttons["Allow"].tap()
return true
}
app.buttons["Request Location"].tap()
app.tap() // need to interact with the app for the handler to fire
The "Location Dialog" is just a string to help the developer identify which handler was accessed, it is not specific to the type of alert.
Xcode 7.0
The following will dismiss a single "system alert" in Xcode 7 Beta 6:
let app = XCUIApplication()
app.launch()
// trigger location permission dialog
app.alerts.element.collectionViews.buttons["Allow"].tap()
Beta 6 introduced a slew of fixes for UI Testing and I believe this was one of them.
Also note that I am calling -element
directly on -alerts
. Calling -element
on an XCUIElementQuery
forces the framework to choose the "one and only" matching element on the screen. This works great for alerts where you can only have one visible at a time. However, if you try this for a label and have two labels the framework will raise an exception.
Is there a way to find if the XCUIElement has focus or not?
I little bit late for the party :) However as far as I can see from dumping the variable XCUIElement it has one interesting property:
property name: hasKeyboardFocus
property type: TB,R
So you can check if your element has focus the following way:
let hasFocus = (yourTextField.value(forKey: "hasKeyboardFocus") as? Bool) ?? false
NB: you can dump the property variables of any NSObject sublass with following extension:
extension NSObject {
func dumpProperties() {
var outCount: UInt32 = 0
let properties = class_copyPropertyList(self.dynamicType, &outCount)
for index in 0...outCount {
let property = properties[Int(index)]
if nil == property {
continue
}
if let propertyName = String.fromCString(property_getName(property)) {
print("property name: \(propertyName)")
}
if let propertyType = String.fromCString(property_getAttributes(property)) {
print("property type: \(propertyType)")
}
}
}
}
Update: Properties dump, Swift 4:*
extension NSObject {
func dumpProperties() {
var outCount: UInt32 = 0
let properties = class_copyPropertyList(type(of: self), &outCount)
for index in 0...outCount {
guard let property = properties?[Int(index)] else {
continue
}
let propertyName = String(cString: property_getName(property))
print("property name: \(propertyName)")
guard let propertyAttributes = property_getAttributes(property) else {
continue
}
let propertyType = String(cString: propertyAttributes)
print("property type: \(propertyType)")
}
}
}
XCTest - UI Testing with XCUIElement using pinch gesture on custom coordinates?
I figured out that I can (but don't want to) add another empty view on top of my blueView
with constraints to half of the size of it (see yellowish rectangle in the illustration below). This works for all my cases so far because no other view overlaps that far. It looks something like this:
Executing a pinchWithScale
on that empty view works and actually pinches the blueView
.
This is a very ugly solution, since I've to add a view which is solely for UI testing.
If anyone has a hint on how to remove it for the release build let me know.
Update
I made a build step running a script which adds this view only when executing the UI automation test target. After the execution the source control (e.g. git reset HEAD~) is used to undo the added view.
Related Topics
Spritekit Not Respecting Zposition
Auto Layout How to Hide 1 View in a View with 3 Equal Width Views
How to Make a Phonegap App for iOS Without Mac
Uitabbar Change Background Color of One UItabbaritem on iOS7
Perform "Use Photo" Button on Custom Image Picker Overlay
Parse Cloud - Livequeries - iOS Client Doesn't Work
Uilabel Word Wrap Feature Leaving Space Even When Sufficient Space Available for The Word
Use Elcimagepickercontroller to Pick Video
How to Show Viewcontroller from a Non-Viewcontroller Helper Class
How to Change Tabbar Icon Color in iOS
Customize Google Maps Blue Dot for Current Location
Is Calling Cellforrowatindexpath: Ever Practical
How to Figure Out When a HTML5 Video Player Enters The Full Screen Mode on iOS/Ipads
How to Detect If My Device Is an iPhone x in Swift 4