Can someone please explain to me why the upper code works as expected but the lower one does not? Thanks a lot!
$ nvm exec 22 node
Running node v22.15.1 (npm v10.9.2)
Welcome to Node.js v22.15.1.
Type ".help" for more information.
> const { JSDOM } = require('jsdom');
undefined
> const dom = new JSDOM("");
undefined
> var $ = require('jquery')(dom.window);
undefined
> $.extend
[Function (anonymous)]
> $(dom.window.document)
jQuery {
'0': Document {
location: [Getter/Setter],
[Symbol(SameObject caches)]: [Object: null prototype] {
childNodes: Proxy [Array],
implementation: DOMImplementation {}
}
},
length: 1
}
$ nvm exec 22 node
Running node v22.15.1 (npm v10.9.2)
Welcome to Node.js v22.15.1.
Type ".help" for more information.
> const { JSDOM } = require('jsdom');
undefined
> function set_up_globals() {
... // Set up a mock document:
... const dom = new JSDOM("");
... global.window = dom.window;
... global.document = dom.window.document;
... global.navigator = dom.window.navigator;
... global.HTMLElement = dom.window.HTMLElement;
... global.$ = require('jquery')(dom.window);
... }
undefined
> set_up_globals();
undefined
> $.extend
[Function (anonymous)]
> $(document)
Uncaught TypeError: $ is not a function
Why is there a TypeError
, suddenly?
To explain my use case: I have a file containing client-side JavaScript code that uses jQuery, whose behavior I want to test using a Node.js script. To do so, I need to create a global mock $
object.
The jquery
module does some checks on the availability of a global window
variable (presumably some sort of "am I running inside a browser?" check) and if it's available, it will export something different then when it's not available.
Since you declare global.window
before loading jquery
, window
exists, jQuery thinks it's running inside a browser, and the code fails.
If you move the import to the top of the function (or rather, before declaring global.window
), it works as expected:
function set_up_globals() {
const jquery = require('jquery');
const dom = new JSDOM("");
global.window = dom.window;
global.document = dom.window.document;
global.navigator = dom.window.navigator;
global.HTMLElement = dom.window.HTMLElement;
global.$ = jquery(dom.window);
}
(FWIW, global
has been deprecated in favor of globalThis
, more info here).