Angular MSAL unit test service calling another service

227 views Asked by At

I am trying to test my service that calls another service.

I have auth.service.ts that contains login method that calls MsalService.loginRedirect();.

import { Inject, Injectable } from '@angular/core';

import {
  MSAL_GUARD_CONFIG,
  MsalGuardConfiguration,
  MsalService,
} from '@azure/msal-angular';
import { RedirectRequest } from '@azure/msal-browser';

@Injectable({
  providedIn: 'root',
})
export class AuthService {
  constructor(
    @Inject(MSAL_GUARD_CONFIG) private msalGuardConfig: MsalGuardConfiguration,
    private msalService: MsalService
  ) {}

  login(): void {
    if (this.msalGuardConfig.authRequest) {
      this.msalService.loginRedirect({
        ...this.msalGuardConfig.authRequest,
        redirectStartPage: '/',
      } as RedirectRequest);
    } else {
      this.msalService.loginRedirect();
    }
  }
}

and a spec file

import { TestBed } from '@angular/core/testing';

import { MsalAuthModule } from '@app/core/msal.module';

import { AuthService } from './auth.service';
import { MsalService } from '@azure/msal-angular';
import { MockService } from 'ng-mocks';

describe('AuthService', () => {
  let service: AuthService;

  const mockMsalService = MockService(MsalService, {
    loginRedirect: void {},
  });

  let msalServiceSpy: jasmine.SpyObj<MsalService>;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [MsalAuthModule],
      providers: [{ provide: MsalService, useValue: mockMsalService }],
    });
    service = TestBed.inject(AuthService);
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });

  it('should login', () => {
    spyOn(service, 'login'); // <- runs login method from service?

    msalServiceSpy = jasmine.createSpyObj(mockMsalService, ['loginRedirect']); // <- creates spy?
    expect(msalServiceSpy).toHaveBeenCalled(); // <- test if msalService.login() is called
  });
});

But I am getting Expected a spy error.

enter image description here

Is my understanding correct?

  1. Mock MsalService
  2. Spy the mocked MsalService
  3. run the login method using spyOn(service, 'login')
  4. test the mocked MsalService' loginRedirect() if it is called using toHaveBeenCalled()

Then why its returning the error? Is my syntax wrong?

I am new to angular unit testing so I really appreciate your help :) Thank you!

1

There are 1 answers

0
moh On

It seems like there are a couple of issues with your testing approach.

unnecessary spyOn(service, 'login')

call the login method on the service

import { TestBed } from '@angular/core/testing';
import { MsalAuthModule } from '@app/core/msal.module';
import { AuthService } from './auth.service';
import { MsalService, RedirectRequest } from '@azure/msal-angular';
import { MockService } from 'ng-mocks';

describe('AuthService', () => {
  let service: AuthService;
  let msalService: jasmine.SpyObj<MsalService>;

  beforeEach(() => {
    const mockMsalService = MockService(MsalService, ['loginRedirect']);
    
    TestBed.configureTestingModule({
      imports: [MsalAuthModule],
      providers: [{ provide: MsalService, useValue: mockMsalService }],
    });

    service = TestBed.inject(AuthService);
    msalService = TestBed.inject(MsalService) as jasmine.SpyObj<MsalService>;
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });

  it('should login', () => {
    service.login();

    expect(msalService.loginRedirect).toHaveBeenCalled();
  });
});