Angular 12中使用Karma和Jasmine测试ResizeObserver事件不生效问题
问题核心原因
你的代码本身没有逻辑错误,该问题是Karma测试环境下的共性问题,核心原因有两个:
- 你修改元素
style.width后,浏览器不会自动触发重排(Reflow),ResizeObserver只有在元素实际布局尺寸发生变化时才会触发回调,未触发重排的情况下浏览器会认为元素尺寸没有变化,自然不会调用回调函数。 - 部分无头浏览器或旧版本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观察者可以完全控制测试流程,避免环境差异导致的不稳定:
- 首先在测试文件全局作用域定义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); } }
- 在测试的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'); });
- 修改测试用例,手动触发观察者回调验证逻辑:
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
相关产品推荐
相关产品推荐

