mocking es6 modules in unit test - node.js

Suppose we have a file(source.js) to test:
// source.js
import x from './x';
export default () => x();
And the unit test code is very simple:
// test.js
import test from 'ava';
import source from './source'
test("OK", t => {
source();
t.pass();
});
But this is the tricky thing. The file "./x" does not exist in the test environment. Since it is a unit test, we do not need "./x". We can mock the function "x()" anyhow(using sinon or something else). But the unit test tool, ava, keeps showing "Error: Cannot find module './x'";
Is there any way to run the unit test without the file "./x"?

To do this, you'd need to override the import process itself. There are libraries for doing something similar-- overriding the require function with proxyquire, for example-- but these force you to invoke their custom function to import the module under test. In other words, you'd need to abandon using ES6 module syntax to use them.
You should also note that ES modules are only supported experimentally (and relatively recently) in Node. If you're transpiling with Babel, you're not actually using ES modules. You're using the syntax, sure, but Babel transpiles them to CommonJS "equivalents", complete with require calls and module.exports assignments.
As such, if you're using Babel, you can probably proxyquire to import modules under test in your test files, even if you're using ES module syntax in those modules. This will break, though, if you ever switch away from Babel. :\
My personal recommendation would be to avoid directly exporting anything you might need to stub. So functions like x should be in a static module imported like import foo from './foo' and invoked like foo.x(). Then, you can easily stub it with sinon.stub(foo, 'x'). Of course, the './foo' file will have to exist for this still, but what it really comes down to is how hardcore you want to be about TDD practices versus how much complexity you're willing to introduce to your mocking/stubbing process. I prefer relaxing the former to avoid the latter, but in the end it's up to you.

If you are using Jest, it can be achieved easily by mocking the import using the inbuilt mock method of jest.
Please refer the link below to find more about ES6 import mocks
https://jestjs.io/docs/en/es6-class-mocks

If you are using jest with JavaScript this is very simple:
use jest.mock('MODULE_NAME')
If it is a node module or your own module, no problem jest will automatically mock that module.

Related

How to use multiple compiled ts files in a node module?

