How to mock window.location.href with Jest + Vuejs?

121,393

Solution 1

You can try:

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

Have a look at the Jest Issue for that problem:
Jest Issue

Solution 2

2020 Update


Basic

The URL object has a lot of the same functionality as the Location object. In other words, it includes properties such as pathname, search, hostname, etc. So for most cases, you can do the following:

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

Advanced

You can also mock Location methods that you might need, which don't exist on the URL interface:

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

Solution 3

I have resolved this issue by adding writable: true and move it to beforeEach

Here is my sample code:

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

Solution 4

Solution for 2019 from GitHub:

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

Solution 5

The best is probably to create a new URL instance, so that it parses your string like location.href does, and so it updates all the properties of location like .hash, .search, .protocol etc.

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

Share:
121,393
Tran Son Hoang
Author by

Tran Son Hoang

Make this shit happen :D

Updated on December 21, 2021

Comments

  • Tran Son Hoang
    Tran Son Hoang over 2 years

    Currently, I am implementing unit test for my project and there is a file that contained window.location.href.

    I want to mock this to test and here is my sample code:

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

    But I get this error:

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

    I had tried some solutions but not resolve it. I need some hints to help me get out of this trouble. Plz help.

  • Jay
    Jay over 4 years
    This solution also works for overwriting window.location.hostname in Jest tests. I needed writable: true in order to change the hostname more than once.
  • peter.swallow
    peter.swallow over 4 years
    This is the only one that seems to work for me and with a helpful reason why! :)
  • Md. Amanullah
    Md. Amanullah over 4 years
    this helps me a lot
  • dshun
    dshun over 3 years
    with typescript update, delete window.location will trigger an error The operand of a 'delete' operator must be optional
  • Sujith
    Sujith over 3 years
    @dhsun any solution to the problem you have mentioned above? I am facing similar issue
  • xbmono
    xbmono over 3 years
    writable: true was necessary for my unit tests to work otherwise the subsequent tests wouldn't be able to overwrite it to something else. Thanks
  • xbmono
    xbmono over 3 years
    For me using global didn't work, I removed global. and I also needed to add writable: true otherwise once set the other tests can't change it.
  • Tom
    Tom over 3 years
    Add // @ts-ignore above the line delete window.location; if you must
  • wlh
    wlh about 3 years
    I wonder if it shouldn't be const realLocation = Object.assign({}, window.location); since I feel just assigning it directly would be passing a reference which is later overwritten. Thoughts?
  • Washington Guedes
    Washington Guedes almost 3 years
    It works, but breaks following tests using postMessage that needs the original location.host property
  • JCQuintas
    JCQuintas almost 3 years
    Reflect.deleteProperty(global.window, 'location') deals with that without ts error
  • Mustafa
    Mustafa almost 3 years
    To get around that TS error you can do delete (window as any).location;
  • RobW
    RobW almost 3 years
    The object that the original window.location points to is not mutated in this code -- the window.location property has different objects set inside it. Since there's no mutation of the original window object, there's no need to clone it.
  • Quoting Eddie
    Quoting Eddie over 2 years
    There is another, seldomly used, property on the Location API: ancestorOrigins. You might want to mock that, too.
  • Enes Kirimi
    Enes Kirimi over 2 years
    This is what I was looking for. Best solution for me.
  • Mohammad Kermani
    Mohammad Kermani about 2 years
    Why the window.location should be deleted? Can't it override it by window.location = location only?