web-dev-qa-db-fra.com

Comment faire fonctionner les composants matériels avec Karma dans les tests unitaires Angular

J'ai un angular CLI configuré. J'ai créé un formulaire qui utilise angular composants matériels, comme <md-card>.

Je commence juste par écrire mon premier test unitaire Karma/Jasmine, en suivant les étapes de la documentation angulaire .

Voici mon modèle de composant:

<md-card [ngClass]="'dialog-card'">
<md-card-title [ngClass]="'dialog-title'">
    {{title}}
</md-card-title>
<md-card-content>

    <form (ngSubmit)="login()" #loginForm="ngForm">

        <md-input-container class="md-block">
            <input md-input [(ngModel)]="user.email" 
                name="userEmail" type="email" placeholder="Email" 
                ngControl="userEmail" 
            required>
        </md-input-container>
        <br>

        <md-input-container class="md-block">
            <input md-input [(ngModel)]="user.password" 
                name="userPassword" type="password" placeholder="Password" 
                ngControl="userPassword" 
            required>
        </md-input-container>
        <br>

        <tm-message msgText="Wrong username or password" *ngIf="showError"></tm-message>
        <br>


        <button md-button type="submit" [disabled]="!loginForm.form.valid">Login</button>

        <p (click)="openForgotPasswordModal()">Forgot Password?</p>

    </form>

</md-card-content>

Voici ma spécification de karma:

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By }              from '@angular/platform-browser';
import { DebugElement }    from '@angular/core';
import { MaterialModule, MdDialogRef, MdDialog  } from '@angular/material';
import { FormsModule } from '@angular/forms';
import { RouterTestingModule } from '@angular/router/testing';

import { TmLoginComponent } from './tm-login.component';
import { TmMessageComponent } from '../../shared/components/tm-message.component';
import { UserAuthenticationService } from '../login/user-authentication.service';

describe('TmLoginComponent (inline template)', () => {

let comp: TmLoginComponent;
let fixture: ComponentFixture < TmLoginComponent > ;
let de: DebugElement;
let el: HTMLElement;

beforeEach(() => {
    TestBed.configureTestingModule({
        declarations: [TmLoginComponent, TmMessageComponent], // declare the test component
        imports: [MaterialModule, FormsModule,
            RouterTestingModule.withRoutes(
                [{
                    path: 'login',
                    component: TmLoginComponent
                }, ])
        ],
        providers: [UserAuthenticationService],

    });

    fixture = TestBed.createComponent(TmLoginComponent);

    comp = fixture.componentInstance; // TmLoginComponent test instance

    // query for the title <h1> by CSS element selector
    de = fixture.debugElement.query(By.css('.title'));
    el = de.nativeElement;
});

    it('should display original title', () => {
        fixture.detectChanges();
        expect(el.textContent).toContain(comp.title);
    });
});

À ce stade, j'essaie simplement d'exécuter le test unitaire de base que le titre s'affiche correctement.

Cependant, je reçois beaucoup d'erreurs matérielles spécifiques. Comme

Aucun fournisseur pour MdDialog.

J'ouvre une boîte de dialogue md en cliquant sur un lien. Le code est dans le fichier .ts (assez long), mais ce n'est pas le problème ici.

Où ajouter MdDialog dans le banc d'essai? Si je l'ajoute aux fournisseurs, j'obtiens l'erreur: "pas de fournisseur pour la superposition". Je ne sais pas comment résoudre ce problème.

Existe-t-il un moyen de configurer le karma pour inclure tous les composants matériels au démarrage?

Merci.

19
Snowman

Tous les fournisseurs sont fournis en appelant forRoot() sur le module

imports: [ MaterialModule.forRoot() ]

Pour les versions 2.0.0-beta.4 et versions ultérieures (puisque la méthode forRoot a été supprimée):

imports: [ MaterialModule ]

Pour les versions 2.0.0-beta.11 et plus tard, puisque MaterialModule a été supprimé, vous devez importer vous-même les modules dont vous avez besoin pour vos cas de test:

imports: [ MatButtonModule, MatDialogModule ]
4
Paul Samsotha

La technique actuelle nécessite des importations individuelles de Angular Modules Material, car MaterialModule est déconseillé et a été supprimé dans 2.0.0-beta.11 :

import {
    MatButtonModule,
    MatIconModule
} from '@angular/material';

Ajoutez ensuite la même liste que les importations dans la configuration TestBed:

beforeEach(async(() => {
    TestBed.configureTestingModule({
        declarations: [ ... ],
        imports: [
            MatButtonModule,
            MatIconModule,
            ...
        ],
        providers: [ ... ]
    })
        .compileComponents();
}));
10
isherwood

J'ai également eu du mal avec cela aujourd'hui et vous devez vous moquer des classes nécessaires vous-même en utilisant des fournisseurs de jasmin. C'est un problème et j'aurais aimé qu'il y ait un meilleur moyen mais au moins plus d'erreurs ...

Si quelqu'un a une meilleure idée, veuillez éclairer le reste de la communauté!

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AlertDialogComponent } from './alert-dialog.component';
import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';

describe('AlertDialogComponent', () => {
  let component: AlertDialogComponent;
  let fixture: ComponentFixture<AlertDialogComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [MatDialogModule],
      declarations: [AlertDialogComponent],
      providers: [
        {
          provide: MatDialogRef, useValue: {}
        },
        {
          provide: MAT_DIALOG_DATA, useValue:{}
        }
     ],
    }).compileComponents();
  }));
1
Peter