Home > Software design >  Angular testing Expected spy navigateByUrl to have been called 0 times. It was called 1 times
Angular testing Expected spy navigateByUrl to have been called 0 times. It was called 1 times

Time:03-25

I have a strange behavior on testing Angular RxJS based funtions with Karma/Jasmine.

I have this test:

describe('LoginComponent', () => {
  let fixture: ComponentFixture<LoginComponent>;
  let component: LoginComponent;
  let debugElement: DebugElement;
  let location: Location;
  let router: Router;
  let authServiceSpy: AuthService = {
    login: () => null,
    user: new BehaviorSubject<UserInterface>(null)
  } as jasmine.SpyObj<any>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [
        HttpClientTestingModule,
        RouterTestingModule,
        AppModule,
      ],
      providers: [
        { provide: AuthService, useValue: authServiceSpy },
      ],
      declarations: [
        LoginComponent,
      ]
    })
    .compileComponents()
    .then(() => {
      router = TestBed.inject(Router);
      location = TestBed.inject(Location);
      fixture = TestBed.createComponent(LoginComponent);
      component = fixture.componentInstance;
      debugElement = fixture.debugElement;
    });
  });

  describe('submit form', () => {
    it('should navigate to dashboard with correct credentials', fakeAsync(() => {
      spyOn(authServiceSpy, 'login').and.returnValue(of(new User()));
      const navSpy = spyOn(router, 'navigateByUrl');
      const button = debugElement.queryAll(By.css('.login-button'));
      fixture.detectChanges();
      fixture.whenStable().then(() => {
        button[0].nativeElement.click();
        tick();
        expect(navSpy).toHaveBeenCalledTimes(1);
        expect(navSpy).toHaveBeenCalledWith('/dashboard');
      });
    }));

    it('should show error with incorrect credentials', fakeAsync(() => {
      spyOn(authServiceSpy, 'login').and.returnValue(throwError('login failed'));
      const navSpy = spyOn(router, 'navigateByUrl');
      const button = debugElement.queryAll(By.css('.login-button'));

      fixture.detectChanges();
      fixture.whenStable().then(() => {
        button[0].nativeElement.click();
        tick();
        fixture.detectChanges();

        expect(navSpy).toHaveBeenCalledTimes(0);
      });
    }));
  });
});

After run these tests I get this error message:

Error: 1 timer(s) still in the queue.

Then I add flush() for the start of both it() funtions. And I get this error:

Expected spy navigateByUrl to have been called 0 times. It was called 1 times.

I tried to use discardPeriodicTasks() and flushMicrotasks() too. But not helped.

When I use it() functions one-by-one with fit() then all works correctly.

Any idea how can I fix this?

CodePudding user response:

As pointed out by @rmjoia, you need to reset the spy object as it will be reused on related test specs. Resetting can be accomplished through the reset method.

navSpy.calls.reset

I would recommend doing this on the beforeEach function.

Another solution would be splitting the tests into two test suites

  • Related