34

I'm working on unit testing under my Angular app.

My version of Angular is 4.0.0.

My component look like this:

component.ts:

import { GdfaClientService } from '../../../service/gdfa-client.service';
import { SharedclientService } from '../../../service/sharedclient.service';
import { Client } from '../../model/client';
import { RouteNavigator } from '../../util/route-navigator';
import { Component, OnInit } from '@angular/core';
import {MonitoringService} from '../../../service/monitoring.service';
@Component({
  selector: 'app-queue-again',
  templateUrl: './queue-again.component.html',
  styleUrls: ['./queue-again.component.css'],
})
export class QueueAgainComponent implements OnInit {

  //-- variables --//
  showError = false;
  queueChoices = [];
  selectedQueue;
  selectedReason;
  requestInProgress = false;
  client: Client;
  errorMessage: string;
  queues: any;
  bankNotAllowed: boolean = false;

  constructor(private sharedclientService: SharedclientService, private gdfaClientService: GdfaClientService
    , private router: RouteNavigator, private monitoringService: MonitoringService) { }

  ngOnInit() {
    this.client = this.sharedclientService.getShared360Client();
    this.getQueues();
    this.bankNotAllowed = this.sharedclientService.bankNotAllowed;
  }


  goToPrevious() {
    this.router.goToHomeAccordingToProfile();
  }

  queueAgain() {
    let currentNd = "";
    let currentUniverse = "";
    let currentCuid = "";
    if (!this.selectedReason) {
      return;
    }
    this.requestInProgress = true;

    let reg = {
      registrationId: this.client.registration.gdfaId,
      gdfaQueueId: this.selectedQueue.id,
      gdfaReasonId: this.selectedReason.id,
      firstProfile: (this.client.firstProfile ? true : false)
    };

    this.gdfaClientService.queueAgain(reg).then(any => {
        currentCuid = this.client.clientIdentity.customerId;

        if (this.client.fromAdvSearch == undefined || this.client.fromAdvSearch == false) {

      currentNd = this.client.nd;
      if (currentNd != undefined && currentNd != "") {
        if (currentNd == "0000000000") {
          currentNd = "";
          currentUniverse = "";
        }
        if (currentNd.substring(0, 2) == "06" || currentNd.substring(0, 2) == "07") {
          currentUniverse = "Mobile";
        } else {
          currentUniverse = "Fixe";
        }
      }
        }
      this.trackReinsertClient(currentCuid, currentNd, currentUniverse);
      this.requestInProgress = false;
      this.showError = false;
      this.sharedclientService.setShared360Client(new Client());
      this.goToPrevious();
    })
      .catch(error => {
        this.requestInProgress = false;
        this.showError = true;
        switch (error.status) {
          case 403:
            this.errorMessage = "Erreur lors de la réinjection du client : utilisateur inconnu";
            console.log(this.errorMessage);
            break;
          case 500:
            this.errorMessage = "Réinscription impossible";
            console.log(this.errorMessage);
            break;
          default:
            this.errorMessage = "Erreur lors de la réinjection du client";
            console.log(this.errorMessage);
        }
      });
  };


  trackReinsertClient(cuid, nd, universe) {
    let uri = "/api/gdfa/client/registration/reinsert";
    let httpMethod = "PUT";
    let name = "réinjection d'un client dans la file d'attente";
    console.log('trackReinsertClient <' + cuid + '>');
    this.monitoringService.trackingAction(name, uri, httpMethod, null, cuid, nd, universe);

  }

  selectQueue(queue) {
    this.selectedQueue = queue;
    this.selectedReason = false;
  };

  isSelectedQueue(queue) {
    return this.selectedQueue.shortName == queue.shortName;
  }

  getQueues() {
    let queueList = this.client.registration.queueAgainChoices;
    // Search for residentiel queue and put it as selectedQueue
    let indexSAVSAUMobile = -1;
    let indexSAVSAUInternet = -1;
    for (let queue of queueList) {
      if (queue.shortName == 'RES')
        this.selectedQueue = queue;
    }

    this.queues = queueList;
    return queueList;
  }

  selectReason(reason) {
    this.selectedReason = reason;

  }


  isSelectedReason(reason) {
    if (this.selectedReason) {
      return this.selectedReason.id == reason.id;
    }
    return null
  }

  getReasons(queue) {
    let reasonList = this.selectedQueue.reasons;
    return reasonList;
  }
}

component.html:

<div>
    <div [hidden]="!requestInProgress" id="div-spinner">
        <img src="/assets/images/indicateur-attente-grand.gif"
            class="spinner-loader" />
    </div>
    <div class="row">
        <!-- fermeture de la recherche avancée -->
        <div class="col-xs-1 pull-right closeCross">
            <img id="ngClick_goToPreviousFromQueueAgain"
                src="/assets/images/asset_icon_close_popup_gray.png"
                class="pull-right mousePointer" (click)="goToPrevious()" />
        </div>
    </div>
    <div class="row">
        <div class="col-xs-10 col-xs-offset-1 error-message"
            *ngIf="showError">{{errorMessage}}</div>
        <div
            class="col-xs-10 col-xs-offset-1 col-sm-3 col-sm-offset-0 register-bloc">
            <div class="titre_bloc">File d'attente</div>
            <div id="files-bloc">
                <div id="ngClick_selectQueueAgain" class="file-cell "
                    *ngFor="let queue of queues | orderBy : 'id'"       
                    [ngClass]="{ 'selected-shop-queue': isSelectedQueue(queue)}"
                    (click)='selectQueue(queue)'>
                    <div class="vertical-center horizontal-middle file_nom">
                        <div>{{queue.name}}</div>
                    </div>
                </div>
            </div>
        </div>
        <div
            class="col-xs-10 col-xs-offset-1 col-sm-6 col-sm-offset-0 register-bloc">
            <div class="titre_bloc">Motifs</div>
            <div id="motifs-bloc">
                <div id="ngClick_queueAgain" class="motif-cell"
                    [ngClass]="{'motif-cell-pro': selectedQueue?.reasons?.length == 4, 'motif-cell-selected':isSelectedReason(reason),
                    'hide-class': (bankNotAllowed && reason.id === 12)}" [hidden]="bankNotAllowed && reason.id === 12"
                    *ngFor="let reason of selectedQueue?.reasons | orderBy : 'motifOrder'"
                    (click)='selectReason(reason)'>
                    <div *ngIf="!bankNotAllowed || reason.id !== 12" class="mIcon">
                            <img
                                src="/bower_components/nomadis/images-no-cache/{{reason?.imageName}}"
                                [ngClass]="{'motif-unique': client?.registration?.queue?.reasons?.length == 1}" />
                            <span>{{reason.name}}</span>
                    </div>
                </div>
            </div>
            <div class="col-sm-offset-4 col-sm-4  btn-validate-reinsert">
                <input id="validateReinsertBtn" type="submit" value="Valider"
                    [ngClass]="{'queueAgain-disabled': !selectedReason}"
                    class="btn btn-lg btn-primary btn-block"
                    (click)='queueAgain()' />
            </div>
        </div>
    </div>

</div>
<router-outlet></router-outlet>

As you can see I'm not using routeLink.

Within my test file config I've done this:

component.spec.ts:

import {async, ComponentFixture, TestBed, tick, fakeAsync} from '@angular/core/testing';
import {QueueAgainComponent} from './queue-again.component';
import {OrderByPipe} from 'app/home/pipe/order-by.pipe';
import {SharedclientService} from 'app/service/sharedclient.service';
import {GdfaClientService} from 'app/service/gdfa-client.service';
import {AuthHttp, AuthConfig, AUTH_PROVIDERS, provideAuth} from 'angular2-jwt';
import {HttpModule} from '@angular/http';
import {EnvVarsService} from 'app/service/env-vars.service';
import {RouteNavigator} from 'app/home/util/route-navigator';
import {Router} from '@angular/router';
import {Observable} from 'rxjs/Observable';
import * as QueueAgainMocks from 'TU/mocks/queue-again-mocks';
import {RouterTestingModule} from '@angular/router/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';

describe('QueueAgainComponent', () => {
    let comp: QueueAgainComponent;
    let fixture: ComponentFixture<QueueAgainComponent>;
    let sharedclientService: SharedclientService;
    let gdfaClientService: GdfaClientService;
    let getShared360Client: jasmine.Spy;
    let queueAgain: jasmine.Spy;
    let client = QueueAgainMocks.CUSTOMER_MOCK;
    let selectedQueue = QueueAgainMocks.SELECTED_QUEUE_MOCK;
    let selectedReason = QueueAgainMocks.SELECTED_REASON;
    let mockRouter = {
        navigate: jasmine.createSpy('navigate')
    };

    // TestBed preparation (async)
    beforeEach(async(() => {
        TestBed.configureTestingModule({
            imports: [HttpModule , RouterTestingModule],
            declarations: [QueueAgainComponent, OrderByPipe],
            providers: [SharedclientService, GdfaClientService, AuthHttp, EnvVarsService, RouteNavigator,
                {provide: Router, useValue: mockRouter},
                provideAuth({
                    headerName: 'Authorization',
                    headerPrefix: 'bearer',
                    tokenName: 'token',
                    tokenGetter: (() => localStorage.getItem('id_token')),
                    globalHeaders: [{'Content-Type': 'application/json'}],
                    noJwtError: true
                })
            ],
            schemas: [ NO_ERRORS_SCHEMA ]
        }).compileComponents();
    }));

    // Fixture & Spies declarations
    beforeEach(() => {
        // Creation of the component fixture
        fixture = TestBed.createComponent(QueueAgainComponent);
        comp = fixture.componentInstance;
        fixture.detectChanges();  // this line will call components ngOnInit() method


        // Getting Services instances from fixture
        sharedclientService = fixture.debugElement.injector.get(SharedclientService);
        gdfaClientService = fixture.debugElement.injector.get(GdfaClientService);

        // Call of fake methods of `sharedclientService` from the AlertServiceSpy
        getShared360Client = spyOn(sharedclientService, 'getShared360Client').and.returnValue(client);
        // Call of fake methods of `gdfaClientService` from the AlertServiceSpy
        queueAgain = spyOn(gdfaClientService, 'queueAgain').and.callFake((reg) => {
            return Observable.of('ok');
        });

        comp.ngOnInit();
    });
    // Test case of component compilation
    it('should be defined', () => {
        expect(comp).toBeDefined();
    });
});

