正如我描述in this answer一样,我创建了一个自定义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
});
}
基于我在"Never again be confused when implementing ControlValueAccessor in Angular forms"上所读的内容,我假设仅向我的输入字段添加一个FormControl应该会触发setupControl,但事实并非如此。我想念什么?
答案 0 :(得分:0)
您需要在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();
}));
这种方式对我有用
答案 1 :(得分:0)
在这里遇到了同样的问题,对我来说,原因是在主测试后调用了registerOnChange,并且此修复程序将TestBed.createComponent(TestComponent)包装在fakeAsync中