Angular 8 - 加载垫模块的单元测试问题

Posted

技术标签:

【中文标题】Angular 8 - 加载垫模块的单元测试问题【英文标题】:Angular 8 - Unit Test issue with loading mat-modules 【发布时间】:2021-01-01 07:56:42 【问题描述】:

我正在尝试为登录组件编写 Angular 的单元测试。 在组件中,我使用 ma​​t-form-fieldma​​t-labelma​​t-iconma​​t-error。 他们工作正常。但是当我运行 ng test --code-coverage

所有模块都导入/导出到一个名为 material-module 的模块。然后我将该模块导入登录模块。 这是我的 login.component.html

<div class="text-center">
  <h1>S'identifier</h1>
</div>
<form class="" [formGroup]="userForm" (ngSubmit)="submit(userForm)">
  <div class="card-body p-6 mb-3">
    <div class="form-group">
      <mat-form-field appearance="outline" class="login-id-form-field">
        <mat-label>Identifiant</mat-label>
        <input
          matInput
          id="email"
          type="email"
          class="login-id"
          [formControl]="userForm.controls['email']"
          [errorStateMatcher]="matcher"
        />
        <mat-icon
          matSuffix
          class="red-icon error-icon"
          *ngIf="
            matcher.isErrorState(userForm.controls['email']) &&
            userForm.controls['email'].errors
          "
          >error</mat-icon
        >
        <mat-icon
          matSuffix
          class="green-icon error-icon"
          *ngIf="!userForm.controls['email'].errors"
        >
          check_circle
        </mat-icon>
        <mat-error *ngIf="userForm.controls['email'].errors">
          Identifiant invalide
        </mat-error>
      </mat-form-field>
    </div>
    <div class="form-group">
      <mat-form-field
        appearance="outline"
        class="login-id-form-field password-form-field"
      >
        <mat-label>Mot de passe</mat-label>
        <input
          matInput
          id="password"
          type="password"
          class="login-id"
          [formControl]="userForm.controls['password']"
          [errorStateMatcher]="matcher"
        />
        <mat-icon
          matSuffix
          class="red-icon error-icon"
          *ngIf="
            matcher.isErrorState(userForm.controls['password']) &&
            userForm.controls['password'].errors
          "
        >
          error
        </mat-icon>
        <mat-icon
          matSuffix
          class="green-icon error-icon"
          *ngIf="!userForm.controls['password'].errors"
        >
          check_circle
        </mat-icon>

        <mat-error *ngIf="userForm.controls['password'].errors">
          Mot de passe invalide (  passwordStrength.label  )
        </mat-error>
      </mat-form-field>
      <div class="d-flex mt-2" style="height: 24px">
        <mat-error *ngIf="auth.loginError.length && userForm.valid">
          E-mail ou mot de passe incorrect
        </mat-error>
        <div class="ml-auto text-right">
          <a [routerLink]="'reset-password'">Mot de passe oublié ?</a>
        </div>
      </div>
    </div>
    <div class="form-footer mt-5">
      <button
        type="submit"
        class="btn d-block mx-auto primary-strada-btn strada-btn-large"
        [disabled]="!userForm.valid || auth.loggingIn"
      >
        Connexion
      </button>
    </div>
  </div>
</form>

这是我的login.component.spec.ts

import  TestBed, ComponentFixture  from "@angular/core/testing";
import  ReactiveFormsModule, FormsModule  from "@angular/forms";
import  LoginPageComponent  from "./login-page.component";
// import  LoginPageComponent, User  from "./login-page.component";

describe("Component: Login", () => 
  let component: LoginPageComponent;
  let fixture: ComponentFixture<LoginPageComponent>;

  beforeEach(() => 
    // refine the test module by declaring the test component
    TestBed.configureTestingModule(
      imports: [ReactiveFormsModule, FormsModule],
      declarations: [LoginPageComponent],
    );

    // create component and test fixture
    fixture = TestBed.createComponent(LoginPageComponent);

    // get test component from the fixture
    component = fixture.componentInstance;
    component.ngOnInit();
  );

  it("form invalid when empty", () => 
    expect(component.userForm.valid).toBeFalsy();
  );
);

我收到这些错误。

Your global Angular CLI version (10.0.5) is greater than your local
version (8.0.6). The local Angular CLI version is used.

To disable this warning use "ng config -g cli.warnings.versionMismatch false".
14 09 2020 15:01:47.510:INFO [framework:karma-parallel]: sharding specs across 4 browsers
 10% building 2/2 modules 0 active14 09 2020 15:01:53.934:INFO [karma-server]: Karma v4.1.0 server started at http://0.0.0.0:9876/
