2016-05-20 21 views
5

Sto scrivendo i miei test ng2 e sto riscontrando dei problemi nell'iniettare il router nel mio componente per il mio test. Il costruttore per il mio componente accetta solo un argomento - private router: Router.Angular2 RC.1 - Injection Router in unit test

Tuttavia, quando eseguo il test case, ricevo un errore mentre sta provando a iniettare il router. Che cosa sto facendo di sbagliato? Qualcuno può fornire un esempio funzionante?

sto usando angular2-RC.1

Ecco l'errore che sto ricevendo: No provider for ComponentResolver! (Router -> ComponentResolver)

Ecco la mia prova:

import {describe, it, expect, beforeEach, afterEach, beforeEachProviders, inject} from "@angular/core/testing"; 
import {ReflectiveInjector, provide} from "@angular/core"; 
import {HTTP_PROVIDERS} from "@angular/http"; 
import {Router, ROUTER_PROVIDERS} from "@angular/router"; 
import {ROUTER_FAKE_PROVIDERS} from "@angular/router/testing"; 
import {Location} from "@angular/common"; 
import {SpyLocation} from "@angular/common/testing/location_mock"; 
import {Observable} from "rxjs/Observable"; 
import {MyComp} from "./MyComp"; 

describe("MyComp",() => { 

    let injector: ReflectiveInjector, 
     myComp: MyComp, 
     router: Router; 

    beforeEach(() => { 

    injector = ReflectiveInjector.resolveAndCreate([   
     HTTP_PROVIDERS, 
     ROUTER_FAKE_PROVIDERS,   
     provide(Location, {useClass: SpyLocation}) 

    ]); 

    router = injector.get(Router); 
    myComp = new MyComp(router); 


    });  

    afterEach(() => { 
    injector = null;  
    myComp = null; 
    router = null; 
    }); 

    it("should be defined",() => { 

    expect(myComp).toBeDefined(); 

    }); 



}); 

risposta

10

È necessario creare un oggetto di gelsomino spia per il router. AppComponent ha un costruttore che accetta un router.

import { AppComponent } from './app.component'; 
import {Router, ROUTER_PROVIDERS} from "@angular/router"; 

describe('app component',() => { 
    let component: AppComponent; 
    let router: Router; 
    beforeAll(() => { 
     router = jasmine.createSpyObj("Router", ['navigate']); 
     component = new AppComponent(router); 
    }); 
    it("should be defined",() => { 
     expect(component).toBeDefined(); 
    }); 
}); 
+0

Ci sono momenti in cui la risposta è così semplice che non puoi vederla. ** (facepalm) **. È fantastico! Soluzione semplice ma efficace! Grazie! – hartpdx

+0

Bella soluzione, grazie! –

1

Alcune modifiche ... questo soluzione semplice funziona per me:

import {MyComp} from "./MyComp"; 
import {RootRouter} from 'angular2/src/router/router'; 
import {provide} from 'angular2/core'; 
import {Router} from 'angular2/router'; 

describe("MyComp",() => { 
    let myComp: MyComp, 
    router; 

beforeEach(() => { 
    provide(Router, {useClass: RootRouter}) 
    myComp = new MyComp(router); 
}) 

it("should be defined",() => { 
    expect(myComp).toBeDefined(); 
    }); 
}); 
+3

Per i ** ** beta versioni di angular2, questo avrebbe funzionato bene. Sto usando il ** RC.1 ** versione in cui l'oggetto RootRouter non esiste più (o se lo fa, non ho idea di dove si trova). – hartpdx

0

Beh, ho trovato una soluzione. Non è l'ideale, ma funziona. Fondamentalmente, sto creando una classe MockRouter che implementa i metodi che mi servono.

MockRouter:

export class MockRouter { 

    public navigate() { 
     console.log(“Mock router was called.”); 
    } 

} 

Ora, nel mio caso di test, tutto quello che devo fare è fornire l'implementazione mock per il router:

provide(Router, {useClass: MockRouter})

Sarebbe davvero bello se i documenti NG2 mostrassero come si può iniettare correttamente Router nei casi di test Jasmine. Prendere in giro i propri oggetti sembra che dovrebbe essere un passaggio inutile.

