58

I have a file named test/helper.js that I use to run Mocha tests on my Node.js apps. My tests structure looks like:

test/
test/helper.js    # global before/after
test/api/sometest.spec.js
test/models/somemodel.spec.js
... more here

The file helper.js has to be loaded because it contains global hooks for my test suite. When I run Mocha to execute the whole test suite like this:

mocha --recursive test/

the helper.js file is loaded before my tests and my before hook gets executed as expected.

However, when I run just one specific test, helper.js is not loaded before the test. This is how I run it:

mocha test/api/sometest.spec.js

No global before called, not even a console.log('I WAS HERE');.

So how can I get Mocha to always load my helper.js file?

Louis
  • 146,715
  • 28
  • 274
  • 320
Zlatko
  • 18,936
  • 14
  • 70
  • 123

6 Answers6

29

Mocha does not have any notion of a special file named helper.js that it would load before other files.

What you are trying to do works when you run mocha --recursive because of the order in which Mocha happens to load your files. Because helper.js is one level higher than the other files, it is loaded first. When you specify an individual file to Mocha, then Mocha just loads this file and, as you discovered, your helper.js file is not loaded at all.

So what you want to do is load a file such that it will set top level ("global") hooks (e.g. before, after, etc.). Options:

  1. You could use Mocha programmatically and feed it the files in the order you want.

  2. You could force yourself to always specify your helper file on the command line first before you list any other file. (I would not do this, but it is possible.)

  3. Another option would be to organize your suite like I've detailed in this answer. Basically, you have one "top level" file that loads the rest of the suite into it. With this method you'd lose the ability of running Mocha on individual files, but you could use --grep to select what is being run.

You cannot use the -r option. It loads a module before running the suite but, unfortunately, the loaded module does not have access to any of the testing interface that Mocha makes available to your tests so it cannot set hooks.

Community
  • 1
  • 1
Louis
  • 146,715
  • 28
  • 274
  • 320
  • Would it be possible to exploit the test files' load order so that I would have only one file inside the `test` folder (with global hooks etc.), i.e `helper.js` and all other test files inside a subdirectory, i.e. `unit`? (**Update:** *Ah, it seems the answer I seek is already part of the question -> yes.:)* ) – Robert Rossmann Jan 28 '15 at 12:32
  • What you suggest is the second option in my answer. I did not repeat what happens when you run `mocha` without arguments (which the OP already knows and understands). I've just mentioned how you could make it work if you want to run only one specific file: `mocha test/helper.js [whatever other file]`. – Louis Jan 28 '15 at 12:36
  • Thanks, but then why would mocha load the helper.js at all? I thought that mocha will only look for files that have `spec` somewhere in the name? – Zlatko Jan 28 '15 at 13:13
  • And now that I've tested, I see that it does not. It was `jasmine`, right? Not mocha. Silly me. – Zlatko Jan 28 '15 at 13:16
  • @Louis Apparently in my case the test_helper.js is always getting loaded first. I've not used any hook or any other directory or configuration. Posted . with all the details and folder structure. Tried on 4 System and even cloud9 ide. but still same behavior from the Mocha http://stackoverflow.com/questions/43229233/how-mocha-knows-which-file-to-load-first-in-the-test-suite – Ankur Anand Apr 05 '17 at 12:41
19

What I do is create a test/test_helper.js file, which exports all the helpers I create:

// test/test_helper.js    
module.exports = {
    MyHelper: require('./helpers/MyHelper')
}

Then I require the helper on any test I need to use it:

// test/spec/MySpec.js
var helper = require('../test_helper');

// Or if you need just "MyHelper"
var myHelper = require('../test_helper').MyHelper;

describe('MySpec', function () {
   // Tests here...
});

I prefer the above approach because its easy to understand and flexible. You can see it in action here in my demo: https://github.com/paulredmond/karma-browserify-demo/tree/master/test

Paul Redmond
  • 683
  • 7
  • 17
18

