3

I am trying to write unit tests for Angular4 app using karma after this I am getting error at TestBed.createComponent(ServicesComponent) so none of the test cases are being executed, and

TypeError: this.expiry.last is not a function at Idle.Array.concat.Idle.watch...

There is a lot of stuff written in the constructor(in which there are service calls being made and also Idle functionality was written), How would the test cases should be written for that?

This is my spec file, Idle functions are used in Component's Constructor, and I had to add IdleExpiry, Keepalive providers to not get exceptions like Error: No provider for IdleExpiry

beforeEach(async(() => {
        TestBed.configureTestingModule({
            declarations: [                    
                ServicesComponent
            ],
            providers: [
                { provide: ServicesService, useClass: ServicesService },
                { provide: LocalStorageService, useClass: MockLocalStorageService },
                { provide: ServiceUtilities, useClass: ServiceUtilities },
                { provide: Idle, useClass: Idle },
                { provide: IdleExpiry, useClass: IdleExpiry },
                { provide: Keepalive, useClass: Keepalive },
                { provide: Router, useValue: routerStub },
                { provide: ActivatedRoute, useValue: activatedrouteStub },
                MockBackend,
                BaseRequestOptions,
                {
                    provide: Http,
                    useFactory: (backend, options) => new Http(backend, options),
                    deps: [MockBackend, BaseRequestOptions]
                }
            ],
            imports: [
                ModalModule.forRoot()
            ]
        }).compileComponents();
    }));
beforeEach(() => {            
        fixture = TestBed.createComponent(ServicesComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
    });

Component (excluding unneccessary details (replaced by ...))

export class ServicesComponent {
    ...
    approxWaitingTime: string;
    idleState = 'Not started.';
  timedOut = false;
  lastPing?: Date = null;
@ViewChild('autoShownModal') public autoShownModal: ModalDirective;
public isModalShown:boolean = false;
timer: any;
constructor(private servicesService: ServicesService, private route: ActivatedRoute, private router: Router, private idle: Idle, private keepalive: Keepalive) {

    this.servicesService.getServices(this.centerId).subscribe(data => { ... });
    this.servicesService.getCategories(this.centerId).subscribe(data => {  ... });
    this.servicesService.getStylists(this.centerId).subscribe(data => { ... });
    this.servicesService.getApproxWaitingTime(this.centerId).subscribe(data => { ... });

    this.route.queryParams.subscribe(params => { ... });

    // sets an idle timeout of 120 seconds, for testing purposes.
    idle.setIdle(10);
    // sets a timeout period of 30 seconds. after 30 seconds of inactivity, the user will be considered timed out.
    idle.setTimeout(5);
    // sets the default interrupts, in this case, things like clicks, scrolls, touches to the document
    idle.setInterrupts(DEFAULT_INTERRUPTSOURCES);

    idle.onIdleEnd.subscribe(() => this.idleState = 'No longer idle.');
    idle.onTimeout.subscribe(() => {
        console.log("ontimeout");
        this.idleState = 'Timed out!';
        this.timedOut = true;
    });
    idle.onIdleStart.subscribe(() => this.idleState = 'You\'ve gone idle!');
    idle.onTimeoutWarning.subscribe((countdown, router, autoShownModal) => {
        console.log("time out" + countdown);
        this.isModalShown = true;
        this.timer = setTimeout(function () { if (this.isModalShown) { this.hideModal(); } this.reset(); this.router.navigate(['']); }.bind(this), 3000);
        this.reset();
    });

    // sets the ping interval to 15 seconds
    keepalive.interval(10);

    keepalive.onPing.subscribe(() => { this.lastPing = new Date(); console.log('Keepalive.ping() called!'); });

    this.reset();
}
...

Am I missing any?

NikhilGoud
  • 574
  • 1
  • 5
  • 21

2 Answers2

9

Here's what I did to make the component load, Mocked IdleExpiry

export class MockExpiry extends IdleExpiry {
  public lastDate: Date;
  public mockNow: Date;

  last(value?: Date): Date {
    if (value !== void 0) {
      this.lastDate = value;
    }

    return this.lastDate;
  }

  now(): Date {
    return this.mockNow || new Date();
  }
}

updated the spec

providers: [
...
    { provide: IdleExpiry, useClass: MockExpiry },
...
],
NikhilGoud
  • 574
  • 1
  • 5
  • 21
1

The proper solution would have been to add the NgIdleKeepaliveModule to the imports of the testingModule.

I also would suggest against extending the class that you are mocking in a mock (implementing wouldn't be a bad idea however).

Mychal Hackman
  • 319
  • 1
  • 8