looking for a full-immersion/face-to-face HTML5, JavaScript, and Mobile Web Development training in the heart of London? Book your spot
Showing posts with label library. Show all posts
Showing posts with label library. Show all posts

Saturday, February 18, 2012

JavaScript Test Framewors: more than 30 + 1

After @szafranek hint and suggestion, wru landed almost at the end of this Wikipedia List of unit testing frameworks page.

If you use this tweet size hand made imperfect script in the wikipedia page console:

a=q="querySelectorAll",[].map.call(document[q](".mw-headline,.wikitable"),function(v,i){i%2?a=v.textContent:o[a]=v[q]("tr").length},o={}),o

You gonna see that JavaScript is third when it comes to number of test frameworks ... and not sure that's good, anyway, here a quick description of mine.

About wru

You can find most info in github page itself but essentially wru is a generic purpose, environment agnostic, JavaScript tests framework compatible with both client and server, where client means every bloody browser, and server means Rhino, node.js, and recently phantom.js too.
To be really fair, wru is not exactly a unit test framework since it does not provide by default anything related to mocks or stubs.
However, wru is so tiny and unobtrusive that any 3rd parts library could be integrated without effort in whatever test you want + need.

wru In A Nutshell

Well, the first thing to do with wru is to write code such:

wru.test([
{
name: "the test name, for feedback purpose",
setup: function (obj) {
// the OPTIONAL setup property performed before the test
// obj will be a freshly new created object
// with a single test lifecycle ... reusable within the test
},
test: function (obj) {
// obj comes from setup, if any
wru.assert(true); // a generic truish condition
setTimeout(wru.async(function () {
// a generic asynchronous condition
// where you will inevitably assert something
wru.assert("this is also true", true);
}), 1000);

// the handy possibility to reuse assert itself
if (wru.assert("this is a truish value", obj)) {
// do stuff with obj
// or simply log the object
wru.log(obj);
}
},
teardown: function (obj) {
// the OPTIONAL teardown property performed after the test
// obj comes from the test function, is the same
// passed through setup, if present, and test
}
}
]);

After this you are basically ready to go.
Both assert() and async() accept one up to two arguments: the optional description of the test, recommended if you want at least understand what's going on and where if something failed, and the second parameter which is returned in both cases.
Via assert() the condition/expression is evaluated as it is, truish or falsy, and returned if addressed.
Via async() the callback is wrapped in an unobtrusive way and this is simply to let wru know that something is going to happen, hopefully in a reasonable timeout of 10 seconds.

How To See Results

Once you have your test in place, you can re-use the same code all over supported environments.
The cool part about wru is that templates for all scenarios are automagically created at build time.
You don't even need to npm install wru to use the test, or include it in a page via script tag, you can simply grab a template and copy and paste or replace, during a build process, the test. This will make your life easier than any setup oriented test framework, isn't it?

Write Once, Run Everywhere

Isn't this the dream we all have about JavaScript in both browsers and server side environments? As far as I know wru is the only one that supports all these environments with a unified, cross platform, and easy to remember API. (until I have discovered JS Class via @jcoglan)
Main principles behind wru? KISS and YAGNI, so that everyone can start, at least, writing tests for what's needed, without any ulterior waste of time about environment, library dependency, or programming language setup.
And what if you want to test platform specific gotchas ? Oh well, you can still recycle the whole test and check the number of positive results, as expected, at the end ... well, not all the code we are writing should work cross platform, but even in this case, wru gonna make you familiar with tests and tests logic so it's a win win in any case.

Pluggable UT Libraries

You must admit the name of this framework is absolutely crap. I didn't even know how to call it in a manner that no other frameworks would have been affected, so I sticked with my blog initials, WebReflection, and the one out of Unit in it, until I introduced this tiny library in one of those amazing BerlinJS events where someone suggested Where Are You acronym, and I simply loved it ... uh wait, let's go back in the topic ...
Any external library able to mock or stub your code should be easy to integrate in a wru test without problems.
In this case you may need to include this library upfront via script tag, in the Web html template, or inside any server side related template through require() or some other mechanism.
For browsers, you may consider JSMock, as example, but others which aim is to provide mocks or stubs functionality should be all supported without problems.

