I have got a problem with mocha tests around global object I'm using with Node.js.
In index file, I set value to global variable
// index.js
global.enums = enumTemp
export default app
And then used it in another file
// other.js
status = global.enums.object.status
It's REST API and runs well if I made a request to a server. However, when I use a Mocha test, it seems to I cannot get the value for Node.js global variable. Any idea everyone?
I have found a solution that works for me by using Mocha hooks to set global variable just for testing:
// setup.test.js
import MyFunc from '../helpers/my-func'
before((done) => {
MyFunc.then((variable) => {
global.variable = variable
done()
})
})
We can use the global.variable in the test just like in the real code.
You should get rid of the globals because they're ugly, which will probably solve your problem as well.
There's a somewhat little known fact about the way Node.js require() works: Modules are cached on the first require. This makes it possible to run costly calculations (or fetch something from the database) and have it cached on subsequent uses of the module.
Observe this example:
randomnumber.js
const calculateRandomNumber = limit => {
console.log('calculateRandomNumber called');
return parseInt(Math.random() * limit);
};
module.exports = calculateRandomNumber(1000);
other.js
module.exports = require('./randomnumber');
test.js
const randomnumber = require('./randomnumber');
const other = require('./other');
console.log(randomnumber);
console.log(other);
This will output the same random number twice and calculateRandomNumber is called only once, even though the randomnumber module has been required in different places.
Related
File my_script.js:
(function() {
console.log("IMPORTED");
})();
Calling this file (run_me.js) should cause IMPORTED to print twice:
require("./my_script");
require("./my_script");
However it only prints once.
How can I change run_me.js so that IMPORTED is printed to the console twice.
Assume for this question, no changes can be made to my_script.js
require() caches its results. So, the first time a module is required, then its initialization code runs. After that, the cache just returns the value of module.exports without running the initialization code again. This is a very desirable feature of node.js modules.
If you want code to be run each time, then you should export a function that you can call after you require it like this:
Your module:
module.exports = function() {
console.log("IMPORTED");
}
Requiring it and running the code each time
require("./my_script")();
require("./my_script")();
Also, please note that there is no reason to use an IIFE in a module. The node.js module is automatically wrapped in a private function already so you don't need to do it again.
As you now say in a comment (but your question does not directly say), if you don't want to edit my_script at all (which is simply the wrong way to solve this issue), then you have to delete the module from the node.js cache before requiring it again which can be done like this:
delete require.cache[require.resolve('./my_script')];
I would not recommend this as a solution. It's not the proper way to code in node.js. It's a hack work-around. And, it is not compatible with ESM modules.
If you use jest and want code to be run each time for testing, you can use jest.isolateModules:
jest.isolateModules(() => {
require("./my_script");
});
jest.isolateModules(() => {
require("./my_script");
});
I don't think it is possible without modifying the myscript.js file. Especially since as you show it, it doesn't export anything.
It will execute the first time you require it (which is why you see "Imported" once), but then nothing will happen on future calls to require because the "cached" value (ie. module.exports) which is returned is empty.
See below for an example of what I think you want (except that myscript.js has been modified). The biggest difference is that in your original myscript.js file the function was actually executed, while in the example below it is just defined, and then actually executed in the require call in the run_me.js file.
File myscript.js:
module.exports = () => console.log("Imported");
File run_me.js:
require('myscript.js')(); // note the () at the end which actually calls the function
require('myscript.js')(); // note the () at the end which actually calls the function
You can use this package, it is an npm module that will clear the cache and load a module from source fresh each time.
https://www.npmjs.com/package/require-uncached
const requireUncached = require('require-uncached');
require('./foo')();
//=> 1
require('./foo')();
//=> 2
requireUncached('./foo')();
//=> 1
requireUncached('./foo')();
//=> 1
Premise: JS ES6, NodeJS
Testing Framework: TAP
Mocking Library: testdouble.js
I am attempting to mock the return value for the method of my class and keep receiving this error:
not ok Unsatisfied verification on test double. Wanted: - called with (true). But there were no invocations of the test double.
Here is my testing code:
// Imports for unit testing
const tap = require('tap');
const Subject = require('../src/iTunesClient.js');
const td = require('testdouble');
let reqJson;
// Ensure the iTunes class methods are called
tap.test('iTunesClient class methods function as intended', (t) => {
t.beforeEach((ready) => {
reqJson = td.replace('../src/reqJson.js');
ready();
});
t.afterEach((ready) => {
td.reset();
ready();
});
t.test('iTunesClient.getData', (assert) => {
const callback = td.function();
const subject = new Subject();
subject.setTerm('abc 123');
subject.setURL();
td.when(reqJson.get(td.callback)).thenCallback(true);
subject.getData(callback);
td.verify(callback(true));
assert.end();
});
t.end();
});
Specifically, this line is related to my issue:
td.verify(callback(true));
How can I fake the callback value of true for reqJson.get()? Right now, Subject.geData() is a method of the iTunesClient class which calls another file, reqJson.js, to use its exported get() method.
It's a little hard to tell from your example, but it looks like you're requiring iTunesClient before you call td.replace. In this case, the real reqJson module will be required and cached on line 3.
You need to call td.replace early enough to avoid this, e.g. in between requiring tap and iTunesClient.
I wanted to update this question, as I recently solved this issue. Essentially, I had two issues:
Account for both reqJson function parameters
Account for all callback return values
Per testdouble documentation for item 1:
When passed td.matchers.anything(), any invocation of that test double function will ignore that parameter when determining whether an invocation satisfies the stubbing.
Hence, I adjusted my line of code as follows:
Before: td.when(reqJson.get(td.callback)).thenCallback(true);
After: td.when(reqJson.get(td.matchers.anything(), td.callback)).thenCallback(null, null, null);
I have a NodeJS application and I want to execute some method for file validations but just one time (this method will validate some files under the node application).
Is there an elegant way to do this? Events?
The NodeJS documentation on modules states that:
Modules are cached after the first time they are loaded.
which you can take advantage of by adding static code to the module. Regardless of how many times the module is loaded, the static code will retain its state(/value).
You can use that state from a method to implement a method that can be called whenever you like -- at the best time during initialization -- but only ever be called once. This is pretty simple:
var called = false;
function checkFiles() {
if (called) return;
// Perform your validation
called = true;
}
module.exports = {
checkFiles: checkFiles
};
Because of the module caching, you can require this file in as many places as you need and it will still only execute once.
To invoke this function, you have a few options:
For a simple application, you can call the function from your main module (or function) and it will be invoked at that time. If the validation should be asynchronous, you can wrap your main method in a function and pass that to the validator as a callback.
//#! /bin/env node
var express = require('express');
var validator = require('./validator');
validator.checkFiles();
var app = express();
var server = app.listen(3000, function () {
...
});
For a more complicated application, you should call this function during your existing initialization routine (again, using callbacks as necessary).
If you have a nice modern promise-based initializer, you could simply add the validator as the first step of the chain.
I'm using Mocha with Sinon to unit test my node.js modules. I've successfully mocked other dependencies (other modules that I've written), but I've run into problems stubbing non-pure functions (like Math.random() and Date.now()). I've tried the following (simplified so that this question isn't so localized), but Math.random() was not stubbed because of an obvious scope problem. The instances of Math are independent between the test file and mymodule.js.
test.js
var sinon = require('sinon'),
mymodule = require('./mymodule.js'),
other = require('./other.js');
describe('MyModule', function() {
describe('funcThatDependsOnRandom', function() {
it('should call other.otherFunc with a random num when no num provided', function() {
sinon.mock(other).expects('otherFunc').withArgs(0.5).once();
sinon.stub(Math, 'random').returns(0.5);
funcThatDependsOnRandom(); // called with no args, so should call
// other.otherFunc with random num
other.verify(); // ensure expectation has been met
});
});
});
So in this contrived example, functThatDependsOnRandom() would look like:
mymodule.js
var other = require('./other.js');
function funcThatDependsOnRandom(num) {
if(typeof num === 'undefined') num = Math.random();
return other.otherFunc(num);
}
Is it possible to stub Math.random() in this scenario with Sinon?
yes, this is an old question but it is valid. Here is an answer that works, though I'd love to hear suggestions on how to make it better.
The way I've dealt with this in the browser is to create a proxy object. For example, you can't stub the window object in the browser so you can create a proxy object called windowProxy. When you want to get the location you create a method in windowProxy called location that returns or sets windowLocation. Then, when testing, you mock windowProxy.location.
You can do this same thing with Node.js, but it doesn't work quite as simply. The simple version is that one module can't mess with another module's private namespace.
The solution is to use the mockery module. After initializing mockery, if you call require() with a parameter that matches what you told mockery to mock, it will let you override the require statement and return your own properties.
UPDATE: I've created a fully functional code example. It is on Github at newz2000/dice-tdd and available via npm. /END UPDATE
The docs are pretty good, so I suggest reading them, but here's an example:
Create a file randomHelper.js with contents like this:
module.exports.random = function() {
return Math.random();
}
Then in your code that needs a random number, you:
var randomHelper = require('./randomHelper');
console.log('A random number: ' + randomHelper.random() );
Everything should work like normal. Your proxy object behaves in the same way as Math.random.
It is important to note that the require statement is accepting a single parameter, './randomHelper'. We'll need to note that.
Now in your test, (I'm using mocha and chai for example):
var sinon = require('sinon');
var mockery = require('mockery')
var yourModule; // note that we didn't require() your module, we just declare it here
describe('Testing my module', function() {
var randomStub; // just declaring this for now
before(function() {
mockery.enable({
warnOnReplace: false,
warnOnUnregistered: false
});
randomStub = sinon.stub().returns(0.99999);
mockery.registerMock('./randomHelper', randomStub)
// note that I used the same parameter that I sent in to requirein the module
// it is important that these match precisely
yourmodule = require('../yourmodule');
// note that we're requiring your module here, after mockery is setup
}
after(function() {
mockery.disable();
}
it('Should use a random number', function() {
callCount = randomStub.callCount;
yourmodule.whatever(); // this is the code that will use Math.random()
expect(randomStub.callCount).to.equal(callCount + 1);
}
}
And that is it. In this case, our stub will always return 0.0.99999; You can of course change it.
It is easy to stub Date.now() with sinon by using Fake timers :
Fake timers provide a clock object to pass time, which can also be used to control Date objects created through either new Date(); or Date.now(); (if supported by the browser).
// Arrange
const now = new Date();
const clock = sinon.useFakeTimers(now.getTime());
// Act
// Call you function ...
// Assert
// Make some assertions ...
// Teardown
clock.restore();
Are you sure that not mocking Math is the problem. It seems that this line make not much sense:
sinon.mock(other).expects('otherFunc').withArgs(0.5).once();
you mock others in one module but use it in another one. I dont think that you will get the mocked version in mymodule.js. On the other hand stubbing Math.random should work, as this is global for all modules.
Also take a look at this SO for mocking dependencies in nodeJS tests.
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?
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);
})
})
})
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.
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