测试自定义字段控件组件时如何提供NgControl?

时间:2019-07-16 01:16:16

标签: unit-testing angular6 custom-controls

我有一个简单的自定义控件,如下所示。一切正常,但是单元测试失败。如何对该自定义控件进行单元测试?如何传递有效的NgControl指令?

我尝试使用提供程序:

[
  {
    provide: NgControl,
    useValue: new FormGroup()
  }
]

但我仍然遇到相同的错误。

core-edi.component.ts

import { Component, OnInit, Input, ViewChild, ElementRef, Self, Optional, forwardRef } from '@angular/core';
import {
  ControlValueAccessor, NG_VALUE_ACCESSOR, Validator, AbstractControl,
  ValidatorFn, Validators, NG_VALIDATORS, NgControl, NgForm
} from '@angular/forms';
import { Placeholder } from '@angular/compiler/src/i18n/i18n_ast';

@Component({
  selector: 'app-core-edi',
  templateUrl: './core-edi.component.html',
  styleUrls: ['./core-edi.component.css'],

})
export class CoreEdiComponent implements ControlValueAccessor, Validator, OnInit {



  @ViewChild('input') input: ElementRef;
  disabled;

  @Input() type = 'text';

  @Input() isRequired: boolean = false;
  @Input() pattern: string = null;
  @Input() label: string = null;
  @Input() placeholder: string;
  @Input() errorMsg: string;
  @Input() min: number;
  @Input() minLength: number;



  myhint: string = '10 digit number';

  constructor(@Self() public controlDir: NgControl) {
    this.controlDir.valueAccessor = this;
  }

  ngOnInit() {
    const control = this.controlDir.control;
    const validators: ValidatorFn[] = control.validator ? [control.validator] : [];
    if (this.isRequired) {
      validators.push(Validators.required);
    }
    if (this.pattern) {
      validators.push(Validators.pattern(this.pattern));
    }

    if (this.min) {
      validators.push(Validators.min(this.min));
    }

    control.setValidators(validators);
    control.updateValueAndValidity();

    this.placeholder = this.placeholder + (this.isRequired ? '*' : '');
  }

  onChange(event) { 

  }


  onTouched() {

   }

  writeValue(obj: any): void {
    this.input.nativeElement.value = obj;
  }
  registerOnChange(fn: any): void {
    this.onChange = fn;
  }
  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }
  setDisabledState?(isDisabled: boolean): void {
    this.disabled = isDisabled;
  }

  validate(c: AbstractControl): { [key: string]: any; } {
    const validators: ValidatorFn[] = [];
    if (this.isRequired) {
      validators.push(Validators.required);
    }
    if (this.pattern) {
      validators.push(Validators.pattern(this.pattern));
    }

    if (this.min) {
      validators.push(Validators.min(this.min));
    }

    return validators;
  }

core-edi.component.html

<div class="form-label-group" fxLayout="column" fxLayoutGap="5px">

  <mat-form-field class="edi-field-width">   
        <input matInput class="form-control" 
            [type]="type" #input
            (input)="onChange($event.target.value)"
            (blur)="onTouched()"
            [disabled]="disabled"
            [placeholder]="placeholder"
            [min]="1111111111"
            [minLength] = 10
            (keyup)="mykeyup()">

            <mat-hint>Hint: {{ myhint }}</mat-hint>

 </mat-form-field>


 <span class="error"
     *ngIf="controlDir && !controlDir.control.valid 
     && controlDir.control.touched">{{errorMsg}}</span>

</div>

core-edi.component.spec.ts

import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { CoreEdiComponent } from './core-edi.component';
import { FormsModule, ReactiveFormsModule, FormControl, NgControl, FormControlDirective } from '@angular/forms';
import { MaterialModule } from 'src/app/material/material.module';



fdescribe('CoreEdiComponent', () => {
  let component: CoreEdiComponent;
  let fixture: ComponentFixture<CoreEdiComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ CoreEdiComponent ],
      imports: [
        FormsModule,
        ReactiveFormsModule,
        MaterialModule
      ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(CoreEdiComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });


 it('should create', () => {
    expect(component).toBeTruthy();
  });

});

No provider for NgControl ("[ERROR ->]<app-core-edi></app-core-edi>"): @0:0
            at syntaxError (./node_modules/@angular/compiler/fesm5/compiler.js?:1275:17)
            at TemplateParser.parse (./node_modules/@angular/compiler/fesm5/compiler.js?:15084:19)
            at JitCompiler._parseTemplate (./node_modules/@angular/compiler/fesm5/compiler.js?:24272:37)
            at JitCompiler._compileTemplate (./node_modules/@angular/compiler/fesm5/compiler.js?:24259:23)
            at eval (./node_modules/@angular/compiler/fesm5/compiler.js?:24202:62)
            at Set.forEach (<anonymous>)
            at JitCompiler._compileComponents (./node_modules/@angular/compiler/fesm5/compiler.js?:24202:19)
            at eval (./node_modules/@angular/compiler/fesm5/compiler.js?:24120:19)
            at Object.then (./node_modules/@angular/compiler/fesm5/compiler.js?:1266:77)
            at JitCompiler._compileModuleAndAllComponents (./node_modules/@angular/compiler/fesm5/compiler.js?:24118:26)
        Expected undefined to be truthy.
            at UserContext.eval (./src/app/core/core-edi/core-edi.component.spec.ts?:30:27)
            at ZoneDelegate.invoke (./node_modules/zone.js/dist/zone.js?:390:26)
            at ProxyZoneSpec.onInvoke (./node_modules/zone.js/dist/zone-testing.js?:288:39)

1 个答案:

答案 0 :(得分:0)

我还没有完全了解如何在角度上进行单元测试,但是也许它需要在app.module中像package com.example.oneclickscanner; import androidx.appcompat.app.AppCompatActivity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; public class AccountActivity extends AppCompatActivity { TextView accountLogo; EditText edtUsername,edtPassword,edtConfirmPassword; Button createButton,exitButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_account); accountLogo = findViewById(R.id.accountLogo); edtUsername = findViewById(R.id.edtUsername); edtPassword = findViewById(R.id.edtPassword); edtConfirmPassword = findViewById(R.id.edtConfirmPassword); createButton = findViewById(R.id.createButton); exitButton = findViewById(R.id.exitButton); createButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String userName = edtUsername.getText().toString(); String password = edtPassword.getText().toString(); String confirmPassword = edtConfirmPassword.getText().toString(); boolean enterRequiredFields = false; boolean passwordMatching = true; if(userName.equals("") || password.equals("") || confirmPassword.equals("")){ enterRequiredFields = true; }else if(!userName.equals("") || !password.equals("") || !confirmPassword.equals("")){ enterRequiredFields = false; } if(!password.equals(confirmPassword)){ passwordMatching = false; }else{ passwordMatching = true; } if(enterRequiredFields){ Toast.makeText(AccountActivity.this,"Please Enter the required Fields",Toast.LENGTH_SHORT).show(); }else if(!passwordMatching) { Toast.makeText(AccountActivity.this,"Password don't Match",Toast.LENGTH_SHORT).show(); }else { Intent intent = new Intent(AccountActivity.this,ModelAndLicenseInfo.class); startActivity(intent); } } }); exitButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(AccountActivity.this,MainActivity.class); startActivity(intent); } }); } } }

那样添加

这个答案帮助了我

Why do I get this Template parse errors in Angular

只需2美分