Mock a variable value in JS unit-tests - javascript

How could I mock(stub?) variable from external module in unit-tests?
I have a lib which would be running at browser as well as at node.js:
exports.Utils = (function (Config) {
return {
sum: function (val) {
return Config.defaultVal + val;
}
};
}(exports.Config));
Because tests run with only one (Utils.js) file, Config would be undefined here.
Tests runs in node.js enviroment.
var expect = require('chai').expect;
var Utils = require('./src/Utils.js').Utils;
describe("Test for Utils sum", function () {
it("example sum test", function () {
//How could I specify Config.defaultVal here?
expect(Utils.sum(1)).to.be.equal(2);
});
});
Perhaps I should use sinonjs, but I didn't find clear example for my case.

Related

Loading dependencies with or without react

I have an old IIFE that is injected into legacy pages via <script src.
However, I want to use all these old libraries in a react app. I just need to use the global function exposed.
I figure loading dependencies that will work both via script or via react's import or nodejs require
Here is an example of an example IIFE
example.js :
var $ = $;
var geocomplete = $.fn.geocomplete;
var OtherExternalLib = OtherExternalLib;
var Example = (function() {
return {
init: function () {
// stuff
}
}
)();
Where the legacy code is calling Example.init(), and likewise the react code will call the same function.
Where $ (jQuery), $.fn.geocomplete, and OtherExternalLib are all dependencies that must be loaded, either they should be loaded on-demand or just throw a big loud error message.
I suspect if the solution loads dynamically example.js would look something like
var $ = load("\libs\jquery.js");
var geocomplete = load("\libs\$.fn.geocomplete.js");
var OtherExternalLib = load("\libs\OtherExternalLib.js");
var Example = (function() {
return {
init: function () {
// stuff
}
}
)();
And the legacy application can still use <script src=example.js and React can use
import {Example} from example
Understandably this is somewhat a round-about way to of using legacy code in new applications, so I am open to other ideas on how best to expose an IIFE (with or without dependencies) and using it in React
I am using react+typescript in my project with some limitations which is why I had to dynamically import my package (my project runs in a shell project with AMD module, not having my own startup, and change the way project files get bundled).
Since I could only use the dependent modules on the fly during the run time, I had to assume them were valid while building and bundling . Most of them were IIFE.
So I used the lazy dynamic import .
something like this
import("somePolyfill");
This would be translated by TSC
new Promise(function (resolve_3, reject_3) { require(["arrayPolyfill"], resolve_3, reject_3); });
This would call the IIFE and execute the polyfills or initializing any window or global variable, so the rest of the code is aware of that.
If it returns a module or throughs error can be handled like normal promise then and catch.
So I created a wrapper
export class DepWrap {
public static Module: any = {};
public constructor() {
this.getPI();
this.getSomeModule();
}
public async getPI() {
DepWrap.Module["PI"] = 3.14;
}
public async getSomeModule() {
await import('somepath/somemodule').then(($package) => {
DepWrap.Module["somemodule"] = $package;
}).catch(() => {
window.console.log("Some Module error");
});
}
}
this got compiled to
define(["require", "exports", "tslib"], function (require, exports, tslib_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var DepWrap = /** #class */ (function () {
function DepWrap() {
this.getPI();
this.getSomeModule();
}
DepWrap.prototype.getPI = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
DepWrap.Module["PI"] = 3.14;
return [2 /*return*/];
});
});
};
DepWrap.prototype.getSomeModule = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, new Promise(function (resolve_1, reject_1) { require(['somepath/somemodule'], resolve_1, reject_1); }).then(function ($package) {
DepWrap.Module["somemodule"] = $package;
}).catch(function () {
window.console.log("Some Module error");
})];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
DepWrap.Module = {};
return DepWrap;
}());
exports.DepWrap = DepWrap;
});
with this I could use all the dependency modules from my wrapper and every time i need to import a new one I would create another function to add that to my wrap module.
import { DepWrap } from "wrapper/path";
const obj = new DepWrap(); // initialize once in the beginning of project so it would import all the dependencies one by one .
Afterwards in all file, I can import my module from the wrapper
import { DepWrap } from "wrapper/path";
const { PI, somemodule} = DepWrap.Module;
I am not sure if the code will work for your scenario as well, but I guess tweaking it a bit might come in handy for your useCase .
Plus : if you are writing unit test case it will help jest to just ignore the modules and can create a mock for this so that you can test your actual code .

Is it possible to create function inside `conf.js`?

Is it possible to create function which is used for every spec to test, for example login function inside the conf.js file or directly sendKeys from conf.js as from spec.js
From nodejs syntax, it supports to do that as following:
// conf.js
exports.config = {
// put config at here as usual
};
exports.login = function(username, password) {
browser.get('');
element.sendKeys('');
};
// spec.js
var login = require('./conf.js').login;
// actually, you can move the login function to another .js file to keep
// conf.js more dedicated on configuration purpose.
describe("A spec (with setup and tear-down)", function() {
it('', function(){
login('username', 'password')
});
});
But that is not a good practice. Because main test framework supports to do something before each test case. For jasmine it supplys beforeEach:
describe("A spec (with setup and tear-down)", function() {
var foo;
beforeEach(function() {
foo = 0;
foo += 1;
});
afterEach(function() {
foo = 0;
});
it("is just a function, so it can contain any code", function() {
expect(foo).toEqual(1);
});
it("can have more than one expectation", function() {
expect(foo).toEqual(1);
expect(true).toEqual(true);
});
});
At last, I can't see the benefit/advantage to do as you required.

