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

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尚未执行。

修复步骤

  1. 等待异步操作完成:给测试函数添加async/await,等待onYesClick的异步逻辑执行完毕。
  2. 跟踪异步方法调用:用Jest的spyOn监听activateUpdate,确保能正确等待其完成。
  3. 确保模拟的可修改性:给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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 19:05:18