Angular 2 Jasmine无法绑定到'routerLink',因为它不是'a'的已知属性 [英] Angular 2 Jasmine Can't bind to 'routerLink' since it isn't a known property of 'a'

查看:300
本文介绍了Angular 2 Jasmine无法绑定到'routerLink',因为它不是'a'的已知属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为我的Navbar组件创建一个单元测试,但是我收到错误:

I'm creating a unit test for my Navbar Component and I'm getting an error:


无法绑定到' routerLink'因为它不是'a'的已知属性

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

Navbar Component 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;
    });

  }

}

Navbar组件规范

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并将其声明为提供程序,我得到相同的错误。

I realize that I need to add router as a spy, but if I add it as a SpyObj and declare it as a provider I get the same error.

我是否有更好的方法来添加修复此错误?

Is there a better way for me to add fix this error?

编辑:工作单位测试

根据答案构建此单元测试:

Built this unit test based on the answer:

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');
            });
        }
}


推荐答案

ng2 Testing docs 通过使用RouterLinkStubDirective和RouterOutletStubComponent来解决这个问题,以便routerLink <<<<一>。基本上它说使用RouterOutletStubComponent是一种测试routerLinks的安全方法,没有使用真正的RouterOutlet的所有复杂性和错误。您的项目需要知道它存在,因此它不会抛出错误,但在这种情况下它不需要实际执行任何操作。 RouterLinkStubDirective使您可以单击< a>与routerLink指令链接并获得足够的信息来测试它是否被点击(navigatedTo)并转到正确的路由(linkParams)。除此之外的任何功能,你真的不再孤立地测试你的组件了。

The ng2 Testing docs address this by using RouterLinkStubDirective and RouterOutletStubComponent so that routerLink is a known property of < a>. Basically it says that using RouterOutletStubComponent is a safe way to test routerLinks without all the complications and errors of using the real RouterOutlet. Your project needs to know it exists so it doesn't throw errors but it doesn't need to actually do anything in this case. The RouterLinkStubDirective enables you to click on < a> links with routerLink directive and get just enough information to test that it is being clicked (navigatedTo) and going to the correct route (linkParams). Any more functionality than that and you really aren't testing your component in isolation any more.

看看他们的 demo 。抓住测试/ router-stubs.ts并添加到您的项目中。然后,您将2个存根项注入TestBed声明。

Take a look at their demo in app/app.component.spec.ts. Grab the testing/router-stubs.ts and add to your project. Then you will inject the 2 stubbed items into your TestBed declarations.

这篇关于Angular 2 Jasmine无法绑定到'routerLink',因为它不是'a'的已知属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