/Illuminator

iOS Automator

Primary LanguageSwiftApache License 2.0Apache-2.0

Illuminator

CI Status Version License Platform

Illuminator makes your UI tests readable, reusable, and repairable

Readability

Where XCUITest generates a sequence of low-level element interactions, Illuminator tests are expressed as sequences of aptly-named (according to you, the developer) actions. A detailed picture of what the test accomplishes should be apparent from the action names alone.

    func testWithIlluminator() {

        initialState
            .apply(wf.welcome.continueAsGuest())
            .apply(wf.pushNotificationPermissions.decline())
            .apply(wf.home.searchFor("table"))
            .apply(wf.browse.verifySubcategory("End tables", expected: true))
            .apply(wf.browse.verifySubcategory("Bobby tables", expected: false))
            .apply(wf.browse.openSubcategory("Coffee tables"))
            .apply(wf.browse.openProduct(atIndex: 3))
            .apply(wf.productPage.addToCart(quantity: 2))
            .apply(wf.welcomePopup.signIn())
            .apply(wf.signInModal.submitCredentials(testAccount, password: testAccountPassword))
            .apply(wf.cart.verifyTotalItems(2))
            .apply(wf.cart.submitOrder())
            .apply(wf.orderConfirmation.verifyIsActive())
            .finish(self)
    }

Reusability

Your tests don't need to explicitly check whether they're on the right screen before every UI element interaction; Illuminator does it for you. Illuminator provides a system for grouping actions into the "screens" where they are available, and centralizes the logic for indicating when that screen is visible.

In the example above, welcome, pushNotificationPermissions, home, browse, productPage, welcomePopup, signInModal, cart, and orderConfirmation are the screens.

A sample app definition would include the following code:

public typealias AppTestState = [String: String]

public struct WayfairTestApp: IlluminatorApplication {

    var welcome: WelcomeScreen {
        get {
            return WelcomeScreen(testCaseWrapper: testCaseWrapper)
        }
    }

    /// snip

And the definition of the welcome screen would include:

public class WelcomeScreen: IlluminatorDelayedScreen<AppTestState> {
        
    public override var isActive: Bool {
        return app.navigationBars["Welcome"].exists
    }

     public func continueAsGuest() -> IlluminatorActionGeneric<AppTestState> {
        return makeAction() {
            try self.app.buttons["Continue as Guest"].ready().tap()
        }
    }

    /// snip

Repairability

Failing XCTestcase test functions indicate the file and line of the failure. That's not good enough. Illuminator tests can indicate the file and line of the failure as well as a detailed description of the app state at the time of the failure. For example, here is a sample of copy-pastable swift code generated by Illuminator between a test failure and the actual XCFail() call:

app.tabBars.elementBoundByIndex(0).buttons["Home"]
app.tabBars.elementBoundByIndex(0).buttons["Sales"]
app.tabBars.elementBoundByIndex(0).buttons["My Boards"]
app.tabBars.elementBoundByIndex(0).buttons["Account"]
app.tabBars.elementBoundByIndex(0).buttons["Cart"]
app.navigationBars["Welcome"]
app.navigationBars["Welcome"].buttons["close"]
app.navigationBars["Welcome"].staticTexts["Welcome"]
app.images["UniformCanvasLogo-Wayfair_US.jpg"]
app.staticTexts["Please Register or Sign In with your Wayfair.com account."]
app.buttons["Register"]
app.buttons["Sign In"]
app.staticTexts["or"]

Of course, this is ordinarily impossible. Illuminator accomplishes this by meticulously working around XCUIElement operations that trigger immediate test failures (like XCUIElementQuery operations that return multiple elements or XCUIElement operations on nonexistent elements). In the previous example, this was accomplished by Illuminator's .ready() function, which throws a catchable exception rather than trigger a test failure.

Bottom line? In many cases you can repair broken CI tests without re-running the failing test in your IDE; just find the relevant element reference in the console output and copy/paste it into your screen or action as appropriate.

Documentation

See Docs/.

Usage

To run the example project, clone the repo, and run pod install from the Example directory first.

Installation

Illuminator is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod "Illuminator"

Authors

License

Illuminator is available under the Apache 2.0 license. See the LICENSE.txt file for more info.