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

如何用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 23:50:32