Angular PWA更新弹窗Jest测试失败:修复reload未调用问题
修复Jest测试中AppUpdateDialog的reload调用失败问题
问题场景
开发了一个PWA的AppUpdateDialog组件,当用户同意更新时,会激活Service Worker更新并重新加载页面。但Jest测试的最后一个用例执行失败,报错:
Expected number of calls: >= 1
Received number of calls: 0
测试代码如下:
describe('AppUpdateDialog', () => { let component: AppUpdateDialog; let fixture: ComponentFixture<AppUpdateDialog>; const dialogMock = { close: () => { // Empty method for testing }, }; const swUpdateMock = { activateUpdate: () => { return Promise.resolve(); }, }; beforeEach(async () => { TestBed.configureTestingModule({ declarations: [AppUpdateDialog], imports: [ MatIconModule, RouterTestingModule, MatDialogModule, ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production, registrationStrategy: 'registerImmediately', }), ], providers: [ { provide: MatDialogRef, useValue: dialogMock, }, { provide: SwUpdate, useValue: swUpdateMock }, ], }).compileComponents(); fixture = TestBed.createComponent(AppUpdateDialog); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); it('should render correctly', () => { expect(fixture).toMatchSnapshot(); }); it('should close the dialog', () => { jest.spyOn(component.dialogRef, 'close'); component.onNoClick(); expect(component.dialogRef.close).toHaveBeenCalled(); }); it('should activate update and reload on yes click', async () => { const mockReload = jest.fn(); const mockLocation = { reload: mockReload }; Object.defineProperty(window, 'location', { value: mockLocation }); component.onYesClick(); expect(mockReload).toHaveBeenCalled(); }); });
问题原因
onYesClick方法内部调用了异步的swUpdate.activateUpdate(),测试中直接调用component.onYesClick()后立刻断言reload被调用,此时异步操作还未完成,reload尚未执行。
修复步骤
- 等待异步操作完成:给测试函数添加
async/await,等待onYesClick的异步逻辑执行完毕。 - 跟踪异步方法调用:用Jest的
spyOn监听activateUpdate,确保能正确等待其完成。 - 确保模拟的可修改性:给
window.location的模拟添加writable: true,避免后续测试出现冲突。
修改后的测试用例代码
it('should activate update and reload on yes click', async () => { // 监听activateUpdate方法,保留原异步实现 const activateSpy = jest.spyOn(swUpdateMock, 'activateUpdate').mockResolvedValue(); // 模拟window.location.reload,设置可写避免后续测试冲突 const mockReload = jest.fn(); Object.defineProperty(window, 'location', { value: { reload: mockReload }, writable: true }); // 等待onYesClick的异步操作全部完成 await component.onYesClick(); // 断言activateUpdate和reload都被调用 expect(activateSpy).toHaveBeenCalled(); expect(mockReload).toHaveBeenCalled(); // 如果组件中还调用了dialogRef.close,可添加额外断言 const closeSpy = jest.spyOn(component.dialogRef, 'close'); expect(closeSpy).toHaveBeenCalled(); });
组件代码配合要求
确保AppUpdateDialog的onYesClick方法返回Promise,示例:
async onYesClick() { await this.swUpdate.activateUpdate(); window.location.reload(); this.dialogRef.close(); }
内容的提问来源于stack exchange,提问作者Developer
相关产品推荐
相关产品推荐

