如何从 Jasmine 测试中触发 ResizeObserver?

How can I trigger ResizeObserver from a Jasmine test?

我有以下组件利用 ResizeObserver(通过 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');
  }
}

如果我手动更改 window 宽度,组件宽度会更改,并且 resized 会按预期通过 resized 函数输出到控制台。

我想编写一个 Jasmine 测试来检查 resized 函数是否在调整元素大小时被调用。

如何触发 resizeObserver

我已尝试发送 resize 事件,但未调用 resized 函数:

 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

我认为问题在于您需要实际调整元素的大小,而不是简单地触发 resize 事件。

也就是说,您实际上必须更改宽度、高度或两者。

所以试试下面的方法。

 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();
  }));

测试这个有点棘手,所以需要模拟组件的实际大小调整。此外 ResizeObserver 在 Angular 的控制之外运行,因此它在测试中表现得很奇怪。当您直接测试组件时,您的组件将 ResizeObserver 注册到 HTML 中根本不存在的组件元素。因此,您需要使用包装器组件来执行此测试。

这是我关于如何测试它的建议。

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);
  }));
});

如您所见,我创建了包装器组件,然后更改了触发组件调整大小的包装器组件的宽度。同样在这种情况下,实际上有两个调整大小事件第一次发生在组件的初始绘制上,第二次发生在实际调整大小时。这是因为在绘制组件之前调用了 ngOnInit

这里还有一个 link to a fork of you StackBlitz 你可以看到它在工作。