49

This seems like it should be extremely simple; however, after two hours of reading and trial-and-error without success, I'm admitting defeat and asking you guys!

I'm trying to use Mocha with Should.js to test some JavaScript functions, but I'm running into scoping issues. I've simplified it down to the most basic of test cases, but I cannot get it working.

I have a file named functions.js, which just contains the following:

function testFunction() {
    return 1;
}

And my tests.js (located in the same folder) contents:

require('./functions.js')

describe('tests', function(){
    describe('testFunction', function(){
        it('should return 1', function(){
            testFunction().should.equal(1);
        })
    })
})

This test fails with a ReferenceError: testFunction is not defined.

I can see why, because most of the examples I've found either attach objects and functions to the Node global object or export them using module.exports—but using either of these approaches means my function code would throw errors in a standard browser situation, where those objects don't exist.

So how can I access standalone functions which are declared in a separate script file from my tests, without using Node-specific syntax?

Mark Bell
  • 28,985
  • 26
  • 118
  • 145
  • Did you use `exports.testFunction = testFunction` in your functions.js ? – drinchev Apr 18 '12 at 06:44
  • 7
    No, the full contents of `functions.js` are shown. Please read the question again—I specifically state that I *don't* want to use Node-specific syntax in the source file. – Mark Bell Apr 18 '12 at 06:48

3 Answers3

30

Thanks to the other answers here, I've got things working.

One thing which wasn't mentioned though—perhaps because it's common knowledge among Noders—was that you need to assign the result of the require call to a variable, so that you can refer to it when calling your exported functions from within the test suite.

Here's my complete code, for future reference:

functions.js:

function testFunction () {
    return 1;
}

// If we're running under Node
if (typeof exports !== 'undefined') {
    exports.testFunction = testFunction;
}

tests.js:

var myCode = require('./functions')

describe('tests', function(){
    describe('testFunction', function(){
        it('should return 1', function(){
            // Call the exported function from the module
            myCode.testFunction().should.equal(1);
        })
    })
})
Mark Bell
  • 28,985
  • 26
  • 118
  • 145
  • +1 and also to @drinchev. I'm using this for now, could not found a better approach yet, but, this leads to a lower coverage, because those lines in functions.js are not executed by any test, only by the mocha spec – Eugenio Miró Feb 23 '21 at 23:15
18
require('./functions.js')

That doesn't do anything since you're not exporting anything. What you're expecting is that testFunction is globally available, essentially the same as

global.testFunction = function() {
    return 1;
}

You just can't bypass the export/globals mechanism. It's the way node has been designed. There is no implicit global shared context (like window on a browser). Every "global" variable in a module is trapped in it's context.

You should use module.exports. If you intend to share that file with a browser environments, there are ways to make it compatible. For a quick hack just do window.module = {}; jQuery.extend(window, module.exports) in the browser, or if (typeof exports !== 'undefined'){ exports.testFunction = testFunction } for node.

Ricardo Tomasi
  • 34,573
  • 2
  • 55
  • 66
  • 6
    Ok that makes sense, thanks. So is Mocha not really intended for testing non-Node JS? It doesn't mention that anywhere in any of the docs or tutorials I've encountered. – Mark Bell Apr 18 '12 at 09:30
  • You might want to try Qunit ( http://docs.jquery.com/Qunit ) for testing on the browser, or zombie.js (https://github.com/assaf/zombie) to simulate a browser environment in mocha. – drinchev Apr 18 '12 at 11:28
  • @MarkBell Mocha should work fine in the browser, in which case you don't need the `exports`. – Ricardo Tomasi Apr 18 '12 at 18:54
  • @MarkBell Three years later, but.. got browser testing with Mocha going today, using https://github.com/nathanboktae/mocha-phantomjs . PhantomJS is a full headless browser, so no need to inject any export statements. – akauppi May 01 '16 at 14:27
9

If you want to make any module available through require you should use

module.exports

as you know ;)

there is a solution if you want to use a module in Node and in browser by doing this

function testFunction() { /* code */ }

if (typeof exports !== 'undefined') {
   exports.testFunction = testFunction
}

by doing this you will be able to use the file in browser and in node environment

drinchev
  • 19,201
  • 4
  • 67
  • 93