About Asynchronous Logic

Let's face reality, asynchronous tests are created exclusively to test the condition after the asynchronous callback has been executed, and this is exactly the wru expectation, you call for async? you wait for async.
If you get how async work you'll realize that you don't have to expect() anything, simply do what your test should do and trigger the done() at the end.
This comes from one of the most appreciated asynchronous pattern out there, Promises, where you simply wait for a done() to be called.
wru does the same, except the equivalent of done() is assert() which is the trigger.
If you have truly complex asynchronous logic, here a common pattern you might find useful with wru.

wru.test([{
name: "async",
test: function () {
var expectation = wru.async(function (arg) {
wru.assert("everything went better than expected", arg === "OK");
});
// your whatever async logic you need
var xhr = new XMLHttpRequest;
xhr.onreadystatechange = function () {
// called multiple times during xhr lifecycle
if (xhr.readyState === 4) {
// async, inside async
doSomeStuffOutThere(xhr.responseText, function (e) {
expectation(e.result); // hopefully the string "OK"
});
}
};
}
}]);

in few words, you don't need to expect a thing since once you define a single asynchronous callback in your test logic, you can trigger it once everything has been tested and, if that will never happen, the timeout will automatically flag the test as failed.

wru Output

Things are kept simple in this case as well, with the happy exception for the cursor.
I mean, you don't really need to stare at it, but the cursor is a visual indication that everything is not just stuck, but it's simply waiting for things to happen, if ever.
A classic infinite loop or endless generator is able to freeze the lifecycle of our app, and only a visual feedback will be able to tell you the truth since any other method, specially in browsers where tests are showed only once executed, won't be able to give you a thing ... except a crash in the best case scenario.
The cursor may interfere with the normal output but, at least when it comes to server side tests, whatever external tool will be able to remove cursor noise in the log and analyze anything that happened during test execution, from green to red or black, providing you an instant feedback if something went wrong.

Improve As You Go

wru is not a universal answer to JS tests but hopefully a good start point or most likely everything you need if the project, and your tests, are not that complex.
Being that simple, the best thing about this library is that we could reproduce its API everywhere else in few lines of code, transforming, as example, your tests into another UT framework without much effort.
The fragmentation of JS tests out there is massive, so I don't really want to go deeper into this, just think that this library made asynchronous tests that easy, as well as normal synchronous one and without interferences, thanks to the chosen namespace, out there.
What else about wru ... well, give i a try :)

Wednesday, December 24, 2008

External selectors as engines and how to create your own library

With "Sizzle event", the challenge about libraries will move from the coolest/fastest selector engine into the coolest/fastest way to use it for library purpose.

Since Sizzle will be just one of them, thanks to our natural behavior ( read: re-create the wheel ) it is possible that there will be more selector engines around the net.

So, why we could not create our own library that does just what we need and nothing else, maintaining a decent size and performing like a jaguar :D ???

Here a truly basic example about how to create your own library, basing it over a generic selector engine or generic library (or just its engine, if you prefer one)

// our wonderful library constructor
function myQuery(){
// just in case we prefer another name for the constructor
// this code is "name proof"
var callee = arguments.callee;
return this instanceof callee ?
this :
callee.prototype.init.apply(new callee, arguments)
;
};

// add some native prototype to created array like instances
// a common pattern for DOM based libraries
with(Array.prototype)
myQuery.prototype = {
constructor:myQuery,
length:0,
pop:pop,
push:push,
shift:shift,
slice:slice,
sort:sort,
splice:splice,
unshift:unshift
};

// add "not standard yet array prototypes", if necessary, or our own cool proottypes
myQuery.prototype.forEach = Array.prototype.forEach || function(Function, self){
for(var i = 0, length = this.length; i < length; i++)
(i in this) && Function.call(self, this[i], i, this);
};

