typescript - Hur man mockar ngControl i anpassad formulärkontroll - Enhetstester Angular


Jag letar efter några exempel med enhetstester för Custom Form Control i Angular 9. Den delen constructor(@Self() private ngControl: NgControl) orsakar ett fel: Error: NodeInjector: NOT_FOUND [NgControl]. Eftersom jag på något sätt behöver sätta value accessor.

Jag injicerar ngControl i konstruktorn eftersom jag behöver använda ngControl senare i min komponent. Det är därför jag inte använde den typiska implementeringen med provide: NG_VALUE_ACCESSOR.

Jag försökte härma det genom att:

beforeEach(async(() => {
    TestBed.configureTestingModule({
        providers: [
            { provide: NgControl, useValue: new FormControlDirective([], [], [], null) }
        ],
        imports: [FormsModule, ReactiveFormsModule]
    }).compileComponents();

Men jag har ett fel: No valid value accessor for form control with unspecified name attribute eftersom jag inte vet vad som ska vara under den tredje parametern av funktionen FormControlDirective som är: valueAccessors: ControlValueAccessor[]

Har någon någon idé om hur jag kan imitera detta?

Svar #1

Försök att driva med det så här:

let mockNgControl: any;

beforeEach(async(() => {
    mockNgControl = jasmine.createSpyObj('ngControl', ['value', /* mock other methods required here */]);
    TestBed.configureTestingModule({
        providers: [
            { provide: NgControl, useValue: mockNgControl }
        ],
        imports: [FormsModule, ReactiveFormsModule]
    }).compileComponents();

Svar #2

Eftersom FormControlName utökar NgControl kommer det accepterade svaret att misslyckas om någon av metoderna i ControlValueAccessor (mer här), såsom writeValue(), anropas.

Till exempel skulle ett av våra projekts tester skriva ett "nytt värde" när det lyssnar på en ngModelChange, så här:

this.ngControl.valueAccessor.writeValue(newVal);

men metoden jasmine.createSpyObj('ngControl', [...]) misslyckades här, även när writeValue definierades som valueAccessor: { writeValue:() => null } i spionobjektet. Jag tyckte det var enklare att mocka ett ngControl på följande sätt:

let mockNgControl: NgControl = new FormControlName(null, null, null, [{writeValue: () => null, registerOnChange: () => null, registerOnTouched: () => null}], null);

b/c här är konstruktorn för FormControlName

constructor(
    parent: ControlContainer,
    validators: (Validator | ValidatorFn)[],
    asyncValidators: (AsyncValidator | AsyncValidatorFn)[],
    **valueAccessors: ControlValueAccessor[],**
    _ngModelWarningConfig: string | null
);

Då kunde mitt ngControl skickas in i konstruktorer för direktiv på detta sätt:

let alphanumericDirective = new AlphanumericDirective(mockNgControl);