In my component I have a child component that looks like this:
<child-component #childComponent></childComponent>
In my parent component I then access this child component using @ViewChild and the read
parameter to get the ElementRef, and not the component reference. I need the ElementRef to ensure I can get some properties from nativeElement
that I need. So it's like this:
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';
}
}
}
So this works for the application, however I am writing the tests and mocking the child component, like this:
@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');
});
So the test will compile the component, and use the mocked child component values as the proper value and compute the value of this.position
, which is then asserted in the test.
However, when the { read: ElementRef }
parameter is set, the mock gets completely ignored by the TestBed, even though it's being added in the declarations array. If I remove { read: ElementRef }
, the mock is used in the test and it passes. But then my application doesn't work, as it is now getting the component reference, where the nativeElement
property doesn't exist, rather than the element reference.
So how do I get the ElementRef in my application and then in my test use the mock component?
Best Answer
I have fixed this by changing the architecture of the app. The child component now finds it's own offsetLeft property, and then puts it into an output EventEmitter to be picked up the parent component.
And then in the HTML, you just define the child component with output variable and method:
In the test, I then mock ElementRef for the child component and use it as a provider.