hbenl / vscode-mocha-test-adapter

Mocha Test Adapter for the VS Code Test Explorer
MIT License
91 stars 31 forks source link

Error: Cannot find module 'jsdom-global/register' #215

Closed machineghost closed 2 years ago

machineghost commented 2 years ago

I have a "monorepo" project, ie. three separate workspace folders. All of them are failing to run any tests, with the following output:

Error: Cannot find module 'jsdom-global/register'
Require stack:
- /home/me/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/out/worker/bundle.js
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)
    at Function.Module._load (node:internal/modules/cjs/loader:778:27)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at /home/me/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/out/worker/bundle.js:5790:35
    at Generator.next (<anonymous>)
    at fulfilled (/home/me/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/out/worker/bundle.js:112:58) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    '/home/me/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/out/worker/bundle.js'
  ]
}

In https://github.com/hbenl/vscode-mocha-test-adapter/issues/210 (also by me, but for a different codebase) someone suggested

@machineghost Try running the command "Mocha Test Explorer: Enable for a workspace folder" from the VS Code command palette.

and it worked ... in that codebase.

However, when I try that command on my server folder in this codebase (which clearly has no need for jsdom) it doesn't do anything: I still have the tests failing.

machineghost commented 2 years ago

I understand your time is valuable, but running tests at the command line sucks :(

If there's any way I could offer to help with some other issue (where you know the problem, and just need someone to code up a solution) I'd be happy to offer to help, in exchange for some advice on fixing this issue.

Or if you can't think of any, maybe I could help modify the adapter to throw more useful error messages (more useful than "you've got something wrong with jsdom-global/register") that actually instruct people how to fix the issue. That way we'd kill two birds with one stone: I'd learn the fix, and I can help save future people from bugging you for it.

hbenl commented 2 years ago

The stacktrace suggests that you aren't using mocha's esm loader (you have either set mochaExplorer.esmLoader to false in your configuration or you're using an old Mocha version that doesn't have that loader). You can check in the diagnostic logs if it says Trying requireOrImport('jsdom-global/register') (that's mocha's esm loader) or Trying require('jsdom-global/register'). I just realized that the require option will only work for globally installed packages without mocha's esm loader, so you should try enabling that.

when I try that command on my server folder in this codebase (which clearly has no need for jsdom) it doesn't do anything: I still have the tests failing.

They're failing with the same error message? In that case I'd need more info: the mocha and VS Code config and ideally the diagnostic log output.

I understand your time is valuable, but running tests at the command line sucks :(

Yeah, sorry, I'll try to be more responsive in the future (but can't make any promises)

maybe I could help modify the adapter to throw more useful error messages

If I had foreseen that problem (that requiring doesn't work properly without mocha's esm loader) I would already have added such error messages. I'll try to come up with a proper fix for this and another issue that you've also run into (where requiring doesn't work properly if the adapter uses the bundled version of mocha).

machineghost commented 2 years ago

you have either set mochaExplorer.esmLoader to false in your configuration or you're using an old Mocha version that doesn't have that loader

I just realized that the require option will only work for globally installed packages without mocha's esm loader, so you should try enabling that.

That setting is already checked, and I most definitely have the esm package because my app uses it :) Also my mocharc.js file has:

require: 'esm',

Unchecking that setting (and refreshing the tests) does nothing.

You can check in the diagnostic logs if it says Trying requireOrImport('jsdom-global/register') (that's mocha's esm loader) or Trying require('jsdom-global/register').

Under the "Mocha Explorer Log" output I see this, among other lines, when I refresh:

[2022-06-26 19:54:07.265] [INFO] Worker: Trying requireOrImport('jsdom-global/register')

(followed by that same error about jsdom-global/register)

They're failing with the same error message? In that case I'd need more info: the mocha and VS Code config

Mocha Config:

process.env['NODE_ENV'] = 'test';
process.env['NODE_PATH'] = '/path/to/my/project/root';

module.exports = {
  exit: true,
  bail: true,
  recursive: true,
  require: 'esm',
  file: ['./src/testMain.js'],
};

VS Code Settings (or at least all the Mocha/Test Explorer ones):

  "mochaExplorer.files": "./{,!(node_modules)/**}/*.spec.js",
  "mochaExplorer.ignore": "node_modules",
  "mochaExplorer.require": ["jsdom-global/register", "@babel/register"],
  "testExplorer.addToEditorContextMenu": true,
  "testExplorer.hideEmptyLog": false,
  "testExplorer.errorDecoration": false,
  "mochaExplorer.logpanel": true,
  "explorer.fileNesting.enabled": true,
  "mochaExplorer.globImplementation": "vscode",
  "mochaExplorer.envPath": ""

and ideally the diagnostic log output.

Where do I find that? In my "Test Explorer" Output I have:

Error: Cannot find module 'jsdom-global/register'
Require stack:
- /home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/out/worker/bundle.js
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)
    at Function.Module._load (node:internal/modules/cjs/loader:778:27)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at /home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/out/worker/bundle.js:5790:35
    at Generator.next (<anonymous>)
    at /home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/out/worker/bundle.js:115:71
    at new Promise (<anonymous>)
    at __awaiter (/home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/out/worker/bundle.js:111:12)
    at execute (/home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/out/worker/bundle.js:5727:12) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    '/home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/out/worker/bundle.js'
  ]
}