// define the init prototype to use the pre defined engine
myQuery.prototype.init = function(){
var self = this.engine.apply(null, arguments);
this.push.apply(this, self instanceof Array ? self : this.slice.call(self, 0));
return this;
};

// define the engine for this library
myQuery.prototype.engine = Sizzle; // or jQuery

onload = function(){

// enjoy your lib
myQuery(".foo .bar").forEach(function(HTMLElement){
HTMLElement.innerHTML = "Hello Lib!";
});

};


Summary


The main limit is the engine itself, or better, arguments that the engin could accept.
If we change engine and this accepts different arguments or same arguments in a different way, we need to change every call to our library but at least everything else will work without problems.
For this reason it is reasonble to choose a common engine arguments model, like Sizzle, for example, presuming other engine will accept the same list of options and will produce an array like result.
Am I suggesting to avoid famous/common library? Absolutely no, I simply think the selector engine is the most important thing for whatever DOM purpose library :-)

Saturday, July 12, 2008

An alternative JavaScript development pattern

A common pattern to develop JavaScript libraries is to use different behaviours inside methods, and based on browser, or browser plus its version.
For about 80% of cases, these behaviours are Internet Explorer dedicated.
This approach is good enough, otherwise we could not have a wide variety of libraries to choose, but is this way to develop libraries the best one?

These are some pro concepts:

  • libraries could be usually merged into a single file, so we can add only one script tag, and for every browser

  • libraries maintenance or improvements are focused into one, or more, constructor, function, or method



The expected result is, usually, a method that is capable to understand which browser is running them, and what to do for that specific case.

// common libraries development pattern
function myGorgeusLib(){};
myGorgeusLib.prototype.sayHello = function(){
if(self.attachEvent)
attachEvent("onload", function(){alert("Hello")});
else if(self.addEventListener)
addEventListener("load", function(e){alert("Hello")}, false);
else
onload = function(onload){return onload ?
function(){onload();alert("Hello")} :
function(){alert("Hello")}
}(self.onload);
};

new myGorgeusLib().sayHello();

Is above code clear enough? If a browser implements attachEvent, use them, otherwise if it implements addEventListener, use them, otherwise use manual onload implementation.

If we would like to modify, for some reason, that method, there is only one "place" to do it, the method itself.
At the same time, every time we would like to use that method, the browser has to check 1 or 2 times which case is suited for its engine.

This concept introduces these side effects:

  • every method size is generally increased for every browser, and often only to make some task IE compatible

  • every method speed execution, is generally increased, because of useless, or necessary, checks to perform each time the method is called

  • every change inside every method, could cause side effects for other browsers, so we have to fix 3 to 4 times instead of once, because of possible problems

  • every changed method should be tested into every library supported browser, even if it worked perfectly with every one, IE a part



Lazy, or direct, method assignment


Some library implements lazy prototype assignment, so that method will be the best one, only after the first time we will use them.

// lazy method assignment
function myGorgeusLib(){};
myGorgeusLib.prototype.sayHello = function(){
myGorgeusLib.prototype.sayHello =
self.attachEvent ? function(){
attachEvent("onload", function(){alert("Hello")});
}:(
self.addEventListener ? function(){
addEventListener("load", function(e){alert("Hello")}, false);
}:
function(){
onload = function(onload){return onload ?
function(){onload();alert("Hello")} :
function(){alert("Hello")}
}(self.onload);
}
);
this.sayHello();
};

new myGorgeusLib().sayHello();

Since we could perform that kind of check directly during prototype assignment, in this case, above pattern, is completely useless.
On the other hand, doing lazy or direct dedicated assignment, we are using a better approach because:

  • method is specific for this, or that, browser, so its execution speed will be the fastest possible

  • if we need to fix that method, we can focus only into specific browser version. Accordingly, we do not need to test with every supported browser, every change we made, but only with one, or more, specific version


