Нет средства доступа к значениям для элемента управления формой с именем… для элементов управления mat-select

#angular #typescript #unit-testing #angular-material #karma-jasmine

#angular #typescript #модульное тестирование #angular-материал #карма-жасмин

Вопрос:

Я провожу некоторый модульный тест с jasmine и karma для приложения angular 6, которое проверяет, является ли поле FormGroup допустимым. У меня возникают проблемы с элементом управления мат-выбором. когда я запускаю тестовый пример, Karma выдает сообщение об ошибке Error: No value accessor for form control with name: 'importId' . Кстати, компонент работает нормально, как я и ожидал.

введите описание изображения здесь

Это мой компонент:

 import {Component, Inject, OnInit} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material";
import {FormBuilder, FormControl, FormGroup, Validators} from "@angular/forms";

@Component({
  selector: 'app-my-component',
  templateUrl: './my.component.html',
  styleUrls: ['./my.component.css']
})
export class MyComponent implements OnInit {
  modelForm: FormGroup;
  imps;
constructor(
    public dialogRef: MatDialogRef<MyComponent>,
    @Inject(MAT_DIALOG_DATA) public data: any) {
      this.imps = data['imp'];
  }


  ngOnInit() {
    this.modelForm = new FormGroup({
      name: new FormControl(null, Validators.required),
      importId: new FormControl(null, Validators.required),
    });
  }
}
 

Мой HTML-шаблон выглядит следующим образом:

 <mat-dialog-content>
  <form [formGroup]="modelForm">

    <mat-form-field>
      <input matInput
             placeholder="Name"
             formControlName="name">
    </mat-form-field>

    <mat-form-field>
      <mat-select placeholder="Source import"
                  formControlName="importId">
        <mat-option *ngFor="let imp of imps" [value]="imp.uuid">
          {{imp.label}}
        </mat-option>
      </mat-select>
    </mat-form-field>

  </form>
</mat-dialog-content>

<mat-dialog-actions>
  <button mat-raised-button color="primary" [disabled]="!modelForm.valid" (click)="someFakeFunction()">Create</button>
  <button mat-raised-button (click)="dialogRef.close()">Cancel</button>
</mat-dialog-actions>
 

Наконец, это мой модульный тест:

 import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {MockMatDialogData, MockMatDialogRef} from '@testing/mock/material';
import {MyComponent} from './evaluation-wizard.component';
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material";
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
import {NO_ERRORS_SCHEMA} from "@angular/core";


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

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [MyComponent],
      imports: [ReactiveFormsModule, FormsModule],
      providers: [
        {provide: MatDialogRef, useValue: MockMatDialogRef},
        {provide: MAT_DIALOG_DATA, useClass: MockMatDialogData}
      ],
      schemas: [NO_ERRORS_SCHEMA],
    })
      .compileComponents();
  }));

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

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  describe('Form validation', () => {
    it('form invalid when empty ', function () {
      expect(component.modelForm.valid).toBeFalsy();
    });

    it('name field validity ', () => {
      let name = component.modelForm.controls['name'];
      expect(name.valid).toBeFalsy();

      let errors = {};
      errors = name.errors || {};
      expect(errors['required']).toBeTruthy();

      name.setValue("test");
      errors = name.errors || {};
      expect(errors['required']).toBeTruthy();
    });

  });
});
 

Я не могу заставить это работать, какие-либо предложения, чего мне не хватает?

Комментарии:

1. Вы не импортируете модули материалов в свой модуль тестирования. Таким образом, mat-form-field, mat-select и т. Д. Просто Рассматриваются Angular как неизвестные элементы (поскольку вы сказали ему сделать это с помощью NO_ERRORS_SCHEMA).

2. @JBNizet, фантастика. это работает для меня. Я действительно ценю. Не стесняйтесь включать ответ в этот канал.

3. У меня была та же проблема, но с мат-флажком. Я добавил MatCheckboxModule в импорт тестового стенда, и это устранило ошибку, спасибо!

4. Для тех, кто использует mat-button-toggle-group , вам нужно будет добавить MatButtonToggleModule в свой тестовый стенд импорт, нет необходимости NO_ERRORS_SCHEMA или BrowserAnimationsModule

Ответ №1:

Вы не импортируете модули материалов в свой модуль тестирования.

Итак mat-form-field , mat-select , и т. Д. Просто Рассматриваются Angular как неизвестные элементы (поскольку вы сказали ему сделать это с помощью NO_ERRORS_SCHEMA ).

Комментарии:

1. Работает как шарм. Кроме того, я включил BrowserAnimationsModule .

2. Спас мой день. Спасибо!!

3. Использование NO_ERRORS_SCHEMA — плохая идея. Это замаскирует другие проблемы с вашими тестами. Используйте CUSTOM_ELEMENTS_SCHEMA вместо этого. medium.com/@fivedicephoto /… объясняет немного больше, почему.

Ответ №2:

В моем случае я забыл

import {MatSelectModule} from '@angular/material/select';

в модуле.

Так что, если вы импортируете, это должно сработать.

Ответ №3:

Я думаю, вам не хватает некоторых важных модулей, поэтому они неизвестны компилятору Angular. Поместите в свой импорт как минимум следующее (и, я думаю, больше):

 imports: [ReactiveFormsModule, FormsModule,
  BrowserModule,
  BrowserAnimationsModule,
  MatSelectModule,
  MatOptionModule,
  MatInputModule
],
 

Используйте также

 schemas: [CUSTOM_ELEMENTS_SCHEMA],
 

чтобы сообщить компилятору, чтобы он мог обнаруживать теги, отличные от HTML.

С этим исправлением вам не понадобится NO_ERRORS_SCHEMA , который не следует использовать в этих простых случаях.