Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No value accessor for form control when mocking MatSelectModule #157

Closed
Volcomix opened this issue Jul 9, 2020 · 6 comments · Fixed by #160
Closed

No value accessor for form control when mocking MatSelectModule #157

Volcomix opened this issue Jul 9, 2020 · 6 comments · Fixed by #160
Assignees
Labels
bug Something isn't working
Milestone

Comments

@Volcomix
Copy link

Volcomix commented Jul 9, 2020

Hi,

When trying to mock the mat-select component from Angular Material 9, the following error appears: Error: No value accessor for form control with name: 'toppings'.

The error occurs only when calling fixture.detectChanges() in the test.

Here is a repo with the minimal setup to reproduce this issue: https://github.com/volcomix/ng-mocks-mat-select-issue

<!-- app.component.html -->

<form [formGroup]="pizzaForm">
  <mat-form-field>
    <mat-label>Toppings</mat-label>
    <mat-select formControlName="toppings" multiple>
      <mat-option *ngFor="let topping of toppingList" [value]="topping">{{
        topping
      }}</mat-option>
    </mat-select>
  </mat-form-field>
</form>
// app.component.ts

import { ChangeDetectionStrategy, Component } from '@angular/core';
import { FormBuilder } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {
  pizzaForm = this.formBuilder.group({
    toppings: [[]],
  });

  toppingList: string[] = [
    'Extra cheese',
    'Mushroom',
    'Onion',
    'Pepperoni',
    'Sausage',
    'Tomato',
  ];

  constructor(private formBuilder: FormBuilder) {}
}
// app.component.spec.ts

import { async, TestBed } from '@angular/core/testing';
import { ReactiveFormsModule } from '@angular/forms';
import { MatSelectModule } from '@angular/material/select';
import { MockModule } from 'ng-mocks';
import { AppComponent } from './app.component';

describe('AppComponent', () => {
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [ReactiveFormsModule, MockModule(MatSelectModule)],
      declarations: [AppComponent],
    }).compileComponents();
  }));

  it('should create the app', () => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.componentInstance;
    fixture.detectChanges();
    expect(app).toBeTruthy();
  });
});

Error details:

Error: No value accessor for form control with name: 'toppings'
            at _throwError (http://localhost:9876/_karma_webpack_/node_modules/@angular/forms/__ivy_ngcc__/fesm2015/forms.js:3576:1)
            at setUpControl (http://localhost:9876/_karma_webpack_/node_modules/@angular/forms/__ivy_ngcc__/fesm2015/forms.js:3400:1)
            at FormGroupDirective.addControl (http://localhost:9876/_karma_webpack_/node_modules/@angular/forms/__ivy_ngcc__/fesm2015/forms.js:7679:1)
            at FormControlName._setUpControl (http://localhost:9876/_karma_webpack_/node_modules/@angular/forms/__ivy_ngcc__/fesm2015/forms.js:8451:24)
            at FormControlName.ngOnChanges (http://localhost:9876/_karma_webpack_/node_modules/@angular/forms/__ivy_ngcc__/fesm2015/forms.js:8368:1)
            at FormControlName.wrapOnChangesHook_inPreviousChangesStorage (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:26966:1)
            at callHook (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:4730:1)
            at callHooks (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:4690:1)
            at executeInitAndCheckHooks (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:4630:1)

Thank you!

@Volcomix
Copy link
Author

For anyone who is experiencing the same issue, here is a workaround by stubbing manually mat-select without ng-mocks:

// app.component.spec.ts

import { Component } from '@angular/core';
import {
  ControlValueAccessor,
  NG_VALUE_ACCESSOR,
  ReactiveFormsModule,
} from '@angular/forms';
import { async, TestBed } from '@angular/core/testing';
import { MatOptionModule } from '@angular/material/core';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MockModule } from 'ng-mocks';
import { AppComponent } from './app.component';

@Component({
  selector: 'mat-select',
  template: '',
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: MatSelectStubComponent,
      multi: true,
    },
  ],
})
class MatSelectStubComponent implements ControlValueAccessor {
  writeValue(obj: any) {}
  registerOnChange(fn: any) {}
  registerOnTouched(fn: any) {}
  setDisabledState(isDisabled: boolean) {}
}

describe('AppComponent', () => {
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        ReactiveFormsModule,
        MockModule(MatFormFieldModule),
        MockModule(MatOptionModule),
      ],
      declarations: [AppComponent, MatSelectStubComponent],
    }).compileComponents();
  }));

  it('should create the app', () => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.componentInstance;
    fixture.detectChanges();
    expect(app).toBeTruthy();
  });
});

@satanTime
Copy link
Member

Thank you for the report, I was able to reproduce the issue and working on the fix.

@satanTime
Copy link
Member

Hi, might you verify that #160 works for you?

@Volcomix
Copy link
Author

Hi, I've pulled the fix and tried with it: it works 👍
Good job, thanks!

satanTime referenced this issue in satanTime/ng-mocks Jul 11, 2020
@satanTime satanTime self-assigned this Jul 11, 2020
@satanTime satanTime added the bug Something isn't working label Jul 11, 2020
@satanTime satanTime added this to the v10.0.1 milestone Jul 11, 2020
satanTime added a commit that referenced this issue Dec 15, 2020
chore(deps): update dependency @types/jest to v26.0.19
@satanTime
Copy link
Member

Hi all dear developers,

This page is quite popular in search results.

Might you create an issue in this repo and describe what you've been looking for?
Hopefully, your case will be answered.

@AnastasiyaFatPanda
Copy link

Sorry for a stupid question, but

  1. how did you understand that mat-select is a problem? Just because we linked toppings formControl to it, right?
  2. how to fix it, if we have a simple input, not a mat component.
  3. why does fixture.detectChanges(); throw this error? if we call component.ngOnInit() instead of fixture.detectChanges(); it's working fine.

Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants