Угловые юнит-тесты: «mat-nav-list» не является известным элементом - PullRequest
0 голосов
/ 15 мая 2019

В настоящее время я работаю над устаревшим кодом 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

Итак, как вы видели, я уже пробовал такое решение:

и т. д..

Эта проблема возникает только при модульном тестировании, веб-сайт работает нормально.

1 Ответ

2 голосов
/ 15 мая 2019

Тестирование требует, чтобы вы импортировали модули вручную.Это позволяет, например, загружать «макетные сервисы» вместо реальных, когда они вам нужны.

Вы найдете соответствующий документ здесь и связанные темы на той же странице документа.

Таким образом, вам придется повторно импортировать необходимые модули в тестовом файле (внутри элемента 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();
}));
...