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

Angular 5:如何测试依赖window/webkitTemporaryStorage的StorageService?

解决Angular StorageService单元测试中Mock window/webkitTemporaryStorage的问题

我完全理解你遇到的困扰——直接操作window或navigator.webkitTemporaryStorage时会碰到只读属性的限制,而且spyOn的方式也没达到预期效果。下面给你两种可行的测试方案,附带详细的代码示例:

方案一:通过Mock全局navigator对象实现测试

这种方式贴合Angular测试的规范,我们可以在测试初始化阶段覆盖全局的navigator属性:

import { TestBed } from '@angular/core/testing';
import { StorageService } from './storage.service';

describe('StorageService', () => {
  let service: StorageService;
  let mockQueryUsageAndQuota: jasmine.Spy;

  beforeEach(() => {
    // 创建Mock的webkitTemporaryStorage对象
    const mockWebkitStorage = {
      queryUsageAndQuota: jasmine.createSpy('queryUsageAndQuota').and.callFake((callback) => {
        // 默认传入80%使用率的测试数据
        callback(800, 1000);
      })
    };

    // 覆盖全局navigator的webkitTemporaryStorage属性
    (window.navigator as any).webkitTemporaryStorage = mockWebkitStorage;

    TestBed.configureTestingModule({
      providers: [StorageService]
    });

    service = TestBed.inject(StorageService);
    mockQueryUsageAndQuota = (window.navigator as any).webkitTemporaryStorage.queryUsageAndQuota;
  });

  it('should return true when used storage is within 80% of granted quota', (done) => {
    service.hasAvailableStorage().subscribe(result => {
      expect(result).toBe(true);
      expect(mockQueryUsageAndQuota).toHaveBeenCalled();
      done(); // 异步Observable测试必须调用done通知完成
    });
  });

  it('should return false when used storage exceeds 80% of granted quota', (done) => {
    // 重新Mock回调逻辑,传入超过阈值的数据
    mockQueryUsageAndQuota.and.callFake((callback) => {
      callback(900, 1000);
    });

    service.hasAvailableStorage().subscribe(result => {
      expect(result).toBe(false);
      expect(mockQueryUsageAndQuota).toHaveBeenCalled();
      done();
    });
  });
});

方案二:使用spyOnProperty处理只读属性

如果直接赋值webkitTemporaryStorage时报错(因为它是只读属性),可以用spyOnProperty来模拟这个只读属性:

import { TestBed } from '@angular/core/testing';
import { StorageService } from './storage.service';

describe('StorageService', () => {
  let service: StorageService;
  let mockWebkitStorage: { queryUsageAndQuota: jasmine.Spy };

  beforeEach(() => {
    mockWebkitStorage = {
      queryUsageAndQuota: jasmine.createSpy('queryUsageAndQuota')
    };

    // 用spyOnProperty模拟只读的webkitTemporaryStorage属性
    spyOnProperty(window.navigator, 'webkitTemporaryStorage', 'get').and.returnValue(mockWebkitStorage);

    TestBed.configureTestingModule({
      providers: [StorageService]
    });

    service = TestBed.inject(StorageService);
  });

  it('should emit true when usage is under 80%', (done) => {
    mockWebkitStorage.queryUsageAndQuota.and.callFake((callback) => {
      callback(400, 500); // 80%使用率场景
    });

    service.hasAvailableStorage().subscribe(res => {
      expect(res).toBe(true);
      expect(mockWebkitStorage.queryUsageAndQuota).toHaveBeenCalled();
      done();
    });
  });
});

核心注意事项

  • 因为hasAvailableStorage返回的是异步Observable,测试时必须使用done回调来通知测试框架异步操作完成,否则测试会提前结束导致断言失败。
  • 每个beforeEach会重新初始化测试环境,所以不需要额外恢复原生的window或navigator对象。
  • 如果你的项目使用RxJS 6+版本,注意Observable.create的写法已经更新,但测试逻辑可以保持一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:26:45