我想根据收到的项目数量为弹出窗口生成一些容器。组件在开发和生产中按预期工作,但在单元测试中没有工作,因为查询列表。变化永远不会发生。我必须调用querylist.notifyChanges()作为变通方法。mapRef是一个Openlayers映射实例
HTML模板:
<ng-container *ngFor="let id of currentDivs">
<div class="popup" #popupContainer [id]="id"></div>
</ng-container>
组件:
@ViewChildren("popupContainer", { read: ElementRef })
popupContainers: QueryList<ElementRef<HTMLElement>>;
ngOnInit(): void {
//init map and other stuff...
init();
}
ngAfterViewInit(): void {
this.popupContainers.changes.subscribe(
(containers: QueryList<ElementRef>) => {
this._mapRef.getOverlays().clear();
containers.forEach((container) => {
//create overlay container for popup
const id = container.nativeElement.id;
if (!this._mapRef.getOverlayById(id)) {
const overlay = new Overlay({
id,
element: container.nativeElement,
autoPan: false,
});
this._mapRef.addOverlay(overlay);
}
});
}
);
}
init(): void {
bService.getItems().subscribe((items) => {
this.ngZone.runOutsideAngular(() => {
divs = items.map((item) =>item.id);
this.ngZone.run(() => {
this.currentDivs = divs;
this.cdr.detectChanges();
});
});
});
}
测试代码:
beforeEach((done) => {
aServiceSpy.getInfo.and.returnValue(of(infos));
bServiceSpy.getItems.and.returnValue(of(items));
fixture.detectChanges();
component.mapRef.once("rendercomplete", () => {
//I have to call notifyChanges() as a workaround
//component.popupContainers.notifyChanges()
done();
});
it("should populate popup",() => {
console.log(component.popupContainers)
// it actually has length == items.length,
//but component.popupContainers.changes in the actual code never emit
})
});
在Angular单元测试中,当QueryList发生变化时,应该自动调用querylist.changes
。有几件事需要注意
- 确保初始化后有查询的内容更改。看来你的考试内容从未改变过。您可以添加
this.popupContainers.changes.pipe(startWith(this.popupContainers))
以始终初始化订阅。 - 我没有看到你的代码有任何计时器停止
queryList
的变化,只是分享我的经验在这里。我在我的内容查询订阅中有一个delay(0)
,我在测试之前运行detectChanges
,这实际上导致测试在订阅发出之前结束。所以我把changeDetection
放进fakeAsync
进程解决了我的问题。
beforeEach(() => {
// Create component etc initialize
fixture.detectChanges();
});
describe('test', fakeAsync(() => {
// Test logic
}));
beforeEach(() => {
// Create component etc initialize
});
describe('test', fakeAsync(() => {
fixture.detectChanges();
// Test logic
}));