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

Jest中测试页面加载URL读取函数:设置window.location遇阻的解决方案求助

解决Jest测试中修改window.location的问题

我完全懂你现在的困扰——在测试页面加载时读取URL的功能时,直接操作window.location总会抛出Not implemented: navigation (except hash changes)的错误,mock了assign方法又没法同步更新href,试了各种办法都不行,确实挺闹心的。

下面给你两个可行的解决方案,能同时满足assign被正确调用且href同步更新的需求:

方案一:自定义带getter/setter的mock Location对象

这个方法手动实现href的读写逻辑,让assign调用时自动更新href:

test('Correct load-state', () => {
  // 保存原始的location,方便测试后恢复
  const originalLocation = window.location;
  
  let currentHref = window.location.href;
  const mockLocation = {
    // 用getter返回当前href
    get href() {
      return currentHref;
    },
    // 用setter更新href值
    set href(newHref) {
      currentHref = newHref;
    },
    // 让assign方法内部调用href的setter
    assign: jest.fn(function(url) {
      this.href = url;
    })
  };

  // 替换window.location
  Object.defineProperty(window, 'location', {
    value: mockLocation,
    writable: true
  });

  // 测试逻辑
  window.location.assign('/about');
  // 断言assign被正确调用
  expect(mockLocation.assign).toHaveBeenCalledWith('/about');
  // 断言href已更新
  expect(window.location.href).toBe('/about');

  // 测试直接修改href
  window.location.href = '/contact';
  expect(window.location.href).toBe('/contact');

  // 测试后恢复原始location
  afterEach(() => {
    Object.defineProperty(window, 'location', {
      value: originalLocation,
      writable: false
    });
  });
});

方案二:利用URL对象模拟Location

URL对象本身就包含href、pathname、search等和Location一致的属性,用它来模拟会更接近真实环境,还能自动处理相对路径:

test('Correct load-state', () => {
  const originalLocation = window.location;
  
  // 创建一个URL对象,初始路径设为你需要测试的路径
  const mockUrl = new URL('/about', window.location.origin);
  // 给URL对象添加assign方法,调用时更新href
  mockUrl.assign = jest.fn(function(url) {
    this.href = new URL(url, this.origin).href;
  });

  // 替换window.location
  Object.defineProperty(window, 'location', {
    value: mockUrl,
    writable: true
  });

  // 测试调用assign
  window.location.assign('/products');
  expect(mockUrl.assign).toHaveBeenCalledWith('/products');
  // 此时href会是完整的URL,比如"http://localhost/products"
  expect(window.location.href).toBe(`${window.location.origin}/products`);
  // 还能直接用pathname等属性
  expect(window.location.pathname).toBe('/products');

  // 测试后恢复
  afterEach(() => {
    Object.defineProperty(window, 'location', {
      value: originalLocation,
      writable: false
    });
  });
});

为什么之前的方法无效?

你之前的mock对象里,href是一个固定的初始值,assign方法只是被调用,但没有修改href的逻辑,所以自然不会更新。上面的两种方案都给href加上了可更新的逻辑,同时让assign方法能触发这个更新,完美解决了你的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 05:24:06