2016-11-22 37 views
13

我創造我的導航欄組件單元測試,我得到一個錯誤:角2茉莉不能綁定到「routerLink」,因爲它不是一個已知的財產「一」

Can't bind to 'routerLink' since it isn't a known property of 'a'

導航欄組件TS

import { Component } from '@angular/core'; 
import { Router } from '@angular/router'; 
import { NavActiveService } from '../../../services/navactive.service'; 
import { GlobalEventsManager } from '../../../services/GlobalEventsManager'; 

@Component({ 
    moduleId: module.id, 
    selector: 'my-navbar', 
    templateUrl: 'navbar.component.html', 
    styleUrls:['navbar.component.css'], 
    providers: [NavActiveService] 
}) 
export class NavComponent { 
    showNavBar: boolean = true; 

    constructor(private router: Router, 
       private navactiveservice:NavActiveService, 
       private globalEventsManager: GlobalEventsManager){ 

    this.globalEventsManager.showNavBar.subscribe((mode:boolean)=>{ 
     this.showNavBar = mode; 
    }); 

    } 

} 

導航欄組件規格

import { ComponentFixture, TestBed, async } from '@angular/core/testing';  
import { NavComponent } from './navbar.component'; 
import { DebugElement } from '@angular/core'; 
import { By }    from '@angular/platform-browser'; 
import { Router } from '@angular/router'; 

export function main() { 
    describe('Navbar component',() => { 

     let de: DebugElement; 
     let comp: NavComponent; 
     let fixture: ComponentFixture<NavComponent>; 
     let router: Router; 

     // preparing module for testing 
     beforeEach(async(() => { 
      TestBed.configureTestingModule({ 
       declarations: [NavComponent], 
      }).compileComponents().then(() => { 

       fixture = TestBed.createComponent(NavComponent); 
       comp = fixture.componentInstance; 
       de = fixture.debugElement.query(By.css('p')); 

      }); 
     })); 


     it('should create component',() => expect(comp).toBeDefined()); 


/*  it('should have expected <p> text',() => { 
      fixture.detectChanges(); 
      const h1 = de.nativeElement; 
      expect(h1.innerText).toMatch(" "); 
     });*/ 


    }); 
} 

我意識到我需要添加路由器作爲間諜,但如果我將它添加爲SpyObj並將其聲明爲提供程序,我會得到相同的錯誤。

有沒有更好的方法讓我補充解決這個錯誤?

編輯:工作單位測試

建立了基於回答這個單元測試:

import { ComponentFixture, TestBed, async } from '@angular/core/testing'; 
import { NavComponent } from './navbar.component'; 
import { DebugElement } from '@angular/core'; 
import { By }    from '@angular/platform-browser'; 
import { RouterLinkStubDirective, RouterOutletStubComponent } from '../../../../test/router-stubs'; 
import { Router } from '@angular/router'; 
import { GlobalEventsManager } from '../../../services/GlobalEventsManager'; 
import { RouterModule } from '@angular/router'; 
import { SharedModule } from '../shared.module'; 


