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

18,346

Solution 1

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

Solution 2

In my case I forgot

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

in module.

So if you import it should work.

Solution 3

I think you're missing some important modules, that's why those are not known to the Angular compiler. Put at least the following (and more I guess) in your imports:

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

Use also

schemas: [CUSTOM_ELEMENTS_SCHEMA],

to tell the compiler to be able to detect non-HTML tags.

With that fix, you won't need the NO_ERRORS_SCHEMA, which should NOT be used in these simple cases.

Share:
18,346
xzegga
Author by

xzegga

Updated on June 29, 2022

Comments

  • xzegga
    xzegga almost 2 years

    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?