Angular 在角度测试中,nativeElement.getBoundingClientRect()始终返回0

Angular 在角度测试中,nativeElement.getBoundingClientRect()始终返回0,angular,typescript,jestjs,Angular,Typescript,Jestjs,我有一个角度组件(5.2),它相对于另一个元素的nativeElement.getBoundingClientRect()输出定位自身 在测试中,我用样式创建了一个包装器组件来模拟定位元素,但返回的ClientRect总是全零 有没有办法让Angular在DOM中实际定位我的元素 下面是我的TestComponent。在内部,组件将使用锚定.nativeElement.getBoundingClientRect()计算其固定位置 我不认为这有什么关系,但我正在使用Jest来执行测试 我试过使用和

我有一个角度组件(5.2),它相对于另一个元素的
nativeElement.getBoundingClientRect()
输出定位自身

在测试中,我用样式创建了一个包装器组件来模拟定位元素,但返回的
ClientRect
总是全零

有没有办法让Angular在DOM中实际定位我的元素

下面是我的
TestComponent
。在内部,
组件将使用
锚定.nativeElement.getBoundingClientRect()
计算其固定位置

我不认为这有什么关系,但我正在使用Jest来执行测试

我试过使用和不使用
async()

@组件({
选择器:“测试”,
风格:[`
:主持人{
宽度:1000px;
高度:1000px;
显示器:flex;
证明内容:中心;
对齐内容:居中对齐;
}
`],
模板:`
你好,世界
`
})
类TestComponent{
@ViewChild('按钮')
公共按钮元素:ElementRef;
}
描述('测试',()=>{
让夹具;
beforeach(异步(()=>{
TestBed.configureTestingModule({
声明:[TestComponent],
导入:[弹出模块]
}).compileComponents()。然后(()=>{
fixture=TestBed.createComponent(TestComponent);
fixture.detectChanges();
});
}));
它('应该定位',()=>{
常量按钮=fixture.componentInstance.buttonElement.nativeElement;
//这两种方法中的任何一种都会失败,因为按钮未定位。
//我还尝试使用按钮的固定位置。
//这将失败
expect(button.getBoundingClientRect().top).not.toEqual(0);
//这也将失败
返回fixture.whenRenderingDone()。然后(()=>{
expect(button.getBoundingClientRect().top).not.toEqual(0);
});
});
});

对我来说,只有当我在viewChild元素上使用此方法时,一切才开始工作,我声明如下:

@ViewChild('progress', { static: true }) progress; 
在这之后,in可以使用
getBoundingClientRect
方法

this.progress.nativeElement.getBoundingClientRect()
PS:当我使用ElementRef时,它对我不起作用。只有使用ViewChild才可以。

长话短说:

您只需要在ngAfterViewInit()钩子中使用
ElementRef
nativeElement
,测试将“看到”DOM中的元素

长读:

.getBoundingClientRect()
仅当元素已呈现且存在于DOM中时才起作用。今天,当我试图访问被单击的元素时,我遇到了这样的情况,并且使用
[routerLink]
它被路由器操作动态地重新呈现-我无法从视觉上识别这种行为。它会导致此元素消失,并且无法进行任何测量。接下来,渲染了一些类似的元素,但在ClientRect中为0,0,0

因此,如果您使用某些元素的动态重新呈现(如菜单或其他),则仅当元素消失、重新呈现或在“操作时”(单击等)时,您的
元素.getBoundingClientRect()
才会返回0,0,0,而DOM中还没有您的情况

因此,您需要等待,它将被重新渲染,下一步-您可以通过
.getBoundingClientRect()
获得它的测量值。对于
@ViewChild()
等待的最佳方式是
ngAfterViewInit()
hook,您可以在其中访问nativeElement(作为最佳方式)。此外,还有一些技巧,如:

private elementInited$ = new Subject();
public desiredElement: ElementRef;
@ViewChild('someElemRef') set setElementRef(el: ElementRef) {
  if (!!el) {
    this.desiredElement= el;
    this.elementInited$.next();
  }
}

ngOnInit() {
  this.elementInited$.subscribe((inited) => {
  // do stuff with nativeElement
  const values = this.desiredElement.nativeElement.getBoundingClientRect() // <== works!
  })
}
private elementInited$=new Subject();
公众期望元素:ElementRef;
@ViewChild('someElemRef')集合setElementRef(el:ElementRef){
如果(!!el){
此。desiredElement=el;
this.elementInited$.next();
}
}
恩戈尼尼特(){
this.elementInited$.subscribe((inited)=>{
//与nativeElement合作

const values=this.desiredElement.nativeElement.getBoundingClientRect()//我想这是一个计时问题。请尝试在每个
之前在
中创建组件,并用
async
包围。我已更新了示例以说明
async()的用法
是否存在
按钮元素.nativeElement
如果存在,您可以尝试访问
按钮.offsetHeight
(仅访问它,无需对该值执行任何操作)查看是否强制将按钮放置在页面中。@JeffFairley您解决了这个问题吗?我没有。我相信这是JSDOM问题。可能是故意的,因为IDK计算DOM大小需要多少成本。