it-swarm.com.de

Mocking router.events.subscribe () Angular2

In meinem app.component.ts habe ich die folgende Funktion ngOnInit:

ngOnInit() {
    this.sub = this.router.events.subscribe(e => {
      if (e instanceof NavigationEnd) {
        if (!e.url.includes('login')) {
          this.loggedIn = true;
        } else {
          this.loggedIn = false;
        }
      }
    });
  }

Momentan teste ich, ob das Sub nicht null ist, aber ich möchte die Funktion mit einer 100% igen Abdeckung testen.

Ich möchte das Router-Objekt verspotten, damit ich die URL simulieren kann und dann testen kann, ob this.loggedIn richtig eingestellt ist.

Wie würde ich vorgehen, um diese Funktion zu verspotten? Ich habe es ausprobiert, weiß aber nicht, wie ich das mit dem Callback und dem NavigationEnd aufnehmen würde.

14
stijn.aerts

Ich habe die Antwort gefunden, wenn jemand danach sucht:

import {
  addProviders,
  async,
  inject,
  TestComponentBuilder,
  ComponentFixture,
  fakeAsync,
  tick
} from '@angular/core/testing';
import { AppComponent } from './app.component';
import { Router, ROUTER_DIRECTIVES, NavigationEnd } from '@angular/router';
import { HTTP_PROVIDERS } from '@angular/http';
import { LocalStorage, WEB_STORAGE_PROVIDERS } from 'h5webstorage';
import { NavComponent } from '../nav/nav.component';
import { FooterComponent } from '../footer/footer.component';
import { Observable } from 'rxjs/Observable';

class MockRouter {
  public ne = new NavigationEnd(0, 'http://localhost:4200/login', 'http://localhost:4200/login');
  public events = new Observable(observer => {
    observer.next(this.ne);
    observer.complete();
  });
}

class MockRouterNoLogin {
  public ne = new NavigationEnd(0, 'http://localhost:4200/dashboard', 'http://localhost:4200/dashboard');
  public events = new Observable(observer => {
    observer.next(this.ne);
    observer.complete();
  });
}
21
stijn.aerts

Ich habe eine Version des Router-Stubs aus Angular -Dokumenten erstellt, die diese Methode zum Implementieren des NavigationEnd-Ereignisses zum Testen verwendet:

import {Injectable} from '@angular/core';
import { NavigationEnd } from '@angular/router';
import {Subject} from "rxjs";

@Injectable()
export class RouterStub {
  public url;
  private subject = new Subject();
  public events = this.subject.asObservable();

  navigate(url: string) {
    this.url = url;
    this.triggerNavEvents(url);
  }

  triggerNavEvents(url) {
    let ne = new NavigationEnd(0, url, null);
    this.subject.next(ne);
  }
}

9
ForrestLyman

Die akzeptierte Antwort ist korrekt, aber dies ist ein bisschen einfacher 

public ne = new NavigationEnd(0, 'http://localhost:4200/login', 'http://localhost:4200/login');
  public events = new Observable(observer => {
    observer.next(this.ne);
    observer.complete();
  });

durch:

public events = Observable.of( new NavigationEnd(0, 'http://localhost:4200/login', 'http://localhost:4200/login'));

Und unten finden Sie eine vollständige Testdatei, um die Funktion in der Frage zu testen:

import { NO_ERRORS_SCHEMA } from '@angular/core';
import {
  async,
  TestBed,
  ComponentFixture
} from '@angular/core/testing';

/**
 * Load the implementations that should be tested
 */
import { AppComponent } from './app.component';

import { NavigationEnd, Router } from '@angular/router';
import { Observable } from 'rxjs/Observable';


class MockServices {
  // Router
  public events = Observable.of( new NavigationEnd(0, 'http://localhost:4200/login', 'http://localhost:4200/login'));
}

describe(`App`, () => {
  let comp: AppComponent;
  let fixture: ComponentFixture<AppComponent>;
  let router: Router;

  /**
   * async beforeEach
   */
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ AppComponent ],
      schemas: [NO_ERRORS_SCHEMA],
      providers: [
        { provide: Router, useClass: MockServices },
      ]
    })
    /**
     * Compile template and css
     */
    .compileComponents();
  }));

  /**
   * Synchronous beforeEach
   */
  beforeEach(() => {
    fixture = TestBed.createComponent(AppComponent);
    comp    = fixture.componentInstance;

    router = fixture.debugElement.injector.get( Router);

    /**
     * Trigger initial data binding
     */
    fixture.detectChanges();
  });

  it(`should be readly initialized`, () => {
    expect(fixture).toBeDefined();
    expect(comp).toBeDefined();
  });

  it('ngOnInit() - test that this.loggedIn is initialised correctly', () => {
    expect(comp.loggedIn).toEqual(true);
  });

});
5
Tonio

Das vorherige Beispiel public events = Observable.of( new NavigationEnd(0, 'http://localhost..')); scheint nicht nach Karma zu funktionieren, was sich beschwert über:

Fehlgeschlagen: undefined ist kein Objekt (evaluiert 'Router.routerState.root') rootRoute @ http: // localhost: 9876/_karma_webpack_/vendor.bundle.js

Trotz (mocked) Router-Instanz events wurde der Subskriptionscallback in ngOninit() der ursprünglichen app.component.ts erfolgreich ausgeführt, d. H. Der von Karma getesteten Hauptanwendungskomponente:

this.sub = this.router.events.subscribe(e => { // successful execution across Karma

Die Art und Weise, in der Router verspottet wurde, sieht unvollständig aus, ungenau als Struktur von Karmas Interessenten: wegen router.routerState, das sich zur Laufzeit als undefiniert herausstellt.

Der Angular -Router wurde genau auf meiner Seite "gestubt", einschließlich RoutesRecognizedeventskünstlich gebacken als Observables in meinem Fall:

class MockRouter {
    public events = Observable.of(new RoutesRecognized(2 , '/', '/',
                                  createRouterStateSnapshot()));
}

const createRouterStateSnapshot = function () {
    const routerStateSnapshot = jasmine.createSpyObj('RouterStateSnapshot', 
                                                     ['toString', 'root']);
    routerStateSnapshot.root = jasmine.createSpyObj('root', ['firstChild']);
    routerStateSnapshot.root.firstChild.data = {
        xxx: false
    };
    return <RouterStateSnapshot>routerStateSnapshot;
};

um dem zu entsprechen, was ngOnInit() body erwartet, ist RoutesRecognizedevent mit tiefer Struktur erforderlich:

ngOnInit() {
   this.router.events.filter((event) => {
        return event instanceof RoutesRecognized;
    }).subscribe((event: RoutesRecognized) => {
        // if (!event.state.root.firstChild.data.xxx) {
        // RoutesRecognized event... to be baked from specs mocking strategy
   });
}

Zusammenfassung/Zusammenfassung meines <package.json> -Inhalts:

winkel/Router: 5.2.9, Karma: 2.0.2, Jasmin-Kern: 2.6.4, Karma-Jasmin: 1.1.2

0
hugo machefer