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