new URL()

I was looking at this code that gives you query params of a page, defaulting to the current page.

function getQueryParams(url = window.location) {
  return new URL(window.location).search
}

Then tests were failing. In tests we were mocking window.location and returning a simple object.

// so browsers don't complain about read-only properties
const setWindowLocation = value => {
  Object.defineProperty(window, 'location', {
    writable: true,
    value,
  });
};

Javascript is great sometimes. Readonly property bringing you down? Just indirectly add a property to it and say that it's writeable.

Anyways, that was causing a test to fail.

We call it with an object like this:

function queryThing(url = window.location) {
  let wut = new URL(url)
  return wut.search
}

new URL({}) is invalid. Weeeiiiiiird.

MDN URL constructor page shows parameters are meant to be strings. They say both arguments should be Strings ('USVString maps to a String when returned in JavaScript' [1])

There is a note about the second argument:

Note: You can still use an existing URL object for the base, which stringifies itself to the object's href attribute.

maybe it is something special about Location

But does it have to be a URL object? What about a regular object? In JS that looks like this:

let fakeLocation = {
  href: 'https://great.com',
  toString: function toString() {
    return this.href
  }
}

new URL(fakeLocation) // works!
// shorthand way
let fakeLocation = {
  href: 'https://great.com',
  toString() {
    return this.href
  }
}

--

Time to check the spec. URL Constructors section gives the steps of parsing. That references the Basic URL Parser with more steps. But everything only ever mentions a string for the first arg.

Still no idea how/why this happpens. Had a skim of the Chromium source and found where the error was coming from, and it's some kind of binding is happening somewhere. Got a semi explanation from #chromium IRC channel but I do not understand enough to pursue it yet.