First, I would definitely use mocha.opts so that you don't have to include the options you want every time. As pointed out, one option is to use --grep, but I am not a huge fan of that personally. It required you name everything in an overly simplistic way. If the before hook is NOT async you can use --require in your mocha.opts. e.g.

#mocha.opts
--recursive
--require test/helpers.js

It sounds like this wouldn't work for you because you want global after hook as well. What I have done is I just call the full test suite every time, but if I am in the middle of deving and only want to test one suite, or even one specific test, I use the exclusivity feature, only https://mochajs.org/#exclusive-tests. You can make it it.only('... or describe.only('... If you do this it looks through all tests and sets up exactly like your full test harness would, but then only executes the test or suite you have specified.

Now you can include those global hooks no problem. @Louis mentions that your helpers.js are loading in the proper order only coincidently. That is not true. If you place any hooks outside of a describe block, it automatically becomes a global hook. This can be accomplished by either putting it in its own file

// helpers.js
before(function() { console.log('testing...'); });

or within a test file

// some.spec.js
before(function() { console.log('testing...'); });

describe('Something', function() {
  it('will be tested', function() {
  ...
  });
});

Obviously, I think putting it in its own file is cleaner. (I called it hooks.js). Point is, this is not a result of the order in which files were loaded.

Just one gotcha that might be obvious to other but I struggled with briefly -- hooks not placed in a describe block are ALL global. They are not directory specific. So if you copy helpers.js into a sub-directory of tests, the before and after hook will now fire twice. Also, if you place a beforeEach hook in there, it will fire before every single test, not just those tests in that directory.

Anyway, I know this post is a bit old, but hopefully this will help others having similar issues.

aray12
  • 1,833
  • 1
  • 16
  • 22
  • 1
    Thanks, but Louis actually was on the right track. I've come to mocha from another test framework, where a `helper.js` would automatically get called, that was my problem. – Zlatko Mar 29 '16 at 09:26
  • 1
    @Zlatko glad you found the right solution for you. This was more because I ran through some similar problems on my own and wanted to share my experiences. Also I hope you realize that some of what Louis said about load order was actually wrong. You can create global hooks, you just can't call the test on an individual file then. – aray12 Mar 29 '16 at 17:26
  • Yep, I've figured a lot of those things since ;) – Zlatko Mar 29 '16 at 18:39
15

Late addition to the answer:-

Mocha (v7.0.0 as of writing) support specifying file as an option:-
As per the docs

  --file               Specify file(s) to be loaded prior to root suite
                       execution 

.mocharc.json


{
    "watch-files": [
       "test/**/*.js"
    ],
    "recursive": true,
    "file": "test/setup"
}

./test/setup.js

const request = require('supertest');
const app = require('../app'); // express app
global.request = request(app);

A Worthy Mention:

I found that the above setup loaded all .js files anyway, probably because of the mocha config extension which is set to js by default. Since I had the convention of naming all tests file with .spec.js, I can ignore other files by adding "ignore": ["test/**/!(*.spec.js)"]

daisura99
  • 1,030
  • 1
  • 12
  • 22
4

I came to this question after trying all sorts of things to get my tests to connect once to a database before subsequently running a bunch of crud tests on my models.

Then I found mocha-prepare which solved my problems.

In your helper.js file you can just define a prepare function.

prepare(done => {
  console.log('do something asynchronously here')
  done()
}, done => {
  console.log('asynchronously clean up after here')
  done()
})

works a treat.

Dave Sag
  • 13,266
  • 14
  • 86
  • 134
  • 1
    Yep, that's what I basically do, just without the mocha-prepare module, I set it up manually. – Zlatko Mar 08 '17 at 17:20
0

In our project, we are using helpers somewhat like this:

clientHelper = require("../../../utils/clientHelper")

You need to configure relative path of your helper properly.

And then calling it like this:

clientHelper.setCompanyId(clientId)
Petter Friberg
  • 21,252
  • 9
  • 60
  • 109