如何在Jest测试中伪造StencilJS组件的Script onload事件以测试私有逻辑?
解决方案:伪造onload事件触发私有初始化函数
当然可以解决这个问题!在Jest测试环境(基于jsdom)中,外部脚本不会被实际加载,所以onload回调自然不会自动触发。我们可以通过mock外部函数+手动触发事件的方式来模拟这个流程,从而验证initialize()的逻辑。
核心思路
- Mock
addScript函数,让它返回一个我们能完全控制的模拟<script>元素,而不是真的创建并加载外部脚本。 - 在组件渲染完成后,手动触发这个模拟脚本的
onload回调(或load事件),从而触发组件内的this.initialize()。 - 通过Spy监听私有方法的调用,验证逻辑是否执行。
具体实现代码
假设你的组件名为GoogleMapsComponent,测试文件可以这样写:
import { newSpecPage } from '@stencil/core/testing'; import { GoogleMapsComponent } from './google-maps.component'; import { addScript } from '../utils/script-utils'; // 替换成你的addScript实际路径 // Mock addScript函数,让它返回我们预设的script元素 jest.mock('../utils/script-utils'); describe('GoogleMapsComponent', () => { let mockScriptElement: HTMLScriptElement; beforeEach(() => { // 创建模拟的script元素 mockScriptElement = document.createElement('script'); // 让mock的addScript返回这个元素 (addScript as jest.Mock).mockReturnValue(mockScriptElement); }); it('should call initialize() when the external script loads', async () => { // 渲染组件 const page = await newSpecPage({ components: [GoogleMapsComponent], html: '<google-maps></google-maps>', }); // 获取组件实例,用`as any`绕过TypeScript对私有方法的访问限制 const componentInstance = page.rootInstance as any; // 创建initialize方法的Spy,用于验证调用 const initializeSpy = jest.spyOn(componentInstance, 'initialize'); // 手动触发script的onload回调(两种方式任选其一) // 方式1:直接调用onload函数 mockScriptElement.onload?.(); // 方式2:派发load事件(更接近真实浏览器行为) // mockScriptElement.dispatchEvent(new Event('load')); // 验证initialize方法被调用 expect(initializeSpy).toHaveBeenCalled(); }); });
关键细节说明
- Mock
addScript:通过jest.mock拦截函数调用,避免测试中真的请求外部资源,同时让我们能控制返回的script元素。 - 访问私有方法:由于
initialize()是私有函数,TypeScript会阻止直接访问,所以我们用as any来绕过类型检查,这在测试场景中是合理的。 - 触发事件的两种方式:直接调用
onload函数和派发load事件都能触发回调,后者更贴近真实浏览器的事件触发流程,推荐使用。
这样就能在测试环境中完美模拟脚本加载完成的场景,验证initialize()内部的逻辑是否符合预期了。
内容的提问来源于stack exchange,提问作者maidi
相关产品推荐
相关产品推荐

