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

Angular应用中Cordova 'deviceready'事件的单元测试

我来帮你搞定这个单元测试的问题!针对Angular 5里依赖Cordova deviceready事件和版本插件的路由守卫,咱们可以分这几步来模拟和测试:

第一步:模拟Cordova全局对象与deviceready事件

单元测试是在浏览器环境跑的,没有真实的Cordova环境,所以首先得手动模拟全局的cordova对象和相关插件方法,还要能触发deviceready事件。

在你的测试文件(比如auth-guard.spec.ts)里,先在beforeEach块里做模拟:

beforeEach(() => {
  // 模拟Cordova全局对象和版本插件
  (window as any).cordova = {
    getAppVersion: {
      getVersionNumber: jasmine.createSpy('getVersionNumber').and.returnValue(Promise.resolve('1.0.0')),
      getBuildNumber: jasmine.createSpy('getBuildNumber').and.returnValue(Promise.resolve('123'))
    }
  };

  // 配置Angular测试模块
  TestBed.configureTestingModule({
    imports: [RouterTestingModule.withRoutes([
      { path: 'login', component: MockLoginComponent },
      { path: 'update', component: MockUpdateComponent }
    ])],
    providers: [AuthGuard]
  });
});

这里用Jasmine的createSpy来模拟版本插件的异步方法,返回预设的版本号和构建号。

然后,写个工具函数用来触发deviceready事件:

function triggerDeviceReady() {
  document.dispatchEvent(new Event('deviceready'));
}
第二步:编写不同场景的测试用例

接下来针对守卫的逻辑,分情况测试:

场景1:版本符合要求,允许进入登录页

it('should allow access to login when version is valid', fakeAsync(() => {
  const guard = TestBed.inject(AuthGuard);
  const router = TestBed.inject(Router);
  
  // 触发deviceready事件
  triggerDeviceReady();
  tick(); // 等待异步操作完成

  guard.canActivate({} as ActivatedRouteSnapshot, router.routerState.snapshot).then(result => {
    expect(result).toBe(true);
  });
}));

这里用fakeAsync和tick来处理Cordova插件返回的Promise异步操作,确保测试能等待结果。

场景2:版本不符合,重定向到更新页

先修改模拟的版本号为不符合要求的值,再测试:

it('should redirect to update page when version is invalid', fakeAsync(() => {
  // 修改模拟的版本号
  (window as any).cordova.getAppVersion.getVersionNumber.and.returnValue(Promise.resolve('0.9.0'));
  
  const guard = TestBed.inject(AuthGuard);
  const router = TestBed.inject(Router);
  
  triggerDeviceReady();
  tick();

  guard.canActivate({} as ActivatedRouteSnapshot, router.routerState.snapshot).then(result => {
    expect(result).toEqual(router.parseUrl('/update'));
  });
}));

场景3:deviceready未触发时的处理

如果你的守卫在deviceready未触发时会等待或者拒绝访问,也可以测试这个场景:

it('should block access until deviceready is triggered', () => {
  const guard = TestBed.inject(AuthGuard);
  
  // 不触发deviceready,直接调用守卫方法
  guard.canActivate({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot).then(result => {
    expect(result).toBe(false); // 或者根据你的实际逻辑调整断言
  });
});
第三步:优化测试的小技巧
  • 如果你把获取版本的逻辑封装成了单独的服务(比如AppVersionService),那可以直接模拟这个服务,不用直接操作全局的cordova对象,这样测试更解耦。比如:
    beforeEach(() => {
      const mockVersionService = jasmine.createSpyObj('AppVersionService', ['getVersion', 'getBuildNumber']);
      mockVersionService.getVersion.and.returnValue(Promise.resolve('1.0.0'));
      
      TestBed.configureTestingModule({
        providers: [
          AuthGuard,
          { provide: AppVersionService, useValue: mockVersionService }
        ]
      });
    });
    
  • Angular 5的测试语法和后续版本略有不同,确保用TestBed.inject(或者旧版本的TestBed.get)来获取服务实例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:08:55