Angular 单元测试:'mat-nav-list' 不是已知元素

Angular Unit Tests : 'mat-nav-list' is not a known element

我目前正在处理遗留 Angular 5 代码,在使用 Angular CLI 生成组件时,除了默认单元测试外没有任何单元测试。

该项目正在使用 Angular Material 5 RC0,单元测试似乎没有考虑我的模块的依赖性。

app.module.ts :

@NgModule({
  declarations: [
    AppComponent,
    /* My module components... */
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    ReactiveFormsModule,
    BrowserAnimationsModule,
    routing,
    DialogsModule,
    SharedModule ,
    MaterialModule,
    MatListModule, // It's the module that should be needed
    MatSidenavModule,
    ToastrModule.forRoot({
      timeOut: 5000,
      positionClass: 'toast-bottom-right',
      preventDuplicates: true
    }),
    HttpClientModule,
    TableFactoryModule
  ],
  providers: [
    /* My module services */,
    AuthGuard
  ],
  bootstrap: [AppComponent]

})
export class AppModule {

}

app.component.ts:

import { Component, Input, ViewChild } from '@angular/core';
import { Router, RouterModule, ActivatedRoute } from '@angular/router';
import { HttpErrorResponse } from '@angular/common/http';
import { JwtHelperService } from '@auth0/angular-jwt';
import * as _ from 'lodash';

import { Subscription } from 'rxjs/Subscription';
import { ToastrService } from 'ngx-toastr';

import { UsersService } from 'app/services/users.service';
import { ComplexesService } from 'app/services/complexes.service';
import { ActivatedUserService } from 'app/shared/activateduser.service';
import { ActivatedComplexesService } from 'app/shared/activatedcomplexes.service';

import { User } from 'app/user';
import { Complex } from './complex/complex'
import { MatSidenav } from '@angular/material';
import { MatList } from '@angular/material/list'


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app works!';
  isConnected = false;
  private subscription;
  private currentUser: User;
  userSubscription: Subscription;
  complexesSubscription: Subscription;
  @ViewChild(MatSidenav) sidenav: MatSidenav;

  constructor(
    private usersService: UsersService,
    private complexesService: ComplexesService,
    private router: Router,
    private toastr: ToastrService,
    private activatedUser: ActivatedUserService,
    private activatedComplexes: ActivatedComplexesService,
  ){
  }
  ngOnInit() {
    let getToken = this.usersService.isConnected();
    if (getToken) {
      this.getComplexes();
      this.userGetById();      
    }
    else
      this.router.navigate(['']);

    this.userSubscription = this.activatedUser.activatedUser$
    .subscribe(user => {
      if(user) {
        this.currentUser = user;
        this.sidenav.open();
      }
    });
  }
  logout(){
    this.usersService.logout();
    this.isConnected = this.usersService.isConnected();
    this.router.navigate(['']);
  }
  ngOnDestroy() {
    this.userSubscription.unsubscribe();
    this.complexesSubscription.unsubscribe();    
  }

  private userGetById(){
    let token = JSON.parse(localStorage.getItem('futbakCurrentUser'));
    let jwtHelperService: JwtHelperService = new JwtHelperService({});
    let currentUser = jwtHelperService.decodeToken(token);
    this.usersService.getByID(currentUser.id).subscribe(
      (res) => {
        this.currentUser = res
      }, (err: HttpErrorResponse) => {
        if (err.error instanceof Error) {
          // A client-side or network error occurred. Handle it accordingly.
          this.toastr.error("Une erreur est survenue : "+err.error.message  , '', { closeButton: true });
        } else {
          this.toastr.error("Une erreur est survenue code : "+ err.status+", message : "+err.statusText, '', { closeButton: true });
        }
      },
      () => {
        if(this.currentUser.role == 'superadmin' || this.currentUser.role == 'complexmanager') {
          this.activatedUser._activatedUser$.next(this.currentUser)
        }
        if(this.currentUser.role == 'superadmin') {
          this.router.navigate(['usersList']);
          this.getComplexes();
        } else if (this.currentUser.role == 'complexmanager') {
          this.router.navigate(['admins/'+this.currentUser._id])
        } else {
          this.toastr.error("Vous n'avez pas les droits pour accèder à l'application.",'',{closeButton :true});
        }
      });
  }

  private getComplexes(){
   return this.complexesService.get()
    .subscribe(
      res => {
        if(res)
          this.activatedComplexes._activatedComplexes$.next(res)
    }, (err: HttpErrorResponse) => {
        if (err.error instanceof Error) {
          this.toastr.error("Une erreur est survenue : "+err.error.message  , '', { closeButton: true });
        } else {
          this.toastr.error("Une erreur est survenue code : "+ err.status+", message : "+err.statusText, '', { closeButton: true });       
        }
      },
      () => {
      });
  }

 }