mocha test (and babel) using global variables

I am writing library using es6, transpiling it with babel via webpack and npm.
The problem is, that my lib is dependent on some code, that I can not change but need to use. I don't know how to load var stuff (from the following example) in my tests so that it is visible for the module.
See the example:
external-stuff.js - this one can not be changed and is loaded before my lib is loaded on prod env.
var stuff = {
get some() { return "some"; }
get stuff() { return "stuff"; }
}
some-module.js - this is one of the modules in the library
export class foo {
static get whatever() { return stuff.some; }
static get whichever() { return stuff.stuff; }
}
test
import {foo} from "../src/foo.js";
let assert = require('assert');
describe('foo', function() {
describe('#whatever()', function() {
it("should do some", function () {
assert.equals(foo.whatever(), "some");
});
});
});
If I run this I get "ReferenceError: stuff is not defined"
I already tried to define "stuff" in before() hook, but no success.
In the end I found a solution that's 'good enough'. I am not sure it would be sufficient for some advanced library though.
I have created file called globals.js
var g = typeof(window) === 'undefined' ? global : window;
// Dependencies - add as many global stuff as needed
g.stuff= typeof(stuff) === 'undefined' ? {} : stuff;
And I import this 'es6module' at the beginning of test
import * as globals from "../lib/global/globals"
import {foo} from "../src/foo.js";
And then I use node-import npm module with which I load the global to the tests in beforeEach hook.
beforeEach(function () {
global.stuff = imports.module("lib/global/stuff.js").stuff;
});
This is perfect for unit testing because I can also mock stuff. And its even more awesome because this way I have a place where I 'define' global dependencies. It would be nice to improve on it and make it per es6modul dependencies... and build on it something fancy... ya know.. dependency injection.
complete test
require('node-import'); // +
import * as globals from "../lib/global/globals"; // +
import {foo} from "../src/foo.js";
let assert = require('assert');
describe('foo', function() {
beforeEach(function () { // +
global.stuff = imports.module("lib/global/stuff.js").stuff; // +
}); // +
describe('#whatever()', function() {
it("should do some", function () {
assert.equals(foo.whatever(), "some");
});
});
});

Using external class during client side Mocha unit testing

I am running unit tests on a javascript class using Mocha using the follow methodology, firstly the test:
var base = require('../moduleone.js');
describe("some test", function() {
it("description", function() {
var check = base.toBeTested(dummyValue)
//test is here ...
});
});
the moduleone.js containing function to be tested:
function toBeTested(category){
//below I calling an assert function defined in moduletwo
//works fine when running in browser
assert(type(category)=='string','category is string type');
//more code..
return something
module.exports.toBeTested = toBeTested;
moduletwo.js:
function assert(outcome, description) {
//see code.tutsplus.com quick and easy javascript testing with assert
var li = outcome ? 'pass' : 'fail';
if (li == 'fail') {
console.log('FAIL: '+description);
}
else {
console.log('PASS: '+description);
}
}
The issue I have is mocha doesn't know anything about moduletwo and when the moduleone function calles the function in moduletwo mocha throws a ReferenceError: assert is not defined. How can I link all my dependencies so that mocha can see them?
In your moduleone.js be sure that you are requireing moduletwo.js to bring your assert function into scope for moduleone.js. Otherwise, you get a ReferenceError, not for any reasons with mocha, but because moduleone does not have access to assert.
// moduletwo.js
function assert(outcome, description) { /* your functionality */ }
module.exports = assert
// moduleone.js
var assert = require('./moduletwo')
function toBeTested(category) { /* your functionality that uses assert */ }
module.exports.toBeTested = toBeTested
Now, with regards to that tutorial. If you are following it to learn how to make an easy assert module, that is fine. But if you are trying to test some code that does something else, consider using an existing assertion library like chai. For example:
// example.test.js
var expect = require('chai').expect
var isValidCategory = require('./is-valid-category')
describe('isValidCategory(category)', function () {
it('validates string categories', function () {
expect(isValidCategory('A String Category')).to.be.true
})
it('does not validate non-string categories', function () {
expect(isValidCategory(['an', 'array', 'somehow'])).to.be.false
})
})
// is-valid-category.js
module.exports = function isValidCategory(category) {
return typeof category === 'string'
}

Making use of browserified NodeJS file into browser

I have a NodeJS file which I browserfied using browserify module. I used following command
browserify testFile.js -o bundle.js
To make use of this file in browser, I am making use of window object.
Assume below code is generated after browserifying the file.
var Main = function () {
this.foo = function () {
},
this.temp= function () {
},
this.bar= function () {
}
}
to make use I changed it to
window.Main = function () {
this.foo = function () {
},
this.temp= function () {
},
this.bar= function () {
}
}
and then to use of these functions, I used following code:
var obj= new Main ();
and then I can say obj.foo(); or obj.bar();
All this is working fine but I wonder if this is the right way to call function from a browserfied file.
Please suggest correct way to make use of browserfied file.
Browserify is a great tool when you use it for the entire project. It makes almost no sense to use it for single files only. The whole point of it is avoiding globals, instead of setting window.Main you could do this:
module.exports = function () {
this.foo = function () {
},
this.temp= function () {
},
this.bar= function () {
}
}
And then in all files that need access to the above, do:
var Main = require('./path/to/main.js');
Browserify resolves and inlines all require calls automatically so you only need to run Browserify on the single file that fires up the app.

Categories

Resources