Reputation: 3393
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
Upvotes: 2
Views: 5172
Reputation: 12052
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.
Upvotes: 2
Reputation: 17059
I think the issue is that you need to actually resize the element, not simply fire the resize
event.
That is, you actually have to change the width, height or both.
So try the following.
it('resized function is called when element is resized', async(() => {
const fixture = TestBed.createComponent(ResizeTestComponent);
fixture.detectChanges();
const resizedSpy = spyOn(fixture.componentInstance, 'resized');
// this or some fixed values e.g. 800, 600.
window.resizeTo(
window.screen.availWidth / 2,
window.screen.availHeight / 2
);
expect(resizedSpy).toHaveBeenCalled();
}));
Upvotes: 0