Issue
I have the following component which utilizes ResizeObserver (via https://www.npmjs.com/package/@juggle/resize-observer)
export class ResizeTestComponent implements OnInit {
constructor(public hostRef: ElementRef) {}
ngOnInit() {
const resizeObserver = new ResizeObserver(() => this.resized());
resizeObserver.observe(this.hostRef.nativeElement);
}
resized() {
console.log('resized');
}
}
If I change the window width manually, the component width changes and resized is output to the console via the resized function, as expected.
I want to write a Jasmine test to check if the resized function is called when the element is resized.
How do I trigger the resizeObserver?
I have tried sending a resize event but the resized function is not called:
it('resized function is called when element is resized', async(() => {
const fixture = TestBed.createComponent(ResizeTestComponent);
fixture.detectChanges();
const resizedSpy = spyOn(fixture.componentInstance, 'resized');
window.dispatchEvent(new Event('resize'));
expect(resizedSpy).toHaveBeenCalled();
}));
Stackblitz: https://stackblitz.com/edit/angular-testing-with-jasmine-f3vgbg?file=app%2Fresize-test.component.spec.ts
Solution
It is a bit tricky to test this you need so simulate an actual resize of of the component. Also the ResizeObserver runs outside the control of Angular so it behave strangely inside the tests. Your component registers the ResizeObserver to the component element which is not present at all in the HTML when you test the component directly. Because of this you need to perform this testing by using a wrapper component.
Here is my suggestion on how to test this.
describe('HostTestComponent', () => {
@Component({
selector: 'test-host',
template: `<resize-test></resize-test>`,
styles: [':host { width: 300px }'],
})
class HostComponent {}
let fixture: ComponentFixture<HostComponent>;
beforeAll(() => {
TestBed.initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
});
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule],
declarations: [ResizeTestComponent, HostComponent],
}).compileComponents();
fixture = TestBed.createComponent(HostComponent);
}));
it('resized function is called when element is resized', async(() => {
const resizeTestComponentDebugElement = fixture.debugElement.query(
By.directive(ResizeTestComponent)
);
const resizedSpy = spyOn(
resizeTestComponentDebugElement.componentInstance,
'resized'
);
resizedSpy.and.callThrough();
fixture.detectChanges();
setTimeout(() => { // process first resize when component is first drawn
fixture.whenStable().then(() => {
fixture.debugElement.nativeElement.style.width = '200px';
fixture.detectChanges();
setTimeout(() => { // process resize due to width change.
fixture.whenStable().then(() => {
expect(resizedSpy).toHaveBeenCalledTimes(2);
});
}, 0);
});
}, 0);
}));
});
As you can see I create the wrapper component and then change the width of the wrapper component that triggers a resize in the component. Also in this scenario actually two resize events happen first time on the initial draw of the component and the second on the actual resize. This is because the ngOnInit is called before the component is drawn.
Here is also a link to a fork of you StackBlitz where you can see it working.
Answered By - AlesD
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.