gpt4 book ai didi

javascript - 使用@ViewChild {读取: ElementRef } of component causes unit test to fail

转载 作者:行者123 更新时间:2023-11-28 03:54:34 28 4
gpt4 key购买 nike

在我的组件中,我有一个如下所示的子组件:

<child-component #childComponent></childComponent>

然后,在我的父组件中,我使用 @ViewChild 和 read 参数访问此子组件以获取 ElementRef,而不是组件引用。我需要 ElementRef 来确保我可以从 nativeElement 获取我需要的一些属性。所以它是这样的:

export class ParentComponent {
@ViewChild('childComponent', { read: ElementRef }) public childComponent: ElementRef;
public position: string;

// some way down the code
private someMethod() {
if (this.childComponent.nativeElement.offsetLeft > 500) {
this.position = 'left';
} else {
this.position = 'right';
}
}
}

所以这适用于应用程序,但是我正在编写测试并模拟子组件,如下所示:

@Component({
selector: 'child-component',
template: ''
})
class ChildComponentMockComponent {
private nativeElement = {
get offsetLeft() {
return 600
}
};
}

beforeEach(async(() => TestBed.configureTestingModule({
imports: [ ... ],
declarations: [ ParentComponent, ChildComponentMockComponent ],
providers: [ ... ],
schemas: [ NO_ERRORS_SCHEMA ]
}).compileComponents()));

it('should have the correct position, based on position of child-component', () => {
spyOn(component, 'someMethod');
expect(component.someMethod).toHaveBeenCalled();
expect(component.position).toBe('left');
});

因此测试将编译组件,并使用模拟的子组件值作为正确的值并计算 this.position 的值,然后在测试中断言该值。

但是,当设置 { read: ElementRef } 参数时,TestBed 会完全忽略模拟,即使它已添加到声明数组中。如果我删除 { read: ElementRef },则模拟将在测试中使用并且通过。但随后我的应用程序无法工作,因为它现在获取的是组件引用,而 nativeElement 属性不存在,而不是元素引用。

那么如何在应用程序中获取 ElementRef,然后在测试中使用模拟组件?

最佳答案

我通过更改应用程序的架构解决了这个问题。子组件现在找到它自己的 offsetLeft 属性,然后将其放入输出 EventEmitter 中以供父组件拾取。

export class ChildComponent implements AfterViewInit {
@Output() offsetPosition: EventEmitter<number> = new EventEmitter<number>();

constructor(private el: ElementRef) {}

public ngAfterViewInit() {
this.offsetPosition.emit(this.el.nativeElement.offsetLeft);
}
}

export class ParentComponent implements AfterViewInit {
public childComponentOffset: number;

public ngAfterViewInit() {
setTimeout(() => {
// this.childComponentOffset is available
// needs to be in setTimeout to prevent ExpressionChangedAfterItHasBeenCheckedError
// more info: https://blog.angularindepth.com/everything-you-need-to-know-about-the-expressionchangedafterithasbeencheckederror-error-e3fd9ce7dbb4
}
}

public getChildComponentOffset(position: number): void {
this.childComponentOffset = position;
}
}

然后在 HTML 中,您只需定义带有输出变量和方法的子组件:

<child-component (offsetPosition)="getChildComponentOffset($event)"></child-component>

在测试中,我随后模拟子组件的 ElementRef 并将其用作提供程序。

const mockElementRef: any = {
get offsetLeft() {
return position;
}
};

beforeEach(async(() => TestBed.configureTestingModule({
imports: [ ... ],
declarations: [ ParentComponent ],
providers: [
{ provide: ElementRef, useValue: mockElementRef }
],
schemas: [ NO_ERRORS_SCHEMA ]
}).compileComponents()));

it('should have the correct position, based on position of child-component', (done) => {
component.getChildComponentOffset(600);
setTimeout(() => expect(component.position).toBe('left'));
done();
});

关于javascript - 使用@ViewChild {读取: ElementRef } of component causes unit test to fail,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47673211/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com