Search code examples
swiftswiftuixcode-ui-testingxctestcase

How should I be designing my UITests with multiple views that are joined by forms?


I'm not sure how to architect UITest code that needs to walk through multiple views, each with their own forms.

I'm in the process of writing UITests for my SwiftUI application. I just wrote out a test that properly walks through my SignUpView, clicking the proper fields, and typing in the information.

But, after this SignUpView is properly submitted, it then goes to another view with new fields to input data... that then go to another view with additional input... etc.

Here's how my SignUpView test looks:

func test_sign_up_view() {
    let app = XCUIApplication()
    app.launchArguments = LaunchArguments.launchLocalArguments
    app.launch()

    let bottom_text_button = app.buttons["To Signup Button"]
    bottom_text_button.tap()

    let first_name_field = app.textFields["Signup form first name field"]
    XCTAssertTrue(first_name_field.exists)
    first_name_field.tap()

    let first_name = "test"
    for letter in first_name {first_name_field.typeText(String(letter))}
    XCTAssertEqual(first_name_field.value as! String, first_name)

    let last_name_field = app.textFields["Signup form last name field"]
    XCTAssertTrue(last_name_field.exists)
    last_name_field.tap()

    let last_name = "test"
    for letter in last_name {last_name_field.typeText(String(letter))}
    XCTAssertEqual(last_name_field.value as! String, last_name)

    let phone_number_field = app.textFields["Signup form phone number field"]
    XCTAssertTrue(phone_number_field.exists)
    phone_number_field.tap()

    let phone_number = "+01234567890"
    for letter in phone_number {phone_number_field.typeText(String(letter))}
    XCTAssertEqual(phone_number_field.value as! String, phone_number)

    let email_field = app.textFields["Signup form email field"]
    XCTAssertTrue(email_field.exists)
    email_field.tap()

    let email = "[email protected]"
    for letter in email {email_field.typeText(String(letter))}
    XCTAssertEqual(email_field.value as! String, email)

    let signup_button = app.buttons["Signup Button"]
    XCTAssertTrue(signup_button.exists)
    signup_button.tap()

}

But now, I want to test the view that is presented after the signup_button is pressed. The problem is, this view is only viewable after the SignUpView is properly submitted.

Should I be writing an entirely new test, with all of the code from my test_sign_up_view, along with the new code that will be walking through the next view, or is there a better way?


Solution

  • You can bypass the setups (like signing in) with Launch Arguments or Environmental Variables. In your case, you can pass the access token with tests, and then "catch" it on app start-up.


    Here is the better version of the code you wrote

    import XCTest
    
    let app = XCUIApplication()
    
    class signUpTests: XCTestCase {
        let bottomTextButton = app.buttons["To Signup Button"]
        let firstNameField = app.textFields["Signup form first name field"]
        let lastNameField = app.textFields["Signup form last name field"]
        let phoneNumberField = app.textFields["Signup form phone number field"]
        let emailField = app.textFields["Signup form email field"]
        let signupButton = app.buttons["Signup Button"]
    
        override func setUp() {
            app.launchArguments = LaunchArguments.launchLocalArguments
            app.launch()
        }
    
        func testSignUpView() {
            // Given
            let firstName = "test"
            let lastName = "test"
            let phoneNumber = "+01234567890"
            let email = "[email protected]"
    
            // When
            bottomTextButton.tap()
            firstNameField.slowType(firstName)
            lastNameField.slowType(lastName)
            phoneNumberField.slowType(phoneNumber)
            emailField.slowType(email)
            signupButton.tap()
    
            // Then
            // final assertions
        }
    }
    
    extension XCUIElement {
        func slowType(_ text: String) {
            tap()
            for letter in text {
                typeText(String(letter))
            }
            XCTAssertEqual(value as! String, text, "Unexpected value of XCUIElement")
        }
    }
    

    For further improvements, you can use ScreenObject (aka PageObject) pattern. Check my realisation here for example https://github.com/rzakhar/xctest-assignment