In "Mocha Tests" I have nothing, and in "Mocha Explorer Log" I have:


[2022-06-26 20:48:04.109] [INFO] Worker finished with code null and signal SIGTERM
[2022-06-26 20:48:04.109] [INFO] Worker: Caught error Error: Cannot find module 'jsdom-global/register'
Require stack:
- /home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/node_modules/mocha/lib/nodejs/esm-utils.js
- /home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/node_modules/mocha/lib/mocha.js
- /home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/node_modules/mocha/index.js
- /home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/out/worker/bundle.js
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)
    at Function.Module._load (node:internal/modules/cjs/loader:778:27)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at exports.requireOrImport (/home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/node_modules/mocha/lib/nodejs/esm-utils.js:49:16) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    '/home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/node_modules/mocha/lib/nodejs/esm-utils.js',
    '/home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/node_modules/mocha/lib/mocha.js',
    '/home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/node_modules/mocha/index.js',
    '/home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/out/worker/bundle.js'
  ]
}
[2022-06-26 20:48:04.109] [INFO] Received error from worker
[2022-06-26 20:48:04.110] [ERROR] Worker (stderr): node:internal/process/promises:279
            triggerUncaughtException(err, true /* fromPromise */);
            ^

Error: Cannot find module 'jsdom-global/register'
Require stack:
- /home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/node_modules/mocha/lib/nodejs/esm-utils.js
- /home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/node_modules/mocha/lib/mocha.js
- /home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/node_modules/mocha/index.js
- /home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/out/worker/bundle.js
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)
    at Function.Module._load (node:internal/modules/cjs/loader:778:27)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at exports.requireOrImport (/home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/node_modules/mocha/lib/nodejs/esm-utils.js:49:16) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    '/home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/node_modules/mocha/lib/nodejs/esm-utils.js',
    '/home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/node_modules/mocha/lib/mocha.js',
    '/home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/node_modules/mocha/index.js',
    '/home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/out/worker/bundle.js'
  ]
}

[2022-06-26 20:48:04.113] [INFO] Worker finished with code 1 and signal null

Yeah, sorry, I'll try to be more responsive in the future (but can't make any promises)

I owe you an apology too, as I completely understand maintaining OSS is a PITA. I swear, while I was trying to get help, I wasn't trying to guilt trip you!