Currently I am trying to use TypeScript to create JavaScript-Files which are then required in a index.js file. I am using VS 2015 Update 3 with node.js tools 1.2 RC. Sadly it is not working like I thought it would.
To begin with here is my initial idea:
I have a node module (to be precise, it is a deployd module http://docs.deployd.com/docs/using-modules/). This module is handling payment providers like paypal or stripe. Now I want to use TypeScript to write interfaces, classes and use types to make it easier to add new payment providers. The old .js files should still be there and used. I want to migrate step by step and use the self-written and compiled .js files together. So I thought I can create .ts files, write my code, save, let VS compile to js and require the compiled js file in another js file. Okay, that is my idea... Now the problem
I have a PaymentProvider.ts file which looks like this
import IPaymentProvider = require("./IPaymentProvider.ts"); // Interface, can't be realized in JavaScript, just TypeScript
export abstract class PaymentProvider implements IPaymentProvider.IPaymentProvider
{
providerName: string;
productInternalId: number;
constructor(providerName : string)
{
this.providerName = providerName;
}
//... some methods
};
The other file is PaypalPaymentProvider.ts
import PaymentProvider = require("./PaymentProvider.ts");
export class PaypalPaymentProvider extends PaymentProvider.PaymentProvider
{
constructor()
{
super("paypal");
}
// more methods
}
VS 2015 doesn't show any errors. The js and .js.map files are generated. Now I thought I could require the files and that's it. I tried to use the PaypalPaymentProvider.js like this const PaypalPaymentProvider = require("./lib/payment-provider/PaypalPaymentProvider.js"); (yes, it is located there) but it's not working. When starting the index.js via node I get the following error:
...\Path\PaymentProvider.ts:1 (function (exports, require, module, __filename, __dirname) { import IPaymentProvider = require("./IPaymentProvider.ts"); Unexpected token import....
I find it strange that this is the error, because JavaScript doesnt't have Interfaces. The compiled IPaymentProvider.js is empty.
Also I thought that TypeScript is mainly for development and the compiled JavaScript for production. So why it is requiring a ts-file? I thought imports in typescript will be converted to require of the compiled js-file?
Do I need to require all compiled js files and not only the one I currently try to use? (I don't think so...)
To be honest, I think the main problem is that I am new to TypeScript and make something wrong from the very beginning.
Any help/advice? Thanks!
I have the solution... Thanks to Paelo's links I was able to see that I need to omit the file ending! So the really simple solution was to write
import IPaymentProvider = require("./IPaymentProvider");
instead of
import IPaymentProvider = require("./IPaymentProvider.ts");
When I changed that in every ts file it worked perfectly!

What determines the order of `require` calls in babel-transpiled scripts?

So, my workflow up to this point was to put
import "babel-polyfill";
when using features like async/await to ask babel to include the regenerator runtime in the transpilation.
I see the the following problems for users requiring my module:
The user is in an ES2015 environment and transpiles his code with babel-polyfill, too. Since babel-polyfill can only be required once, he will not be able to use my module at all.
If I thus choose not to include babel-polyfill, babel doesn't know that the module does require babel-polyfill and won't respect that in the generated require order (at least that's what I think happens).
I've recently created an npm module that does not come with babel-polyfill, but requires the user to include babel-polyfill before calling require on my npm module, since it uses async and await.
Thus, in my current project, I'd like to use my module like so in index.js:
import "babel-polyfill";
import Server from "./Server";
import foo from "bar";
import baz from "qux";
where Server is a class that extends my module that requires babel-polyfill.
However, the transpilation of index.js starts like this:
!function(e, r) {
if ("function" == typeof define && define.amd)
define(["bar", "qux", "./Server", "babel-polyfill"], r);
else if ("undefined" != typeof exports)
r(require("bar"), require("qux"), require("./Server"), require("babel-polyfill"));
// etc.
}();
Here, I can clearly see that ./Server is required before babel-polyfill, although my ES2015 import syntax asks for the opposite. In fact, the entire order is mixed up.
That's why I'm getting the error:
ReferenceError: regeneratorRuntime is not defined
How can I tell babel to respect the order in my source?
From what I can tell, you can't tell Babel to respect the order of your source - it will always hoist the imports and evaluate everything else afterwards. The only way seems to be switching to require when you want to ensure evaluation of some code (usually global assignments) first. As per my answer here.
Numerous issues raised (and closed/rejected) against Babel relating to this.

How to import node module in TypeScript without type definitions?

When I try to import node.js module in TypeScript like this:
import co = require('co');
import co from 'co';
without providing type definitions, both lines reports same error:
error TS2307: Cannot find module 'co'.
How to import it correctly?
The trick is to use purely JavaScript notation:
const co = require('co');
Your options are to either import it outside TypeScript's module system (by calling a module API like RequireJS or Node directly by hand) so that it doesn't try to validate it, or to add a type definition so that you can use the module system and have it validate correctly. You can stub the type definition though, so this can be very low effort.
Using Node (CommonJS) imports directly:
// Note there's no 'import' statement here.
var loadedModule: any = require('module-name');
// Now use your module however you'd like.
Using RequireJS directly:
define(["module-name"], function (loadedModule: any) {
// Use loadedModule however you'd like
});
Be aware that in either of these cases this may mix weirdly with using real normal TypeScript module imports in the same file (you can end up with two layers of module definition, especially on the RequireJS side, as TypeScript tries to manage modules you're also managing by hand). I'd recommend either using just this approach, or using real type definitions.
Stubbing type definitions:
Getting proper type definitions would be best, and if those are available or you have time to write them yourself you should definitely should.
If not though, you can just give your whole module the any type, and put your module into the module system without having to actually type it:
declare module 'module-name' {
export = <any> {};
}
This should allow you to import module-name and have TypeScript know what you're talking about. You'll still need to ensure that importing module-name does actually load it successfully at runtime with whatever module system you're using, or it will compile but then fail to actually run.
I got an error when I used the "Stubbing type definitions" approach in Tim Perry's answer: error TS2497: Module ''module-name'' resolves to a non-module entity and cannot be imported using this construct.
The solution was to rework the stub .d.ts file slightly:
declare module 'module-name' {
const x: any;
export = x;
}
And then you can import via:
import * as moduleName from 'module-name';
Creating your own stub file lowers the barrier to writing out real declarations as you need them.
Just import the module the following way:
import 'co';

Load a chaplin module synchronously

I'm trying to just load the event_broker module in the chaplinjs . I am able to to do by doing something like
require(["underscore", "chaplin"], function(_, chaplin)
{
var eventBroker = _({}).extend(chaplin.EventBroker);
});
But, this is not good enough in my case. I need to be able to load the event_broker module synchronously. I know that is what require designed to do. Is there a way to do that?
I know that is what require designed to do.
No, that's not what RequireJS is designed to do. (Did you forget to put "not" in there?) RequireJS is designed to load modules asynchronously.
I would normally suggest loading Chaplin through a script element because that would be synchronous but, after looking at the code of Chaplin, I see that it fails with throw new Error('Chaplin requires Common.js or AMD modules'); if it does not detect a CommonJS or AMD environment.
Almond can be used to load bundles of AMD modules synchronously so this may be an option for you.

Write a module that works both in nodejs and requirejs

I wrote a small parser that currently works in node app, but wondering if there is a way that I can make a module that will work both in NodeJS app and client side app that uses requirejs?
path/to/lib/index.js
function someRandom(strings) {
// we are doing something here
return strings
}
exports.someRandom = someRandom;
Right now I'm getting this in client-side
Uncaught ReferenceError: exports is not defined
I know that I can use node requirejs and then change the structure to use define but is there other way without adding node requirejs?
This is my js/main.js file
require(["path/to/lib/index"], function(something) {
// will do something here
});
The way I prefer to do it is to write all my modules in the AMD syntax (use define) and use amd-loader to load them in Node. Note that this solution is not using RequireJS, even though the AMD syntax is used.
However, there's a way to do it without having to use the AMD syntax. You can use r.js to wrap your Node modules. For instance, if you put your tree of Node modules in in, you can do:
$ r.js -convert in out
This will create in out a tree of files that correspond to those in in but wrapped with the define call. You can then load these in the browser using RequireJS. There are limitations. Some are obvious, like not being able to use the Node modules that depend on the Node runtime (like fs, child_process, etc.). Some are more subtle, like the fact that you can't use require(foo) where foo is a variable (RequireJS will handle only string literals there). See the documentation for the details.

Resources