export function main() { 
    let comp: NavComponent; 
    let fixture: ComponentFixture<NavComponent>; 
    let mockRouter:any; 
    class MockRouter { 
     //noinspection TypeScriptUnresolvedFunction 
     navigate = jasmine.createSpy('navigate'); 
    } 

    describe('Navbar Componenet',() => { 

     beforeEach(async(() => { 
      mockRouter = new MockRouter(); 
      TestBed.configureTestingModule({ 
       imports: [ SharedModule ] 
      }) 

      // Get rid of app's Router configuration otherwise many failures. 
      // Doing so removes Router declarations; add the Router stubs 
       .overrideModule(SharedModule, { 
        remove: { 
         imports: [ RouterModule ], 

        }, 
        add: { 
         declarations: [ RouterLinkStubDirective, RouterOutletStubComponent ], 
         providers: [ { provide: Router, useValue: mockRouter }, GlobalEventsManager ], 
        } 
       }) 

       .compileComponents() 

       .then(() => { 
        fixture = TestBed.createComponent(NavComponent); 
        comp = fixture.componentInstance; 
       }); 
     })); 

     tests(); 
    }); 


     function tests() { 
      let links: RouterLinkStubDirective[]; 
      let linkDes: DebugElement[]; 

      beforeEach(() => { 
       // trigger initial data binding 
       fixture.detectChanges(); 

       // find DebugElements with an attached RouterLinkStubDirective 
       linkDes = fixture.debugElement 
        .queryAll(By.directive(RouterLinkStubDirective)); 

       // get the attached link directive instances using the DebugElement injectors 
       links = linkDes 
        .map(de => de.injector.get(RouterLinkStubDirective) as RouterLinkStubDirective); 
      }); 

      it('can instantiate it',() => { 
       expect(comp).not.toBeNull(); 
      }); 

      it('can get RouterLinks from template',() => { 
       expect(links.length).toBe(5, 'should have 5 links'); 
       expect(links[0].linkParams).toBe('/', '1st link should go to Home'); 
       expect(links[1].linkParams).toBe('/', '2nd link should go to Home'); 
expect(links[2].linkParams).toBe('/upload', '3rd link should go to Upload'); 
       expect(links[3].linkParams).toBe('/about', '4th link should to to About'); 
       expect(links[4].linkParams).toBe('/login', '5th link should go to Logout'); 
      }); 

      it('can click Home link in template',() => { 
       const uploadLinkDe = linkDes[1]; 
       const uploadLink = links[1]; 

       expect(uploadLink.navigatedTo).toBeNull('link should not have navigated yet'); 

       uploadLinkDe.triggerEventHandler('click', null); 
       fixture.detectChanges(); 

       expect(uploadLink.navigatedTo).toBe('/'); 
      }); 


      it('can click upload link in template',() => { 
       const uploadLinkDe = linkDes[2]; 
       const uploadLink = links[2]; 

       expect(uploadLink.navigatedTo).toBeNull('link should not have navigated yet'); 

       uploadLinkDe.triggerEventHandler('click', null); 
       fixture.detectChanges(); 

       expect(uploadLink.navigatedTo).toBe('/upload'); 
      }); 

      it('can click about link in template',() => { 
       const uploadLinkDe = linkDes[3]; 
       const uploadLink = links[3]; 

       expect(uploadLink.navigatedTo).toBeNull('link should not have navigated yet'); 

       uploadLinkDe.triggerEventHandler('click', null); 
       fixture.detectChanges(); 

       expect(uploadLink.navigatedTo).toBe('/about'); 
      }); 

      it('can click logout link in template',() => { 
       const uploadLinkDe = linkDes[4]; 
       const uploadLink = links[4]; 

       expect(uploadLink.navigatedTo).toBeNull('link should not have navigated yet'); 

       uploadLinkDe.triggerEventHandler('click', null); 
       fixture.detectChanges(); 

       expect(uploadLink.navigatedTo).toBe('/login'); 
      }); 
     } 
} 
+0

您正在使用哪個Angular版本?因爲在Angular 2最終發佈的版本 –

+0

中,「提供者」選項不存在於組件元數據中,我使用的是2.1.0。你的意思是提供不再是單元測試的選項嗎?我相信你仍然在模塊中使用提供者。我使用角種子,他們仍然在這個例子中:https://github.com/mgechev/angular-seed/blob/master/src/client/app/home/home.module.ts – Bhetzie

+0

我是談論你的NavComponent的提供者選項 –

回答

14

ng2 Testing docs地址本使用RouterLinkStubDirective和RouterOutletStubComponent使routerLink 的已知屬性< a>。基本上它說使用RouterOutletStubComponent是一種安全的方式來測試routerLinks,沒有使用真正的RouterOutlet的所有複雜和錯誤。你的項目需要知道它存在,所以它不會拋出錯誤,但在這種情況下它不需要實際做任何事情。通過RouterLinkStubDirective,您可以點擊< a>鏈接到routerLink指令,並獲取足夠的信息來測試它正在被點擊(導航到)並轉到正確的路線(linkParams)。除此之外,還有更多的功能,而且你實際上不再孤立地測試你的組件。

在app/app.component.spec.ts中查看他們的demo。抓住testing/router-stubs.ts並添加到您的項目中。然後你會將2個殘留物品注入你的TestBed聲明中。

+0

謝謝你,我很欣賞在你的回答中提到的文檔 – Bhetzie

+0

增加了我的工作單元測試,希望能幫助別人如果他們掙扎。再次感謝! – Bhetzie

+0

我不明白爲什麼這些存根不會出現在/ master – FlavorScape

相關問題