If I had foreseen that problem (that requiring doesn't work properly without mocha's esm loader) I would already have added such error messages. I'll try to come up with a proper fix for this and another issue that you've also run into (where requiring doesn't work properly if the adapter uses the bundled version of mocha).

Again, I totally understand.

I just imaged that somewhere in the code is a require('jsdom-global/register') line (or something like it) that could be wrapped with a try/catch that does nothing except rethrow the error ... with a message more like "A library used by Mocha Test Explorer wouldn't load; please see https://github.com/hbenl/vscode-mocha-test-adapter/issues/215 for possible solutions."

hbenl commented 2 years ago

The diagnostic log is the "Mocha Explorer Log" output. The stacktrace shown there is different from the one in the "Test Explorer" output, so my guess is that we may be looking at logs from different workspace folders (unfortunately the diagnostic doesn't say which workspace folder a message came from, I'll have to fix this). The stacktrace in the diagnostic log indicates that it's using the bundled mocha version, which doesn't play well with mochaExplorer.require. You'll have to try opening each workspace folder separately in VS Code to see what's happening in that folder. Check in the diagnostic log which installation of mocha it's using, it must be installed in the same node_modules folder as jsdom-global so that it can find it.

hbenl commented 2 years ago

The whole monorepo-and-require story is currently causing a lot of issues, I'm still trying to figure out all the ways it breaks and how I can steer users towards a configuration that works, that's why I'm holding off on adding an error message that currently could only tell users that "it's complicated".

machineghost commented 2 years ago

Ah, that all makes sense. Well, except this part:

indicates that it's using the bundled mocha version

It took me awhile, but I think that meant that I didn't have:

"mochaExplorer.mochaPath": "node_modules/mocha"

in my settings? If so, I added that line, and now I get ... the same error, but with new stuff in front!

[2022-06-27 19:53:53.226] [INFO] Worker finished with code 1 and signal null [2022-06-27 19:53:53.306] [DEBUG] Found test files [] [2022-06-27 19:53:53.307] [DEBUG] Adding files ["/home/jeremy/project/admin/server/src/testMain.js"] [2022-06-27 19:53:53.308] [DEBUG] Using environment variables from config: {} [2022-06-27 19:53:53.309] [DEBUG] Spawning /home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/out/worker/bundle.js with IPC options {} [2022-06-27 19:53:53.381] [INFO] Worker: Using the mocha package at /home/jeremy/project/admin/server/node_modules/mocha [2022-06-27 19:53:53.480] [INFO] Worker: Patching Mocha

It looks like things have progressed much farther now ... but then the next lines are:

[2022-06-27 19:53:53.480] [INFO] Worker: Trying require('jsdom-global/register') [2022-06-27 19:53:53.485] [INFO] Worker: Caught error Error: Cannot find module 'jsdom-global/register' Require stack:

  • /home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/out/worker/bundle.js at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15) at Function.Module._load (node:internal/modules/cjs/loader:778:27) at Module.require (node:internal/modules/cjs/loader:1005:19) at require (node:internal/modules/cjs/helpers:102:18) at /home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/out/worker/bundle.js:5790:35 at Generator.next () at fulfilled (/home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/out/worker/bundle.js:112:58) { code: 'MODULE_NOT_FOUND', requireStack: [ '/home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/out/worker/bundle.js' ] }

As an aside, shouldn't that setting be the default? I'd think it'd be far more common for a project that wants to use this extension to have mocha in their devDependencies ... in fact, it'd be rather odd if they didn't ... no?

Anyhow, I tried installing jsdom-global and it got me two more lines:

[2022-06-27 19:58:31.820] [INFO] Worker: Trying require('jsdom-global/register') [2022-06-27 19:58:33.086] [INFO] Worker: Trying require('@babel/register') [2022-06-27 19:58:33.090] [INFO] Worker: Caught error Error: Cannot find module '@babel/register'

I thought I might be going down the wrong rabbit hole with that approach though, so I didn't try to figure out what package(s) to install to get '@babel/register.

hbenl commented 2 years ago

As an aside, shouldn't that setting be the default?

The default is to try look if node_modules/mocha exists and is a directory and use that if it does or fall back to the bundled mocha otherwise. If you add that setting, it will not fall back to the bundled mocha because you've clearly stated that's not what you want. Apparently you have node_modules/mocha and it works so I don't understand why that check fails so that it falls back to the bundled mocha. Is node_modules/mocha perhaps symlinked?

[2022-06-27 19:58:31.820] [INFO] Worker: Trying require('jsdom-global/register')

So now it's not using the esm loader anymore (at least in your server folder)!? Furthermore, why is it trying to require jsdom-global/register even if that isn't needed in that folder? Do you have it in the VS Code settings for this folder?

I didn't try to figure out what package(s) to install to get '@babel/register'

That package is literally @babel/register.

machineghost commented 2 years ago

Is node_modules/mocha perhaps symlinked?

Nope, it's just a regular old npm install.

One thing of note though: two of my folders have the same name. One is root/client and one is root/admin/client. I only see one "client" in the test pane, so maybe that's why ... but it seems unlikely that it's making my root/admin/server tests not work.

So now it's not using the esm loader anymore (at least in your server folder)!?

My server output, when I rerun today, is:

[2022-06-29 18:49:19.230] [INFO] Worker finished with code 1 and signal null
[2022-06-29 18:49:19.981] [INFO] Worker: Patching Mocha
[2022-06-29 18:49:19.981] [INFO] Worker: Trying require('jsdom-global/register')
[2022-06-29 18:49:25.560] [INFO] Worker: Trying require('@babel/register')
[2022-06-29 18:49:25.579] [INFO] Worker: Caught error Error: Cannot find module '@babel/register'
Require stack:
- /home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/out/worker/bundle.js
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)
    at Function.Module._load (node:internal/modules/cjs/loader:778:27)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at /home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/out/worker/bundle.js:5790:35
    at Generator.next (<anonymous>)
    at fulfilled (/home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/out/worker/bundle.js:112:58) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    '/home/jeremy/.vscode/extensions/hbenl.vscode-mocha-test-adapter-2.13.5/out/worker/bundle.js'
  ]
}

Furthermore, why is it trying to require jsdom-global/register even if that isn't needed in that folder?