失败的测试:

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

app.component.html :

<mat-sidenav-container fullscreen >

  <mat-sidenav #sidenav mode="side" disableClose>
    <!-- sidenav content -->

    <div><img src="./assets/logo.png" class="logo" ></div>
    <div class="title-app">
      <h2>Admin</h2>
    </div>

    <mat-nav-list>
      <a mat-list-item routerLinkActive="active" routerLink="['usersList']">
        <!-- <mat-icon fontSet="fa" fontIcon="fa-users" ></mat-icon> -->
        <i class="fa fa-users fa-fw fa-lg"></i> Joueurs
      </a>
      <a mat-list-item routerLink="['adminsList']">
        <i class="fa fa-user fa-fw fa-lg"></i> Admins
      </a>
      <a mat-list-item routerLinkActive="active" routerLink="['gamesList']">
          <i class="fa fa-futbol-o fa-fw fa-lg"></i> Matchs
      </a>
      <a mat-list-item routerLinkActive="active"  routerLink="['playgroundsList']">
        <i class="fa fa-cubes fa-fw fa-lg"></i> Terrains
      </a>
      <a mat-list-item routerLinkActive="active" routerLink="['complexesList']">
        <i class="fa fa-cube fa-fw fa-lg"></i> Complexes
      </a>
      <a mat-list-item routerLinkActive="active" routerLink="['devicesList']">
        <i class="fa fa fa-share-alt fa-fw fa-lg"></i> Capteurs
      </a>
      <a mat-list-item routerLinkActive="active" routerLink="['experimental', 'playgrounds']">
        <i class="fa fa fa-share-alt fa-fw fa-lg"></i> Business
      </a>
      <a mat-list-item routerLinkActive="active" routerLink="['experimental', 'devices']">
        <i class="fa fa fa-share-alt fa-fw fa-lg"></i> Technique
      </a>
    </mat-nav-list>
    <mat-nav-list class="account">
        <button mat-button (click)="logout()"><i class="fa fa-sign-out"></i> Déconnexion</button>
    </mat-nav-list>

  </mat-sidenav>
  <div class="main mat-typography">
    <!-- primary content -->
    <router-outlet ></router-outlet>
  </div>
</mat-sidenav-container>

最后,错误:

Failed: Template parse errors:
'mat-nav-list' is not a known element:
1. If 'mat-nav-list' is an Angular component, then verify that it is part of this module.
2. If 'mat-nav-list' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message. ("
    </div>

    [ERROR ->]<mat-nav-list>
      <a mat-list-item routerLinkActive="active" routerLink="['usersList']">
       "): ng:///DynamicTestModule/AppComponent.html@10:4

因此,如您所见,我已经尝试过这些解决方案:

等等。

我只在单元测试时遇到这个问题,网站 运行 正常。

测试需要您手动导入模块。例如,它允许在需要时加载 "mockup services" 而不是真实的

您将在同一文档页面上找到相应的文档 here 和相关主题。

因此,您必须 re-import 测试文件中的所需模块(在您的 describe 项目中),例如:

beforeEach(async(() => {
  TestBed.configureTestingModule({
    declarations: [ /* Your component */ ],
    imports: [
      /* Here, import your Angular material modules */
    ],
    providers: [
      /* Here, use custom or usual providers for your injected services */
    ]
  })
  .compileComponents();
}));