Search code examples
swiftuser-interfacetestingcucumberbdd

Load controller from storyboard using Cucumberish with UI Testing


I am trying to implement UI testing with BDD using Cucumberish framework. I understand quite well the Feature files parsing system and I managed to tests some UI elements of the main screen.

However I would like to load any controller from storyboard before using UI testing on the corresponding screen.

Here is my initialization code:

@objc class CucumberishSwiftInit: NSObject {
@objc class func CucumberishSwiftInit()
{
    var application : XCUIApplication!
    //A closure that will be executed just before executing any of your features
    beforeStart { () -> Void in
        application = XCUIApplication()
    }
    //A Given step definition
    Given("the app is running") { (args, userInfo) -> Void in
        application.launch()
        let bundle = Bundle.main

        // I double checked the storyboard name and I can access it in my Unit Tests target
        // application crashes here
        let storyboard = UIStoryboard(name: "Main", bundle: bundle)

        // never executed 
        Swift.print("storyboard \(storyboard)")
    }
    let bundle = Bundle(for: CucumberishSwiftInit.self)

    Cucumberish.executeFeatures(inDirectory: "Features", from: bundle, includeTags: nil, excludeTags: ["skip"])
}
}

Some feature file:

@run @welcome
Feature: Some feature
Some feature desc

Scenario: Can load screen
    Given the app is running
    ...

The application crashed on the UIStoryboard init statement, caught "NSInvalidArgumentException", "Could not find a storyboard named 'Main' in bundle NSBundle (loaded). I have no clue why as it is working using with my unit tests.


Solution

  • The error you're getting is due to the fact that the .storyboard file you are trying to load is not part of the bundle of the application you are running.

    The reason that's happening is that when you run a UI test your code is not running in the same process as your application, and it can only interact with it through the XCUIApplication proxy. (The mechanics might be slightly different, but that's gist, unfortunately there's little documentation that I can link.)

    UI testing is a different style of testing than what you can do with XCTest. Programmatically loading an instance of a screen from a .storyboard is not possible.

    In other words, you can't use any code from your app in your UI tests, but rather have to interact with it like a real user would, and write assertions for what's on the screen.