14 09 2020 15:01:53.936:INFO [launcher]: Launching browsers ChromeHeadless, ChromeHeadless, ChromeHeadless, ChromeHeadless with concurrency unlimited
14 09 2020 15:01:53.943:INFO [launcher]: Starting browser ChromeHeadless
14 09 2020 15:01:53.950:INFO [launcher]: Starting browser ChromeHeadless
14 09 2020 15:01:53.954:INFO [launcher]: Starting browser ChromeHeadless
14 09 2020 15:01:53.964:INFO [launcher]: Starting browser ChromeHeadless
14 09 2020 15:02:10.647:INFO [HeadlessChrome 85.0.4183 (Windows 10.0.0)]: Connected on socket ASC5nD0AuFD0GspSAAAA with id 52943636
14 09 2020 15:02:10.652:INFO [HeadlessChrome 85.0.4183 (Windows 10.0.0)]: Connected on socket QA4STEUC5v4EV55_AAAB with id 27694527
14 09 2020 15:02:10.655:INFO [HeadlessChrome 85.0.4183 (Windows 10.0.0)]: Connected on socket 060bO_di1o_9LmmsAAAC with id 63183944
14 09 2020 15:02:10.658:INFO [HeadlessChrome 85.0.4183 (Windows 10.0.0)]: Connected on socket iAPjmFOsygupfAcZAAAD with id 2553141
HeadlessChrome 85.0.4183 (Windows 10.0.0): Executed 0 of 1 SUCCESS (0 secs / 0 secs)
WARN: 'Spec '[karma-parallel] Add single test to prevent failure should prevent on this shard failing by having successful tests' has no expectations.'
HeadlessChrome 85.0.4183 (Windows 10.0.0): Executed 0 of 1 SUCCESS (0 secs / 0 secs)
WARN: 'Spec '[karma-parallel] Add single test to prevent failure should prevent on this shard failing by having successfHeadlessChrome 85.0.4183 (Windows 10.0.0): Executed 1 of 1 SUCCESS (0.032 secs / 0.004 secs)
HeadlessChrome 85.0.4183 (Windows 10.0.0): Executed 1 of 1 SUCCESS (0.032 secs / 0.004 secs)
HeadlessChrome 85.0.4183 (Windows 10.0.0): Executed 1 of 1 SUCCESS (0.032 secs / 0.004 secs)
HeadlessChrome 85.0.4183 (Windows 10.0.0) WARN: 'Spec '[karma-parallel] Add single test to prevent failure should prevent on this shard failing by having successful tests' has no expectations.'
HeadlessChrome 85.0.4183 (Windows 10.0.0): Executed 1 of 1 SUCCESS (0.032 secs / 0.004 secs)
HeadlessChrome 85.0.4183 (Windows 10.0.0): Executed 0 of 1 SUCCESS (0 secs / 0 secs)
HeadlessChrome 85.0.4183 (Windows 10.0.0) Component: Login form invalid when empty FAILED
        1. If 'mat-label' is an Angular component, then verify that it is part of this module.
        2. If 'mat-label' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message. ("class="form-group">
              <mat-form-field appearance="outline" class="login-id-form-field">
                [ERROR ->]<mat-label>Identifiant</mat-label>
                <input
                  matInput
                  class="login-id"
                  [formControl]="userForm.controls['email']"
                  [ERROR ->][errorStateMatcher]="matcher"
                />
                <mat-icon
        1. If 'mat-icon' is an Angular component, then verify that it is part of this module.
        error properties: Object( ngSyntaxError: true, ngParseErrors: [ 'mat-label' is not a known element:
        "): ng:///DynamicTestModule/LoginPageComponent.html@7:8, Can't bind to 'errorStateMatcher' since it isn't a known property of 'input'. ("
        "): ng:///DynamicTestModule/LoginPageComponent.html@14:10, 'mat-icon' is not a known element:
        2. If 'mat-icon' is a Web  ...
            at <Jasmine>
            at syntaxError (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/compiler/fesm2015/compiler.js:2175:1)
            at TemplateParser.parse (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/compiler/fesm2015/compiler.js:11169:1)
            at JitCompiler._parseTemplate (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/compiler/fesm2015/compiler.js:25541:1)
            at JitCompiler._compileTemplate (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/compiler/fesm2015/compiler.js:25529:61)
            at http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/compiler/fesm2015/compiler.js:25473:1
            at <Jasmine>
            at JitCompiler._compileComponents (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/compiler/fesm2015/compiler.js:25473:1)
            at http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/compiler/fesm2015/compiler.js:25393:1
            at Object.then (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/compiler/fesm2015/compiler.js:2166:27)
            at JitCompiler._compileModuleAndAllComponents (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/compiler/fesm2015/compiler.js:25391:1)
        TypeError: Cannot read property 'userForm' of undefined
            at <Jasmine>
            at UserContext.<anonymous> (http://localhost:9876/_karma_webpack_/webpack:/src/app/login/login-page/login-page.component.spec.ts:26:22)
            at ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:359:1)
            at ProxyZoneSpec.push../node_modules/zone.js/dist/zone-testing.js.ProxyZoneSpec.onInvoke (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-testing.js:308:1)
            at ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:358:1)
            at Zone.run (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:124:1)
            at runInTestZone (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-testing.js:561:1)
            at UserContext.<anonymous> (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-testing.js:576:1)
            at <Jasmine>
HeadlessChrome 85.0.4183 (Windows 10.0.0): Executed 1 of 1 SUCCESS (0.032 secs / 0.004 secs)
HeadlessChrome 85.0.4183 (Windows 10.0.0): Executed 1 of 1 (1 FAILED) (0 secs / 0.255 secs)
HeadlessChrome 85.0.4183 (Windows 10.0.0): Executed 2 of 5 SUCCESS (0 secs / 0.159 secs)
HeadlessChrome 85.0.4183 (Windows 10.0.0): Executed 1 of 1 SUCCESS (0.026 secs / 0.004 secs)
HeadlessChrome 85.0.4183 (Windows 10.0.0) Component: Login form invalid when empty FAILED
        1. If 'mat-label' is an Angular component, then verify that it is part of this module.
        2. If 'mat-label' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message. ("class="form-group">
              <mat-form-field appearance="outline" class="login-id-form-field">
                [ERROR ->]<mat-label>Identifiant</mat-label>
                <input
                  matInput
                  class="login-id"
                  [formControl]="userForm.controls['email']"
                  [ERROR ->][errorStateMatcher]="matcher"
                />
                <mat-icon
        1. If 'mat-icon' is an Angular component, then verify that it is part of this module.
        error properties: Object( ngSyntaxError: true, ngParseErrors: [ 'mat-label' is not a known element:
        "): ng:///DynamicTestModule/LoginPageComponent.html@7:8, Can't bind to 'errorStateMatcher' since it isn't a known property of 'input'. ("
        "): ng:///DynamicTestModule/LoginPageComponent.html@14:10, 'mat-icon' is not a known element:
        2. If 'mat-icon' is a Web  ...
            at <Jasmine>
            at syntaxError (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/compiler/fesm2015/compiler.js:2175:1)
            at TemplateParser.parse (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/compiler/fesm2015/compiler.js:11169:1)
            at JitCompiler._parseTemplate (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/compiler/fesm2015/compiler.js:25541:1)
            at JitCompiler._compileTemplate (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/compiler/fesm2015/compiler.js:25529:61)
            at http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/compiler/fesm2015/compiler.js:25473:1
            at <Jasmine>
            at JitCompiler._compileComponents (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/compiler/fesm2015/compiler.js:25473:1)
            at http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/compiler/fesm2015/compiler.js:25393:1
            at Object.then (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/compiler/fesm2015/compiler.js:2166:27)
            at JitCompiler._compileModuleAndAllComponents (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/compiler/fesm2015/compiler.js:25391:1)
        TypeError: Cannot read property 'userForm' of undefined
            at <Jasmine>
            at UserContext.<anonymous> (http://localhost:9876/_karma_webpack_/webpack:/src/app/login/login-page/login-page.component.spec.ts:26:22)
            at ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:359:1)
            at ProxyZoneSpec.push../node_modules/zone.js/dist/zone-testing.js.ProxyZoneSpec.onInvoke (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-testing.js:308:1)
            at ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:358:1)
            at Zone.run (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:124:1)
            at runInTestZone (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-testing.js:5HeadlessChrome 85.0.4183 (Windows 10.0.0): Executed 1 of 1 SUCCESS (0.032 secs / 0.004 secs)
HeadlessChrome 85.0.4183 (Windows 10.0.0): Executed 1 of 1 (1 FAILED) ERROR (0.307 secs / 0.255 secs)
HeadlessChrome 85.0.4183 (Windows 10.0.0): Executed 5 of 5 SUCCESS (0.3 secs / 0.248 secs)
HeadlessChrome 85.0.4183 (Windows 10.0.0): Executed 1 of 1 SUCCESS (0.026 secs / 0.004 secs)

=============================== Coverage summary ===============================
Statements   : 23.48% ( 31/132 )
Branches     : 2.44% ( 1/41 )
Functions    : 10.42% ( 5/48 )
Lines        : 21.14% ( 26/123 )
================================================================================

【问题讨论】:

如果您不打算测试我们通常不做的html,您可以添加TestBed.configureTestingModule(...).overrideTemplate(LoginPageComponent, ''); 【参考方案1】:

我只需要导入 AngularMaterialModule

    // refine the test module by declaring the test component
    TestBed.configureTestingModule(
      imports: [
        ReactiveFormsModule, 
        FormsModule,
        AngularMaterialModule],  <-------------------------------------------
      declarations: [LoginPageComponent],
    );```

【讨论】:

以上是关于Angular 8 - 加载垫模块的单元测试问题的主要内容,如果未能解决你的问题,请参考以下文章

Angular 单元测试 - 忽略样式表

Angular:单元测试路由:预期 '' 是 '/route'

将 Swiper 6 升级到 7 后,在单元测试(开玩笑)上找不到模块“swiper_angular”

Angular 2 单元测试 - 出现错误无法加载“ng:///DynamicTestModule/module.ngfactory.js”

Angular 8 急切加载模块(包括应用程序模块)不会出现在 chrome 开发工具中

在 AngularJS 单元测试中模拟模块依赖