I have an Angular 16 component that gets passed the form that it will be inside of, and the viewProviders
allows that to work which I received as an answer to another question I asked
@Component({
selector: 'app-question-form-editor',
standalone: true,
imports: [ CommonModule, FormsModule ],
templateUrl: './question-form-editor.component.html',
viewProviders: [{ provide: ControlContainer, useExisting: NgForm }],
})
export class QuestionFormEditorComponent implements OnInit {
@Input() form!: NgForm;
//Logic goes here...
}
This now works as expected, however now my unit tests break since they need to have this provider and I'm not sure what value I need to provide.
const mockQuestionForm = new NgForm([], []);
mockQuestionForm.form.addControl('example', new FormControl('', Validators.required));
describe('QuestionFormEditorComponent', () => {
let component: QuestionFormEditorComponent;
let fixture: ComponentFixture<QuestionFormEditorComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [QuestionFormEditorComponent],
providers: [{ provide: ControlContainer, useValue: mockQuestionForm }],
});
fixture = TestBed.createComponent(QuestionFormEditorComponent);
component = fixture.componentInstance;
component.form = mockQuestionForm;
});
it('should create', () => {
fixture.detectChanges(); //triggers ngOnInit()
expect(component).toBeTruthy();
});
});
I have also tried useExisting
instead of useValue
and have tried NgForm
instead of my mockQuestionForm
- all have the same result
Here is the error message Jasmine fails with
NullInjectorError: R3InjectorError(Standalone[QuestionFormEditorComponent])[NgForm -> NgForm -> NgForm]:
NullInjectorError: No provider for NgForm!
error properties: Object({ ngTempTokenPath: null, ngTokenPath: [ 'NgForm', 'NgForm', 'NgForm' ] })
at NullInjector.get (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/fesm2022/core.mjs:8890:27)
at R3Injector.get (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/fesm2022/core.mjs:9334:33)
at R3Injector.get (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/fesm2022/core.mjs:9334:33)
at R3Injector.get (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/fesm2022/core.mjs:9334:33)
at ChainedInjector.get (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/fesm2022/core.mjs:14018:36)
at lookupTokenUsingModuleInjector (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/fesm2022/core.mjs:4608:39)
at getOrCreateInjectable (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/fesm2022/core.mjs:4656:12)
at ɵɵdirectiveInject (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/fesm2022/core.mjs:11801:19)
at ɵɵinject (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/fesm2022/core.mjs:848:60)
at NodeInjectorFactory.factory (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/fesm2022/core.mjs:9556:29)
You should be able to override component annotation settings as follows:
TestBed.overrideComponent(
MyComponent,
{
set: {
viewProviders: [{
// your view provider code goes here
}]
}
}
);
(Code example comes from here)
In your case, I think you are missing the FormsModule and/or ReactiveFormsModule... I would suggest to try importing those into your test module and see if that resolves your issue before taking this customization step.