7

This has been asked before and I did all the suggested comments but none seem to work. I am having a combo of an issue. Getting wallaby.js to work with my project and figure out the error when I run ng test.

Can't bind to 'routerLink' since it isn't a known property of 'a'. ("<header id="header">                                                                                         <h1 id="logo">                                                                                                                                                                    <a [ERROR ->][routerLink]="['/home']"></a>                                                                                                        
                </h1>
        "): AppComponent@2:5
        Can't bind to 'routerLink' since it isn't a known property of 'a'. ("
                <div id="menu">
                        <a [ERROR ->][routerLink]="['/home']" class="btn">Home</a>
                        <a [routerLink]="['/about']" class="btn">About</a>
                        "): AppComponent@6:5
        Can't bind to 'routerLink' since it isn't a known property of 'a'. ("
                <div id="menu">
                        <a [routerLink]="['/home']" class="btn">Home</a>
                        <a [ERROR ->][routerLink]="['/about']" class="btn">About</a>
                        <a [routerLink]="['/experiments']" class="btn">Expe"): AppComponent@7:5
        Can't bind to 'routerLink' since it isn't a known property of 'a'. ("terLink]="['/home']" class="btn">Home</a>
                        <a [routerLink]="['/about']" class="btn">About</a>
                        <a [ERROR ->][routerLink]="['/experiments']" class="btn">Experiments</a>
                </div>
        "): AppComponent@8:5
        'router-outlet' is not a known element:
        1. If 'router-outlet' is an Angular component, then verify that it is part of this module.
        2. If 'router-outlet' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. ("
        <div id="container">
                [ERROR ->]<router-outlet></router-outlet>
        </div>
        "): AppComponent@18:1

My NgModule

import {BrowserModule} from "@angular/platform-browser";
import {NgModule,CUSTOM_ELEMENTS_SCHEMA} from "@angular/core";
import {FormsModule} from "@angular/forms";
import {HttpModule} from "@angular/http";
import {RouterModule} from "@angular/router";
import {HomeComponent} from "./home/home.component";
import {ExperimentsComponent} from "./experiments/experiments.component";
import {AboutComponent} from "./about/about.component";
import {AppComponent} from "./app.component";
import {ExperimentsService} from "./common/experiments.service";
import {StateService} from "./common/state.service";
import {ExperimentDetailComponent} from "./experiments/experiment-details/experiment.detail.component";

@NgModule({
    declarations: [
        AppComponent,
        AboutComponent,
        HomeComponent,
        ExperimentsComponent,
        ExperimentDetailComponent
    ],
    imports: [
        BrowserModule,
        FormsModule,
        HttpModule,
        RouterModule.forRoot([
            {path: '', redirectTo: '/home', pathMatch: 'full'},
            {path: 'home', component: HomeComponent},
            {path: 'about', component: AboutComponent},
            {path: 'experiments', component: ExperimentsComponent},
            {path: '**', component: HomeComponent}
        ])
    ],
    schemas: [
      CUSTOM_ELEMENTS_SCHEMA
    ],
    providers: [
        ExperimentsService,
        StateService
    ],
    bootstrap: [AppComponent]
})
export class AppModule {
}

This is the only module. It is a simple application:

enter image description here

enter image description here

I have also posted the project on GitHub HERE

--------------------- Answer and the explanation is below------------

import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
import {RouterTestingModule} from "@angular/router/testing";
import {HomeComponent} from "./home/home.component";
import {AboutComponent} from "./about/about.component";
import {ExperimentsComponent} from "./experiments/experiments.component";

describe('AppComponent', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        RouterTestingModule.withRoutes([
          {path: '', redirectTo: '/home', pathMatch: 'full'},
          {path: 'home', component: HomeComponent},
          {path: 'about', component: AboutComponent},
          {path: 'experiments', component: ExperimentsComponent},
          {path: '**', component: HomeComponent}
        ])
      ],
      declarations: [
        AppComponent
      ],
    });
    TestBed.compileComponents();
  });

  it('should create the app', async(() => {
    let fixture = TestBed.createComponent(AppComponent);
    let app = fixture.debugElement.componentInstance;
    expect(app).toBeTruthy();
  }));
});

However now I am getting Failed: Component HomeComponent is not part of any NgModule or the module has not been imported into your module. Error: Component HomeComponent is not part of any NgModule or the module has not been imported into your module.

