Lesson 16

[Sprint Three] Logout

Adding a logout feature

PRO

Lesson Outline

Feat: Ability to log out

Let's move on to our first proper user story for this sprint.

User story: As a massage therapist, I want the ability to log out, so that I can protect sensitive client information and interact with the application as a non-admin user


Project management

Remember to move the card for this task to the Test column, and create a new task branch to work on.


For this one, we are just going to add a logout button on the client-dashboard page. Let's start with an E2E test in clients.cy.ts:

it('can log out', () => {
  getLogoutButton().should('be.visible');
});

This test might seem a bit odd - it's not doing much. Typically we would want to actually click the button and see if it does what it is supposed to do - but this is a bit of a special case. Remember that we are using cypress-firebase to bypass the authentication process, because we can't really get through that process properly just by interacting with the app with Cypress. If we click the logout button, we are going to mess with our E2E tests because we are going to be triggering real logout functionality. We avoid this problem with our login button because we completely bypass the authentication process if we are already authenticated (and we are thanks to cypress-firebase). We don't have a mechanism for bypassing the logout functionality.

So, we are making a compromise here - a weak test to avoid the trouble of actually triggering a logout in our E2E tests. We are still going to test the logout functionality properly with our unit tests.

We have also added a new utility method here:

export const getLogoutButton = () => cy.get('[data-test="logout-button"]');

and now let's run it to make sure it fails:

Timed out retrying after 4000ms: Expected to find element: [data-test="logout-button"], but never found it.

If we're following the errors, we can now add a logout button to the template in client-dashboard.page.html:

<ion-header>
  <ion-toolbar>
    <ion-title data-test="page-title">Clients</ion-title>
    <ion-buttons slot="start">
      <ion-button data-test="logout-button" (click)="authService.logout()">
        <ion-icon slot="icon-only" name="power-outline"></ion-icon>
      </ion-button>
    </ion-buttons>
    <ion-buttons slot="end">
      <ion-button
        data-test="add-client-button"
        routerLink="add"
        routerDirection="forward"
      >
        <ion-icon slot="icon-only" name="add"></ion-icon>
      </ion-button>
    </ion-buttons>
  </ion-toolbar>
</ion-header>

But of course we don't have a logout method defined yet in our AuthService so the test will still fail. Let's add a unit test for that now.

describe('AuthService', () => {
  let service: AuthService;
  let auth: AngularFireAuth.Auth;
  let navCtrl: NavController;

  beforeEach(() => {
    jest.restoreAllMocks();
    jest.clearAllMocks();

    TestBed.configureTestingModule({
      providers: [
        AngularFireAuth.Auth,
        { provide: NavController, useValue: { navigateRoot: jest.fn() } },
      ],
    });
    service = TestBed.inject(AuthService);
    auth = TestBed.inject(AngularFireAuth.Auth);
    navCtrl = TestBed.inject(NavController);
  });
  describe('logout()', () => {
    it('should call the signOut method', async () => {
      jest.spyOn(AngularFireAuth, 'signOut');
      await service.logout();
      expect(AngularFireAuth.signOut).toHaveBeenCalledWith(auth);
    });

    it('should navigate back to the home page', async () => {
      await service.logout();
      expect(navCtrl.navigateRoot).toHaveBeenCalledWith('/home');
    });
  });

We have also added a test for navigating back to the root page when the logout is triggered. Before we can run our tests we will need to add a dummy logout method:

PRO

Thanks for checking out the preview of this lesson!

The full version of this lesson is only available to pro members. If you would like full access to this module and all of the other pro modules on Elite Ionic you can become a pro member (or log in if you are already a member).