Angular: 在使用自定义ControlValueAccessor测试组件时,registerOnChange从未被调用

3

如我在这个答案中所描述的,我创建了一个自定义ControlValueAccessor指令来控制何时触发我的组件的onChange事件,一切都完美地工作,除了当我测试时,registerOnChange 从未被调用过,因此,我的测试失败了。

我的指令看起来像这样:

export const MASK_CONTROL_VALUE_ACCESSOR: any = {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => MaskDirective),
  multi: true
};

@Directive({
  selector: "[testMask]",
  providers: [MASK_CONTROL_VALUE_ACCESSOR]
})

export class MaskDirective implements ControlValueAccessor {

  private onChange;
  private nativeElement;

  constructor(private element: ElementRef) {
    this.nativeElement = this.element.nativeElement;
  }

  registerOnChange(fn: any): void {
    this.onChange = fn;
  }
  registerOnTouched(fn: any): void {
  }
  setDisabledState(isDisabled: boolean): void {
    this.nativeElement.disabled = isDisabled;
  }
  writeValue(newValue) {
    newValue = newValue == null ? "" : newValue;
    this.nativeElement.value = newValue;
  }
  @HostListener("input", ["$event"])
  onInput(event: KeyboardEvent) {
    /*DO YOUR STUFF HERE*/
    // Call onChange to fire the valueChanged listeners
    this.onChange(newValue);
  }
}

并且我的测试:

describe("Test Custom Directive", () => {
  @Component({
    template:
        `<input type="text" [formControl]=inputFormControl testMask/>`
  })
  class TestComponent {

    _inputFormControl: FormControl;

    constructor(private element: ElementRef) {
      this._inputFormControl = new FormControl();
    }

    get inputFormControl() {
      return this._inputFormControl;
    }
  }

  let fixture: ComponentFixture<TestComponent>;
  let inputField: HTMLInputElement;

  const getInput = (fix: ComponentFixture<TestComponent>) => {
    const inputDebug = fix.debugElement.query(By.directive(MaskDirective));
    return inputDebug.nativeElement as HTMLInputElement;
  };

 beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [
        TestComponent,
        MaskDirective
      ]
    });
  });
    beforeEach(() => {
      fixture = TestBed.createComponent(TestComponent);
      fixture.detectChanges();
      inputField = getInput(fixture);
    });

    it("test", async () => {
      //Tests fails because there's no onChange callback
    });
}

根据我在“再也不会在实现Angular表单中的ControlValueAccessor时感到困惑”上阅读到的内容,我认为只需将FormControl添加到我的输入字段中就应该触发setupControl,但显然并非如此。我错过了什么?

2个回答

1

我这里也遇到了相同的问题,原因是registerOnChange在主要测试之后被调用,解决方法是使用fakeAsync包装TestBed.createComponent(TestComponent)。


1

你需要在configureTestingModule声明中导入FormsModule。

我有一点不同。使用ReactiveFormsModule和名为“directiveForm”的指令。

@Component({
  template: `<form [formGroup]="testForm"><input type="text" formControlName="testControl" directiveForm></form>`
})
class TestComponent {

  public testForm: FormGroup;

  constructor(private fb: FormBuilder) {

    this.testForm = this.fb.group({
      testControl: new FormControl()
    });
  }
}

describe('Directive Test', () => {

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        DirectiveForm,
        TestComponent
      ],
      imports: [DirectiveFormModule],
      schemas: [CUSTOM_ELEMENTS_SCHEMA]
    }).compileComponents();
  }));

这种方式对我来说很有效


我认为这里有一个打字错误,“imports: [DirectiveFormModule]”应该导入“ReactiveFormsModule”。 - Doug

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接