如何用Jasmine编写Angular单元测试移除URL中的place参数?
如何为移除URL中place参数的函数编写单元测试?
我有一个函数,负责检测URL中的place参数,若存在则移除该参数并更新location.href。尝试编写单元测试时遇到了"href is not declared configurable"的错误,求解决方法。
原服务代码
export class Auth0IdentityService extends IdentityService { constructor() {} removePlaces(): void { const url = new URL(window.location.href) if (url.searchParams.get("place")) { // 注:原代码多了一个左括号,需修正避免语法错误 url.searchParams.delete("place"); window.location.href = url.href; } } }
我的测试代码
it('should remove place from url', async () => { const spy = spyOnProperty(window.location, 'href', 'get').and.returnValue("http://localhost:3000/?place=xxxx"); component.removePlaces() expect (window.location.href).toBe ("http://localhost:3000/?place=xxxx") })
错误提示
运行测试后出现错误:"href is not declared configurable"
问题原因
window.location.href是浏览器原生属性,默认不可配置,直接用spyOnProperty拦截读写操作会触发上述错误。
解决方法
方法1:模拟可配置的window.location对象
在测试前重定义window.location为可配置的对象,测试完成后恢复原始对象:
it('should remove place from url', () => { // 保存原始location,测试后恢复 const originalLocation = window.location; // 创建模拟的location对象,支持读写 Object.defineProperty(window, 'location', { writable: true, configurable: true, value: new URL('http://localhost:3000/?place=xxxx') }); const service = new Auth0IdentityService(); service.removePlaces(); // 验证URL是否已移除place参数 expect(window.location.href).toBe('http://localhost:3000/'); // 恢复原始location window.location = originalLocation; });
方法2:抽离纯函数,降低依赖
把URL处理逻辑单独抽成纯函数,这样可以脱离window.location直接测试核心逻辑,再单独验证页面跳转行为:
修改后的服务代码
export class Auth0IdentityService extends IdentityService { constructor() {} removePlaces(): void { const updatedUrl = this.removePlaceParam(window.location.href); if (updatedUrl !== window.location.href) { window.location.href = updatedUrl; } } // 抽离的纯函数,仅负责URL参数处理 removePlaceParam(url: string): string { const urlObj = new URL(url); if (urlObj.searchParams.get('place')) { urlObj.searchParams.delete('place'); return urlObj.href; } return url; } }
对应的单元测试
// 测试纯函数的参数处理逻辑 it('should remove place parameter from URL', () => { const service = new Auth0IdentityService(); const testUrl = 'http://localhost:3000/?place=xxxx&foo=bar'; const result = service.removePlaceParam(testUrl); expect(result).toBe('http://localhost:3000/?foo=bar'); }); it('should return original URL if place parameter does not exist', () => { const service = new Auth0IdentityService(); const testUrl = 'http://localhost:3000/?foo=bar'; const result = service.removePlaceParam(testUrl); expect(result).toBe(testUrl); }); // 测试页面跳转逻辑 it('should update window location when place parameter exists', () => { const originalLocation = window.location; Object.defineProperty(window, 'location', { writable: true, configurable: true, value: { href: 'http://localhost:3000/?place=xxxx' } }); const service = new Auth0IdentityService(); service.removePlaces(); expect(window.location.href).toBe('http://localhost:3000/'); window.location = originalLocation; });
内容的提问来源于stack exchange,提问作者Thank A
相关产品推荐
相关产品推荐

