0

I'm working with an application with Angular 11.

I've a loginService that allows users to interact with their profiles. In my application there's the jwt authentication and every 30 minutes the token is refreshed.

My LoginService looks like the following

@Injectable()
export class LoginService {

    private intervalId: any;

    constructor(private readonly http: HttpClient,
                private readonly ngZone: NgZone) {
        this.ngZone.runOutsideAngular(() => {

            this.intervalId = setInterval(() => {
                ngZone.run(() => {
                    this.renewJwtToken();
                });
            }, 1000 * 60 * 30);
        });
    }

    callLogin(loginRequest: LoginRequest): Observable<HttpResponse<LoginResponse>> {
        // call in order to login user
    }

    renewJwtToken() {
        // call in order to renew the token
    }
}

My problems are during the shallow tests (the ones in which we create the TestBed). I'm using jasmine 3.8 with karma 6.3.4

Every test returns with the following error

Error: Timeout - Async function did not complete within 5000ms (set by jasmine.DEFAULT_TIMEOUT_INTERVAL)
            at <Jasmine>

If I comment the content of the LoginService constructor everything works fine.

How can I test my application without disabling the setInterval I have in the LoginService constructor?

Thank you

Gavi
  • 1,300
  • 1
  • 19
  • 39

1 Answers1

0

See if fakeAsync and flush will help you (https://stackoverflow.com/a/53864251/7365461). fakeAsync and tick will allow you to manually progress time, tick with no arguments will allow you to ensure all promises have completed (same as flushMicroTasks()) but timeout and interval are macrotasks and see if the flush command inside of a fakeAsync zone helps you.

I think since your setInterval is in the constructor, ensure your service = TestBed.inject(LoginService); is also in a fakeAsync zone.

Something like this:

import { fakeAsync, flush } from '@angular/core/testing';
....
beforeEach(fakeAsync(() => {
    service = TestBed.inject(LoginService);
    flush();
}));

The code running in runOutsideAngular might cause complications though so you can consider creating a re-usable service for setInterval and then just mocking this in your test. Check out this link.

AliF50
  • 16,947
  • 1
  • 21
  • 37