0

i've implemented idle-functionality with ng-idle, which works fine. i'am trying to implement tests with karma/jasmine but i can not use my idle-service:

UPDATE2

import { Injectable, OnInit, OnDestroy} from '@angular/core';
import { RoutingService } from '../../services/routing/routing.service';
import { Idle, DEFAULT_INTERRUPTSOURCES } from '@ng-idle/core';
import { Keepalive } from '@ng-idle/keepalive';

@Injectable()
export class TimeoutService {

    idleState = 'Not started.';
    timedOut = false;
    lastPing?: Date = null;
    title = 'angular-idle-timeout';
    idleTime = 0;
    timeoutTime = 0;

    constructor(
        public idle: Idle,
        private keepalive: Keepalive,
        public routingService: RoutingService) {
    }

    initIdle(): void {
        this.idle.setIdle(5);
        this.idle.setTimeout(5);
        this.idle.setInterrupts(DEFAULT_INTERRUPTSOURCES);
        this.idle.onIdleEnd.subscribe(() => {
            this.idleState = 'No longer idle.';
            this.reset();
          });

        this.idle.onTimeout.subscribe(() => {
            this.idleState = 'Timed out!';
            this.timedOut = true;     
            this.idle.stop();
            this.timedOut = false;
            this.routingService.navigateToIndex();
        });

        this.idle.onIdleStart.subscribe(() => {
            this.idleState = 'Inaktivität nach 10 Sekunden festgestellt!';

        });

        this.idle.onTimeoutWarning.subscribe((countdown) => {
        this.idleState = 'Buchvorgang wird abgebrochen in ' + countdown + ' Sekunden!';

        });

        this.keepalive.interval(15);
        this.keepalive.onPing.subscribe(() => this.lastPing = new Date());
        this.reset();
    }

    setIdleTime(idleTime): void {
        this.idleTime = idleTime;
    }

    setTimeoutTime(timeoutTime): void {
        this.timeoutTime = timeoutTime;
    }

    getIdleTime(): number {

        return this.idleTime;
    }

    reset() {
        this.idle.watch();
        this.idleState = 'Started.';
        this.timedOut = false;
    }
}

my spec for injectable service

    import { Router } from '@angular/router';
import {async} from '@angular/core/testing';
import { inject, TestBed } from '@angular/core/testing';
import { RoutingService } from '../../services/routing/routing.service';
import { RouterTestingModule } from '@angular/router/testing';
import { TimeoutService } from './timeout.service';
import { Idle, IdleExpiry, DEFAULT_INTERRUPTSOURCES } from '@ng-idle/core';
import { CoreTestingModule } from '../../core-testing.module';
import { Keepalive } from '@ng-idle/keepalive';
import { HttpClient, HttpHandler} from '@angular/common/http';
import { HttpClientTestingModule } from '@angular/common/http/testing';
//import { MockExpiry } from './MockExpiry';

fdescribe('TimeoutService', () => {
    /** let router: Router; */
    let service: TimeoutService;
    let router: Router;
    const mockIdleService = jasmine.createSpyObj('idle', ['initIdle', 'setIdleTime',
                                                            'setTimeoutTime', 'reset',
                                                            'setIdle','setTimeout','setInterrupts',
                                                            'onIdleEnd','onTimeout','onIdleStart',
                                                            'onTimeoutWarning','keepalive','idling']);
    const spies = {
        navigate: null
    };
    jasmine.clock().install();
    beforeEach(async(() => {
        TestBed.configureTestingModule({
            imports: [HttpClientTestingModule, RouterTestingModule],
            providers: [HttpClient, RoutingService,
                        Keepalive, TimeoutService, Idle, IdleExpiry, { provide: IdleExpiry, useValue: mockIdleService }]
        });
        service = TestBed.get(TimeoutService);
        router = TestBed.get(Router);
        spies.navigate = spyOn(router, 'navigate').and.stub();
    }));

    fit('should navigate to index after 15 Seconds', () => {
        console.log('IDLE TIME VOR DEM INIT-IDLE' + service.idleTime);
        service.initIdle();
        service.setIdleTime(1);
        service.setTimeoutTime(1);
        expect(service.idleTime).toBe( 1 );
        expect(service.timeoutTime).toBe( 1 );
        expect(spies.navigate).toHaveBeenCalledWith(['/index']);

    });
});

Error during test is:

TypeError: this.expiry.now is not a function at Idle.watch at TimeoutService.reset at TimeoutService.initIdle

