如何对 ngControl 用 @Self 装饰的反应组件进行单元测试
How to unit test a reactive component where ngControl is decorated with @Self
我通过注入 NgControl 编写了一个响应式组件,并使用 @Self 装饰器对其进行了装饰。我的问题与此类组件的单元测试有关。
请看下面的代码:
免责声明:我已经快速复制了代码并进行了一些内联更改。所以,这可能不是编译器满意的代码。
我的反应组件:
@Component({
selector: 'text-input',
templateUrl: '<input type="text" class="native_input" />'
})
class TextInput implements ControlValueAccessor {
protected constructor(@Self() public controlDir: NgControl) {
this.controlDir.valueAccessor = this;
}
// ...followed by other ControlValueAccessor methods
}
单元测试:
describe('TextInput -', () => {
let fixture: ComponentFixture<TextInputHost>;
let textInput: TextInput;
let inputElement: HTMLInputElement;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
TextInput, TextInputHost
],
imports: [
FormsModule, ReactiveFormsModule
]
});
}));
beforeEach(fakeAsync(() => {
fixture = getTestBed().createComponent(TextInputHost);
textInput = fixture.componentInstance.textInputComponent;
textInput.writeValue('TestValue');
inputElement = fixture.debugElement
.query(By.css('native_input')).nativeElement;
fixture.detectChanges();
tick();
}));
it('Should have the initial value applied.', () => {
expect(inputElement.value).toBe('TestValue');
});
});
// Host component
@Component({
template: `
<form [formGroup]="pageForm">
<text-input formControlName="testInput">
</text-input>
</form>`
})
class TextInputHost {
@ViewChild(TextInput)
public textInputComponent: TextInput;
public pageForm: FormGroup = new FormGroup({
testInput: new FormControl('Initial Value')
});
}
每当我尝试 运行 上述单元测试时。它失败并出现以下错误:
Template parse errors: No provider for NgControl --> <text-input>....</text-input>
所以我正在寻找一种方法来成功 运行 上述单元测试。什么,我正在寻找一种将 NgControl 注入 TextInput
组件的方法。
如果有人偶然发现这个问题,我使用 TestBed 的 overrideComponent() 方法解决了它 class。
注意:如果您认为您还有其他答案,请随时回答。
要注入 NgControl:
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
TextInput, TextInputHost
],
imports: [
FormsModule, ReactiveFormsModule
]
})
.overrideComponent(TextInput, {
set: {
providers: [
{
provide: NgControl,
useValue: new FormControlDirective([], [], null, null)
}
]
}
});
}));
尝试在 controlDir 的构造函数中的 @Self 之前添加装饰器 @Optional 属性。
@Component({
selector: 'text-input',
templateUrl: '<input type="text" class="native_input" />'
})
class TextInput implements ControlValueAccessor {
protected constructor(
@Optional() // <- in this place
@Self() public controlDir: NgControl) {
this.controlDir.valueAccessor = this;
}
// ...followed by other ControlValueAccessor methods
}
并且您可以在测试中从 TestBed 中删除 overrideComponent 方法。
希望对你有帮助。
我通过注入 NgControl 编写了一个响应式组件,并使用 @Self 装饰器对其进行了装饰。我的问题与此类组件的单元测试有关。 请看下面的代码:
免责声明:我已经快速复制了代码并进行了一些内联更改。所以,这可能不是编译器满意的代码。
我的反应组件:
@Component({
selector: 'text-input',
templateUrl: '<input type="text" class="native_input" />'
})
class TextInput implements ControlValueAccessor {
protected constructor(@Self() public controlDir: NgControl) {
this.controlDir.valueAccessor = this;
}
// ...followed by other ControlValueAccessor methods
}
单元测试:
describe('TextInput -', () => {
let fixture: ComponentFixture<TextInputHost>;
let textInput: TextInput;
let inputElement: HTMLInputElement;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
TextInput, TextInputHost
],
imports: [
FormsModule, ReactiveFormsModule
]
});
}));
beforeEach(fakeAsync(() => {
fixture = getTestBed().createComponent(TextInputHost);
textInput = fixture.componentInstance.textInputComponent;
textInput.writeValue('TestValue');
inputElement = fixture.debugElement
.query(By.css('native_input')).nativeElement;
fixture.detectChanges();
tick();
}));
it('Should have the initial value applied.', () => {
expect(inputElement.value).toBe('TestValue');
});
});
// Host component
@Component({
template: `
<form [formGroup]="pageForm">
<text-input formControlName="testInput">
</text-input>
</form>`
})
class TextInputHost {
@ViewChild(TextInput)
public textInputComponent: TextInput;
public pageForm: FormGroup = new FormGroup({
testInput: new FormControl('Initial Value')
});
}
每当我尝试 运行 上述单元测试时。它失败并出现以下错误:
Template parse errors: No provider for NgControl --> <text-input>....</text-input>
所以我正在寻找一种方法来成功 运行 上述单元测试。什么,我正在寻找一种将 NgControl 注入 TextInput
组件的方法。
如果有人偶然发现这个问题,我使用 TestBed 的 overrideComponent() 方法解决了它 class。
注意:如果您认为您还有其他答案,请随时回答。
要注入 NgControl:
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
TextInput, TextInputHost
],
imports: [
FormsModule, ReactiveFormsModule
]
})
.overrideComponent(TextInput, {
set: {
providers: [
{
provide: NgControl,
useValue: new FormControlDirective([], [], null, null)
}
]
}
});
}));
尝试在 controlDir 的构造函数中的 @Self 之前添加装饰器 @Optional 属性。
@Component({
selector: 'text-input',
templateUrl: '<input type="text" class="native_input" />'
})
class TextInput implements ControlValueAccessor {
protected constructor(
@Optional() // <- in this place
@Self() public controlDir: NgControl) {
this.controlDir.valueAccessor = this;
}
// ...followed by other ControlValueAccessor methods
}
并且您可以在测试中从 TestBed 中删除 overrideComponent 方法。
希望对你有帮助。