Testing mutually exclusive JavaScript - javascript

I'm working on a web application that includes different JavaScript files, depending on where I am in the app. For instance, I have a display.js for each page, each of which has an "init()" function that is called as soon as the page is loaded.
This works well for the webapp, but in my QUnit tests, where all script files are included from a single index.html, functions of the same names override each other.
How are such problems best handled? One test index.html file per page creates lots of boilerplate code and makes it non-trivial to execute all test cases. That's why I decided to name each and every function distinctively, e.g. "initFrontPage()" instead of "init()". This, however, makes the application code a bit weird: Not only do I have to include the right file, I also have to call the right functions in it. Is there a better way?

The solution is to use namespaces:
In foo/display.js:
window.foo = {};
foo.init = function () { ... };
In bar/display.js:
window.bar = {};
bar.init = function () { ... };
Then, in the page that uses bar/display.js's init method:
(function (display) {
display.init();
}(bar));
It would be a good idea to wrap your display.js code in an IIFE as well.

Related

How to appropriately reuse the describe blocks of mocha tests?

I have an app that runs in different modes (think of it as running for different platforms as well as using different protocols), one of which has a long loading period every time a page is opened. There are some other minor changes, but all of those could just be taken care of using wdio's setting variables.
Currently I have one test file (with a describe) for each section of the app. Which would be fine if one of the configurations being tested didn't have such a long wait time. Anyway, I've decided to deal with this test case, to handle it all in one file, which will all be on the same page.
Anyway, instead of copying and pasting all the tests I had previously to this one large file I was wondering if I could somehow reuse them, as if they were functions.
As it is right now I did just wrap things in functions, so for example:
// test1.js
module.exports = function test1 () {
describe('Test1', function () {
var settings = {}
before(function () {
// do something
})
it('do something', function () {
assert.ok(true)
})
it('do something else', function () {
assert.ok(true)
})
})
}
In another file we run every single function we created:
test1 = require('./test1')
test2 = require('./test2')
...
test10 = require('./test10')
describe('Main Test', function () {
test1()
test2()
...
test10()
}
This would have solved my DRY problem, if I could somehow select which test functions to run upon my command using
wdio wdio/wdio.conf.js --specs
wdio/test/spects/browser/test1.js
Which obviously will not work.
Basically I want a solution to be able to reuse my tests (the describe blocks). Is what I was doing the right path? If not, how should it be done?
So I have figured out the best way to go about this after I found some documentation about it here.
I will just do as I previously described, however instead of shoving all those functions in the same file, I'll keep them in their own files. There still may be a better solution out there, but it is still an improvement from copying and pasting all test cases for the different modes of running my app.
Just programmatically create different describe blocks. Wrap the describe block in a function with all the parameters that change (including the name of the block) and simply invoke the function to create the variations.
I made a small repo to show this in practice: https://github.com/fatso83/forum-support-code/commit/cb2bc10b1d8bdae31e8f0a8c4e724c70583a5e11

Unit tests in JavaScript with mocked objects

So I'm working with an enterprise tool where we have javascript scripts embedded throughout. These scripts have access to certain built-in objects.
Unfortunately, the tool doesn't give any good way to unit test these scripts. So my thinking was to maintain the scripts in a repo, mock the built-in objects, and then set up unit tests that run on my system.
I'm pretty ignorant to how JavaScript works in terms of building, class loading, etc. but I've been just trying things and seeing what works. I started by trying out Mocha by making it a node project (even though it's just a directory full of scripts, not a real node project). The default test works, but when I try and test functions from my code, I get compiler errors.
Here's what a sample script from my project looks like. I'm hoping to test the functions, not the entire script:
var thing = builtInObject.foo();
doStuff(thing);
doMoreStuff(thing);
function doStuff(thing) {
// Code
}
function doMoreStuff(thing) {
// More Code
}
Here's what a test file looks like:
var assert = require('assert');
var sampleScript = require('../scripts/sampleScript.js');
describe('SampleScript', function() {
describe('#doStuff()', function() {
it('should do stuff', function() {
assert.equal(-1, sampleScript.doStuff("input"));
});
});
});
Problem happens when I import ("require") the script. I get compilation errors, because it doesn't builtInObject. Is there any way I can "inject" those built in objects with mocks? So I define variables and functions that those objects contain, and the compiler knows what they are?
I'm open to alternative frameworks or ideas. Sorry for my ignorance, I'm not really a javascript guy. And I know this is a bit hacky, but it seems like the best option since I'm not getting out of the enterprise tool.
So if I get it right you want to do the unit tests for the frontened file in the Node.js environment.
There are some complications.
First, in terms of Node.js each file has it's own scope so the variables defined inside of the file won't be accessible even if you required the file. So you need to export the vars to use them.
module.exports.doStuff = doStuff; //in the end of sample script
Second, you you start using things like require/module.exports on the frontend they'll be undefined so you'll get an error.
The easiest way to run your code would be. Inside the sample script:
var isNode = typeof module !== 'undefined' && module.exports;
if (isNode) {
//So we are exporting only when we are running in Node env.
//After this doStuff and doMoreStuff will be avail. in the test
module.exports.doStuff = doStuff;
module.exports.doMoreStuff = doMoreStuff;
}
What for the builtInObject. The easies way to mock it would be inside the test before the require do the following:
global.builtInObject = {
foo: function () { return 'thing'; }
};
The test just passed for me. See the sources.
Global variables are not good anyway. But in this case seems you cannot avoid using them.
Or you can avoid using Node.js by configuring something like Karma. It physically launches browser and runs the tests in it. :)

Manually Invoke IIFE

I've got a library (Hubspot Odometer) which I am using in a web application I am developing and it works fine to create and run Odometer style widgets on a page.
The trouble is that they are part of a dashboard interface which has panes that are loaded via AJAX. The initial view is not loaded via AJAX so the JavaScript executes fine and the odometers render correctly.
When I load a new pane with odometers however they are not rendered correctly nor do they act as they should. The reason for this is that the odometer library runs as one big IIFE.
What I am wondering is can I re-invoke the IIFE manually after I load content via AJAX so that the odometers are rendered and bound to correctly?
I am also using jQuery if that offers me any additional options.
Try this:
var funcName = (function funcName() {
// rest of the code
return funcName;
}());
Also see this jsbin.
The whole idea of the IIFE is that its an anonymous function that is immediately executed. So by definition, no there is no way to re-execute it.
With that said however, you can store the function expression to a global variable, and execute it. For example
window.my_iife = (function() { /* stuff */ });
window.my_iife();
Notice the slight difference in syntax compared to the traditional IIFE: ((function() {})());
By storing the function in window, you are able to access it later from either the developer console or anywhere else in your code. If you simply store it in a var, or declare it as function my_iife() { /* ... */ } somewhere you risk that var or function declaration itself being wrapped in an IIFE and thus being inaccessible. As an example, that scenario could occur if the file you declared your var/function in is part of a Sprockets manifest (such as application.js in Rails).
var funcName = null;
(funcName = function funcName() {
// rest of the code
return funcName;
}());
funcName();
This is what worked for me

How to parse and load javascript object?

I have one js files . I load it using other javascrupt file using eval() function. I have seen eval is slow and with some other limtation. Since i need to store my JS file object in cache and use it anytime i need after apllication starts. I dont want to do eval() everytime.
Is there anyway to do it in simple way.
var evalObj;
if(evalObj) {
console.log('eval object already evaluated');
_myfunctionInJSFile_(layouts.FormatDate(startTime), threadName, level, categoryName, message);
}
else {
evalObj = eval(fs.readFileSync('./myJSFile', 'utf8'));
console.log('re evaluating object ..' );
_myfunctionInJSFile_(layouts.FormatDate(startTime), threadName, level,message);
}
myJSFile
var _sigmaAlarmHandler_ =function(args)
{
var args = Array.prototype.slice.call(arguments);
args.unshift();
console.log('Alarm : ', args);
}
Either the conditional eval is not working.
In node.js you can simple require your js-file:
var obj = require('./myJSFile');
obj.foo();
./myJSFile.js:
exports.foo = function() {
console.log('foo');
}
This file becomes a module with exported functions, that you need.
It loads once, then every require reuse already loaded module.
If it is not commonjs-compliant (i.e. using module.exports will not work), then you can run it in its own vm:
var vm = require('vm');
vm.runInNewContext(jscode,{/*globalvars*/});
where the second parameter is an object with global vars made available in the context in which the jscode is run. So if the second param is, say, {a:1,b:"foo"} then your jscode will run with the global variable a set to 1 and the global variable b set to "foo".
The jscode itself is a string that you load from a file or elsewhere.
Think of vm.runInNewContext() as "practice safe eval". Well, relatively safe, you can still do some dangerous stuff if you pass in particular vars, like process or file etc.
I used this for the declarative part of cansecurity http://github.com/deitch/cansecurity for nodejs
You can view the sample in the file lib/declarative.js
Here is the API for vm http://nodejs.org/api/vm.html
There are options to run in the same context, etc. But that is very risky.
When you actually run the code, using your example above:
_myfunctionInJSFile_(layouts.FormatDate(startTime), threadName, level,message);
you are looking to pass in 4 params: startTime, threadName, level, message and execute the function. The issue is that you cannot run the function on the current context. You need the function to be defined and run in the file. So you should have something like:
vm.runInNewContext(jscode,{startTime:layouts.FormatDate(startTime),threadName:threadName,level:level,message:message});
And then the jscode should look like
function _myfunctionInJSFile(startTime,threadName,level,message) {
// do whatever you need to do
}
// EXECUTE IT - the above vars are set by the global context provide in vm.runInNewContext
_myfunctionInJSFile(startTime,threadName,level,message);
If you prefer to define the function and have it loaded and run in this context, then just use the commonjs format.
I think i have found the answer for this.
Since my application is running in node js which uses v8 engine platform. When the application starts v8 engine caches all the code/configuration and can be used anytime.
Similarly in my code i will pre-load the JS code using eval and i will do it only once. So on next call i will return only the loaded JS code. Here i need to modify the code to load once.
But main point we have look is that in future if any body has similar requirement they can cache their JS codes using eval (thanks to v8 engine) and use it till your application is running.

javascript strategy / best practice

I'm getting into writing some more complex javascript applications, and I'm running into the limitations of my own knowledge-- please forgive any naming errors or obvious noob stuff, I'm not a js pro!
I have about 4 or 5 scripts I've put in their own files, just to keep things a little easier to maintain. So maybe there's one script that deals with building page elements (like complex forms), another that just handles data, creating generic ajax request objects, defining parsers and error functions for the data returned, and another that is purely display-oriented.
I've set global variables in the page that then get populated by various scripts that get loaded at run time. For example, I define var myapp = { }; in the main HTML page, and then in the scripts various function populate this "namespace" like:
myapp.myfunction = function(){
// do stuff
}
The problem is that despite all the scripts including a $(document).ready(function() block that wraps all function definitions, when a function is called from one script that refers to another (that is, if my data.js file calls a function myapp.myDisplayFunction that is in the display.js file, I sometimes get an Object has no method 'myDisplayFunction'
Other than slamming all functions into one massive script, how do you deal with this problem? Is there a best practice that I'm missing? or is this just a question of specifying a different order that the scripts are called in?
Thanks
When you are not sure if method you are about to call exists (is already loaded) you can do a check:
if (myapp) //my app namespace is defined
{
if (myapp.myFunction) //myFunction is defined
{
myapp.myFunction();
}
else
alert('You have to load myFile.js first!');
}
Just check for the function before using:
if(typeof(myapp.myDisplayFunction) !== undefined) {
// do your stuff
} else {
// wait for a while
}
And check whether you have async attribute set while loading the .js files.

Categories