如何对 ngControl 用 @Self 装饰的反应性组件进行单元测试
Posted
技术标签:
【中文标题】如何对 ngControl 用 @Self 装饰的反应性组件进行单元测试【英文标题】:How to unit test a reactive component where ngControl is decorated with @Self 【发布时间】:2019-03-26 16:07:56 【问题描述】:我通过注入 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
组件的方法。
【问题讨论】:
【参考方案1】:如果有人偶然发现这个问题,我使用 TestBed 类的 overrideComponent() 方法解决了它。
注意:如果您认为您还有其他答案,请随时回答。
注入 NgControl:
beforeEach(async(() =>
TestBed.configureTestingModule(
declarations: [
TextInput, TextInputHost
],
imports: [
FormsModule, ReactiveFormsModule
]
)
.overrideComponent(TextInput,
set:
providers: [
provide: NgControl,
useValue: new FormControlDirective([], [], null, null)
]
);
));
【讨论】:
这是唯一有帮助的答案,因为我没有将 NgControl 注入我的构造函数,只是在文件中使用它?【参考方案2】:尝试在 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 装饰的反应性组件进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章
如何在角度 2 中将输入值转换为大写(传递给 ngControl 的值)