96

I am writing test cases for my Node.js application using Mocha. The test cases need an API key as an extra input option or parameter. The API key is private, so I don't want to include it directly in the test files as everyone then can see it on GitHub. I know there are some options available for Mocha at:

http://mochajs.org/#usage

But is it possible to include some parameters to let testers specify their own API key for the test in the commandline? Such as:

./node_modules/mocha/bin/mocha test/*.js --key YOUR_KEY
Yves M.
  • 29,855
  • 23
  • 108
  • 144
afterglowlee
  • 11,670
  • 5
  • 22
  • 23

10 Answers10

94

I don't think Mocha itself supports passing extra parameters to your tests, but you could use environment variables:

env KEY=YOUR_KEY mocha test/*.js # assumes some sort of Unix-type OS.

And read them in your test files:

var key = process.env.KEY;
robertklep
  • 198,204
  • 35
  • 394
  • 381
  • 11
    For multiple parameters `env KEY1=YOUR_KEY1 KEY2=YOUR_KEY2 mocha test` – Philiiiiiipp Feb 09 '16 at 15:59
  • in 2017 it is now possible, see my answer below – danday74 Apr 26 '17 at 09:58
  • 2
    @danday74 the problem is not sharing sensitive information. I don't see how your solution works around that, because it means that certain files _still_ can't be checked in. Using environment variables passed on the command line prevents having to do that. – robertklep Apr 26 '17 at 10:47
34

Take a look at the optimist module by Substack and nconf from flatiron. A lot of my tests depend on external parameters and the optimist and nconf modules makes it easy to load configuration options from a json file

In your test command pass the path to the config.json file

test command

mocha test/api-test.js --config=/path/to/config.json --reporter spec

api-test.js

var path = require('path')
var fs = require('fs')
var assert = require('assert')
var argv = require('optimist').demand('config').argv
var configFilePath = argv.config
assert.ok(fs.existsSync(configFilePath), 'config file not found at path: ' + configFilePath)
var config = require('nconf').env().argv().file({file: configFilePath})
var apiConfig = config.get('api')
var apiKey = apiConfig.key

config.json

{
  "api": {
    "key": "fooKey",
    "host": "example.com",
    "port": 9000
  }
}

Alternative

Another pattern I have been using recently is the config module. You can specify a ./config/default.yml file for running regularly and a ./config/test.yml file for tests.

When running your test suite, export NODE_ENV=test and the config module will load test.yml

In your code it is easy to access the configuration object

var config = require('config')

// config now contains your actual configuration values as determined by the process.env.NODE_ENV
var apiKey = config.api.key

An easy way to set NODE_ENV=test is by running your tests with a makefile. Run all your tests via make test. To run a single test execute make one NAME=test/unit/sample-test.js

Sample makefile

MOCHA?=node_modules/.bin/mocha
REPORTER?=spec
GROWL?=--growl
FLAGS=$(GROWL) --reporter $(REPORTER) --colors --bail

test:
        @NODE_ENV="test" \
        $(MOCHA) $(shell find test -name "*-test.js") $(FLAGS)

one:
        @NODE_ENV="test" \
        $(MOCHA) $(NAME) $(FLAGS)

unit:
        @NODE_ENV="test" \
        $(MOCHA) $(shell find test/unit -name "*-test.js") $(FLAGS)

integration:
        @NODE_ENV="test" \
        $(MOCHA) $(shell find test/integration -name "*-test.js") $(FLAGS)

acceptance:
        @NODE_ENV="test" \
        $(MOCHA) $(shell find test/acceptance -name "*-test.js") $(FLAGS)

.PHONY: test
Noah
  • 33,851
  • 5
  • 37
  • 32
34

One of the easiest ways to pass parameters similar to the process.argv[index] method mentioned in this thread is using the npm config variables. This allows you to see the variable name a little more clearly:

test command:

npm --somevariable=myvalue run mytest

package.json:

"scripts": {
"mytest": "mocha ./test.js" }

test.js

console.log(process.env.npm_config_somevariable) // should evaluate to "myvalue"
Adam Levine
  • 351
  • 3
  • 2
  • this solution seems quite nice as its using the npm facility. could you comment on how you might pass multiple arguments from the command line like this? – roman Mar 08 '19 at 14:54
  • @roman: Have you tried `npm ---somevar=myval --anothervar = anotherVal run mytest` with `process.env.npm_config_somevar` and `process.env.npm_config_anothervar`? – Brett Zamir Jun 23 '19 at 02:57
27

The other answers are limited in that they do not support code execution prior to running your test suite. They only support passing parameters.

This answer supports code execution BEFORE your test suite is executed and is fully documented by mocha

mocha docs: http://unitjs.com/guide/mocha.html#mocha-opts

create ./test/mocha.opts

--recursive
--reporter spec
--require ./server.bootstrap
--require ./test/test.bootstrap

create ./server.bootstrap.js

global.appRoot = require('app-root-path');
// any more server init code

create ./test/test.bootstrap.js

process.env.NODE_ENV='test';
// any more test specific init code

finally in your server.js:

require('./server.bootstrap');

DONE!

The code in the server bootstrap will be executed prior to testing and server execution (npm start and npm test)

The code in the test bootstrap will only be executed prior to testing (npm test)

Thanks to @damianfabian for this one - see How to initialise a global variable in unit test runs?

danday74
  • 52,471
  • 49
  • 232
  • 283
20

There's no supported way to do this with Mocha. the suggested way is to use a file (for instance config.json), require it, and let other people change it.

That being said, if you pass your key at the end of the commandline (after the file to test) and use -- it should be available using process.argv (if you don't use -- or it's not after a regular file name, then mocha will fail).

if you run ./node_modules/mocha/bin/mocha --reporter spec test.js --apiKey=someKey , and test.js contains the code:

var assert = require("assert")
describe("testy", function () {
    it("shouldy", function (done) {
        var value;
        for (var index in process.argv) {
            var str = process.argv[index];
            if (str.indexOf("--apiKey") == 0) {
                value = str.substr(9);
            }
        }
        assert.equal(value,"someKey")
        done();
    })
})

the test should pass

Alon Bar David
  • 1,757
  • 14
  • 15
16

You can pass an argument to mocha test script using 'minimist' module. Install with npm install minimist

Terminal:

mocha test.js --config=VALUE

Mocha node script:

var argv = require('minimist')(process.argv.slice(2));
console.log('config', argv.config);
David Douglas
  • 10,377
  • 2
  • 55
  • 53
6

A simple way, using process.argv that contain the command line args

$ mocha  -w test/*.js --KEY=YOUR_VALUE

Later, you can get YOUR_VALUE in your code:

let LAST_PARAM = process.argv[process.argv.length-1]

let PARAM_NAME  = LAST_PARAM.split("=")[0].replace("--","")
let PARAM_VALUE = LAST_PARAM.split("=")[1]

console.log("KEY: ", PARAM_VALUE)

To see all process.argv:

process.argv.forEach((value, index) => {
        console.log(`process.argv[${index}]: ${value}`);
})

Output:

$ mocha  -w test/*.js --KEY=YOUR_VALUE

KEY:  YOUR_VALUE
process.argv[0]: /usr/local/bin/node
process.argv[1]: /Users/pabloin/.npm-packages/lib/node_modules/mocha/bin/_mocha
process.argv[2]: -w
process.argv[3]: test/tt.js
process.argv[4]: test/tt2.js
process.argv[5]: --KEY=YOUR_VALUE

KEY:  YOUR_VALUE
process.argv[0]: /usr/local/bin/node
process.argv[1]: /Users/pabloin/.npm-packages/lib/node_modules/mocha/bin/_mocha
process.argv[2]: -w
process.argv[3]: test/tt.js
process.argv[4]: test/tt2.js
process.argv[5]: --KEY=YOUR_VALUE
Serg
  • 2,346
  • 3
  • 29
  • 38
Pablo Ezequiel Inchausti
  • 16,623
  • 7
  • 28
  • 42
  • 1
    Wouldn't it be easier to understand for the people here if you call it ```mocha -w test/*.js --KEY=YOUR_VALUE``` instead of ```--KEY=YOUR_KEY```? – hardfork Nov 01 '19 at 13:58
  • unfortunately this does not work for newly introduced --parallel mode. It spawns new nodejs processes, and these args are not passed to them – Xotabu4 Mar 27 '21 at 19:36
  • @Xotabu4 do you know if there is a way of passing the args when in --parallel mode? – Don Charlie Jun 23 '21 at 23:26
  • @DonCharlie you can use env variables – Xotabu4 Jul 16 '21 at 15:33
3

I could send parameter thought mochaStream (require('spawn-mocha-parallel').mochaStream).

like:

var mochaStream = require('spawn-mocha-parallel').mochaStream;

var mocha = mochaStream({
    env: function(){
        return {yourParam: 'value'}
    }
});

return gulp.src('test/**/*-specs.js', {read: false})
    .pipe(mochaStream)
    .on('error', console.warn.bind(console));

Inside ..spec.js file

var yourParam = process.env.yourParam;
SM Adnan
  • 555
  • 2
  • 10
2

I have been reading quite some answers, most of them more complex than the actual solution has to be.

Let's say I have config.yml or config.json. In my case it's a YAML file.

First of all I install the yamljs dependency. It has a function called load.

Basically what I do:

const YAML = require('yamljs'); const ymlConfig = YAML.load('./config.yml');

Then I go for:

process.env.setting1 = ymlConfig.setting1; process.env.setting2 = ymlConfig.setting2;

And of course - this is all done in your test file.

Bilger Yahov
  • 377
  • 4
  • 14
1

if you are debugging/testing with Mocha sidebar (VS Code extension), just put it:

{
    "mocha.env": {
        "KEY": "YOUR_KEY",
        "MY_VARIABLE": "MY VALUE"
    }
}

at .vscode/settings.json

fsilva
  • 406
  • 1
  • 3
  • 9
  • 1
    This solution is too tied to a specific tool. – MattiSG Aug 28 '20 at 13:52
  • yep, I guess I'm clear when I put conditional at the beginning the answer, I'm just giving complement/other options about the main reference. :) – fsilva Aug 29 '20 at 19:14