hbenl / vscode-mocha-test-adapter

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

Error: Couldn't load options using mocha: child process exited with code 1 and signal null #92

Open cristian-spiescu opened 4 years ago

cristian-spiescu commented 4 years ago

Hello,

I started receiving this error these days. And of course, the tests are not any more listed in the "Test Explorer" section. The complete stack trace:

[Error: Couldn't load options using mocha: child process exited with code 1 and signal null
    at ChildProcess.<anonymous> (c:\Users\Cristi\.vscode\extensions\hbenl.vscode-mocha-test-adapter-2.2.2\out\optsReader.js:76:32)
    at Object.onceWrapper (events.js:288:20)
    at ChildProcess.emit (events.js:200:13)
    at maybeClose (internal/child_process.js:1021:16)
    at Process.ChildProcess._handle.onexit (internal/child_process.js:283:5)]

I did do some modifications to my .mocharc.js files. Before starting to undo them one by one, I was wondering if someone has any hints about this issue. Or at least hints about steps that I could take to debug.

Thanks in advance! Regards, Cristian

hbenl commented 4 years ago

Could you please attach your .mocharc.js so I can reproduce this (since the error occurs in a child process, there's no easy way to debug this that I could describe to you, but I'm sure I'll be able to figure it out myself).

donwinters commented 4 years ago

Our team is seeing this problem also. We are on CentOS 7 machines and this started happening with version 2.4.0. Hard to debug because there error seems to be happening in a another process. Willing to help debug but not sure what would be needed.

cristian-spiescu commented 4 years ago

I have 2 projects pretty similar. However, on one it works, and on another one it doesn't work.

A particularity is that i have a .mocharc.js in the "main" project which then calls a "general" .mocharc.js. In a linked folder. I had a handful of issues due to this because of this setup with many pieces of the tool chain (create-react-app based app). My guess is that this plays a role. But difficult to isolate for me again, because of the 2 rather similar projects with different behaviors.

hbenl commented 4 years ago

@donwinters Could you attach your config file? @cristian-spiescu Could you attach both config files? If they're relatively similar, there's a good chance that it could show me where the problem is.

cristian-spiescu commented 4 years ago

I'm attaching my setup. I have:

Our intention was to have a common .mocharc. And why 2 files? Actually because of the VSCode extension. This way, the code from .mocharc2.js would be loaded by the extension, which was needed. I left all my comments that explain the various hacks. Maybe one of this hack annoys the plugin.

But anyway: some investigation tool/process/way would be needed. I'm sure that if we see what's the actual exception => the solution is close.

my-project/.mocharc.js

global.projectDir = __dirname;
module.exports = require("@crispico/foundation-react/scripts/.mocharc1");

.../.mocharc1.js

/**
 * Reusing this was really tricky!
 * 
 * Called from <project>/.mocharc.js, which has set a global: projectDir. See in the sibbling file, i.e. .mocharc2.js
 * how this is used. We need this because nodejs resolves the path of the linked folders, and looks there for their
 * dependencies. I.e. would look in `<project>/node_modules/foundation-react/node_modules` instead of looking in 
 * `<project>/node_modules`. There is a node option /env var to prevent this, namely `--preserve-symlinks`. From cmd
 * line it works, because we can set it in NODE_OPTIONS before invoking mocha. But from the IDE: no, because this option
 * doesn't exist there.
 * 
 * Hence from the original script we pass as a global the project dir. But this is not all. I think when the IDE (extension)
 * evaluates these files, and resolving modules, it somehow clears the global stuff. That's why:
 * 
 * 1) we cannot do the stuff from `.mocharc2.js` here. It would work from cmd line, but not from IDE. And we need to `.mocharc2.js`
 * string to the "require" below.
 * 2) the global I was talking about is not available at the "other end". Hence a trick: include the original file again. It doesn't
 * do any harm. The second time (i.e. from "require" below), we don't need it's exported stuff. We only need the value of the global.
 * 
 * UPDATE: the trick w/ global.projectDir is not needed any more. But just when I tried to remove it I ran into another issue. Hence
 * I keep it for now. @see .mocharc2 around comment starting w/ "REALLY ODD".
 */
module.exports = {
    spec: ["src/**/*test.ts", "src/**/*test.js", "src/**/*test.tsx"],
    require: [".mocharc.js", "@crispico/foundation-react/scripts/.mocharc2.js"],

    // needed so that mocha can listen to changes on .tsx & co files; 
    // however, this is probably not used, because of bug #2 mentioned in "mocha-monkeypatched.js"
    extension: ["ts", "tsx", "js", "jsx"]
}

// w/o this, on "import 'my.css'" => error
require("ignore-styles");

// inspired from: https://github.com/ale-cristofori/test-openlayers/blob/master/setup.js
// and https://medium.com/@compatt84/how-to-test-open-layers-react-components-with-mocha-part-i-9a2ca0458ba1

const { JSDOM } = require('jsdom');
const jsdom = new JSDOM('<!doctype html><html><body></body></html>');
const { window } = jsdom;
const { canvas } = require('canvas');

function copyProps(src, target) {
  const props = Object.getOwnPropertyNames(src)
    .filter(prop => typeof target[prop] === 'undefined')
    .reduce((result, prop) => ({
      ...result,
      [prop]: Object.getOwnPropertyDescriptor(src, prop),
    }), {});
  Object.defineProperties(target, props);
}

global.window = window;
global.document = window.document;
global.navigator = {
  userAgent: 'node.js',
};

global.requestAnimationFrame = function (callback) {
  return setTimeout(callback, 0);
};
global.cancelAnimationFrame = function (id) {
  clearTimeout(id);
};
copyProps(window, global);

.../.mocharc2.js

/**
 * This script configures babel, using the preset used by CRA.
 */

process.env.BABEL_ENV = 'test';
process.env.NODE_ENV = 'test';

const register = require(global.projectDir + '/node_modules/@babel/register').default;

// TODO: tsx and jsx don't work currently; see .mocharc1.js 
const extensions = ['.ts', '.tsx', '.js', '.jsx'];

register({
  // Array of ignore conditions, either a regex or a function. (Optional)
  ignore: [
    // Method 1: regex. When a file path matches this regex then it is **not** compiled. 
    //
    // Until now, only OL needs to be transpiled, because it uses ES6 modules. Hence we hardcode it here.
    // If more is needed, we'll think of a solution to allow the end project to customize this.
    //  
    // The original regexp for OL from the tutorial seemed to have a bug
    // which actually allowed compilation for all from node_modules => huge perf issue. I debugged this by manually modifying the file: "\node_modules\@babel\register\lib\node.js"
    // and adding a "console.log()" in method "compile()", somewhere in the middle.
    /node_modules\\(?!(ol)\\)/

    // Method 2: function. Kept here for reference. 
    // The file's path is also passed to any ignore functions. It will
    // **not** be compiled if `true` is returned.
    //function(filepath) {
    //return filepath !== "/path/to/es6-file.js";
    //},
  ],
  extensions: extensions,
  // this is the preset used by CRA, which seems to have been developed with the intention to be reused
  // outside CRA. I.e. what we are doing here.
  presets: ["react-app"], // method 1 of including: specify string w/o "babel-preset" or "babel-plugin"
  retainLines: true, // w/ this, debug seems to work properly
  plugins: [
    // cf. https://github.com/babel/babel/issues/10022#issuecomment-495797723
    // needed because babel + ts doesn't process tsconfig.json. We have there already "baseUrl" set
    // which enables the use of non-relative imports (i.e. it looks also in "src").
    [require.resolve(global.projectDir + '/node_modules/babel-plugin-module-resolver'), { // method 2 of including: get the actual module
      /** 
       * REALLY ODD: I don't know why/how, the line below stopped working. And I had to use the trick w/ global.projectDir. This happened when
       * I has switching from npm -> yarn, and I just removed the hack w/ global.projectDir. I think somehow the "working dir" is not any more
       * the project dir.
       */
      // root: ["./src"],
      root: [global.projectDir + "/src"],
      // even though we have specified the extensions at top level, this plugin seems to need them explicitly
      extensions: extensions
    }],
  ],
});
hbenl commented 4 years ago

some investigation tool/process/way would be needed.

Absolutely. I have just published version 2.6.1 which will log all output from the child process stdout/stderr. Add "mochaExplorer.logpanel": true to your VS Code settings and it should show up in the "Mocha Explorer Log" output panel.

So if I understand this correctly you're doing some setup work for your tests in the config file. Unfortunately that won't work with Mocha Explorer (even if we get it to discover the tests correctly) because it doesn't load the config file when it runs the tests. It loads the config file first, merges the result with any configuration done in the VS Code settings and then passes the resulting configuration directly to Mocha when running the tests. Is there a particular reason why you do the setup work in the config file? If you do it in a separate file and load it using the --require option it would be compatible with Mocha Explorer.

cristian-spiescu commented 4 years ago

Unfortunately that won't work with Mocha Explorer Actually it does work (well, only in my smaller project) ...

If you do it in a separate file and load it using the --require Because this is what .mocharc1.js does. It prepares some stuff, and then passes w/ --require .mocharc2.js, which is loaded indeed by mocha even in "Mocha Explorer" mode.

module.exports = {
    spec: ["src/**/*test.ts", "src/**/*test.js", "src/**/*test.tsx"],
    require: [".mocharc.js", "@crispico/foundation-react/scripts/.mocharc2.js"],

It's not exactly --require; but it's also accepted.

Is there a particular reason

To be honest, despite my attempt to properly document the various hacks, I don't have an explanation for this. I do recall that I started from a simpler solution, and I "complicated" it to make it work in Mocha Explorer as well. And even with all this, I still had to add in settings.json:

    "mochaExplorer.env": {
        "NODE_OPTIONS": "--preserve-symlinks"
    },

I have just published version 2.6.1 which will log all output from the child process stdout/stderr This is great! Thanks a lot for your prompt support!

donwinters commented 4 years ago

[2020-07-01 13:56:44.887] [INFO] Worker: Patching Mocha [2020-07-01 13:56:44.888] [INFO] Worker: Trying require('ts-node/register') [2020-07-01 13:56:45.236] [INFO] Worker: Loading files [2020-07-01 13:56:45.239] [INFO] Worker: Patching describe [2020-07-01 13:56:45.239] [INFO] Worker: Patching describe.skip [2020-07-01 13:56:45.239] [INFO] Worker: Patching describe.only [2020-07-01 13:56:45.239] [INFO] Worker: Patching it [2020-07-01 13:56:45.239] [INFO] Worker: Patching it.only [2020-07-01 13:56:45.239] [INFO] Worker: Patching it.skip [2020-07-01 13:56:45.239] [INFO] Worker: Copying it.retries [2020-07-01 13:56:45.239] [INFO] Worker: Patching context [2020-07-01 13:56:45.239] [INFO] Worker: Patching context.skip [2020-07-01 13:56:45.239] [INFO] Worker: Patching context.only [2020-07-01 13:56:45.239] [INFO] Worker: Patching specify [2020-07-01 13:56:45.239] [INFO] Worker: Patching specify.only [2020-07-01 13:56:45.239] [INFO] Worker: Patching specify.skip [2020-07-01 13:56:45.239] [INFO] Worker: Copying specify.retries [2020-07-01 13:56:45.239] [INFO] Worker: Patching describe [2020-07-01 13:56:45.239] [INFO] Worker: Patching describe.skip [2020-07-01 13:56:45.239] [INFO] Worker: Patching describe.only [2020-07-01 13:56:45.239] [INFO] Worker: Patching it [2020-07-01 13:56:45.239] [INFO] Worker: Patching it.only [2020-07-01 13:56:45.239] [INFO] Worker: Patching it.skip [2020-07-01 13:56:45.239] [INFO] Worker: Copying it.retries [2020-07-01 13:56:45.239] [INFO] Worker: Patching context [2020-07-01 13:56:45.239] [INFO] Worker: Patching context.skip [2020-07-01 13:56:45.239] [INFO] Worker: Patching context.only [2020-07-01 13:56:45.239] [INFO] Worker: Patching specify [2020-07-01 13:56:45.239] [INFO] Worker: Patching specify.only [2020-07-01 13:56:45.239] [INFO] Worker: Patching specify.skip [2020-07-01 13:56:45.239] [INFO] Worker: Copying specify.retries [2020-07-01 13:56:47.220] [INFO] Worker (stdout): Arguments must begin with --

[2020-07-01 13:56:47.220] [INFO] Worker (stdout): Usage: appserver [OPTION]...

"specific usage options here that I deleted"

[2020-07-01 13:56:47.241] [INFO] Worker finished with code 1 and signal null

This is the error I'm getting. I have

"mochaExplorer.require": "ts-node/register",

For a setting. It's trying to launch our server and because the options being passed aren't recognized, it's failing. I guess it's trying to launch the server because of one of our npm scripts ?? Looking into that.

donwinters commented 4 years ago

But this does work with version 2.3.0 so any insight as to what changed might be useful

hbenl commented 4 years ago

@cristian-spiescu

this is what .mocharc1.js does. It prepares some stuff, and then passes w/ --require .mocharc2.js, which is loaded indeed by mocha even in "Mocha Explorer" mode.

Yes, that's what I meant when I said "load it using the --require option". But .mocharc1.js also seems to do some setup: it adds some variables to global and those will be gone when the tests are run. If those variables aren't needed in the tests, this could work (but then you could remove those variables altogether).

@donwinters Your issue seems to be different: the failing child process is the one that runs the tests, not the one that loads the configuration. Looking at the changes from 2.3.0 to 2.4.0 my first guess would be that you're using a glob for your test files that includes files in node_modules (e.g. "**/*.test.ts"). In version 2.3.0, files in node_modules were automatically excluded, even if the glob included them. This was causing some other issues, so I changed it in 2.4.0: now Mocha Explorer behaves more like Mocha itself, it doesn't exclude node_modules automatically.

donwinters commented 4 years ago

Ok, our problem is on our side, but I just couldn't debug it without that debug flag you added, so thanks for that. We seem to be running the actual server in some of the tests, (wasn't aware of that) and it's looking for some configuration files, we seem to have a bug wrt that so it complains that it's getting bad command line arguments. But I wasn't seeing any of that before.

donwinters commented 4 years ago

We do use a glob in our test files btw, I don't see how node_modules would be an issue though. Still not clear on why is works in 2.3.0

"mochaExplorer.files": ["nodejs/apiserver/test/**/*.test.ts", "nodejs/apiserver/test-int/**/*.test.ts"],

donwinters commented 4 years ago

And a quick question if you don't mind, these .mocharc1.js files, is that the way to go, was never clear on that?

donwinters commented 4 years ago

Question, it looks like you send a along an empty object as a command line argument. Why is that? Our code reads that as a bad command line parameter. I'm thinking that's what changed between 2.3.0 and 2.4.0

argv: .../extensions/hbenl.vscode-mocha-test-adapter-2.6.1/out/worker/bundle.js,{}

hbenl commented 4 years ago

I don't see how node_modules would be an issue though

You're right, your globs don't include node_modules, so that's not the issue

it looks like you send a along an empty object as a command line argument

Yes, and that's actually one of the changes in 2.4.0. (This object is only filled when you use the mochExplorer.ipc* settings, in this case it contains information about how the worker should establish a TCP/IP connection to communicate with Mocha Explorer. When it's empty (the default), the worker will use Node's standard IPC mechanism for child processes. The reason I introduced it is to support the vscode-test framework for extension tests (in this case Node's IPC mechanism doesn't work)). So it looks like we've found the problem.

these .mocharc1.js files, is that the way to go, was never clear on that?

Depends on what you mean by that. .mocharc.[json|yaml|js] are the new config file formats introduced in Mocha 6, the old format (mocha.opts) is deprecated. So yeah, I'd recommend putting your mocha configuration in one of those files, because then you use the same configuration when you use Mocha on the command line and when you use it through Mocha Explorer.

donwinters commented 4 years ago

Ok so the empty object is the problem. I take it that isn't going away. I can make a tweak to our code (I guess) to handle that. But should it really send along an empty object? idk about that.

yairEO commented 3 years ago

I am experiencing the same problem in my project. I am of course able to run tests via CLI by simply running the command mocha. I'm on Node v12.21.0 and Windows 10. I've tried to upgrade to Node 14 but still same error.

.mocharc.json

{
  "spec": "src/**/*.test.js"
}

output

[2021-04-19 19:20:07.909] [INFO] Loading test files of c:\projects\catalog-one\master\catalogone-ui-components
[2021-04-19 19:20:07.909] [DEBUG] Using working directory: c:\projects\catalog-one\master\catalogone-ui-components
[2021-04-19 19:20:08.099] [DEBUG] Using nodePath: C:\Program Files\Volta\node.exe
[2021-04-19 19:20:08.294] [ERROR] Worker (stderr): child_process.js:127
  p.open(fd);
    ^

Error: EBADF: bad file descriptor, uv_pipe_open
    at Object._forkChild (child_process.js:127:5)
    at setupChildProcessIpcChannel (internal/bootstrap/pre_execution.js:337:30)
    at prepareMainThreadExecution (internal/bootstrap/pre_execution.js:59:3)
    at internal/main/run_main_module.js:7:1 {
  errno: -4083,
  code: 'EBADF',
  syscall: 'uv_pipe_open'
}

[2021-04-19 19:20:08.306] [ERROR] Couldn't load options using mocha: child process exited with code 1 and signal null
[2021-04-19 19:20:08.306] [ERROR] Error while loading tests: Error: Couldn't load options using mocha: child process exited with code 1 and signal null
    at ChildProcess.<anonymous> (c:\Users\Yaire\.vscode-insiders\extensions\hbenl.vscode-mocha-test-adapter-2.11.0\out\optsReader.js:89:32)
    at Object.onceWrapper (events.js:422:26)
    at ChildProcess.emit (events.js:315:20)
    at maybeClose (internal/child_process.js:1048:16)
    at Process.ChildProcess._handle.onexit (internal/child_process.js:288:5)
yairEO commented 3 years ago

Now I just have this output:

Error: Couldn't load options using mocha: child process exited with code 1 and signal null
    at ChildProcess.<anonymous> (c:\Users\Yaire\.vscode-insiders\extensions\hbenl.vscode-mocha-test-adapter-2.12.1\out\optsReader.js:89:32)
    at Object.onceWrapper (events.js:422:26)
    at ChildProcess.emit (events.js:315:20)
    at maybeClose (internal/child_process.js:1048:16)
    at Process.ChildProcess._handle.onexit (internal/child_process.js:288:5)

With my project and also a clone of this very repo:

image

I have Mocha installed globally (npm i mocha@8.2.1 -g). The error of this extension is coming from hbenl.vscode-mocha-test-adapter-2.12.1\out\worker\loadConfig.js so I looked inside:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const options_1 = require("mocha/lib/cli/options");
process.send(options_1.loadOptions(process.argv.slice(2)));
//# sourceMappingURL=loadConfig.js.map

So I opened my node in vscode terminal and ran this command (in my project's path):

> require("mocha/lib/cli/options").loadOptions()

Which worked and yielded:

{       
  _: [],
  diff: true,
  config: false,
  package: false,
  require: [ 'test/register.js', 'test/setup.js' ],
  r: [ 'test/register.js', 'test/setup.js' ],
  timeout: 10000,
  t: 10000,
  timeouts: 10000,
  exit: true,
  extension: [ 'js', 'cjs', 'mjs' ],
  reporter: 'spec',
  R: 'spec',
  slow: 75,
  s: 75,
  ui: 'bdd',
  u: 'bdd',
  'watch-ignore': [ 'node_modules', '.git' ]
}
BryanHunt commented 3 years ago

I have a trivial project that reproduces this failure: https://github.com/BryanHunt/ts-debug

dhowe commented 1 year ago

Same problem

HolisticDeveloper commented 1 year ago

I was getting this error when using nodist to manage multiple Node versions. I switched to NVM for Windows and now things are working.

Thanks to Cactusbone's Stack Overflow answer for pointing me to the problem.

ssbarnea commented 2 months ago

Once I ask it to load .mocharc.yml it does crash.