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

问题描述 投票:0回答:21

目前,我正在为我的项目实施单元测试,并且有一个文件包含

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);
    });

但我收到此错误:

TypeError: Cannot redefine property: href
        at Function.defineProperty (<anonymous>)

我该如何解决?

vue.js unit-testing jestjs jasmine vue-test-utils
21个回答
191
投票

你可以尝试:

window = Object.create(window);
const url = "http://dummy.com";
Object.defineProperty(window, 'location', {
  value: {
    href: url
  },
  writable: true // possibility to override
});
expect(window.location.href).toEqual(url);  

查看该问题的 Jest Issue:
笑话问题


113
投票

2020更新


基本

URL 对象 具有许多与 Location 对象 相同的功能。换句话说,它包括诸如

pathname
search
hostname
等属性。因此,对于大多数情况,您可以执行以下操作:

delete window.location
window.location = new URL('https://www.example.com')

高级

您还可以模拟您可能需要的位置方法,这些方法在 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

48
投票

我通过添加

writable: true
并将其移至
beforeEach

解决了这个问题

这是我的示例代码:

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

25
投票

2019 年解决方案来自 GitHub

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

21
投票

最好的方法可能是创建一个新的

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");
});

https://repl.it/repls/VoluminousHauntingFunctions


13
投票

2020 年使用

@testing-library/react
进行 window.location.assign 的工作示例:

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

12
投票

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

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

Setter 和 Getters 的工作方式与 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);

        // ...
    });
});

4
投票

扩展@jabacchetta 的解决方案以避免此设置渗透到其他测试中:

describe("Example", () => {
  let location;

  beforeEach(() => {
    const url = "https://example.com";
    location = window.location;
    const mockLocation = new URL(url);
    mockLocation.replace = jest.fn();
    delete window.location;
    window.location = mockLocation;
  });

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

4
投票

你可以尝试jest-location-mock

npm install --save-dev jest-location-mock

更新

jest
文件中的
jest.config.js
配置或
jest
内的
package.json
道具:

setupFilesAfterEnv: [ "./config/jest-setup.js" ]

创建

jest-setup.js

import "jest-location-mock";

用途:

it("should call assign with a relative url", () => {
    window.location.assign("/relative-url");
    expect(window.location).not.toBeAt("/");
    expect(window.location).toBeAt("/relative-url");
});

4
投票

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);

3
投票

如何在代码库中重新分配 window.location;我们为 Jest 测试找到的最简单的工作设置:

const realLocation = window.location;

beforeEach(() => {
  delete window.location;
});

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

2
投票

你可以尝试一个帮手:

const setURL = url => global.jsdom.reconfigure({url});

describe('Test current location', () => {
  test('with GET parameter', () => {
    setURL('https://test.com?foo=bar');
    // ...your test here
  });
});

2
投票

我使用以下方式使用 Jest 的模拟机制(

jest.spyOn()
)而不是直接覆盖对象属性。

describe("...", () => {
  beforeEach(() => {
    const originalLocation = window.location;
    jest.spyOn(window, "location", "get").mockImplementation(() => ({
      ...originalLocation,
      href: "http://dummy.com", // Mock window.location.href here.
    }))
  });
  afterEach(() => {
    jest.restoreAllMocks()
  });

  it("...", () => {
    // ...
  })
});

我从这篇文章中学到了它。


1
投票

这对于 Jest + TypeScript + Next.js 有效(如果您使用

useRoute().push

const oldWindowLocation = window.location;

beforeAll(() => {
  delete window.location;
  window.location = { ...oldWindowLocation, assign: jest.fn() };
});

afterAll(() => {
  window.location = oldWindowLocation;
});

1
投票

JSDOM 版本

另一种方法,使用 JSDOM,它将提供

window.location.href
以及
window.location
的所有其他属性(例如
window.location.search
用于获取查询字符串参数)。

import { JSDOM } from 'jsdom';

...

const { window } = new JSDOM('', {
    url: 'https://localhost/?testParam=true'
});
delete global.window;
global.window = Object.create(window);

1
投票

我找不到如何测试

window.location.href
是否已设置正确的值并测试
window.location.replace()
是否已使用正确的参数调用,但我尝试了这个,它看起来很完美。

    const mockWindowLocationReplace = jest.fn()
    const mockWindowLocationHref = jest.fn()
    
    const mockWindowLocation = {}
    Object.defineProperties(mockWindowLocation, {
      replace: {
        value: mockWindowLocationReplace,
        writable: false
      },
      href : {
        set: mockWindowLocationHref
      }
    })
    jest.spyOn(window, "location", "get").mockReturnValue(mockWindowLocation as Location)

    describe("my test suite", () => {
        // ...
        expect(mockWindowLocationReplace).toHaveBeenCalledWith('foo')
        expect(mockWindowLocationHref).toHaveBeenCalledWith('bar')
    })

0
投票

可以通过在每次测试中删除此全局来重写 window.location。

delete global.window.location;
const href = 'http://localhost:3000';
global.window.location = { href };

0
投票

基于上面和其他线程中的示例,这里是一个使用

jest
的具体示例,可能会对某人有所帮助:

describe('Location tests', () => {
    const originalLocation = window.location;

    const mockWindowLocation = (newLocation) => {
        delete window.location;
        window.location = newLocation;
    };

    const setLocation = (path) =>
        mockWindowLocation(
            new URL(`https://example.com${path}`)
        );

    afterEach(() => {
        // Restore window.location to not destroy other tests
        mockWindowLocation(originalLocation);
    });

    it('should mock window.location successfully', () => {
        setLocation('/private-path');

        expect(window.location.href).toEqual(
            `https://example.com/private-path`
        );
    });
});

0
投票

可能无关紧要。但对于那些寻求 window.open('url', attribute) 解决方案的人来说,我在上面的一些评论的帮助下应用了这个:

window = Object.create(window);
const url = 'https://www.9gag.com';
Object.defineProperty(window, 'open', { value: url });

expect(window.open).toEqual(url);

0
投票

这是一个简单的,您可以在每次测试中使用

beforeEach
或点菜。

它利用 Javascript

window.history
及其
pushState
方法来操作 URL。

window.history.pushState({}, 'Enter Page Title Here', '/test-page.html?query=value');

0
投票

简单干净的方法:

 Object.defineProperty(window, "location", {
    value: new URL("http://example.com"),
    configurable: true,
  });
© www.soinside.com 2019 - 2024. All rights reserved.