Although I've imported NO_ERRORS_SCHEMA and I've used a mockRouter, it seems that something is still going wrong with routing with this error:

TypeError: Cannot read property 'root' of undefined

      at rootRoute (node_modules/@angular/router/bundles/router.umd.js:6110:30)
      at _callFactory (packages/core/src/view/ng_module.ts:185:1)
      at _createProviderInstance$1 (packages/core/src/view/ng_module.ts:124:1)
      at resolveNgModuleDep (node_modules/@angular/core/bundles/core.umd.js:9517:17)
      at _createClass (packages/core/src/view/ng_module.ts:158:1)
      at _createProviderInstance$1 (packages/core/src/view/ng_module.ts:121:1)
      at resolveNgModuleDep (node_modules/@angular/core/bundles/core.umd.js:9517:17)
      at NgModuleRef_.Object.<anonymous>.NgModuleRef_.get (node_modules/@angular/core/bundles/core.umd.js:10609:16)
      at resolveDep (node_modules/@angular/core/bundles/core.umd.js:11112:45)
      at createClass (node_modules/@angular/core/bundles/core.umd.js:10976:32)
      at createDirectiveInstance (node_modules/@angular/core/bundles/core.umd.js:10796:37)
      at createViewNodes (packages/core/src/view/view.ts:354:1)
      at createRootView (node_modules/@angular/core/bundles/core.umd.js:12139:5)
      at callWithDebugContext (packages/core/src/view/services.ts:815:1)
      at Object.debugCreateRootView [as createRootView] (node_modules/@angular/core/bundles/core.umd.js:12842:12)
      at ComponentFactory_.Object.<anonymous>.ComponentFactory_.create (node_modules/@angular/core/bundles/core.umd.js:9904:46)
      at initComponent (node_modules/@angular/core/bundles/core-testing.umd.js:924:49)
      at ZoneDelegate.Object.<anonymous>.ZoneDelegate.invoke (node_modules/zone.js/dist/zone-node.js:392:26)
      at ProxyZoneSpec.Object.<anonymous>.ProxyZoneSpec.onInvoke (node_modules/zone.js/dist/proxy.js:79:39)
      at ZoneDelegate.Object.<anonymous>.ZoneDelegate.invoke (node_modules/zone.js/dist/zone-node.js:391:32)
      at Object.onInvoke (node_modules/@angular/core/bundles/core.umd.js:3922:33)
      at ZoneDelegate.Object.<anonymous>.ZoneDelegate.invoke (node_modules/zone.js/dist/zone-node.js:391:32)
      at Zone.Object.<anonymous>.Zone.run (node_modules/zone.js/dist/zone-node.js:142:43)
      at NgZone.Object.<anonymous>.NgZone.run (node_modules/@angular/core/bundles/core.umd.js:3853:69)
      at TestBed.Object.<anonymous>.TestBed.createComponent (packages/core/testing/src/test_bed.ts:471:1)
      at Function.Object.<anonymous>.TestBed.createComponent (node_modules/@angular/core/bundles/core-testing.umd.js:691:29)
      at src/app/home/advisor/queue-again/queue-again.component.spec.ts:53:27

From the last line of the log that points on the 53:27 line which is exactly:

fixture = TestBed.createComponent(QueueAgainComponent);

So it seems that it's not able to create the fixture.

Any ideas?

2 Answers 2

99

I had the same problem, just figured it out. Remove the line:

{provide: Router, useValue: mockRouter}

and it will work.

The thing is when you import RouterTestingModule you should remove all router mocked providers, same for ActivatedRoute, and other services provided by RouterModule in @angular/router.

Sign up to request clarification or add additional context in comments.

Comments

3

If you want to use your custom stub/mock, for reference in the cases where we don't want to configure testing routes explicitly, you can make it like this:

export class RouterStub {
  routerState = { root: '' };
  navigate() {
    return;
  }
}

Just add routerState object that angular tries to find.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.