jsdom: localStorage implementation can't be spied on. webidl converter issue?

Basic info:

  • Node.js version: v9.11.2
  • jsdom version: 11.12.0

Minimal reproduction case

In the latest release 11.12.0 jsdom implemented localStorage and sessionStorage support. That’s really awesome and great but the issue I am experiencing is that we can’t spy On it or mock it during testing with jest.

I’ve created a simple repo for the use case at: https://github.com/vlad0/jest-localstorage-issue

As much as I hate to do this but I’d like to give a link to the jest issue I’ve created https://github.com/facebook/jest/issues/6798

and mainly because of the setter implementation(webidl I guess):

What I have discovered is that in ./node_modules/jsdom/lib/jsdom/living/generated/Storage.js the issue is with the set method of the Proxy

Currently the code below is on line 278.
if (ownDesc === undefined) {
          const parent = Reflect.getPrototypeOf(target);
          if (parent !== null) {
            return Reflect.set(parent, P, V, receiver);
          }
          ownDesc = { writable: true, enumerable: true, configurable: true, value: undefined };
        }
if we remove receiver from return Reflect.set(parent, P, V, receiver); we will be able to spy on it. But I guess that's coming from webidl converter

How does similar code behave in browsers?

(Link to a jsbin or similar suggested.)

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 19 (14 by maintainers)

Most upvoted comments

Thanks for the report. Unfortunately I don’t think any of us are very familiar with the methods offered by Jest, since we’re a separate project.

Despite @SimenB’s reply - if a long-term fix is needed, it seems like the proper location for it is in Jest.

That works in Chrome, but not JSDOM.

console.log("before", localStorage.setItem);
Object.defineProperty(window, 'localStorage', {value: {}})
console.log("after", localStorage.setItem);

Chrome:

before ƒ setItem() { [native code] }
after undefined

JSDOM:

"before"
function setItem()
"after"
function setItem()
undefined

EDIT: It also doesn’t work in Firefox (it behaves the same as JSDOM), so at least it’s consistent there