Jsdom: How Can I Use JSDom With ES6 Module Syntax?

Created on 29 Jul 2016  路  4Comments  路  Source: jsdom/jsdom

This Stack Overflow describes the problem in details:

http://stackoverflow.com/questions/38651209/how-can-i-wrap-an-import-with-jsdom

But basically my question is this: jsdom has to "wrap" code to get used, but it's impossible to "wrap" an ES6 module import (ie. import foo form 'bar') because they have to come before any code. And if DOM-using code is part of the import itself, it needs to be wrapped by JSDom

Is there a way around this?

Most helpful comment

First off, thanks for the wiki link; it was a piece in the puzzle which ultimately led me to the solution (at this awesome blog: http://www.2ality.com/2014/09/es6-modules-final.html). As it explains, there _is_ a way to do imports in a way that they can be wrapped by JSDom: System.import.

Here's the solution to the problem for other ES6/JSDom-lovers:

import jsdom;

jsdom({
    html: '<div></div>',
    done: () => {
        // don't do this:
        //      import setup from 'setup';

        // do this:
        System.import('setup')
            .then((setup) => {
                    // test code that uses setup
            })
    }
});

NOTE: If you're using a test framework like Mocha, you'll need to use it's asynchronous test functionality to make this work (ie. you need a done argument in your it function, and then you'll need to invoke done after the test finishes).

Anyhow, I hope that helps anyone else going down this road, and thanks again for the help in solving it.

All 4 comments

Since JS modules are not supported in any engine, you are presumably using some transpiler like Babel or TypeScript to convert your source to normal, supported JavaScript that can run in Node.js or browsers. You should do the same thing before feeding your code to jsdom. We have no intention of supporting something that is not yet implemented in browsers.

Well, I am using Babel, as part of Mocha, ie mocha --compilers js:babel-core/register test.js. So, I am using a transpiler "before feeding [my] code to jsdom." It just doesn't help, because of the problem I described.

It's true that ES6 modules are new and not supported in the browser, so I would totally understand not supporting them. However, major libraries are using them in their documentation as if they were the standard (eg. Redux, http://redux.js.org/docs/basics/ExampleTodoList.html) ... which makes sense because they (arguably) are the standard module system for JS.

So I guess what I'm saying is, ES6 modules aren't going away, and this problem seems to be intrinsic to them. JSDom can solve the problem now or kick the can down the road (a _totally_ legitimate option), but ultimately if the library is going to work with this increasingly popular standard then someone will have to address the problem.

Either way, thanks for considering the issue.

There are two issues you're encountering here.

  1. You're trying to use jsdom as a global environment, which is not how jsdom works. Even if you switched to commonjs, your code wouldn't work. See this wiki page, which details the problem a bit and my comment on a similiar issue. You might be able to make this work by combining babel and jest.
  2. import is just not implemented yet (in node). Chances are, this will be resolved somewhat-automatically when node implements those for us, although we might have to implement an actual loader.

First off, thanks for the wiki link; it was a piece in the puzzle which ultimately led me to the solution (at this awesome blog: http://www.2ality.com/2014/09/es6-modules-final.html). As it explains, there _is_ a way to do imports in a way that they can be wrapped by JSDom: System.import.

Here's the solution to the problem for other ES6/JSDom-lovers:

import jsdom;

jsdom({
    html: '<div></div>',
    done: () => {
        // don't do this:
        //      import setup from 'setup';

        // do this:
        System.import('setup')
            .then((setup) => {
                    // test code that uses setup
            })
    }
});

NOTE: If you're using a test framework like Mocha, you'll need to use it's asynchronous test functionality to make this work (ie. you need a done argument in your it function, and then you'll need to invoke done after the test finishes).

Anyhow, I hope that helps anyone else going down this road, and thanks again for the help in solving it.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

potapovDim picture potapovDim  路  4Comments

jhegedus42 picture jhegedus42  路  4Comments

philipwalton picture philipwalton  路  4Comments

JacksonGariety picture JacksonGariety  路  4Comments

jacekpl picture jacekpl  路  4Comments