(FYI, ho provato ad utilizzare il ROUTER_FAKE_PROVIDERS e ancora ottenuto l'errore ComponentResolver sopra)

0

Ecco una soluzione alternativa, che è un po 'più prolisso ma ci permette di utilizzare SpyLocation al fine di verificare i cambiamenti di rotta. Per prima cosa creiamo provider di router di prova generici.

router-test-providers.ts

import { ComponentResolver } from '@angular/core'; 
import { Type } from '@angular/core/src/facade/lang'; 
import { SpyLocation } from '@angular/common/testing'; 
import { Location } from '@angular/common'; 
import { Router, RouterOutletMap } from '@angular/router'; 
import { RouteSegment } from '@angular/router/src/segments'; 
import { RouterUrlSerializer, DefaultRouterUrlSerializer } from '@angular/router/src/router_url_serializer'; 
/** 
* this class provides the means of loading the tested component type 
*/ 
export class FakeRootComponentLoader { 
    constructor(private rootComponentType: Type) { 
     this.rootComponentType = rootComponentType; 
    } 
    public getRootComponentType =() => { 
     return this.rootComponentType; 
    } 
} 

let routerFactory = function (
     fakeRootComponentLoader: FakeRootComponentLoader, 
     componentResolver: ComponentResolver, 
     urlSerializer: RouterUrlSerializer, 
     routerOutletMap: RouterOutletMap, 
     location: Location): Router 
{ 
    let fakeRootComponentType = fakeRootComponentLoader.getRootComponentType(); 
    /** 
    * _rootComponent should not be null, but it is what in angular2 rc.1 code 
    * so we replicate the behaviour 
    */ 
    return new Router(
     null, 
     fakeRootComponentType, 
     componentResolver, 
     urlSerializer, 
     routerOutletMap, 
     location); 
}; 

export const ROUTER_TEST_PROVIDERS: any[] = [ 
    {provide: RouterUrlSerializer, useClass: DefaultRouterUrlSerializer}, 
    RouterOutletMap, 
    {provide: Location, useClass: SpyLocation}, 
    {provide: RouteSegment, useFactory: (r) => r.routeTree.root, deps: [Router]}, 
    { 
    provide: Router, 
    useFactory: routerFactory, 
    deps: [FakeRootComponentLoader, ComponentResolver, RouterUrlSerializer, RouterOutletMap, Location] 
    } 
]; 

Il test gelsomino corrispondente è fornita di seguito.

navigation.spec.ts

import { Component } from '@angular/core'; 
import { beforeEach, beforeEachProviders, inject } from '@angular/core/testing'; 
import { ROUTER_DIRECTIVES, Route, Routes, Router } from '@angular/router'; 
import { TestComponentBuilder } from '@angular/compiler/testing'; 
import { Location } from '@angular/common'; 
import { ROUTER_TEST_PROVIDERS, FakeRootComponentLoader } from './router-test-providers'; 
/** 
* We inject router into the EmptyComponent, 
* Due to the way DI works in angular2, if we import the ROUTER_TEST_PROVIDERS, 
* and inject the Router, we will get our own implementation of the Router injected. 
*/ 
@Component({selector: 'empty-component', template: `empty`}) 
@Component({ 
    selector: 'empty-component', 
    template: `empty`, 
    directives: [ROUTER_DIRECTIVES] 
}) 
class EmptyComponent { 
    constructor (private router: Router){ } 
    public getRouter() {return this.router;} 
} 

@Component({ 
    selector: 'root-component', 
    template: `<router-outlet></router-outlet>`, 
    directives: [ROUTER_DIRECTIVES] 
}) 
@Routes([new Route({path: '/login', component: EmptyComponent})]) 
class RootComponent { } 
describe('navigation',() => { 
    beforeEachProviders(() => [ 
     { 
      provide: FakeRootComponentLoader, 
      useFactory:() => new FakeRootComponentLoader(RootComponent) 
     }, 
     ROUTER_TEST_PROVIDERS, 
     EmptyComponent 
    ]); 


    let location: Location; 
    let testCb: TestComponentBuilder; 
    let emptyComp: EmptyComponent; 
    beforeEach(inject([Location, TestComponentBuilder, EmptyComponent], (loc, tcb, emptyCt) => { 
     location = loc; 
     testCb = tcb; 
     emptyComp = emptyCt; 

    })); 

    it('should be defined',() => { 
     expect(EmptyComponent).toBeDefined(); 
    }); 

    it('Should navigate to login', (done) => { 
     expect(location.path()).toEqual(''); 
     testCb.createAsync(RootComponent).then(fixture => { 
      emptyComp.getRouter().navigate(['login']).then(() => { 
       fixture.detectChanges(); 
       expect(location.path()).toBe('/login'); 
       done(); 
      }).catch(e => done.fail(e)); 
     }); 
    }); 
}); 
2

Utilizzando anonima ES 6 classe e jasmine:

beforeEach(() => addProviders([ 
{ 
    provide: Router, 
    useClass: class { navigate = jasmine.createSpy("navigate"); } 
}])); 
+0

GRAZIE! questo ha funzionato per me, dopo aver provato un centinaio di esempi diversi – ganjan