Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No value accessor for form control with name... for mat-select controls

I am making some unit test with jasmine and karma for an angular 6 app that validate if a formGroup field is valid. I am experiencing problems with mat-select control. when I run the test case, Karma fires me an error saying Error: No value accessor for form control with name: 'importId'. By the way, the component works fine as I expected.

enter image description here

This is my component:

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),
    });
  }
}

My HTML template looks like this:

<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>

Finally, this is my unit test:

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();
    });

  });
});

I can't make that works, any suggestions what I am missing?

like image 562
xzegga Avatar asked Apr 16 '19 23:04

xzegga


People also ask

How do you resolve no value accessor for form control with name?

you lost name attribute to the element has [ngModel] . To fix this issue, you can add more name="fieldName" ngDefaultControl to your element.

Should create no value accessor for form control with unspecified name attribute?

When you get the error No value accessor for form control with unspecified name attribute , there are generally two things that possibly has gone wrong: You are using ngModel with a third party control that doesn't register a NG_VALUE_ACCESSOR . In this case you need to use ngDefaultControl on the element.

What is control value accessor?

Control Value Accessor is an interface that provides us the power to leverage the Angular forms API and create a communication between Angular Form API and the DOM element. It provides us many facilities in angular like we can create custom controls or custom component with the help of control value accessor interface.

How do you use ngDefaultControl?

Third party controls require a ControlValueAccessor to function with angular forms. Many of them, like Polymer's <paper-input> , behave like the <input> native element and thus can use the DefaultValueAccessor . Adding an ngDefaultControl attribute will allow them to use that directive.


1 Answers

You're not importing the material modules in your testing module.

So mat-form-field, mat-select, etc. are just treated as unknown elements by Angular (since you told it to do so by using NO_ERRORS_SCHEMA).

like image 73
JB Nizet Avatar answered Sep 21 '22 04:09

JB Nizet