角度测试 - 无法读取未定义的属性"清除"



我有一个类似的组件

<select #tabSelect (change)="tabLoad($event.target.value)" class="mr-2">
<option value="tab1">First tab</option>
<option value="tab2">Second tab</option>
</select>

<div class="tab-content">
<div class="tab-pane fade show active">
<ng-template #tabContent></ng-template>
</div>
</div>

有两个选项卡,它们调用tabLoad((函数并发送参数单击了哪个选项卡。

export class DemoComponent implements OnInit {
@ViewChild('tabContent', { read: ViewContainerRef }) entry: ViewContainerRef;
activeTab: any = 'tab1';
constructor(private resolver: ComponentFactoryResolver) { }
ngOnInit() {
this.tabLoad(this.activeTab);
}
tabLoad(page) {
setTimeout(() => {
this.activeTab = page;
this.entry.clear();
if (page == 'tab1') {
const factory = this.resolver.resolveComponentFactory(Tab1Component);
console.log(this.entry);
this.entry.createComponent(factory);
} else if (page == 'tab2') {
const factory = this.resolver.resolveComponentFactory(Tab2Component);
this.entry.createComponent(factory);
}
}, 500);
}
}

在这个.tsfle中,我创建了一个名为entry的变量,它指向#tabContent.Tab内容加载组件取决于哪个页面是活动的。

我为这种行为写了一个测试套件,如下

fdescribe('DemoComponent', () => {
let component: DemoComponent;
let fixture: ComponentFixture<DemoComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [RouterModule.forRoot([]), SharedModule],
declarations: [Tab1Component, Tab2Component],
}).compileComponents().then(() => {
fixture = TestBed.createComponent(DemoComponent);
component = fixture.componentInstance;
});
}));
it('should set activeTab correctly and clear entry when tabLoad is called', fakeAsync(() => {
component.tabLoad("tab1");
flush();
expect(component.activeTab).toBe('tab1');
}));
});

当我调用This.entry.clear((;时,此测试失败并显示Cannot read property 'clear' of undefined。此外,console.log(this.entry);打印未定义。然后我决定在上添加fixture.detectChanges()compileComponents().then(() => {})作用域,但仍以相同方式失败。但当我在发球后转到页面时,一切都很好。

第一个fixture.detectChanges()调用ngOnInit,您需要在fakeAsync区域中调用它才能使flush生效,因为setTimeout是在ngOnInit调用上创建的。本质上,计时器需要在fakeAsync区域中创建。因此,尝试将fixture.detectChanges()放入测试(it块(中,并将其从.then中移除。

beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [RouterModule.forRoot([]), SharedModule],
declarations: [Tab1Component, Tab2Component],
}).compileComponents().then(() => {
fixture = TestBed.createComponent(DemoComponent);
component = fixture.componentInstance;
// !! remove fixture.detectChanges() from here
});
}));
it('should set activeTab correctly and clear entry when tabLoad is called', fakeAsync(() => {
// !! add it here
fixture.detectChanges();
component.tabLoad("tab1");
flush();
expect(component.activeTab).toBe('tab1');
}));

正如Petr所说,您可以使用ngAfterViewInit而不是使用500ms

试试这个:

export class DemoComponent implements OnInit, AfterViewInit { /* add AfterViewInit */
@ViewChild('tabContent', { read: ViewContainerRef }) entry: ViewContainerRef;
activeTab: any = 'tab1';
constructor(private resolver: ComponentFactoryResolver) { }
ngOnInit() {
}
ngAfterViewInit() {
this.tabLoad(this.activeTab);
}
tabLoad(page) {
this.activeTab = page;
this.entry.clear();
if (page == 'tab1') {
const factory = this.resolver.resolveComponentFactory(Tab1Component);
console.log(this.entry);
this.entry.createComponent(factory);
} else if (page == 'tab2') {
const factory = this.resolver.resolveComponentFactory(Tab2Component);
this.entry.createComponent(factory);
}
}
}

然后我认为你不需要fakeAsyncflush

最新更新