But HomeCompenent is clearly in my @NgModule

Mike3355
  • 11,305
  • 24
  • 96
  • 184

3 Answers3

8

This is your app.component.spec.ts

You should also add routerModule there

beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [
        AppComponent
      ],
      imports:[RouterModule.forRoot([])] //add the router module here as well
    });
    TestBed.compileComponents();
  });

When you're testing your AppComponent , like I said , you should give the test bed what ever you've given to your root @NgModule , so :

 beforeEach( () => {
    TestBed.configureTestingModule( {
        imports : [
            BrowserModule,
            FormsModule,
            HttpModule,
            RouterTestingModule.withRoutes( [
                { path : '', redirectTo : '/home', pathMatch : 'full' },
                { path : 'home', component : HomeComponent },
                { path : 'about', component : AboutComponent },
                { path : 'experiments', component : ExperimentsComponent },
                { path : '**', component : HomeComponent }
            ] )
        ],
        declarations : [
            AppComponent,
            AboutComponent,
            HomeComponent,
            ExperimentsComponent,
            ExperimentDetailComponent
        ],

        schemas : [
            CUSTOM_ELEMENTS_SCHEMA
        ],
        providers : [
            ExperimentsService,
            StateService
        ]
    } );
    TestBed.compileComponents();
} );
Milad
  • 27,506
  • 11
  • 76
  • 85
  • Please see my update. This seemed to as well take care of routerLink error but now it is saying my `HomeComponent` is not in my `@NgModule` when it clearly is. – Mike3355 Dec 31 '16 at 17:21
  • @Drew1208 , dude , if you're going to test app.component , you should define everything you've defined in you NgModule – Milad Dec 31 '16 at 17:38
  • Why would you wan't to test your AppComponent anyway, that's really time consuming , you should do unit testing, testing the whole app is more like end to end testing – Milad Dec 31 '16 at 17:43
  • You are absolutely right. This is e2e what I am trying to do. I am still getting familiar with testing Angular 2 testing. – Mike3355 Dec 31 '16 at 19:31
8

When you use the TestBed you are configuring a module from scratch. In your current configuration, all you have is

TestBed.configureTestingModule({
  declarations: [
    AppComponent
  ],
});

So all that's included in the module for the test environment is the AppComponent. Nothing from the AppModule is included.

So you're getting the error because you are missing all the router directives that are included in the RouterModule. You could import the RouterModule, but for tests, you should instead use the RouterTestingModule

import { RouterTestingModule } from '@angular/core/testing'

TestBed.configureTestingModule({
  imports: [
    RouterTestingModule.withRoutes([])
  ],
  declarations: [
    AppComponent
  ],
});

You can add routes to the withRoutes.

See Also:

Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • Please my updated post. I think you are right one point, thank you. – Mike3355 Dec 31 '16 at 17:13
  • Please read the very first sentence of my post. That means you need add anything required for testing just like you would in a normal module – Paul Samsotha Dec 31 '16 at 17:17
  • Basically, if you added your routes to the RouterTestingModule, then you need to declare the corresponding components that go with those routes – Paul Samsotha Dec 31 '16 at 17:25
  • For testing though you probably don't want to add the real component. Just use mock components. See the example link – Paul Samsotha Dec 31 '16 at 17:29
0

I had this issue too, and I was using a self-created mock router.

All examples of using/importing the routing, router, RouterTestingModule.withRoutes([]) etc just gave me more errors.

The solution for me was too create a mock for the routerLink directive (I'm not sure where the implementation is found when you don't mock the router but use the RouterTestingModule, probably in the RouterTestingModule itself?)

So in hindsight I could have created the mock myself, but as they say "The real RouterLinkDirective is quite complicated and entangled with other components and directives of the RouterModule. It requires challenging setup to mock and use in tests."

I found the implementation for it at the Angular documentation page here: https://angular.io/guide/testing-components-scenarios#routerlink

As links can go away, I post the code here:

@Directive({
  selector: '[routerLink]'
})
export class RouterLinkDirectiveStub {
  @Input('routerLink') linkParams: any;
  navigatedTo: any = null;

  @HostListener('click')
  onClick() {
    this.navigatedTo = this.linkParams;
  }
}
Michel
  • 23,085
  • 46
  • 152
  • 242