ONE_FE
ONE_FE

Reputation: 1006

Unit Testing in Jasmine: Spy on service function and call another service function

Below is my component function I want to write unit tests. I want to write a unit test to test the tokenRefresh function in auth service is being called when getItem returns a string to the component.

Component.ts

refreshTokens(): void {
    const refreshToken = this.localStorageService.getItem('refresh_token');
    if (refreshToken) {
      this.authService.tokenRefresh(refreshToken).subscribe({
        next: (data: TokenModel) =>
          this.authService.routeToDashboard(
            data.access_token,
            data.refresh_token,
            data.expires_at
          ),
      });
    } else {
      this.notificationService.openSnackBar('Please login again.');
    }
  }

localStorage.service.ts

@Injectable({
  providedIn: 'root'
})
export class LocalStorageService {

  constructor() { }

  getItem(key: string): string | null {
    return localStorage.getItem(key);
  }
}

I have created mick services in my component.spec.ts to mock LocalStorageService and AuthService as below.

export class LocalStorageStub {
  getItem(key: string): string | null {
    return '7677673437437';
  }
}

export class AuthorizeServiceStub {
  tokenRefresh(key: string) {
    return of({});
  }
  setItem(): void {

  }
}

Below is my complete component.spec.ts.

describe('LoginComponent', () => {
  let component: LoginComponent;
  let fixture: ComponentFixture<LoginComponent>;
  let el: HTMLElement;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [ LoginComponent ],
      imports: [
        HttpClientModule,
        RouterTestingModule,
        MatSnackBarModule,
        BrowserAnimationsModule
      ],
      providers:[
        { provide: LocalStorageService, useClass: LocalStorageStub },
        { provide: AuthorizeService, useClass: AuthorizeServiceStub}
      ]
    })
    .compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(LoginComponent);
    component = fixture.componentInstance;
  });

  it('should call token refresh if localstorage has refreshtoken', function() {
    component.refreshTokens();
    let service = fixture.debugElement.injector.get(LocalStorageService);
    let authService = fixture.debugElement.injector.get(AuthorizeService);
    service.getItem('key');
    const setPageSpy2 = spyOn(authService, 'tokenRefresh');
    expect(setPageSpy2).toHaveBeenCalled();
  });
});

I get the below result for my test case.

enter image description here

Appreciate if someone can tell me what's the issue here.

Edit: The new order of unit test case

it('should call token refresh if localstorage has refreshtoken', function() {
    let service = fixture.debugElement.injector.get(LocalStorageService);
    let authService = fixture.debugElement.injector.get(AuthorizeService);
    service.getItem('key');
    component.refreshTokens();
    const setPageSpy2 = spyOn(authService, 'tokenRefresh');
    expect(setPageSpy2).toHaveBeenCalled();
  });

Upvotes: 2

Views: 9467

Answers (1)

Eugene
Eugene

Reputation: 1517

I did not find the problem, but I found a workaround :D

describe('LoginComponent', () => {
  let component: LoginComponent;
  let fixture: ComponentFixture<LoginComponent>;
  const authorizeServiceStub: AuthorizeService = jasmine.createSpyObj(
    AuthorizeService,
    { 'tokenRefresh': of({}) },
  );

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [ LoginComponent ],
      imports: [
        HttpClientModule,
        RouterTestingModule,
        MatSnackBarModule,
        BrowserAnimationsModule
      ],
      providers:[
        { provide: LocalStorageService, useClass: LocalStorageStub },
        { provide: AuthorizeService, useValue: authorizeServiceStub },
      ]
    })
    .compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(LoginComponent);
    component = fixture.componentInstance;
  });

  it('should call token refresh if localstorage has refreshtoken', function() {
    let service = fixture.debugElement.injector.get(LocalStorageService);
    service.getItem('key');
    component.refreshTokens();
    expect(authorizeServiceStub.tokenRefresh).toHaveBeenCalled();
  });
});

Upvotes: 1

Related Questions