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
相关产品推荐
相关产品推荐

