Angular中如何用Jasmine+Karma测试window.location.href并阻止测试跳转
修复方案(无需修改业务代码)
你遇到的两个问题本质都是测试时直接操作了原生window.location.href导致的,只需要在测试用例中拦截href的赋值操作即可同时解决跳转和断言错误的问题:
修改a.component.spec.ts中的测试用例代码:
it('test redirect function', () => { // 监听window.location.href的set操作,stub方法会拦截原生赋值行为,避免页面跳转 const hrefSetSpy = spyOnProperty(window.location, 'href', 'set').and.stub(); component.redirect(); // 校验spy是否接收到了预期的URL参数 expect(hrefSetSpy).toHaveBeenCalledWith('https://sample.com'); });
这个方案的原理是利用Jasmine的spyOnProperty监听href属性的setter,and.stub()会拦截原生的赋值逻辑,不会真的修改浏览器地址,自然也不会触发跳转,同时可以通过校验spy的调用参数来确认赋值是否符合预期。
提示:如果部分浏览器环境下因安全限制无法spy原生
window.location.href的setter,直接使用下面的优化方案即可。
更易测试的优化方案
如果后续有调整需求,推荐用Angular依赖注入封装全局window对象,完全避免测试时污染全局环境:
1. 定义全局Window注入令牌
新增src/app/tokens/window.token.ts:
import { InjectionToken, FactoryProvider } from '@angular/core'; export const WINDOW = new InjectionToken<Window>('WindowToken'); export function windowFactory(): Window { return window; } export const WINDOW_PROVIDER: FactoryProvider = { provide: WINDOW, useFactory: windowFactory };
2. 模块中注册提供者
在你的功能模块或者根模块的providers数组中加入WINDOW_PROVIDER。
3. 改造业务组件
修改a.component.ts:
import { Component, OnInit, Inject } from '@angular/core'; import { Service } from 'services/service'; import { WINDOW } from 'src/app/tokens/window.token'; @Component({ selector: 'a', templateUrl: './a.component.html', styleUrls: ['./a.component.scss'] }) export class AComponent implements OnInit { constructor( private service: Service, @Inject(WINDOW) private window: Window ) {} ngOnInit(): void {} redirect() { this.window.location.href = 'https://sample.com' } }
4. 改造测试用例
修改a.component.spec.ts的测试配置,直接注入mock的window对象:
describe('#AComponent', () => { let component: AComponent; let fixture: ComponentFixture<AComponent>; // 定义mock window对象 const mockWindow = { location: { href: '' } }; beforeEach(async(() => { TestBed.configureTestingModule({ imports: [HttpClientModule], declarations: [AComponent], // 用mock对象替换原生window providers: [{ provide: WINDOW, useValue: mockWindow }] }).compileComponents(); })); // 其余基础配置保持不变 it('test redirect function', () => { component.redirect(); // 直接校验mock对象的属性即可 expect(mockWindow.location.href).toEqual('https://sample.com'); }); });
这个方案完全不会触及全局原生window对象,从根源上避免了测试时触发页面跳转的问题,也更符合Angular的依赖注入设计规范。
内容的提问来源于stack exchange,提问作者Ryo
相关产品推荐
相关产品推荐

