wlf
wlf

Reputation: 3393

How can I trigger ResizeObserver from a Jasmine test?

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

Answers (2)

Aleš Doganoc
Aleš Doganoc

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

Fraser
Fraser

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

Related Questions