Code minifier maniacs, could think that in this way, and for each method that requires that strategy, the final size of the library could increase about 30%, and this is, basically, true.
So, at this point, we have the best method ever to perform that specific task, but not the best size. How could we solve this last problem?

An alternative library development pattern


Before I will talk about my proposal, we should focus on a simple, as useful, thing about libraries: modularity
What we do like about this, or that, library, is the possibility to include only what we need, to obtain the final result with smallest possible footprint.
In other words, we chose exactly what we need, and we load or use only them, without useless piece of code that could only increase our page size, with or without cache help.
A lot of libraries use this concept runtime, like Dojo, or directly during library generation, like MooTools.
This way to develop, mantain, and use libraries, is loads of benefits for both developers, and users.
At the same time, and as far as I know, nobody though to port this development pattern, to create each library "portion" a part.
This is an example of what I am talking about:

// alternative library development pattern
function myGorgeusLib(){};
myGorgeusLib.prototype.sayHello = function(){
addEventListener("load", function(e){alert("Hello")}, false);
};

// IE dedicated changes, separated file
myGorgeusLib.prototype.sayHello = function(){
attachEvent("onload", function(){alert("Hello")});
};

// if we would like to support really old browsers too, in a separated file
myGorgeusLib.prototype.sayHello = function(){
onload = function(onload){return onload ?
function(){onload();alert("Hello")} :
function(){alert("Hello")}
}(self.onload);
};


This is a benefits summary, about this proposal:

  • smallest library size ever, thanks to common standard methods used by the library itself (a sort of FireFox, Opera, and Safari dedicated version)

  • modular methods development, with separed files dedicated for one, or more, browser version (IE6, IE7, IE8), thanks to conditional IE standard HTML comments: <!--[if IE 7]><script type="text/javascript" src="library.IE7.js"></script><![endif]-->

  • "future proof", when IE will implement standard DOM or Events methods, and behaviours, we can reduce IE dedicated file size

  • single debug, modular updates. We changes only one, or more, file, instead of recompile, regenerate, redistribute, the entire library file

  • intranet friendly, update only library version for dedicated environment, if it uses only a specific browser


So why shoulld we use JavaScript to define library behaviour, instead of browser itself?
Anyway, this pattern completely brakes practices about script tags in a generic (x)?HTML page. But, at the same time, could be the key to solve a wide number of problems, starting from modern devices with possible memory limits for JavaScript files, up to library execution speed, the best possible, and maintenance, focused in a single browser, or a single browser version.
The best implementation could be a Dojo "progressive library load" style, where the core automatically knows which file should be loaded, depending on browser, or its version.
Finally, these are side effects about this pattern:

  • final and complete library size will be the biggest possible one, but there shouldn't be a case where a browser download every file, redefining N times one or more methods

  • more effort to develop an entire library using this way, if there are a lot of methods that are not compatible with every browser

  • probably something else, that I am not thinking about



Now, after this explanation, would you like to write your impressions? Cheers :)

Monday, April 21, 2008

Phomet - PHP Comet tiny library

Comet is a particular technique to interact asyncronously with the client.
Instead of perform a lot of calls using Ajax (polling) the server is able to send to client, whenever it wants, a generic response.

Unfortunately in the PHP world there's no simple way to implement this kind of technique and I'll write more posts to explain better how to implement this library and what is generally possible to do, or not possible yet, with Comet idea inside a dedicated PHP environment.

At the moment, the only thing you can do is read documentation inside JavaScript and PHP files (truly few lines) and test the first basic example, a server side clock in less than 30 lines of mixed code.

As last information, Phomet comes with all necessary to be optimized on client, and its final result is about 1.57Kb on client, and ridiculously 4.52 Kb on server, comments included :)

Here is the download, unpack them into your localhost, and go into phomet folder to view the first demo.

Compatibility? I've tested them with IE6, 7, 8, Opera 9, FireFox 1.5, 2, 3, Safari 3 windows but I am sure there are other browsers compatible.

I am waiting for your suggestions, bugs, opinions, whatever :D

Cheers, and please stay tuned for next Comet appointments :geek: