Question

I'm having quite the time trying to set up node/npm with Mocha and RequireJS. Here's what I've done.

I've created a testing/ directory, with this structure:

testing/
   |
   +-- package.json
   |
   +-- README.md
   |
   +-- test/
         |
         +-- mocha.opts
         |
         +-- widgets/
                |
                +--mywidget/
                       |
                       +-- test.js

Here is what each relevant file contains:

package.json:

{
    "name":"testing-project",
    "version":"2.5.0",
    "description":"Testing Project",
    "keywords":["test"],
    "engines": { "node": ">= 0.7.0 < 0.11.0" },
    "scripts" : {
        "test": "./node_modules/.bin/mocha"
    },
    "devDependencies": {
        "mocha": ">= 1.18.2",
        "requirejs": ">= 2.1.11",
        "should": ">= 3.2.0",
        "expect.js": ">= 0.3.1"
    }
}

test/mocha.opts:

--require expect.js
--require should
--require requirejs
--require mocha
--reporter spec
--ui tdd
--recursive
--growl

test/widgets/mywidget/test.js

'use strict';
var requirejs = require('requirejs');
// Also tried with:  require('../../../r.js')  which I downloaded from RequireJS' site

requirejs.config({
    baseUrl: '../../../../',
    nodeRequire: require
});

console.log('before require');
requirejs(['mywidget/trunk/src/mywidgetfile.js'], function(myObj){
    console.log('after require');

    var expect = require('expect.js');

    // Instead of the above "requirejs['mywidget..." line, I've also tried:
    // var myObj = requirejs('mywidget/trunk/src/mywidgetfile.js');   AND:
    // var myObj = requirejs('../../../../mywidget/trunk/src/mywidgetfile.js');

    describe('My Widget', function(){
        describe('my-widget#getInfo', function(){

            it('should pass this test', function(done){
                expect( myObj.returnString('test') ).to.equal( 'test' );

                done();
            })
        })
    });
});
console.log('done');

It will output the console lines "before require" and "done", but as long as I have the requirejs(['mywidget... line in, it will not hit the after require. If I remove the requirejs line (and the corresponding closing brace/paren line), and instead use the direct "var myObj =" line, I get "cannot find module", and if I use the second "var myObj" line, I get "Reference Error: define is not defined".

I'm trying to package this all, for convenience for other developers, with npm, such that I'm running the command "npm test" from within the top "testing/" directory.

I've been scouring for answers and trying so many things, but I can't seem to require a file using RequireJS and have "define()" defined. I can execute tests, that's not a problem... it's just trying to insert RequireJS into the mix that is when I start having the issues.

Any help would be tremendous!

Thank you!

Was it helpful?

Solution

There are multiple problems going on in what you are showing us. You are incorrectly using both RequireJS and Mocha.

RequireJS

I am pretty sure your baseUrl is incorrect. You seem to think that Mocha's current working directory will be set to test/widgets/mywidget/ when it executes the tests in test/widgets/mywidget/test.js. That's not the case. The working directory is wherever you happen to be when you run npm test. According to your description you are in testing/ when you run it. It is not clear to me what value your baseUrl should be because you do not provide enough information in your question but I trust that from the explanation I just gave you can figure it out.

Now you may think "surely, my baseUrl is correct because when I execute requirejs(['mywidget/trunk/src/mywidgetfile.js'], function(myObj){ I don't get an error". This would be an incorrect inference. While this requirejs invocation schedules the loading of your module, RequireJS does not get the opportunity to try loading it because Mocha exits before RequireJS tries to load it. You can check this by replacing your module path with complete garbage and you won't get an error.

Once you fix this baseUrl issue, using var myObj = requirejs('mywidget/trunk/src/mywidgetfile.js') will work as you expect. So you'll be able to avoid using the asynchronous form of require (this is the form that uses an array of dependencies as the first argument). (The requirejs function you use is just an alias for the function normally called require in RequireJS' documentation.)

Mocha

Your tests are not running because Mocha does not see them. The way Mocha works is by reading all of the test files it finds and then executing them. The callbacks to each describe calls are executed right away, and the callbacks to each it calls are recorded as tests to be run. Once Mocha is done figuring out what tests exist, it runs them.

What happens with your test file is that Mocha executes it, as usual. However, there is no call to describe or it in the top scope of your test file. There are calls in your callback to requirejs but remember what I said above: RequireJS does not get the opportunity to load the module so it does not get the opportunity to run the callback. (And even if it did run it, it would be too late.) So Mocha does not see any tests and exits right away.

The Way Forward

Figure out the baseUrl you need, and then this should work:

'use strict';
var requirejs = require('requirejs');

requirejs.config({
    baseUrl: <whatever value is needed here>,
    nodeRequire: require
});

var myObj = requirejs('mywidget/trunk/src/mywidgetfile.js');

describe('My Widget', function() {
// etc...

You might also consider dropping RequireJS entirely from your test suite. I've written a library that works just as well in Node as in the browser. It is composed of AMD modules and is loaded by RequireJS in the browser, but I don't use RequireJS in the test suite. This is the loader I use to load my modules in Node. There's also amdefine which I've not used but should give similar capabilities.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top