如何使用Jest + Vuejs模拟window.location.href?

Hoa*_*Son 14 unit-testing jasmine vue.js vuejs2 vue-test-utils

目前,我正在为我的项目实施单元测试,并且其中包含一个文件window.location.href

我想对此进行测试,这是我的示例代码:

it("method A should work correctly", () => {
      const url = "http://dummy.com";
      Object.defineProperty(window.location, "href", {
        value: url,
        writable: true
      });
      const data = {
        id: "123",
        name: null
      };
      window.location.href = url;
      wrapper.vm.methodA(data);
      expect(window.location.href).toEqual(url);
    });
Run Code Online (Sandbox Code Playgroud)

但是我得到这个错误:

TypeError: Cannot redefine property: href
        at Function.defineProperty (<anonymous>)
Run Code Online (Sandbox Code Playgroud)

我尝试了一些解决方案,但没有解决。我需要一些提示来帮助我摆脱困境。请帮助。

jab*_*tta 59

2020 更新


基本的

URL的对象有很多相同的功能与定位的对象。换句话说,它包括性能,如pathnamesearchhostname在大多数情况下,你可以做以下的,等于是:

delete window.location
window.location = new URL('https://www.example.com')
Run Code Online (Sandbox Code Playgroud)

先进的

您还可以模拟您可能需要的Location 方法,这些方法在 URL 界面上不存在:

const location = new URL('https://www.example.com')
location.assign = jest.fn()
location.replace = jest.fn()
location.reload = jest.fn()

delete window.location
window.location = location
Run Code Online (Sandbox Code Playgroud)

  • 使用打字稿更新,“删除 window.location”将触发错误““删除”运算符的操作数必须是可选的” (11认同)
  • 要解决该 TS 错误,您可以执行“delete (window as any).location;” (9认同)
  • 在删除 window.location 行上方添加 // @ts-ignore; 如果你必须 (5认同)
  • `Reflect.deleteProperty(global.window, 'location')` 处理这个问题,没有 ts 错误 (2认同)
  • 为什么要删除“window.location”?它不能仅通过“window.location = location”覆盖它吗? (2认同)

mav*_*ava 25

你可以试试:

global.window = Object.create(window);
const url = "http://dummy.com";
Object.defineProperty(window, 'location', {
  value: {
    href: url
  }
});
expect(window.location.href).toEqual(url);  
Run Code Online (Sandbox Code Playgroud)

看看该问题的Jest Issue
Jest Issue

  • 对我来说,使用“global”不起作用,我删除了“global.”,并且还需要添加“writable: true”,否则一旦设置,其他测试就无法更改它。 (5认同)
  • 打字错误:位置不可重写 (2认同)

ser*_*inc 24

来自 GitHub 的2019 年解决方案:

delete global.window.location;
global.window = Object.create(window);
global.window.location = {
  port: '123',
  protocol: 'http:',
  hostname: 'localhost',
};
Run Code Online (Sandbox Code Playgroud)


Jua*_*ago 8

提供的许多示例并未模拟原始 Location 对象的属性。

我所做的只是用 URL 替换 Location 对象 (window.location),因为 URL 包含与 Location 对象相同的属性,如“href”、“search”、“hash”、“host”。

Setter 和 Getter 的工作方式也与 Location 对象完全相同。

例子:

const realLocation = window.location;

describe('My test', () => {

    afterEach(() => {
        window.location = realLocation;
    });

    test('My test func', () => {

        // @ts-ignore
        delete window.location;

        // @ts-ignore
        window.location = new URL('http://google.com');

        console.log(window.location.href);

        // ...
    });
});
Run Code Online (Sandbox Code Playgroud)


Kai*_*ido 7

最好的可能是创建一个新的URL实例,以便它分析你的字符串一样location.href做,所以它更新的所有属性location一样.hash.search.protocol等。

it("method A should work correctly", () => {
  const url = "http://dummy.com/";
  Object.defineProperty(window, "location", {
    value: new URL(url)
  } );

  window.location.href = url;
  expect(window.location.href).toEqual(url);

  window.location.href += "#bar"
  expect(window.location.hash).toEqual("#bar");
});
Run Code Online (Sandbox Code Playgroud)

https://repl.it/repls/VoluminousHauntingFunctions


Zgr*_*doo 6

2022 年 TS

const orgLocation: Location = window.location;

beforeEach(() => {
  delete (window as any).location;
  window.location = (new URL("http://localhost") as any);
  window.location.assign = ({configurable:true, value:jest.fn()} as any);
  window.location.replace = ({configurable:true, value:jest.fn()} as any);
  window.location.reload = ({configurable:true, value:jest.fn()} as any);
});

afterAll(() => window.location = orgLocation);
Run Code Online (Sandbox Code Playgroud)


Hoa*_*Son 5

我已解决此问题writable: true,方法是将其添加并移至beforeEach

这是我的示例代码:

global.window = Object.create(window);
const url = "http://dummy.com";
Object.defineProperty(window, "location", {
    value: {
       href: url
    },
    writable: true
});
Run Code Online (Sandbox Code Playgroud)

  • 此解决方案还适用于在 Jest 测试中覆盖“window.location.hostname”。我需要“writable: true”才能多次更改“主机名”。 (2认同)

Dev*_*ark 5

@testing-library/react2020 年 window.location.assign 的工作示例:

  afterEach(cleanup)
  beforeEach(() => {
    Object.defineProperty(window, 'location', {
      writable: true,
      value: { assign: jest.fn() }
    })
  })
Run Code Online (Sandbox Code Playgroud)

  • `writable: true` 对于我的单元测试的工作是必需的,否则后续测试将无法将其覆盖为其他内容。谢谢 (3认同)