I've written a node module with UMD (Universal Module Definition) Pattern to make it compatible with amd and plain javascript as well.
The definition is as below
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define(factory);
} else if (typeof exports === 'object') {
module.exports = factory();
} else {
root.myModule = factory();
}
}(this, function (global) {
...
return {};
}));
With mocha & chai the tests are running fine, the only issue is that since the tests are executed from within node the code coverage for define(factory); and root.myModule = factory(); lines is showing red.
Just wanted to know if there is any way(maybe a hack) to get 100% coverage for this code with mocha chai.
Sure!
How coverage tools for JS basically work, is that their injecting little bit of tracker code for each line. So what you need is that the execution flow wonders there.
Since this is an if-else logic, to get 100% you will be needing multiple test scenarios to cover this.
Note: it's also important for actually achieving this effect, that loading that file (factory) should happen after every scenario setup, because that is when those module-loading-if-else lines are executed. Now this depends on what is your file/module loading in your test execution environment.
Now to enter into that branch of the if-else create a test scenario where you can just enforce the existence of that define function with a few lines like (e.g. in a beforeEach section):
define = function () {
console.log('hello I am a fake define, but I will be defined ...');
console.log(' ... so that if else branch will be executed.');
}
// and of course the needed .amd property.
define.amd = true;
I think the same weird stuff can be done w/ the exports variable, but it might be hard to achieve if you are just pure CommonJS require-ing that file, since require-ing defines the exports variable for that file context, so maybe you could modify your production code for this weird case. I wouldn't do that, but you said any way:
...
} else if (typeof exports === 'object' && testExportsEnabled) {
...
Now using this you can just have one scenario where in beforeEach you do: testExportsEnabled = true; and w/ this being false, the last branch should be executed.
Of course you can execute all branches with such a simple trick! Now to have no code modification AND trigger the third branch (basically the case for simple script-tag-loading in browser), you will need to dig in into your module loading code and create some hacks there, but that is a bit too much for me in an SO question! :]
Take care!
Related
I've run into a problem with RequireJS that pops up randomly in different areas over and over, after a long period (about a year) of working fine.
I declare my requireJS file like this:
define(['TestController'], function (TestController)
{
return {
oneFunction: function(callback)
{
//When I try to use "TestController" here, I get the
//"Error: Module name "TestController" has not been
//loaded yet for context" error...
TestController.test(); //ERROR
//I had been using the above for years, without changes,
//and it worked great. then out of the blue started not
// working. Ok, let's try something else:
if(typeof TestController == "undefined")
{
var TestController = require('TestController'); //ERROR
}
//The above method worked for a few months, then broke AGAIN
// out of the blue, with the same error. My last resort is one
// that always works, however it makes my code have about 20+
//layers of callbacks:
require(['TestController'], function(TestController){
TestController.test();
//WORKS, but what's the point of declaring it as a
//requirement at the top if it doesn't work and I have to
//wrap my code every time? :(
});
},
anotherFunction: function()
{
console.log("hello");
}
}
});
I am getting the "Error: Module name "TestController" has not been loaded yet for context" error over and over until I re-declare the dependency... My question is, what's the point of declaring 'TestController' at the top as a dependency if I have to keep re-declaring it as if I never listed it? What am I doing wrong here?
I declare 'TestController' in other files and it works great, but every once and a while, ONE of the declarations will fail...and it's always a different file (there are about 200-300)... I never know which one, and the only way to fix it is to re-declare it and wrap it.
Anyone see anything I'm doing wrong that could be causing this? I keep updating RequireJS to see if it fixes it and it doesn't :/
Version
RequireJS 2.1.22
jquery-1.12.1
node 4.2.6
As #Louis pointed out, it was circular dependencies that was causing the problem.
Circular Dependency Solution #1: 'exports'
Here's the solution straight from RequireJS's documentation:
If you define a circular dependency ("a" needs "b" and "b" needs "a"), then in this case when "b"'s module function is called, it will get an undefined value for "a". "b" can fetch "a" later after modules have been defined by using the require() method (be sure to specify require as a dependency so the right context is used to look up "a"):
//Inside b.js:
define(["require", "a"],
function(require, a) {
//"a" in this case will be null if "a" also asked for "b",
//a circular dependency.
return function(title) {
return require("a").doSomething();
}
}
);
If you are familiar with CommonJS modules, you could instead use exports to create an empty object for the module that is available immediately for reference by other modules.
//Inside b.js:
define(function(require, exports, module) {
//If "a" has used exports, then we have a real
//object reference here. However, we cannot use
//any of "a"'s properties until after "b" returns a value.
var a = require("a");
exports.foo = function () {
return a.bar();
};
});
Circular Dependency Solution #2: Visualize with madge
I came accross this npm module that will create a dependency graph for you : https://github.com/pahen/madge
I've decided to analyze my code with madge and remove the circular dependencies.
Here is how I used the tool:
cd <Client-Code-Location>
madge --image dep.png .
This gave me an image of the dependencies, however there were no circular dependencies found. So I decided to try another way:
cd <Client-Code-Location>
madge --image dep.png --format amd .
This way I was able to see where I had the circular dependency. :)
I'm trying to use Jest for unit testing my React code but I'm also using requirejs and so all my React code is in AMD modules. It obviously works well in browser but when I run Jest tests, it can't load my AMD modules.
Initially it was giving me error for define saying define is not defined, so I used amdefine by Requirejs to fix it. Now it can understand define but still can't load my module.
I had the same problem today and here is what I've done :
Module.js
(()=> {
const dependencies = ['./dep.js'];
const libEnv = function (dep) {
// lib content
function theAnswer (){
return dep.answer;
}
return {theAnswer}; // exports
};
//AMD & CommonJS compatibility stuff
// CommonJS
if (typeof module !== 'undefined' && typeof require !== 'undefined'){
module.exports = libEnv.apply(this, dependencies.map(require));
module.exports.mockable = libEnv; // module loader with mockable dependencies
}
// AMD
if (typeof define !== 'undefined') define(dependencies, libEnv);
})();
You will found all needed files on my github repository to test :
in browser for requirejs
with node for jest
https://github.com/1twitif/testRequireJSAmdModulesWithJest
I ran into same problem, so I went ahead and mocked my dependency at the top of test file:
jest.mock('../../components/my-button', () => {
// mock implementation
})
import MyButton from '../../components/my-button';
This way, when MyButton is loaded, its dependency is already mocked, so it won't try to load the RequireJS module.
There's no official Facebook support for requirejs in Jest yet. But's planned. Look this thread:
https://github.com/facebook/jest/issues/17
Also in this thread Sterpe posted a plugin he wrote to do it (but I didn't try it):
https://github.com/sterpe/jest-requirejs
Suppose I have a JS-library, neatly wrapped in a define('myModule', function(myModule) { return myModule.someObject; });
How could I bind the myModule.someObject to global scope (please don't ask why, I know modular programming has a lot of benefits over putting stuff on the global scope), without using requirejs or any other module handling framework?
The thing is: while developing, I'd like to use requirejs. The library that we build should be able to be included by somebody using requirejs (AMD, CommonJS, whatever), but should also be available as window.SomeObject for the people that don't want to use require just for the sake of being able to use our SomeObject. After the development phase, all code will be minified and obfuscated to a single JS file.
I think I'm just googling with the wrong search terms, because all I can find is an answer to the question how to include code that isn't wrapped in a requirejs friendly define function.
Any ideas on this would greatly be appreciated. Thanks!
--- EDIT ---
My file (before it all started) looked like:
(function(define, global) {
define([a,b,c],function(theA, theB, theC) {
return theA + theB + theC; // or something, it doesn't matter
});
})(define, this);
I'm thinking of something like this:
(function(define, global) {
// same as above
})(typeof define === 'function'
? define
: function(factory /* need more args? */) { /* solution here */ }, this);
But I'm not sure how to implement it properly...
I guess you need to wrap your modules so that they could be accessed without requirejs:
if ( typeof define === "function" && define.amd ) {
define( "mymodule", [], function () {
// do your logic
return mystuff;
} );
} else {
// do your logic
window.mystuff = mystuff;
}
Look at jQuery as an example.
I would refrain from giving your module an id if you can help it, it makes it less portable. jQuery is incredibly annoying that it forces you to set a jquery path option, but they did it for compatibility reasons. Always prefer anonymous modules if you can.
From the jQuery source
// Register as a named AMD module, since jQuery can be concatenated with other
// files that may use define, but not via a proper concatenation script that
// understands anonymous AMD modules. A named AMD is safest and most robust
// way to register. Lowercase jquery is used because AMD module names are
// derived from file names, and jQuery is normally delivered in a lowercase
// file name. Do this after creating the global so that if an AMD module wants
// to call noConflict to hide this version of jQuery, it will work.
James Burke goes into a little more detail here also.
I would instead use a more common example from the umdjs repository:
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['b'], factory);
} else {
// Browser globals
root.amdWeb = factory(root.b);
}
}(this, function (b) {
//use b in some fashion.
// Just return a value to define the module export.
// This example returns an object, but the module
// can return a function as the exported value.
return {};
}));
For another example that also supports CommonJS, check out the reqwest library:
!function (name, context, definition) {
if (typeof module != 'undefined' && module.exports) module.exports = definition()
else if (typeof define == 'function' && define.amd) define(definition)
else context[name] = definition()
}('reqwest', this, function () {
return {};
});
How can I provide a library to others that does not depend on RequireJS?
This allows you to ship code that does not ship with all of RequireJS, and allows you to export any kind of API that works on a plain web page without an AMD loader.
You need to make a build config file which uses wrap and almond.
It all feels pretty dirty, but I've had it working (by following the almond ReadMe) with exactly what you're describing.
After following instructions on the emscripten wiki I have managed to compile a small C library. This resulted in an a.out.js file.
I was assuming that to use functions from this library (within node.js) something like this would have worked:
var lib = require("./a.out.js");
lib.myFunction('test');
However this fails. Can anyone help or point me to some basic tutorial related to this?
Actually, all the functions are already exported. Generated JavaScript contains following lines:
var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
// …
if (ENVIRONMENT_IS_NODE) {
// …
module['exports'] = Module;
}
If you got a function called my_fun in your C code, then you'll have Module._my_fun defined.
There are some problems with this approach, though.
Optimizer may remove or rename some functions, so always specify them passing -s EXPORTED_FUNCTIONS="['_main','_fun_one','_fun_two']". Function signatures in C++ are bit mangled, so it's wise to extern "C" { … } the ones which you want to export.
Furthermore, such a direct approach requires JS to C type conversions. You may want to hide it by adding yet another API layer in file added attached with --pre-js option:
var Module = {
my_fun: function(some_arg) {
javascript to c conversion goes here;
Module._my_fun(converted_arg) // or with Module.ccall
}
}
Module object will be later enhanced by all the Emscripten-generated goodies, so don't worry that it's defined here, not modified.
Finally, you will surely want to consider Embind which is a mechanism for exposing nice JavaScript APIs provided by Emscripten. (Requires disabling newest fastcomp backend.)
The problem here is that your a.out.js file is going to look like this
function myFunction() {
...
}
Not like this
function myFunction() {
...
}
exports.myFunction = myFunction;
You need to write a build script that lists the tokens you want to publically export from each C program and appends exports.<token> = <token>;\n to the end of your file for each token.
How can I detect whether my Node.JS file was called using SH:node path-to-file or JS:require('path-to-file')?
This is the Node.JS equivalent to my previous question in Perl: How can I run my Perl script only if it wasn't loaded with require?
if (require.main === module) {
console.log('called directly');
} else {
console.log('required as a module');
}
See documentation for this here: https://nodejs.org/docs/latest/api/modules.html#modules_accessing_the_main_module
There is another, slightly shorter way (not outlined in the mentioned docs).
var runningAsScript = !module.parent;
I outlined more details about how this all works under the hood in this blog post.
For those using ES Modules (and Node 10.12+), you can use import.meta.url:
import path from 'path';
import { fileURLToPath } from 'url'
const nodePath = path.resolve(process.argv[1]);
const modulePath = path.resolve(fileURLToPath(import.meta.url))
const isRunningDirectlyViaCLI = nodePath === modulePath
Things like require.main, module.parent and __dirname/__filename aren’t available in ESM.
Note: If using ESLint it may choke on this syntax, in which case you’ll need to update to ESLint ^7.2.0 and turn your ecmaVersion up to 11 (2020).
More info: process.argv, import.meta.url
I was a little confused by the terminology used in the explanation(s). So I had to do a couple quick tests.
I found that these produce the same results:
var isCLI = !module.parent;
var isCLI = require.main === module;
And for the other confused people (and to answer the question directly):
var isCLI = require.main === module;
var wasRequired = !isCLI;
Try this if you are using ES6 modules:
if (process.mainModule.filename === __filename) {
console.log('running as main module')
}
I always find myself trying to recall how to write this goddamn code snippet, so I decided to create a simple module for it. It took me a bit to make it work since accessing caller's module info is not straightforward, but it was fun to see how it could be done.
So the idea is to call a module and ask it if the caller module is the main one. We have to figure out the module of the caller function. My first approach was a variation of the accepted answer:
module.exports = function () {
return require.main === module.parent;
};
But that is not guaranteed to work. module.parent points to the module which loaded us into memory, not the one calling us. If it is the caller module that loaded this helper module into memory, we're good. But if it isn't, it won't work. So we need to try something else. My solution was to generate a stack trace and get the caller's module name from there:
module.exports = function () {
// generate a stack trace
const stack = (new Error()).stack;
// the third line refers to our caller
const stackLine = stack.split("\n")[2];
// extract the module name from that line
const callerModuleName = /\((.*):\d+:\d+\)$/.exec(stackLine)[1];
return require.main.filename === callerModuleName;
};
Save this as is-main-module.js and now you can do:
const isMainModule = require("./is-main-module");
if (isMainModule()) {
console.info("called directly");
} else {
console.info("required as a module");
}
Which is easier to remember.
First, let's define the problem better. My assumption is that what you are really looking for is whether your script owns process.argv (i.e. whether your script is responsible for processing process.argv). With this assumption in mind, the code and tests below are accurate.
module.parent works excellently, but it is deprecated for good reasons (a module might have multiple parents, in which case module.parent only represents the first parent), so use the following future-proof condition to cover all cases:
if (
typeof process === 'object' && process && process.argv
&& (
(
typeof module === 'object' && module
&& (
!module.parent
|| require.main === module
|| (process.mainModule && process.mainModule.filename === __filename)
|| (__filename === "[stdin]" && __dirname === ".")
)
)
|| (
typeof document === "object"
&& (function() {
var scripts = document.getElementsByTagName("script");
try { // in case we are in a special environment without path
var normalize = require("path").normalize;
for (var i=0,len=scripts.length|0; i < len; i=i+1|0)
if (normalize(scripts[i].src.replace(/^file:/i,"")) === __filename)
return true;
} catch(e) {}
})()
)
)
) {
// this module is top-level and invoked directly by the CLI
console.log("Invoked from CLI");
} else {
console.log("Not invoked from CLI");
}
It works correctly in all of the scripts in all of the following cases and never throws any errors†:
Requiring the script (e.x. require('./main.js'))
Directly invoking the script (e.x. nodejs cli.js)
Preloading another script (e.x. nodejs -r main.js cli.js)
Piping into node CLI (e.x. cat cli.js | nodejs)
Piping with preloading (e.x. cat cli.js | nodejs -r main.js)
In workers (e.x. new Worker('./worker.js'))
In evaled workers (e.x. new Worker('if (<test for CLI>) ...', {eval: true}))
Inside ES6 modules (e.x. nodejs --experimental-modules cli-es6.js)
Modules with preload (e.x. nodejs --experimental-modules -r main-es6.js cli-es6.js)
Piped ES6 modules (e.x. cat cli-es6.js | nodejs --experimental-modules)
Pipe+preload module (e.x. cat cli-es6.js | nodejs --experimental-modules -r main-es6.js)
In the browser (in which case, CLI is false because there is no process.argv)
In mixed browser+server environments (e.x. ElectronJS, in which case both inline scripts and all modules loaded via <script> tags are considered CLI)
The only case where is does not work is when you preload the top-level script (e.x. nodejs -r cli.js cli.js). This problem cannot be solved by piping (e.x. cat cli.js | nodejs -r cli.js) because that executes the script twice (once as a required module and once as top-level). I do not believe there is any possible fix for this because there is no way to know what the main script will be from inside a preloaded script.
† Theoretically, errors might be thrown from inside of a getter for an object (e.x. if someone were crazy enough to do Object.defineProperty(globalThis, "process", { get(){throw 0} });), however this will never happen under default circumstances for the properties used in the code snippet in any environment.
How can I detect whether my node.js file was called directly from console (windows and unix systems) or loaded using the ESM module import ( import {foo} from 'bar.js')
Such functionality is not exposed. For the moment you should separate your cli and library logic into separate files.
Answer from node.js core contributor devsnek replying to nodejs/help/issues/2420
It's the right answer in my point of view