I have no idea ... you tell me ;)

Do you have it in the VS Code settings for this folder?

Here are my (relevant) VS Code settings:

  "mochaExplorer.files": "./{,!(node_modules)/**}/*.spec.js",
  "mochaExplorer.ignore": "node_modules",
  "mochaExplorer.require": ["jsdom-global/register", "@babel/register"],
  "testExplorer.addToEditorContextMenu": true,
  "testExplorer.hideEmptyLog": false,
  "testExplorer.errorDecoration": false,
  "mochaExplorer.logpanel": true,
  "explorer.fileNesting.enabled": true,
  "mochaExplorer.globImplementation": "vscode",
  "mochaExplorer.envPath": "",
  "mochaExplorer.mochaPath": "node_modules/mocha",

That package is literally @babel/register.

Oh, heh.

But my larger point is that I shouldn't be fixing a problem with an extension by installing new dependencies in my project. That project already works with its existing dependencies, as I can npx mocha and run my tests fine.

hbenl commented 2 years ago

So you have "mochaExplorer.require": ["jsdom-global/register", "@babel/register"] in your config, if these aren't really needed in that folder you should remove that. The next question is: are you using npm workspaces? I just looked into npm/yarn workspaces and realized why this extension is having problems with monorepos that use that npm feature. I'll have a fix for that in the next couple of days, hopefully this will solve your problems as well.

machineghost commented 2 years ago

So you have "mochaExplorer.require": ["jsdom-global/register", "@babel/register"] in your config

No, I do not. My .mocharc (for my server folder, ie. the one I'm trying to run test on) is:

'use strict';

process.env['NODE_ENV'] = 'test';
process.env['NODE_PATH'] = '/home/me/projectRoot/admin/server';

module.exports = {
  exit: true,
  bail: true,
  recursive: true,
  require: 'esm',
  file: ['./src/testMain.js'],
};

are you using npm workspaces?

No. I have three separate folders, each with their own completely separate package.json. The only thing the folders have in common is a common parent folder ... and the fact that I've added all three folders to VS Code.

hbenl commented 2 years ago

No, I do not.

I meant the VS Code settings that you posted earlier. Your .mocharc.js looks quite different from those settings: it tells mocha to require esm, whereas the VS Code settings are telling the extension to require jsdom-global/register and @babel/register. That's why they're behaving differently. I'd recommend removing all mochaExplorer.* settings, the extension will use the settings from .mocharc.js. Then re-add individual settings only when you really need them.

machineghost commented 2 years ago

When I do that ... well first off, it stops showing my other folders in the test pane, but that makes sense since they don't have (Mocha) tests ... but second, I do make progress! I now get:

/home/me/project/admin/server/src/graphql/mutations/login.spec.js:1
Error: Cannot find module 'src/graphql/authenticationUtil'
Require stack:
- /home/me/project/admin/server/src/graphql/mutations/login.spec.js

But that's a perfectly valid path, if this line from my .mocharc is respected:

process.env['NODE_PATH'] = '/home/me/project/admin/server';

And again, when I run npx mocha at the command line it does work, so it seems the plugin is somehow breaking that line of my config.

hbenl commented 2 years ago

The extension only takes the exported config from .mocharc.js, but it does this in a separate process, so any changes that .mocharc.js makes to the process (like setting environment variables) are not used. Most people that need environment variables for their tests put them in a .env file and use the dotenv package to load them, setting them in .mocharc.js is a neat trick that simplifies this but unfortunately that's currently not supported by this extension.

So here's what you could do:

Alternatively, if you don't want to add dotenv to your project, you could set the following VS Code setting (and keep the environment variables in .mocharc.js so that they're used when running npx mocha):

  "mochaExplorer.env": {
    "NODE_ENV": "test",
    "NODE_PATH": "/home/me/project/admin/server"
  }

The downside to this approach is that you're duplicating the environment variables, so if you ever change them you have to remember to make the same change in both places.

machineghost commented 2 years ago

That worked, thank you! I would submit a PR, adding further info about how environmental variables are an exception to:

Put your Mocha command line options (if you have any) in a mocha configuration file (either a .mocharc.* file or a mocha property in your package.json or a mocha.opts file) or VS Code's settings (see below)

... but you still haven't accepted my last PR :( And it's just a documentation PR also, which is like the easiest PR in the world to accept.

Surely you don't want to have to keep explaining this stuff to people in issues threads, when you can just explain it in the documentation?

hbenl commented 2 years ago

That worked, thank you!

:tada:

but you still haven't accepted my last PR :(

I've done that now, more PRs are welcome.

machineghost commented 2 years ago

PR added; thanks again for all the help!