Last active
November 13, 2018 21:16
-
-
Save JasonCanCode/5c29d3a0cde535583c5d0a3d00d0fa43 to your computer and use it in GitHub Desktop.
An easier way to access UI elements or check for existence within a UI Test.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extension XCTestCase { | |
var app: XCUIApplication { return XCUIApplication() } | |
func checkExistenceOfElements(_ typesAndTexts: [(XCUIElement.ElementType, String)], timeout: TimeInterval = 3) { | |
for (type, text) in typesAndTexts { | |
checkExistenceOfElement(type, text, timeout: timeout) | |
} | |
} | |
func checkExistenceOfElement(_ type: XCUIElement.ElementType, _ text: String, timeout: TimeInterval = 3) { | |
XCTAssertTrue(element(ofType: type, withText: text, timeout: timeout).exists, "Element with text \"\(text)\" could not be found.") | |
} | |
/// Search for element in multiple locations within the view hierarchy | |
func element(ofType type: XCUIElement.ElementType, withText text: String, timeout: TimeInterval = 3) -> XCUIElement { | |
assert(type != .other, "It is not safe to use ElementType \"other\" in this helper method as it can create a recursive loop") | |
let shouldOnlyUsePredicates: Bool = text.count > 128 | |
let inDescendants = app.descendants(matching: type).descendants(matching: type).matching(labelPredicate(forText: text)).firstMatch | |
let closeMatch = app.descendants(matching: type).element(matching: labelPredicate(forText: text)).firstMatch | |
var possibleElements: [XCUIElement] = [inDescendants, closeMatch] | |
if !shouldOnlyUsePredicates { | |
let inScrollView = app.scrollViews.otherElements.descendants(matching: type)[text] | |
let inApp = app.descendants(matching: type)[text] | |
let inTableView = app.tables.descendants(matching: type)[text] | |
let inTabBar = app.tabBars.descendants(matching: type)[text] | |
let inNavBar = app.navigationBars.descendants(matching: type)[text] | |
let lastDitchEffort = app.staticTexts[text] | |
possibleElements.append(contentsOf: [inScrollView, inApp, inTableView, inTabBar, inNavBar, lastDitchEffort]) | |
} | |
let matchFilter: (XCUIElement) -> Bool = { $0.exists && $0.elementType == type } | |
var elapsedTime: TimeInterval = 0 | |
while elapsedTime < timeout { | |
if let validElement = possibleElements.lazy.filter(matchFilter).first { | |
return validElement | |
} | |
usleep(200000) // sleep for .2 seconds | |
elapsedTime += 0.2 | |
} | |
return app.descendants(matching: type)["Intentionally returning an element that does not exist"] | |
} | |
/// Breaks down multi-line text for predicate use | |
private func labelPredicate(forText text: String) -> NSPredicate { | |
let linesOfText = text.components(separatedBy: "\n") | |
var format = "label CONTAINS '\(linesOfText.first!)'" | |
if linesOfText.count > 1 { | |
for i in 1..<linesOfText.count where !linesOfText[i].isEmpty { | |
format += " AND label CONTAINS '\(linesOfText[i])'" | |
} | |
} | |
return NSPredicate(format: format) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example usage: