0

I've written a function to get the value of a given query string based on David Walsh's Get Query String Parameters.

export const getQueryStringValue = (name) => {
  const formattedName = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
  const regex = new RegExp(`[\\?&]${formattedName}=([^&#]*)`);
  const results = regex.exec(window.location.search);

  return results === null
    ? ''
    : decodeURIComponent(results[1].replace(/\+/g, ' '));
};

I've written a test for the function based on How to mock window.location.href with Jest + Vuejs?.

it('should return query string value', () => {
  global.window = Object.create(window);
  Object.defineProperty(window, 'location', {
    value: {
      href: 'http://dummy.com?foo=bar'
    }
  });

  expect(getQueryStringValue('foo')).toBe('bar');
});

However, when I run the test I get the following error.

expect(received).toBe(expected) // Object.is equality

Expected: "bar"
Received: ""

And when I console log window.location.search it returns undefined.

  console.log __tests__/getQueryStringValue.test.js:14
    undefined

Why does Window.location search return undefined even when Window.location.href includes a query string (?foo=bar)? Shouldn't setting href be enough?

Ryan Payne
  • 5,249
  • 4
  • 28
  • 69
  • It could be because in the define property the value is an object with only href, so the search attribute is undefined – Haibrayn González Jan 29 '20 at 23:00
  • @HaibraynGonzález That makes sense. It makes me wonder: how does the browser set `window.location.search` when a page loads? – Ryan Payne Jan 29 '20 at 23:12
  • 1
    Why does it fail? Your mock is wrong. You are only setting href, it is not going to automatically set up the other methods of location. – epascarello Jan 29 '20 at 23:42

1 Answers1

1

Window.location search doesn't get automatically mocked when you set Window.location href because jsdom does not currently handle navigation. You have a couple options to resolve the error.

Option 1: Set Window.location Search

it('should return query string value', () => {
  global.window = Object.create(window);
  Object.defineProperty(window, 'location', {
    value: {
      search: '?foo=bar'
    }
  });

  expect(getQueryStringValue('foo')).toBe('bar');
});

Option 2: Set Window.location To New URL Instance

it('should return query string value', () => {
  global.window = Object.create(window);
  Object.defineProperty(window, 'location', {
    value: new URL('http://dummy.com/?foo=bar')
  });

  expect(getQueryStringValue('foo')).toBe('bar');
});

Source: https://stackoverflow.com/a/59979453/11809808

Ryan Payne
  • 5,249
  • 4
  • 28
  • 69
  • 1
    "I don't know why ", because it was not mocked.... You do not get all of the properties for free. – epascarello Jan 29 '20 at 23:45
  • @epascarello "because it was not mocked.... You do not get all of the properties for free". That answers my question. I've updated my answer accordingly. – Ryan Payne Jan 30 '20 at 04:40
  • 1
    I posted an answer there that should help you: https://stackoverflow.com/a/59979453/3702797 – Kaiido Jan 30 '20 at 05:10
  • @Kaiido I've updated my answer based on your link. Thanks for providing that answer. I actually prefer it to my original answer. – Ryan Payne Jan 30 '20 at 15:58