Roma Kap
  • 517
  • 1
  • 8
  • 23

1 Answers1

1

It seems that TimeoutService relies on Idle.

You have to mock Idle

import { Router } from '@angular/router';
import { inject, TestBed } from '@angular/core/testing';
import { TimeoutService } from './timeout.service';
import { NgIdleKeepaliveModule } from '@ng-idle/keepalive';

fdescribe('TimeoutService', () => {
    let router: Router;
    const spies = {
        navigate: null
    };

    beforeEach(() => {
        TestBed.configureTestingModule({
            imports: [RouterTestingModule, NgIdleKeepAliveModule],
            providers: [TimeoutService]
        });
    });


    fit('should navigate to index after 15 Seconds', inject([TimeoutService], (timeoutService: TimeoutService) => {
        // let's assume the idle service has a method idleTime()
        // you can do mockIdleService.idleTime.and.returnValue(10);
        timeoutService.setIdleTime(10);
        timeoutService.setTimeoutTime(5);
        console.log('TEST FINISHED');

    }));
});

Check out Mock Idle in Angular 4 Unit tests. Maybe you can import the whole module itself like Mychal Hackman states.

AliF50
  • 16,947
  • 1
  • 21
  • 37
  • thx, public methods, which i'am using you can see within test: setIdleTime and setTimeoutTime. So i'am creating 'mockIdleService' like this: let mockIdleService = jasmine.createSpyObj('idle', [ 'setIdleTime','setTimeoutTime']); Then i get error: StaticInjectorError(Platform: core)[Keepalive -> HttpClient]: NullInjectorError: No provider for HttpClient! – Roma Kap Feb 27 '20 at 09:32
  • Please, look on update-section, i've edit my spec with a new error – Roma Kap Feb 27 '20 at 10:03
  • Add `setIdle` to the array of `['initTime', 'setIdleTime', 'setTimeoutTime']`, should be `jasmine.createSpyObj('idle', ['initTime', 'setIdleTime', 'setTimeoutTime', 'setIdle']);` – AliF50 Feb 27 '20 at 18:09
  • Pls. look on Update 2, so you see my service and spec now i have to mock this.expiry.now from ng-idle, how can i do that? i've triede out: 'this.expiry.now', 'expiry.now' and 'Idle.expiry.now' Nothing works – Roma Kap Feb 28 '20 at 11:55
  • I think you need to add `watch` to the array as well. But this is getting out of hand, I think you should import the `NgIdleKeepaliveModule` and put it in the `imports` array and not mock it anymore. – AliF50 Feb 28 '20 at 12:22
  • sorry, i'dont understand, how and where excatly i should import **NgIdleKeepaliveModule** I've tried to import NgIdleKeepaliveModule in array of jasmine.createSpyObj, but it is not working – Roma Kap Feb 28 '20 at 14:14
  • Check out my edit. And I mean to add `watch` to this array `['initIdle', 'setIdleTime', 'setTimeoutTime', 'reset', 'setIdle','setTimeout','setInterrupts', 'onIdleEnd','onTimeout','onIdleStart', 'onTimeoutWarning','keepalive','idling']` but it is getting out of hand so try importing all of `NgIdleKeepaliveModule` in the `imports` of the configuration. – AliF50 Feb 28 '20 at 14:28
  • yes, cause of so much array values, i've tried to import ``` NgIdleKeepaliveModule ``` like this: TestBed.configureTestingModule({ imports: [NgIdleKeepaliveModule, HttpClientTestingModule, RouterTestingModule], providers: [HttpClient, RoutingService, Keepalive, TimeoutService, Idle, IdleExpiry, { provide: IdleExpiry, useValue: mockIdleService }] }); but it is not working – Roma Kap Feb 28 '20 at 14:41
  • Check out my edit, we are not going to mock it anymore. We are going to use its actual implementation. – AliF50 Feb 28 '20 at 14:43
  • thx, this seems to be a right way. Now i can not enter any event. For instance, a first event, which be entered within is this.idle.onIdleStart. But it will never be called. Seems, that i still have to mock this.idle.onIdleStart and other events, but i don't know how, when i am using NgIdleKeepaliveModule – Roma Kap Mar 02 '20 at 08:21
  • I am not sure, I have not used this module before or even worse, unit tested it. Try going back to the long array and mocking everything. – AliF50 Mar 02 '20 at 12:06