Why do I see "define not defined" when running a Mocha test with RequireJS?

54,172

Solution 1

The Mocha documentation is lacking on how to set this stuff up, and it's perplexing to figure out because of all the magic tricks it does under the hood.

I found the keys to getting browser files using require.js to work in Mocha under Node: Mocha has to have the files added to its suites with addFile:

mocha.addFile('lib/tests/Main_spec_node');

And second, use beforeEach with the optional callback to load your modules asynchronously:

describe('Testing "Other"', function(done){
    var Other;
    beforeEach(function(done){
        requirejs(['lib/Other'], function(_File){
            Other = _File;
            done(); // #1 Other Suite will run after this is called
        });
    });

    describe('#1 Other Suite:', function(){
        it('Other.test', function(){
            chai.expect(Other.test).to.equal(true);
        });
    });
});

I created a bootstrap for how to get this all working: https://github.com/clubajax/mocha-bootstrap

Solution 2

You are trying to run JS modules designed for browsers (AMD), but in the backend it might not work (as modules are loaded the commonjs way). Because of this, you will face two issues:

  1. define is not defined
  2. 0 tests run

In the browserdefine will be defined. It will be set when you require something with requirejs. But nodejs loads modules the commonjs way. define in this case is not defined. But it will be defined when we require with requirejs!

This means that now we are requiring code asynchronously, and it brings the second problem, a problem with async execution. https://github.com/mochajs/mocha/issues/362

Here is a full working example. Look that I had to configure requirejs (amd) to load the modules, we are not using require (node/commonjs) to load our modules.

> cat $PROJECT_HOME/test/test.js

var requirejs = require('requirejs');
var path = require('path')
var project_directory = path.resolve(__dirname, '..')

requirejs.config({
  nodeRequire: require, 
  paths: {
    'widget': project_directory + '/src/js/some/widget'
  }
});

describe("Mocha needs one test in order to wait on requirejs tests", function() {
  it('should wait for other tests', function(){
    require('assert').ok(true);
  });
});


requirejs(['widget/viewModel', 'assert'], function(model, assert){

  describe('MyViewModel', function() {
    it("should be 4 when 2", function () {
        assert.equal(model.square(2),4)
    })
  });

})

And for the module that you want to test:

> cat $PROJECT_HOME/src/js/some/widget/viewModel.js

define(["knockout"], function (ko) {

    function VideModel() {
        var self = this;

        self.square = function(n){
            return n*n;
        }

    }

    return new VideModel();
})
Share:
54,172
andrew cooke
Author by

andrew cooke

When I first used this site it was wonderful. Professional programmers helping each other while learning. Now I cannot ask a question without "showing what I have done" because "people aren't here to do free work". I used to do "free work" and I enjoyed it - see my old answers below - but these days all people seem to care about is whether you are cheating at homework. So I no longer participate here. I work on projects that mix computing and physics - I have a pile of experience as a software engineer, but my education, way back in the day, was as an astronomer. It was research in astronomy that first took me to Chile, where I now live. So I telecommute from Santiago, working with companies in the USA and UK. Currently I'm part of a small team developing software related to geophysics - I guess you could call it a consultancy, but really we're just people that understand what you need and then - importantly! - make it. Some of my favourite answers: Exploring constraint programming Converting recursion to iteration with Python generators Tiling pipes Correlated random numbers Matching integer ranges with regexps In every case I learnt something new, which iswas what's so good about this site :)

Updated on July 29, 2022

Comments

  • andrew cooke
    andrew cooke almost 2 years

    I am trying to understand how to develop stand-alone Javascript code. I want to write Javscript code with tests and modules, running from the command line. So I have installed node.js and npm along with the libraries requirejs, underscore, and mocha.

    My directory structure looks like this:

    > tree .
    .
    ├── node_modules
    ├── src
    │   └── utils.js
    └── test
        └── utils.js
    

    where src/utils.js is a little module that I am writing, with the following code:

    > cat src/utils.js 
    define(['underscore'], function () {
    
        "use strict";
    
        if ('function' !== typeof Object.beget) {
            Object.beget = function (o) {
                var f = function () {
                };
                f.prototype = o;
                return new f();
            };
        }
    
    });
    

    and test/utils.js is the test:

    > cat test/utils.js 
    var requirejs = require('requirejs');
    requirejs.config({nodeRequire: require});
    
    requirejs(['../src/utils'], function(utils) {
    
        suite('utils', function() {
            test('should always work', function() {
                assert.equal(1, 1);
            })
        })
    
    });
    

    which I then try to run from the top level directory (so mocha sees the test directory):

    > mocha
    
    node.js:201
            throw e; // process.nextTick error, or 'error' event on first tick
                  ^
    Error: Calling node's require("../src/utils") failed with error: ReferenceError: define is not defined
        at /.../node_modules/requirejs/bin/r.js:2276:27
        at Function.execCb (/.../node_modules/requirejs/bin/r.js:1872:25)
        at execManager (/.../node_modules/requirejs/bin/r.js:541:31)
        ...
    

    So my questions are:

    • Is this the correct way to structure code?
    • Why is my test not running?
    • What is the best way to learn this kind of thing? I am having a hard time finding good examples with Google.

    Thanks...

    [sorry - momentarily posted results from wrong code; fixed now]

    PS I am using requirejs because I also want to run this code (or some of it) from a browser, later.

    Update / Solution

    Something that is not in the answers below is that I needed to use mocha -u tdd for the test style above. Here is the final test (which also requires assert) and its use:

    > cat test/utils.js 
    
    var requirejs = require('requirejs');
    requirejs.config({nodeRequire: require});
    
    requirejs(['../src/utils', 'assert'], function(utils, assert) {
    
        suite('utils', function() {
            test('should always work', function() {
                assert.equal(1, 1);
            })
        })
    
    });
    > mocha -u tdd
    
      .
    
      ✔ 1 tests complete (1ms)
    
  • bennidi
    bennidi over 9 years
    +1 for the solution of requirejs dependency loading in beforeEach