Swiftpack.co - Package - treatwell/twuitests

Usage

Purpose

Lightweight UITests framework based on XCTest to help you write and maintain UITests quickly and easily with well organised code structure.

Use Swift Package Manager as a dependancy manager

The Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift compiler. To add a package dependency to your Xcode project, select File > Swift Packages > Add Package Dependency and enter https://github.com/treatwell/twuitests.git

or add dependency to your Package.swift

import PackageDescription

let package = Package(
    name: "MySPMLibrary",
    dependencies: [
        .package(url: "https://github.com/treatwell/twuitests.git", from: "0.20.0")
    ]
)

Use Carthage as a dependancy manager

  1. Add git "https://github.com/treatwell/twuitests.git" to your Cartfile.
  2. Run carthage updateto fetch & build. Append --platform iOS if only iOS build is needed.

Main project UITests target configuration

  1. Build settings: in Runpath Search Paths add $(PROJECT_DIR)/Carthage/Build/iOS to tell linker where to find frameworks.
  2. Build phases: drag and drop TWUITests and Swifter frameworks in Link binaries and frameworks phase. Frameworks are in Carthage/Build/iOS.
  3. Info plist file: add App Transport Security Settings dictionary and key-value NSAllowsLocalNetworking = true to allow loading of local resources.

Start adding tests

  1. Create Configuration class to hold parameters and initial API stubs.
  2. Create project specific parameters to be injected into main app.
  3. Create API stubs structure.
  4. Tip: use template to generate UITests code. Add template to Xcode by running add_ui_tests_templates.sh script (in Xcode Templates folder).

Other information

Server API local responses should be kept at path: LIBRARY_DIR + "/Developer/CoreSimulator/Devices/" + DEVICE_ID + "/data/Library/Caches/ApiStubs/" Tip: have a script to copy stubs to required destination in build phase. Python script example can be found here.

Example

Working example project can be found in Example folder.

Test:

final class LoginUITests: UITestCase {
    func testSomething() throws {
        try start(with: Configuration())
        .loginStep.someAction()
        .loginStep.loginPageIsVisible()
    }
}

Step:

final class LoginStep: UITestBase, Step {
    private lazy var loginPage = LoginPage(app: app)

    func tapSomeButton() -> Self {
        loginPage.someButton.tap()
        return self
    }
}
// MARK: - Validation
extension LoginStep {
    func loginPageIsVisible() {
        loginPage.someView.existsAfterDelay()
        loginPage.someButton.existsAfterDelay()
    }
}

Page:

final class LoginPage: UITestBase, Page {
    var someView: XCUIElement {
        return app.otherElements[LoginAccessibilityIndetifiers.View.some] 
    }
    var someButton: XCUIElement {
        return app.buttons[LoginAccessibilityIndetifiers.Button.some]
    }
}

Author Information

Ignas Urbonas - ignas.urbonas@treatwell.com

Marius Kažemėkaitis - marius.kazemekaitis@treatwell.com

License

The contents of this repository is licensed under the Apache License, version 2.0.

Github

link
Stars: 24

Dependencies

Used By

Total: 0

Releases

Swift Package Manager support - 2020-10-07 16:57:51

Try - catch for `replace` and `update` - 2020-07-17 10:14:06

Add try - catch to replace and update methods.

Try - catch support - 2020-07-15 12:00:12

Add try - catch support in tests.

Custom HTTP created 201 response body - 2020-06-11 09:12:08

Add support for custom HTTP created 201 response body

Inject custom API mocks on app launch - 2020-06-10 08:49:00

In order to use custom API response mocks (with special data) we used

start(using: AppConfiguration())

app.replaceValues(
    of: [
        "result": "NOT_AUTHENTICATED"
    ],
    in: Stub.Authentication.success
)

But API mocked responses were replaced only after next refresh/API call. So as a workaround we had to do additional UI actions like pull to refresh, closing and opening screens again and so on, just to get that API endpoint called again.

This PR adds nicer way to do that by introducing initiationClosure param to start(using:) So, now there is a way to do:

start(using: Configuration()) { app in
    app.replaceValues(
        of: [
            "result": "NOT_AUTHENTICATED"
        ],
        in: Stub.Authentication.success
    )
}
.loginStep.authenticationStatusIsVisible()
.loginStep.authenticationStatusIs(equal: "NOT_AUTHENTICATED")

Using this closure we get our custom replaced API mocks right after UI Tests launches the app.

To better illustrate that, I have updated example app with few examples.

- 2020-06-01 13:41:07

Add created http status code

- 2020-06-01 09:22:24

Expose start function to be used in tests for restart scenario.

Add scrollView swipe helpers - 2020-02-05 12:39:22

Tableview load checking - 2020-01-09 10:24:01

Add tableview loaded checking method

Check element if it exists on screen - 2019-12-13 10:28:53

Surface local server port - 2019-09-24 13:19:30

Add server port to launch environment dictionary.

Port range support - 2019-09-24 12:39:31

UITests are now capable to retry to start local server with new port number (picked randomly from portRange) if current port number is in use.

Add queue for stub replacements - 2019-08-12 14:38:03

Replace JSON stub values and keys feature - 2019-08-09 13:45:44

Add "replace JSON values and keys" feature as part of framework.

Add support for HTTP status errors - 2019-07-02 10:55:03

Add XCUIElement support for swipeUp to element - 2019-06-24 14:33:49

Update formatting with swiftlint - 2019-06-10 11:18:28

Add swiftlint rules and update code formatting.

TWUITests - 2019-05-28 13:56:14

First public release