如何测试组件模板包含mat-error

How to test that component template contains mat-error

我想为检查是否显示 mat-error 的组件创建测试。

我创建了一个测试,但它失败了,因为 DOM 在测试期间根本没有 mat-error。虽然它在项目服务时工作正常。

模板片段

<mat-error>
    Error message
</mat-error>

测试设置

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

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        MatFormFieldModule,
        ReactiveFormsModule,
        MatInputModule,
        MatFormFieldModule,
        BrowserAnimationsModule
      ],
      declarations: [MyComponent]
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(MyComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  fit('should display error', () => {
    const matErrorEl: HTMLElement = 
    fixture.debugElement.query(By.directive(MatError)).nativeElement;
    expect(matErrorEl).toBeTruthy();
  });
});

tldr;在显示任何错误之前,您必须触摸 FormControl


您必须先触摸组件。
使用反应形式(其中 nameFormControl 是类型 FormControl):

component.nameFormControl.markAsTouched();

您的 mat-error 元素现在将显示在视图中。


对于真实场景,您将在 mat-error 元素上有一个 ngIf,并且还需要设置该错误。

示例模板:

<mat-error *ngIf="nameFormControl.hasError('required')">
    Error message
</mat-error>

添加错误:

component.nameFormControl.setErrors({ required: true} as ValidationErrors);

这个问题的类似问题:
How to catch the <mat-error> error message text content using Protractor

关于Angular 表单验证的官方文档:
https://angular.io/guide/form-validation#why-check-dirty-and-touched

我采用了另一种方式,我使用了一个名为 spectator 的库来帮助我处理使用 angular-material spectator

的场景

文件测试

import { createComponentFactory, Spectator } from '@ngneat/spectator';
describe('InputEmailComponent', () => {
 let spectator: Spectator<InputEmailComponent>;
 const createComponent = createComponentFactory({
   component: InputEmailComponent,
 });

 beforeEach(() => (spectator = createComponent()));

 it(`should get the component mat-error with a email empty`, () => {
   // Pass a value null for a email validator required
   spectator.component.email.setValue(null);

   expect(spectator.query('mat-error')).toHaveText('Insira um e-mail válido');
 });

});

文件组件

import { Component, Input, OnInit } from "@angular/core";
import {
  ControlContainer,
  FormControl,
  FormGroupDirective,
  Validators,
} from "@angular/forms";

@Component({
  selector: "input-email",
  templateUrl: "./input-email.component.html",
  viewProviders: [
    {
      provide: ControlContainer,
      useExisting: FormGroupDirective,
    },
  ],
})
export class InputEmailComponent implements OnInit {
  @Input() style: string = "";
  email: FormControl;
  constructor() {
    this.email = new FormControl("", [Validators.required, Validators.email]);
  }
  ngOnInit(): void {}

  getErrorMessage(): string | null {
    if (this.email.hasError("required") || this.email.hasError("email")) {
      return "Insira um e-mail válido";
    }
    return null;
  }
}

文件模板html

<mat-form-field [style]="style" appearance="fill">
  <mat-label>e-mail</mat-label>
  <input
    type="email"
    formControlName="email"
    matInput
    placeholder="digite seu e-mail"
  />
  <mat-error *ngIf="!email.valid">{{ getErrorMessage() }}</mat-error>
</mat-form-field>

前几天我在使用 angular testing-library 和 Jest 时遇到了同样的问题。 @RonanCodes 的回答实际上让我走上了正确的轨道。不过,我还必须在 markAsTouched() 之后添加 detectChanges() 语句。

不可否认,我的设置有点不同,因为日期选择器是一个单独的共享组件,您可以在其中注入错误映射以根据添加到表单控件的验证器函数进行处理。

无论如何,如果添加 markAsTouched 无法解决您的问题,请尝试添加 detectChanges

it('should show error', async () => {
    const reqMsg = 'This field is required';
    const errors = new Map([['required', reqMsg]]);
    const control = new FormControl(null, [Validators.required]);
    const rc = await renderComponent('ariaLabel', 'label', control, errors);
    
    control.setErrors({ required: true });
    control.markAsTouched();
    rc.detectChanges();
    
    expect(screen.getByTestId('date-picker-error')).toHaveTextContent(reqMsg);
  });