Remi
Remi

Reputation: 5367

How to test an node file, receiving an 'EACCES' error when spawning the function

When creating a CLI I would like to test my function. For that I'm using the module child_process.

const path = require('path');
const { execFile } = require('child_process');

describe('cli test', () => {
  test('thing', () => {

    const myCli = execFile(
      `${path.resolve(__dirname, '..')}/cli.js`, ['--foo', 'Bar'],
      (err, stdout, stderr) => {
      if (err) {
        console.log('err: ', err);
      }
    });
});

But this produces the following error:

Attempted to log "err:  { Error: spawn /projects/cli/src/cli.js EACCES
        at Process.ChildProcess._handle.onexit (internal/child_process.js:240:19)
        at onErrorNT (internal/child_process.js:415:16)
        at process._tickCallback (internal/process/next_tick.js:63:19)
      errno: 'EACCES',
      code: 'EACCES',

Running this script directly in the terminal via the command: $ node cli.js --foo Bar works perfectly.

Now a suggestion is to chmod +x <file> that file (source). But the test should also work on CI, and on a different computer which pulls the Git repo.

Any idea?

Upvotes: 1

Views: 3285

Answers (3)

MER
MER

Reputation: 1561

I was receiving an EACCESS -13 error from child_process.spawn when trying to run a the command line mysql command.

There was something wrong with my PATH and updating it to add /usr/local/mysql/bin/ resolved the problem.

The temporary fix is to run export PATH=$PATH:/usr/local/mysql/bin/.

The permanent fix is to:

  1. type: sudo nano /etc/paths
  2. Add /usr/local/mysql/bin at the end
  3. Ctrl + X
  4. Yes
  5. Enter key
  6. type hash -r @ command line or close the terminal app and open it again

NOTE: I got the temporary fix from a site ... I don't know why it has a / on the end of the bin but all of the mysql executables appear to be available without it in the /etc/paths file

Upvotes: 0

Jacob
Jacob

Reputation: 78920

I'd suggest using fork instead of execFile.

The child_process.fork() method is a special case of child_process.spawn() used specifically to spawn new Node.js processes.

This will allow you to execute JS files without needing them to be shell executable.

Upvotes: 2

derbenoo
derbenoo

Reputation: 333

To the best of my knowledge, git actually tracks the executable bit for files. There are some things to consider though as pointed out in this article: https://medium.com/@tahteche/how-git-treats-changes-in-file-permissions-f71874ca239d

Another solution would be to not rely on the ./ execution syntax (which requires the executable bit to be turned on for the respective file) but instead to explicitly use the shell command:

const path = require('path');
const { execFile } = require('child_process');

describe('cli test', () => {
  test('thing', () => {

    const myCli = execFile(
      `sh ${path.resolve(__dirname, '..')}/cli.js`, ['--foo', 'Bar'],
      (err, stdout, stderr) => {
      if (err) {
        console.log('err: ', err);
      }
    });
});

Notice the sh prefix I added to your code, This way you thell the sh command (which should be available in all of your environments e.g. the CI) to execute the contents of the file, regardless of whether the file itself can be executed or not!

Upvotes: 0

Related Questions