Jaime Agudo
Jaime Agudo

Reputation: 8296

Write modular UI Tests in XCode

I am pretty new to UI Testing on XCode. I found the record function pretty cool and it's working just fine but as long as you have decision points the code breaks the DRY principle. Therefore my idea is to write modular tests and invoke them depending of the user login status, role etc.

The problem is I don't find a way to tag my functions as not-tests (they are helpers invoked when appropriate from the main entry point). This is what I came up with

func testExample() {
   let exists = NSPredicate(format: "exists == true")

   let app = XCUIApplication()

   if(!app.staticTexts[""].exists){
       testLaunchScreen()
   }
   testAsRole1()

}

func testLaunchScreen(){
    let app = XCUIApplication()

    let scrollViewsQuery = app.scrollViews
    scrollViewsQuery.otherElements.containing(.image, identifier:"image0").element.swipeLeft()
    app.buttons["Continue"].tap()
    testFacebookLoginScreen()
}


func testFacebookLoginScreen() {
    let app = XCUIApplication()

    // set up an expectation predicate to test whether elements exist
    let exists = NSPredicate(format: "exists == true")
    // as soon as your sign in button shows up, press it
    let facebookSignInButton = app.buttons["Join with Facebook!"]
    expectation(for: exists, evaluatedWith: facebookSignInButton, handler: nil)
    facebookSignInButton.tap()


    self.waitForExpectations(timeout: 10, handler: nil)  
    if(app.staticTexts["Confirm"].exists){
        // create a reference to the button through the webView and press it
        let webView = app.descendants(matching: .webView)
        webView.buttons["OK"].tap()
    } else {
        let webViewsQuery = app.webViews
        webViewsQuery/*@START_MENU_TOKEN@*/.textFields["Email or Phone"]/*[[".otherElements[\"Welcome to Facebook\"]",".otherElements[\"main\"].textFields[\"Email or Phone\"]",".textFields[\"Email or Phone\"]"],[[[-1,2],[-1,1],[-1,0,1]],[[-1,2],[-1,1]]],[0]]@END_MENU_TOKEN@*/.typeText("[email protected]")
        webViewsQuery/*@START_MENU_TOKEN@*/.secureTextFields["Facebook Password"]/*[[".otherElements[\"Welcome to Facebook\"]",".otherElements[\"main\"].secureTextFields[\"Facebook Password\"]",".secureTextFields[\"Facebook Password\"]"],[[[-1,2],[-1,1],[-1,0,1]],[[-1,2],[-1,1]]],[0]]@END_MENU_TOKEN@*/.typeText("password")
        webViewsQuery.buttons["Login"].tap()   
    }
    // wait for your app to return and test for expected behavior here
    self.waitForExpectations(timeout: 10, handler: nil)  
}


func testAsRole1(){

  ///
}

The problem is that all the testXXX functions are run in order which is not what I want, I'd like to run just testExample. I have found some post regarding extensions but I don't think those would fit in my case

Edited: I have found https://github.com/kif-framework/KIF which seems a very nice library but I'd like to be able to just record sequences and name them as functions I can reuse, I think it would be easier to maintain

Many thanks

Upvotes: 1

Views: 349

Answers (1)

Dave Weston
Dave Weston

Reputation: 6635

XCTest treats every method in an XCTestCase subclass that starts with test as a standalone test. Just change your method names. Alternatively, you can put them in a separate class that doesn't inherit from XCTestCase, but then you lose the convenience methods defined there.

From the documentation:

Test methods are instance methods that have no parameters, do not return a value, and whose name begins with the lowercase word "test".

So, there are a couple of different ways you could modify those methods so that they're not treated as tests.

Upvotes: 2

Related Questions