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

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

问题描述

我正在为我的导航栏组件创建单元测试,但出现错误:

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'

导航栏组件 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 并将其声明为提供者,则会出现相同的错误.

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

推荐答案

Angular测试文档通过使用RouterLinkDirectiveStubRouterOutletStubComponent 解决了这个问题,这样routerLink 的一个已知属性代码>.

The Angular Testing docs address this by using RouterLinkDirectiveStub and RouterOutletStubComponent so that routerLink is a known property of <a>.

基本上它说使用RouterOutletStubComponent 是一种安全的测试routerLinks 的方法,没有使用真正的RouterOutlet 的所有复杂性和错误.您的项目需要知道它存在,所以它不会抛出错误,但在这种情况下它实际上不需要做任何事情.

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.

RouterLinkDirectiveStub 使您可以点击带有 routerLink 指令的 链接,并获得足够的信息来测试它正在单击 (navigatedTo) 并转到正确的路线 (linkParams).任何比这更多的功能,您就真的不再孤立地测试您的组件了.

The RouterLinkDirectiveStub 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.

测试演示>app/app.component.spec.ts.获取 testing/router-link-directive-stub.ts 并添加到您的项目中.然后,您将把 2 个存根项目注入到您的 TestBed 声明中.

Take a look at their Tests Demo in app/app.component.spec.ts. Grab the testing/router-link-directive-stub.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天全站免登陆