Is it possible to open a screen directly in XCUITest?
Asked Answered
P

1

8

I have 3 screens, lets say,

  1. Login
  2. Forgot Password
  3. Help screen

By default the Login screen open when the app starts. The Forgot Password screen is shown when you click on the Forgot Password button, and Help Screen opens when the Help link is clicked.

Can I somehow open the the Forgot Password Screen directly without going through the procedure of clicking the button using XCUITest?

I am suggesting something in the same lines as passing an adb intent to open a View directly.

Polytrophic answered 28/2, 2018 at 0:53 Comment(0)
S
12

As far as I know, you can't go directly to the second screen using XCUITest Framework. Anyway, documentation states:

UI testing exercises your app's UI in the same way that users do without access to your app's internal methods, functions, and variables. This enables your tests to see the app the same way a user does, exposing UI problems that users encounter.

Which means that if user of your app can't reach the second screen directly, why could your UI tests.

I know it's time consuming to wait to go to the second screen when you run your tests, but you can bypass writing it for every test. To write it only once, in your XCTestCase class write a function where you implement calling a second screen and call that function in setUp() method. Then, the process of skipping the first screen will be called every time you run a test because setUp() method is called before every test run.

EDIT

After reading your comment, I could think of one hacky solution. You can communicate with your app from your tests using Launch Environment and/or Launch Arguments. So, in your XCTestCase class, set up argument and environment:

class ForgotPasswordUITest: XCTestCase {
    let app = XCUIApplication()

    override func setUp() {
        app.launchArguments += ["UI-TESTING"]
        app.launchEnvironment["pageToGo"] = "forgotPassword"
        app.launch()
    }
}

Then, in your ViewController, write these computed properties:

var isUiTestingEnabled: Bool {
    get {
        return ProcessInfo.processInfo.arguments.contains("UI-TESTING")
    }
}

var shouldShowForgotPassword: Bool {
    get {
        return ProcessInfo.processInfo.environment["pageToGo"] == "forgotPassword"
    }
}

var shouldShowHelpScreen: Bool {
    get {
        return ProcessInfo.processInfo.environment["pageToGo"] == "helpScreen"
    }
}

And in viewDidLoad() method, you can have something like this:

    if isUiTestingEnabled {
        if shouldShowForgotPassword {
            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            let secondViewController = storyboard.instantiateViewController(withIdentifier: "ForgotPasswordViewController")
            self.present(secondViewController, animated: true, completion: nil)
        } else if shouldShowHelpScreen {
            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            let secondViewController = storyboard.instantiateViewController(withIdentifier: "HelpScreenViewController")
            self.present(secondViewController, animated: true, completion: nil)
        }
    }

Note: this is a really dirty hack and it is not recommended way of writing UI tests.

Sandbank answered 1/3, 2018 at 7:14 Comment(10)
@logoman Thats a good answer. and I agree with you completely. But there are certain times when you have tested a flow already and don't really need to do it over and over again. Thereby speeding up the tests. I am upvoting your answer, but I will wait for more answers. Even if there is a hacky way to do it.Polytrophic
@Vinayaka, I edited my answer adding one hacky solution.Sandbank
@lagoman using the launch arguments and/or launch environment to communicate from the UI tests to the app is an ingenious solution, nice. I would be skeptical to adopt it though, as you say it's a bit of a hack. What would worry me is the extra code we have to write to establish this relationship. I don't like "polluting" production code with code only meant for the tests. As always in software development it's a matter of tradeoffs. Is the UI tests suite faster run time worth the extra code to maintain? It depends on the project :)Ioab
@mokagio, agreed :)Sandbank
@lagoman i think your solution through which we can directly go to the screen was perfect as i don't see any otherway than using environment/ launch argument.Calumnious
@lagoman Is it possible to change the pageToGo variable during the text. For example, I'd like to test the navigation within a certain view. How might I properly navigate and test it occured?Thirlage
@Thirlage Not sure that it is possible. Let me try to understand what you need. If you have something like this: Page1 --> Page2 --> Page3 --> Page4 and you'd like to go to Page2 directly, after which you'd like to go to Page4 directly. Instead of setting app.launchEnvironment["pageToGo"] two times (which I don't think is possible, but please read the docs), I would set something like app.launchEnvironment["secondPageToGo"] = "Page4" where I'd read "secondPageToGo" from the environment and then I'd decide where to go. Would this be helpful?Sandbank
@lagoman I'd like to go to Page2 directly, and then test the navigation that is possible within that particular view, which, in my case, is a back button to Page1 and the next button to Page3Thirlage
If I were to initialize the setUp() within my test with an additional environment variable like app.launchEnvironment["secondPageToGo"] = "Page2", how would I differentiate how to navigate to this view at an appropriate time if this state is set during setUp?Thirlage
It doesn't matter where this state is set (either in setUp or the test itself), it matters only if you set it before calling app.launch(). Calling launch will basically run your app (in another process) which can be able to read launch environments and arguments (see the answer how). From the app itself, you should be able to decide what to do. If this still doesn't help you solve your problems, please ask a question referring to this answer and explaining what you have tried so far.Sandbank

© 2022 - 2024 — McMap. All rights reserved.