Setting global variables in a script loaded by jsdom

…衆ロ難τιáo~ 提交于 2021-02-19 05:35:08

问题


I'm trying to run some browser code in Node.js in order to simplify testing (deasync is the reason).

Currently, I use jsdom to parse the only html file. At first, I was trying to make it also load the scripts, which are linked in <script> tags. But due to some stupid issues with relative file paths I have switched to passing a list of absolute paths to the script files as a parameter to jsdom.env function.

Now I'm pretty sure that jsdom finds my scripts properly, but I cannot set any global variables in them. Also, console.log is not working there. I have checked that if I load a script through require command, then both global variables and console output are working as expected. But with jsdom.env they are not working.

I use Node.js version 4.2.6 on Windows 7. The following 4 files are used to reproduce the issue (they are located in the same directory):


main.js - started with node.exe:

var jsdom = require("jsdom");
require("./module");

var window = jsdom.env(
  '<p><a class="the-link" href="https://github.com/tmpvar/jsdom">jsdom!</a></p>',
  [
//  "http://code.jquery.com/jquery.js",
  "file://" + __dirname + "/myjquery.js",
  "file://" + __dirname + "/script.js"
  ],
  undefined,
  function(error, window) {
    console.log("contents of a.the-link:", window.$("a.the-link").text());
    console.log(global.hello, window.hello, global.hi);
  }
);

module.js:

console.log("Hi!");
global.hi = 15

script.js:

console.log("Hello!");
global.hello = 126;

myjquery.js is just jQuery downloaded from http://code.jquery.com/jquery.js.


It prints out:

Hi!
contents of a.the-link: jsdom!
undefined undefined 15

So it definitely loads myjquery.js properly, because it is used to print the first line. Also, it sets a global variable and prints a line in the module, but it does not do it in the script.

Could you please explain why and propose a way to fix it?


回答1:


The hello global

global is a NodeJS thing, not a browser thing. In your script.js, if you want to set global variables in the page (like jQuery does), you would either just declare them at global scope:

var hello = 126;

or assign them as properties on window:

window.hello = 126;

or (at global scope and if you're not using strict mode) to this:

this.hello = 126;

If you do any of those in script.js, window.hello will be set in your callback.

Seeing console.log

The JSDom page quite clearly says that to see console output from within the window, you must do something:

// Create and configure a virtual console
var virtualConsole = jsdom.createVirtualConsole();
virtualConsole.on("log", function (message) {
  console.log("console.log called ->", message);
});

// Use it in the config object    
var window = jsdom.env(
  '<p><a class="the-link" href="https://github.com/tmpvar/jsdom">jsdom!</a></p>',
  [
//  "http://code.jquery.com/jquery.js",
  "file://" + __dirname + "/myjquery.js",
  "file://" + __dirname + "/script.js"
  ],
  { virtualConsole: virtualConsole },                          // <== Here
  function(error, window) {
    console.log("contents of a.the-link:", window.$("a.the-link").text());
    console.log(window.hello, global.hi);
  }
);

Seeing errors

You mentioned that you don't see errors (which would have been useful, since global.hello = 126; does indeed cause an error);

The JSDom documentation talks about how to listen for errors, too:

virtualConsole.on("jsdomError", function (error) {
  console.error(error.stack, error.detail);
});

That just goes after our console setup above. Now, errors in script.js and such are reported to the Node console.

Relative paths

You'd mentioned some trouble with relative paths. Just FYI, this worked just fine for me:

var window = jsdom.env(
  '<p><a class="the-link" href="https://github.com/tmpvar/jsdom">jsdom!</a></p>',
  [
  "myjquery.js",
  "script.js"
  ],
  { virtualConsole: virtualConsole },
  function(error, window) {
    console.log("contents of a.the-link:", window.$("a.the-link").text());
    console.log(window.hello, global.hi);
  }
);

...as did using "http://code.jquery.com/jquery.js" directly.


Side note: The JSDom documentation around virtualConsole shows the configuration object slightly different than I do above. I did this:

var window = jsdom.env(
  // ...
  { virtualConsole: virtualConsole },
  // ...
);

whereas their docs show this:

var window = jsdom.env(
  // ...
  { virtualConsole },
  // ...
);

The reason for the difference is that you were using ES5 only in your code, so I translated. They're using an ES2015 (ES6) feature that lets you specify a property using a shorthand if the property name and the name of the variable you're taking it from are the same. So { virtualConsole } and { virtualConsole: virtualConsole } are exactly the same thing in ES2015, but the former doesn't work in ES5 and earlier. If you're using the current Node and JSDom, you can use that ES2015 feature.



来源:https://stackoverflow.com/questions/35099863/setting-global-variables-in-a-script-loaded-by-jsdom

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!