mocha config lacks tools to use localstorage in jsdom

Created on 12 Nov 2018  路  5Comments  路  Source: mochajs/mocha

I can no longer check if session storage exists or not using mocha. The root cause is a jsdom update that now throws a security exception when accessing window.sessionStorage

since jsdom 11.12.0 (released in the past june) test runners need to explicitly set a url for jsdom in order to use localstorage or sessionstorage otherwise an exception is thrown:

SecurityError: localStorage is not available for opaque origins

Details on the jsdom release can be found here: https://github.com/jsdom/jsdom/issues/2304

Jest has patched the same issue by adding a letting a field 'testURL' be defined in the config:

https://github.com/facebook/jest/issues/6766

I am currently navigating around this issue by locking my jsdom package to 11.11.0 but this is not a viable long-term solution.

Please let me know if there is a fix for this in the pipeline, or if one already exists that I have overlooked.

Thanks!

PS - steps to reproduce:

it should be possible to make the following test pass with the latest jsdom installed:
mocha --exit --require ts-node/register --require jsdom-global/register ./app/test/*.ts

  @test public async sessionStorate() {
    try {
      if(window && window.localStorage) {
        //have access
        assert.ok("does not break control flow");
      } else {
        //dont have access
        assert.ok("does not break control flow");
      }
    } catch {
      assert.fail("breaks control flow");
    }
  }
integration invalid unconfirmed-bug

All 5 comments

@domenic ping! Shouldn't there be _something_ in your Wiki explaining how to work around this issue?

Fail to see how this is a Mocha problem. You'll need to explain further how we're preventing you from using whatever version of the jsdom package. I see this in one of their unit tests, being run by old version of Mocha unchanged...

  describe("storageQuota", () => {
    describe("not set", () => {
      it("should be 5000000 code units by default", () => {
        const { localStorage, sessionStorage } = (new JSDOM(``, { url: "https://example.com" })).window;
        const dataWithinQuota = "0".repeat(4000000);

        localStorage.setItem("foo", dataWithinQuota);
        sessionStorage.setItem("bar", dataWithinQuota);

        assert.strictEqual(localStorage.foo, dataWithinQuota);
        assert.strictEqual(sessionStorage.bar, dataWithinQuota);

        const dataExceedingQuota = "0".repeat(6000000);

        assert.throws(() => localStorage.setItem("foo", dataExceedingQuota));
        assert.throws(() => sessionStorage.setItem("bar", dataExceedingQuota));
      });
  });

@plroebuck

my test suite interfaces with mocha exclusively. Mocha is using jsdom behind the scenes to mock out window.* globals. My tests and application code never interfaced with jsdom directly before aside from loading it with my call to mocha:

mocha --exit --require ts-node/register --require jsdom-global/register ./app/test/*.ts

I appreciate that this is an issue interfacing with a third party utility and as such the responsibility on maintaining that interface isn't clear cut. The docs for jsdom-global glaze right over this issue entirely in their mocha section:

https://github.com/rstacruz/jsdom-global#mocha

The issue remains, however, that mocha seems to be the one newing up the jsdom object (perhaps you could verify if this is correct?) and there is no way for me to pass the required parameter to the constructor at this point.

Looking forward to your feedback.
Cheers,
Kyle

Mocha is using jsdom behind the scenes to mock out window.* globals.
The issue remains, however, that mocha seems to be the one newing up the jsdom object...

Take a look at "package.json". Notice the lack of any "jsdom" package. In other words, we have _nothing_ to do with jsdom...

Attn: @rstacruz

And "jsdom-global" package already has an issue for this problem.

What you want as a longterm fix is for the "jsdom-global" package to interpret the object from the key jsdom-global in _your_ "package.json" as the JSDom ctor's options argument. See example if you don't follow what I wrote.

Full Disclosure: Never used (or seen) either "jsdom" or "jsdom-global" package before.
This is how I would attempt to workaround the problem.

The relevant portion of "jsdom-global" package is the exported function.

Follow their instructions and put the advanced section part in a file named "setup.js". The before hook does the setup (the exported function wraps the "jsdom" ctor), and the after hook does the teardown.

So change the before hook to this:

  var html;    // Unsure what _your code_ needs here -- using `undefined` to trigger default value
  var options = { url: http://localhost/ };
  this.jsdom = require('jsdom-global')(html, options);

Now run Mocha as such:

$ mocha --require ts-node/register --require jsdom-global/register --file "./app/test/setup.js" --exit  "./app/test/*.ts"

Good luck...

Thank you for your insight.

After looking into it, you are (of course) correct. You do not 'new up jsdom' as I initially expected, you simply require() any packages placed in the command line --require flags. The difference is subtle but ultimately mocha works on required libs in such a generic way it would open up a 'pandoras box' of scope creep if you were to make exceptions and begin passing parameters down to required libs.

I will do what you suggest and try importing jsdom-global in my test runner, where I can pass parameters in on initialization.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

CADBOT picture CADBOT  路  3Comments

delta62 picture delta62  路  3Comments

niftylettuce picture niftylettuce  路  3Comments

seelikes picture seelikes  路  3Comments

danielserrao picture danielserrao  路  3Comments