Search code examples
angulartypescriptunit-testing

Angular unit Test: Error: No value accessor for form control with name: 'phoneNumber'


In my Angular Component I am using a 3rd party Component that is part of a form, a simplified template would look like this:

<form novalidate autofill="off" [formGroup]="addPhoneForm">
    <div>
        <int-phone-prefix [locale]="'en'" [defaultCountry]="'us'" formControlName="phoneNumber"></int-phone-prefix>
     </div>
     <div>
        <input type="text"formControlName="phoneName">
    </div>
</form>

Everything works great... until it is time to write tests for my component's methods. I know that I need to mock the 3rd party component to prevent it complaining about the component not being a known element. I also don't want to not use [NO_ERRORS_SCHEMA] as the 3rd party component is part of my FormGroup. So in my test file I add a mock like so before I set up my test suite, notice how I add a formControlName to the mock template, how I add the mock to the declarations array and how I even use forwardRef in my providers array so the mock will be considered part of my form....

// Mock Component
@Component({
  template: '<input type="text" formControlName="phoneNumber">',
  // tslint:disable-next-line
  selector: 'int-phone-prefix',
})
class IntPhonePrefixComponent {
  constructor() { }
}

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

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ AddPhoneComponent, IntPhonePrefixComponent],
      imports: [
        FormsModule,
        ReactiveFormsModule
      ],
      schemas: [CUSTOM_ELEMENTS_SCHEMA],
      providers: [
        {
          provide: NG_VALUE_ACCESSOR,
          multi: true,
          useExisting: forwardRef(() => IntPhonePrefixComponent),
        }
      ]
    })
    .compileComponents();
  }));

However, despite the mock and including it in my providers array and the declarations array I still get the following error when I run my test suite.

Error: No value accessor for form control with name: 'phoneNumber'

Can someone please tell me what I am doing wrong?


Solution

  • Your providers array are in the wrong place: it's the int-phone-prefix that should have the NG_VALUE_ACCESSOR, not the testing module itself.

    The simplest solution would be to stub the three required ControlValueAccessor methods for the stub IntPhonePrefixComponent (and move the provide: NG_VALUE_ACCESSOR // etc. fragment to its decorator). I'm not arguing that it's the best or the most elegant one, probably not.