# Test-Driven Development: #7 Navigation

# Introduction
Hey hey, so we’re back for a quick one today, which is navigation, let’s start it with a good question 🙋‍♂️ 
> Did you try implementing last blog post’s challenge of doing it on your own?
![](https://c.tenor.com/4WZm1vgS_-8AAAAS/the-simpsons-homer-simpson.gif)

Well, fear not, because we’re here to fix that!
![](https://c.tenor.com/rPOqhxQBOz0AAAAS/all-might-my-hero-academia.gif)

# Enters Navigation
Last time we talked was about displaying alerts, since we have a private access to the current visible Controller, we can do navigation access on it, all while encapsulating it, but first, let’s imagine how our tests would be, so you can also learn the thought process
## Imagining the Code in Tests

```swift
func testGivenUserLogsInSuccessfully_WhenSuccessHappens_ThenHeShouldBeNavigatedToHomeScreen() {
    // Given
    let email = "valid_email@gmail.com"
    let password = "Somevalid1Password"
    
    // When
    sut.login(email: email, password: password)
    
    // Then
    XCTAssertTrue(
      router.actions.contains(
        .present(
          HomeViewController.self,
          presentationStyle: .fullScreen
        )
      )
    )
  }
```

So what I want at the end is something that tells me, hey, the type of the controller u passed is `HomeViewController`, and the presentation style is `fullScreenPresentation`

> 💡 For those reading outside iOS background, the fullScreen presentation is needed here as there are two types of presenting a screen, so we specify that here to avoid returning back to the login screen without a need, hence reinforcing our navigation logic

Now that we have an imagination in place of how our APIs would look like, let’s try to implement them

## Making it real
```swift
private extension LoginViewModel {
  func validate(_ email: String, _ password: String) {
	...
    router.alertWithAction(
      title: "Validation Errors",
      message: errors.map { $0.text }.joined(separator: "\n"),
      alertStyle: .actionSheet,
      actions: [
        (title: "Ok", style: .default, action: { [weak self] in
          self?.state.send(.idle) <- Added
        })
      ]
    )
  }
}
```
First, let’s reset our state to `idle` once the user dismissed the alert sheet, this way we can have a better state handling

## Sneak peak into the future of this Series
Second, in our `login method`, we can edit the implementation to go to a pre-built ViewController called `HomeViewController` where we will later on build an mini part of an E-Commerce app, so that we can later on test Common E-Commerce logic
```swift
public func login(email: String, password: String) {
    validate(email, password)
    
    guard state.value.errors.isEmpty else { return }
    
    ServiceLocator.main.network.call(
      api: AuthEndpoint.login(email: email, password: password),
      model: AccessToken.self
    ).sink(receiveCompletion: { onComplete in
      guard case let .failure(error) = onComplete else { return }
      self.state.send(.failure([error.toOError()]))
    }, receiveValue: { [weak self] token in
      guard let self = self else { return }
      try? ServiceLocator.main.cache.save(value: token, for: .accessToken)

	// Addition starts
      self.router.present(
        HomeViewController(),
        presentationStyle: .fullScreen
      )
	// Addition ends
    }).store(in: &cancellables)
  }
```

You will notice the pattern that we’re trying to reach now, we are testing if `Home` screen was pushed to the UI after a successful login

> Note: We don’t call an actual API, WE’RE THE API 😎
> Just kidding, indeed we don’t have an API, but that’s the power of Fake, where we can later on have our API installed in a backend server, and we can replace the contract with ease 🎉

## Green Checkmarks
What comes next is seeing the green check marks ticking into our tests, and a safety net if something broke
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1647874261262/UoCSZvaIU.png)
# Conclusion
What we did today was a good way of integration testing, as you can see we are testing if the user gets routed correctly as per the business, when logging in, there might be a case that I decided to not do in the current project since it’s too simple and lots of setup is needed to make it possible which is `automatically routing the user to Home after he logs in correctly`
If you’re looking for pointers on how to do this, here are some steps you can follow and some ideas
1. Programmatically launch Home or Login if the user already logged in once by finding the Access Token in the Cache/Storage
2. Introduce the concept of Coordinator, which programmatically (not in the Interface builder) determines which screen is required to be present

I think it’s time to close down this series 🥲


![](https://c.tenor.com/2jwpBY5ujg8AAAAC/loki-very.gif)


Anyway, I’ve been thinking on writing a series on The Composable Architecture (TCA), and it’s time to introduce a video series about building a chat app using it 😆

It’s been exciting dealing with TCA so far and how it makes it easy to work with SwiftUI

So next stop is returning to the good old `Redux` series
