So I have this XCTestCase, it runs a simple function and I'm satisfied with the results, but every time the function ends, it displays "TEST FAILED" and shut down the app.
One more thing, I tried to change the continueAfterFailure boolean to true and yet it still shut down the app after failure...
I couldn't find a solution yet, hope someone can help me :)
Thanks
Update:
Here's the code:
func loginSuccess (element: XCUIElement) {
//Entering invalid input to the text field
//App has validator a that doesn't let the input in
element.typeText("!##$%^")
XCTAssertTrue((element.value as? String == ""), "Test Passed!")
if element.value as? String == "" {
print ("Test Passed!") //This line works every run
} else {
XCTFail("Invalid text can be inserted") //Managed to force fail and succeded, but not pass.
}
}
You have things reversed. XCTAssertTrue evaluates that an expression is true and logs the provided message and fails the test if the expression is false.
Related
I have weather app. It fetches the data from API. I enter needed city, then next screen opens and shows me the name of the city and temperature. I am writing UI test, which should open the app, handle an alert which asks to use location, then test should write the city name and check if this city exists in the screen. All works except checking the city name at the end. I thought maybe the problem is because it needs some time to get the answer from API, and tests doesn’t wait for it. Maybe I need to set timer to wait for answer. Or the problem is in smth else?
Here is my code and it fails at the last line.
func testExample() throws {
let app = XCUIApplication()
app.launchArguments = ["enable-testing"]
app.launch()
app/*#START_MENU_TOKEN#*/.staticTexts["My location"]/*[[".buttons[\"My location\"].staticTexts[\"My location\"]",".staticTexts[\"My location\"]"],[[[-1,1],[-1,0]]],[0]]#END_MENU_TOKEN#*/.tap()
addUIInterruptionMonitor(withDescription: "Allow “APP” to access your location?") { (alert) -> Bool in
let button = alert.buttons["Only While Using the App"]
if button.exists {
button.tap()
return true // The alert was handled
}
return false // The alert was not handled
}
app.textFields["Enter your city"].tap()
app.textFields["Enter your city"].typeText("Barcelona")
app.buttons["Check weather"].tap()
XCTAssertTrue(app.staticTexts["Barcelona"].exists)
}
XCTest comes with a built-in function you need
Documentation: https://developer.apple.com/documentation/xctest/xcuielement/2879412-waitforexistence/
Example:
XCTAssertTrue(myButton.waitForExistence(timeout: 3), "Button did not appear")
I found the function and used it to wait before the result.
Here is the function and its usage in my code.
func waitForElementToAppear(_ element: XCUIElement) -> Bool {
let predicate = NSPredicate(format: "exists == true")
let expectation = expectation(for: predicate, evaluatedWith: element,
handler: nil)
let result = XCTWaiter().wait(for: [expectation], timeout: 5)
return result == .completed
}
app.textFields["Enter your city"].tap()
app.textFields["Enter your city"].typeText("Barcelona")
app.buttons["Check weather"].tap()
let result = app.staticTexts["Barcelona"]
waitForElementToAppear(result)
XCTAssertTrue(result.exists)
I'm using Fastlane's snapshot to create screenshots for an app I'm about to submit to the App Store.
It works "as advertised" for the most part, but it doesn't seem to like the way I access the UserDefaults within my app. On one test, it generates an Exit status: 65 error.
UI Testing Failure - com.me.MyApp crashed in (extension in MyApp):__ObjC.NSObject.defaultTime () -> Swift.Float
I find UserDefaults.standard.value(forKey: "defaultTime") to an invitation for a syntax error, so I created an extension to access UserDefaults. Here's what the extension looks like:
class CustomExtensions: NSObject {
/*
This is blank. Nothing else in here. No really...nothing else
*/
}
extension NSObject {
// User Defaults
func defaultTime() -> Float {
return UserDefaults.standard.value(forKey: "defaultTime") as! Float
}
// a bunch of other UserDefaults
}
Wihin the app, whenever I need defaultTime, I just type defaultTime(). Using this method to access UserDefaults values works fine in the Simulator and on the devices I've tested. I only encounter a problem with snapshot.
I've tried adding in sleep(1) within the test, but that doesn't seem to do anything. I welcome suggestions re: alternative means of accessing UserDefaults that enable me to access them easily throughout MyApp.
What's probably happening is that, in your simulator and on device, you're writing a value to user defaults for the key defaultTime before it is ever read. value(forKey: returns an optional, and if you force-unwrap it (or force down-cast as your are doing here), you will crash if the value is nil. Try either returning an optional:
func defaultTime() -> Float? {
return UserDefaults.standard.value(forKey: "defaultTime") as? Float
}
or using a default value:
func defaultTime() -> Float {
return UserDefaults.standard.value(forKey: "defaultTime") as? Float ?? 0.0
}
I'm trying to make a simple UI Test in my iOS Application. I'd like to fill a textfield with some text but an error always appears.
First try:
let searchField = app.textFields.elementBoundByIndex(0);
searchField.tap()
searchField.typeText("Holy Grail")
The field is highlighted, the keyboard appears and, after some seconds, randomly one of these:
- Timed out waiting for IDE barrier message to complete
- failed to get attributes within 15.0s ui test
- failed to get snaphots within 15.0s ui test
Second try:
func setText(text: String, application: XCUIApplication) {
//Instead of typing the text, it pastes the given text.
UIPasteboard.generalPasteboard().string = text
doubleTap()
application.menuItems["Paste"].tap()
}
...
let searchField = app.textFields.elementBoundByIndex(0);
searchField.tap()
searchField.setText("Holy Grail")
Same result.
Tried with Connect Hardware Keyboard on and off.
Tried with iPhone 6s simulator, iPad Retina simulator, iPad 2 simulator.
Tried only with Xcode 7 (8 will break the project)
Ideas? Thanks in advance!
I don't have an answer on why this is happening, but for any future guy that has my same problem here is my workaround, on which I'm working on.
Basic idea is to make the keyboard appear, and then hit every single key I need to build my string.
func testPlayground() {
let app = XCUIApplication()
waitAndTap(app.textFields["MyTextField"])
type(app, text: "hej")
}
func waitAndTap(elm: XCUIElement){
let exists = NSPredicate(format: "exists == true")
expectationForPredicate(exists, evaluatedWithObject: elm, handler: nil)
waitForExpectationsWithTimeout(10.0, handler: nil)
elm.tap()
}
func type(app: XCUIApplication, text : String){
//Wait for the keyboard to appear.
let k = app.keyboards;
waitForContent(k, time: 10.0)
//Capitalize the string.
var s = text.lowercaseString;
s.replaceRange(s.startIndex...s.startIndex, with: String(s[s.startIndex]).capitalizedString)
//For each char I type the corrispondant key.
var key: XCUIElement;
for i in s.characters {
if "0"..."9" ~= i || "a"..."z" ~= i || "A"..."Z" ~= i {
// Then it's alphanumeric!
key = app.keys[String(i)];
}
else {
// Then is special character and is necessary re-map them.
switch i {
case "\n":
key = app.keys["Next:"]; // This is to generalize A LOT.
default:
key = app.keys["space"];
}
}
waitAndTap(key);
}
So: waitAndTap() is a function that I use A LOT in my tests. It waits for the existence of an element and it taps it. If in ten seconds it doesn't show up, fail the test.
testPlayground() taps the textfield in which I wanna write and then calls type()
type() is the core. Basically, look at every single character in the string and tap it. Problems:
If I look for character H in a keyboard where shift is not activated it will never find an uppercase letter. My solution is to capitalize the string, but it works only in specific cases. This is enhanceable
It doesn't work with special characters, where you cannot look for it exactly, but for the key´s name ("space" instead of " "). Well, no solution here, aside that horrible switch-case, but well, for what I need to do it works.
Hope this can help someone!
First try to disable I/O -> Hardware Keyboard and see what will happen.
If still not working
instead of
searchField.tap()
searchField.typeText("Holy Grail")
try this
app.keys["H"].tap()
app.keys["o"].tap()
app.keys["l"].tap()
app.keys["y"].tap()
This method allows you to enter Uppercase and Lowercase strings
func enterUsername(username: String?) {
guard
let input = username,
var previousCharaterIsLowerCase = input.first?.isUppercase else {
XCTFail("Username is not set")
return
}
for char in input {
if char.isUppercase && previousCharaterIsLowerCase {
// Switch on capslock
app.buttons["shift"].tap()
app.buttons["shift"].tap()
}
if char.isLowercase && previousCharaterIsLowerCase == false {
// Switch off capslock
app.buttons["shift"].tap()
app.buttons["shift"].tap()
app.buttons["shift"].tap()
}
previousCharaterIsLowerCase = char.isLowercase
app.keys[String(char)].tap()
}
}
I am trying to write a do-try-catch in swift for my iOS UI test which uses XCUI testing. I am reading the error-handling section: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html#//apple_ref/doc/uid/TP40014097-CH42-ID508
but am unsure of which error should be thrown when an element is not found.
func tapElement(string:String) throws {
do{
waitFor(app.staticTexts[string], 5)
try app.staticTexts[string].tap()
}
catch {
NSLog("Element was not found: \(string)")
//how can i check specifically that the element was not found?
}
}
....
func waitFor(element:XCUIElement, seconds waitSeconds:Double) {
NSLog("Waiting for element: \(element)")
let exists = NSPredicate(format: "exists == 1")
expectationForPredicate(exists, evaluatedWithObject: element, handler: nil)
waitForExpectationsWithTimeout(waitSeconds, handler: nil)
}
any help greatly appreciated!!
You should use element.exists AND element.isHittable
element.exists checks whether the element is an element of the UIApplication/ScrollView/..
element.isHittable determines if a hit point can be computed for the element.
If you don't check for both, than element.tap() throws the following error, for example, if the element is under the keyboard:
Failed: Failed to scroll to visible (by AX action) TextField,...
Example code:
let textField = elementsQuery.textFields.allElementsBoundByIndex[i]
if textField.exists && textField.isHittable {
textField.tap()
} else {
// text field is not hittable or doesn't exist!
XCTFail()
}
You shouldn't need to try-catch finding elements in UI Testing. Ask the framework if the element exists() before trying to tap() it.
let app = XCUIApplication()
let element = app.staticTexts["item"]
if element.exists {
element.tap()
} else {
NSLog("Element does not exist")
}
Check out my blog post on getting started with UI Testing for more specific examples, like tapping an button.
Hi I'm starting to become a regular on here but if any can help me with the following. I want to test to see if a user is using a reset password and have the following:
if FIREBASE_REF.authData.providerData["isTemporaryPassword"] == true {
// run some code
}
but xcode is saying expression expected, if anyone knows the correct syntax I would appreciate it.
Thanks
Think I have now got it sort and the solution is as follows for anyone else who is struggling with this:
let handle = FIREBASE_REF.authData.providerData["isTemporaryPassword"] as? Bool
if (handle == true) {
// run code here.
}