You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 12中使用Karma和Jasmine测试ResizeObserver事件不生效问题

问题核心原因

你的代码本身没有逻辑错误,该问题是Karma测试环境下的共性问题,核心原因有两个:

  1. 你修改元素style.width后,浏览器不会自动触发重排(Reflow),ResizeObserver只有在元素实际布局尺寸发生变化时才会触发回调,未触发重排的情况下浏览器会认为元素尺寸没有变化,自然不会调用回调函数。
  2. 部分无头浏览器或旧版本Karma运行时对ResizeObserver的原生支持存在缺陷,也可能导致回调无法触发。

解决方案

方案1:主动触发重排(依赖原生API)

修改测试用例,修改元素尺寸后主动读取元素的布局属性强制触发重排,再等待Angular任务队列稳定后执行断言:

it('should resize when external is resized', (done) => {
  divResizeMe.style.width = '200px';
  // 主动读取offsetWidth触发浏览器重排
  void divResizeMe.offsetWidth;

  fixture.whenStable().then(() => {
    fixture.detectChanges();
    expect(component.resizable.dimensions).toBeTruthy();
    expect(component.resizable.dimensions?.width).toBe(200);
    done();
  });
});

该方案接近真实运行场景,但依然可能因为浏览器环境差异出现偶现的测试失败。

方案2:Mock ResizeObserver(更稳定的单元测试方案)

单元测试的核心是验证组件自身逻辑,不需要依赖浏览器原生ResizeObserver的行为,通过Mock观察者可以完全控制测试流程,避免环境差异导致的不稳定:

  1. 首先在测试文件全局作用域定义ResizeObserver的Mock类:
class ResizeObserverMock {
  observe = jasmine.createSpy('observe');
  unobserve = jasmine.createSpy('unobserve');
  disconnect = jasmine.createSpy('disconnect');

  // 手动触发回调的方法,模拟浏览器触发ResizeObserver
  trigger(entries: Partial<ResizeObserverEntry>[]) {
    const observerCallback = (window.ResizeObserver as jasmine.Spy).calls.mostRecent().args[0];
    observerCallback(entries, this);
  }
}
  1. 在测试的beforeEach钩子中替换原生ResizeObserver:
beforeEach(() => {
  window.ResizeObserver = jasmine.createSpy('ResizeObserver')
    .and.callFake(() => new ResizeObserverMock());
  
  // 其余原有初始化逻辑不变
  fixture = TestBed.createComponent(TestResizable);
  component = fixture.componentInstance;
  fixture.detectChanges();
  divResizeMe = fixture.nativeElement.querySelector('#resizeMe');
});
  1. 修改测试用例,手动触发观察者回调验证逻辑:
it('should resize when external is resized', () => {
  const observerInstance = (window.ResizeObserver as jasmine.Spy).calls.mostRecent().returnValue as ResizeObserverMock;
  
  // 模拟浏览器触发ResizeObserver回调,传入目标元素和新的尺寸
  observerInstance.trigger([
    {
      target: component.resizable.aDiv.nativeElement,
      contentRect: { width: 200, height: 100 }
    } as ResizeObserverEntry
  ]);

  fixture.detectChanges();
  expect(component.resizable.dimensions).toBeTruthy();
  expect(component.resizable.dimensions?.width).toBe(200);
});

该方案运行速度更快,结果稳定无偶现失败,是单元测试的优先选择。

内容的提问来源于stack exchange,提问作者Iogui

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 10:54:04