jQuery: The Write Less, Do More JavaScript Library

jQuery test suite and jsUnit compatibility

View: New views
7 Messages — Rating Filter:   Alert me  

jQuery test suite and jsUnit compatibility

by Colin Clark-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Some parts of this message have been removed. Learn more about Nabble's security policy.
Hi all,

On the Fluid Project, we have been using Edward Hieatt's jsUnit (http://www.jsunit.net/ 
) for unit testing all of our code. A number of problems--including  
the inability to use Firebug to debug failing tests--caused us to look  
elsewhere for a less intrusive JavaScript testing framework.

The jQuery testing suite is great! I've ported all of my tests over to  
it, and have been really happy with the results.  Along with this,  
I've made some simple extensions to the jQuery testing suite (which  
I've started calling "jqUnit" for convenience) that I wanted to share  
with the wider community and get your feedback.

First of all, I've attached a patch to testrunner.js, which moves all  
its functions into a closure for privacy and exposes the public test  
API within a namespace called "jqUnit." This will help avoid conflicts  
in the global namespace. Since I pass $ in as an argument, it also  
ensures that we don't have any problems in noConflicts mode.

This patch isn't an example of beautiful refactoring, but I wanted to  
favour clarity--if people find this interesting, I can clean up the  
code and indenting.

Secondly, I've written a number of adaptor functions to provide  
compatibility for my old jsUnit tests. These provide xUnit-style  
asserts, and are just wrappers around the underlying jQuery assert  
functions such as ok(). Perhaps these are useful for others who are  
porting from jsUnit?

Lastly, I've added support for setUp() and tearDown() functions which  
get run before and after each test. I've created a simple object  
called TestCase. Its constructor takes three arguments: the module's  
name, your setUp function, and your tearDown function.

Is this useful to anyone?

Colin



 
var jqUnit = jqUnit || {};

(function ($) {
    var jsUnitCompat = {
        assertEquals: function (msg, expected, actual) {
            jqUnit.equals (actual, expected, msg);
        },

        assertTrue: function (msg, expected) {
            jqUnit.ok (expected, msg);
        },

        assertFalse: function (msg, expected) {
            jqUnit.ok (!expected, msg);
        },

        assertUndefined: function (msg, expected) {
            jqUnit.equals ((typeof expected), 'undefined', msg);
        },

        assertNotUndefined: function (msg, expected) {
            jqUnit.ok (!(typeof expected === 'undefined'), msg);
        },

        assertNull: function (msg, expected) {
            jqUnit.equals (expected, null, msg);
        },

        assertNotNull: function (msg, expected) {
            jqUnit.ok (!(expected === null), msg);
        }
    };

    // Mix these compatibility functions into the jqUnit namespace.
    $.extend(jqUnit, jsUnitCompat);

    // TestCase object
    function TestCase (moduleName, setUpFn, tearDownFn) {
        this.moduleName = moduleName;
        this.setUp = setUpFn || null;
        this.tearDown = tearDownFn || null;

        jqUnit.module(this.moduleName);
    };

    TestCase.prototype.test = function (string, testFn) {
        if (this.setUp) {
            this.setUp ();
        }

        jqUnit.test (string, testFn);

        if (this.tearDown) {
            this.tearDown ();
        }
    };

    //  Mix the TestCase type into the jqUnit namespace.
    $.extend(jqUnit, {TestCase: TestCase});
}) (jQuery);

Test Title Goes Here

Test Title Goes Here




    ---
    Colin Clark
    Technical Lead, Fluid Project
    http://fluidproject.org


    testrunner.js.patch (910 bytes) Download Attachment

    Re: jQuery test suite and jsUnit compatibility

    by Michael Grosser :: Rate this Message:

    Reply to Author | View Threaded | Show Only this Message


    Re: jQuery test suite and jsUnit compatibility

    by fuzziman :: Rate this Message:

    Reply to Author | View Threaded | Show Only this Message

    thanks for the post. i love the idea of having tests in the same module using the same setup and teardown, great idea.

    Noticed a glitch though. You'll need to call jqUnit.module(this.moduleName) just before jqUnit.test().
    Otherwise, you end up with whatever module name was last called, and not the associated module name (e.g. if you create module1 and module2 first, then tests afterwards, all tests will say module2)

    Colin Clark-2 wrote:
    ... I've attached a patch to testrunner.js, which moves all  
    its functions into a closure for privacy and exposes the public test  
    API within a namespace called "jqUnit." This will help avoid conflicts  
    in the global namespace...
    This is an interesting one. Since QUnit's original intent was to test the core of jQuery, testrunner.js can only use vanilla javascript. I think its a great idea though, and it would be an easy thing for the jquery team to build another version as a plugin, and would be another thing to spread the adoption of QUnit.

    to the jquery team: QUnit is great in that can be easily incorporated into the enterprise build process, and one of the few JS unit testing frameworks with active development these days. but if you really want QUnit to have a greater adoption, it should really be released as an offical plugin, and include xunit assertions and namespacing.

    QUnit, jqUnit, and rhino

    by fuzziman :: Rate this Message:

    Reply to Author | View Threaded | Show Only this Message

    I was thinking about modifying testrunner.js (the rhino version) with jqUnit, and getting it run to a point where it will be compatible with the latest QUnit and jqUnit test framework.

    before I dive in, has anyone done any work on this they'd be able to share, so I won't be reinventing the wheel?

    thanks

    Re: QUnit, jqUnit, and rhino

    by John Resig :: Rate this Message:

    Reply to Author | View Threaded | Show Only this Message


    I'm working on this (well, trying to get more of the jQuery test suite
    to pass). I've broken it out into a separate project here:
    http://github.com/jeresig/env-js/tree/master

    I'm also trying to get it to run on more platforms (such as
    Ruby/Johnson, Perl/Spidermonkey, and Python/Spidermonkey).

    --John


    On Thu, Jun 26, 2008 at 12:18 AM, fuzziman <Kenneth.Ko@...> wrote:

    >
    >
    > I was thinking about modifying testrunner.js (the rhino version) with jqUnit,
    > and getting it run to a point where it will be compatible with the latest
    > QUnit and jqUnit test framework.
    >
    > before I dive in, has anyone done any work on this they'd be able to share,
    > so I won't be reinventing the wheel?
    >
    > thanks
    > --
    > View this message in context: http://www.nabble.com/jQuery-test-suite-and-jsUnit-compatibility-tp15882865s27240p18126261.html
    > Sent from the jQuery General Discussion mailing list archive at Nabble.com.
    >
    >

    Re: QUnit, jqUnit, and rhino

    by fuzziman :: Rate this Message:

    Reply to Author | View Threaded | Show Only this Message

    So excited to see that you are actively working on this John!

    I can see you've been concentrating on document parsing behavior, while I've just been looking at "automated testing in rhino". From my testing perspective, I made a couple of patches:
    - in test(), wrapping fn() and the next lines in try/catch/fail, so tests don't fail silently but get logged
    - as part of testrunner's results() method, quit with error code if there was a failure, so ant build can stop if a failure occurred.

    I also patched another bug (I'm not sure whether you experience this bug too..)
    $.get callback wasn't being called.
    I tracked it down to the setInterval/clearInterval code.
    2 problems:
    - the very first setInterval returns 0, which evaluates to false in jquery, and so timer will never be stopped, because in jquery you do    if (ival)
    - as soon as stop() is called, the entire rhino engine stops! not sure why..... stop() is deprecated anyway. easy workaround though, I changed it to use the standard java runnable stop pattern of checking a local variable and returning:


    //--------------
            // Timers

            var timers = [{}];
           
            window.setTimeout = function(fn, time){
                    var num;
                    return num = setInterval(function(){
                            fn();
                            clearInterval(num);
                    }, time);
            };
           
            window.setInterval = function(fn, time){
                    var num = timers.length;
                    var isRunning = true;
                    var timerObj = {
                            thread: new java.lang.Thread(new java.lang.Runnable({
                                    run: function(){
                                            while (isRunning){
                                                    java.lang.Thread.currentThread().sleep(time);
                                                    fn();
                                            }
                                    }
                            })),
                            stop: function() {isRunning = false;}
                    };
                    timers[num] = timerObj;
                    timers[num].thread.start();
           
                    return num;
            };
           
            window.clearInterval = function(num){
                    if ( timers[num] ) {
                            timers[num].stop();
                            delete timers[num];
                    }
            };

    //--------------

    If you like, I can keep posting my findings on this thread as I find them.
    Once again, good to see you working on env.js, its amazing!
    Keep up the good work John!




    John Resig wrote:
    I'm working on this (well, trying to get more of the jQuery test suite
    to pass). I've broken it out into a separate project here:
    http://github.com/jeresig/env-js/tree/master

    Re: QUnit, jqUnit, and rhino

    by chris thatcher-4 :: Rate this Message:

    Reply to Author | View Threaded | Show Only this Message

    Wow this is good news.  I've been mucking up env.js for awhile now locally and was afraid I wouldn't see it go where I hope it will.

    John you mentioned the other platforms you want it to be used on and I think this would be ideal.  One thing that is currently preventing that is that the basic window code, which essentially emulates the browsers behavior and provides the standard global functions and objects available in browsers, is mixed with Java specific code.  If env.js has these provided by the container, eg rhino jar + 'implementation of xmlhttprequest jar', then env.js could stay generic across all the implementations.  It's a little more work but inverts the control so env.js could be used by javascript/spidermonkey  to emulate the browser as well.  This doesnt really help perl/python but might keep the patterns clearer.

    So I guess what I'm asking is, for the javascript 'env.js' is it worth it to abstract so the same script could be used across javascript engines?  A simple way to achieve this is to use 'providers' which are just aliases to implementations:
    - in env.js -
    window.XMLHttpRequest = Env.XMLHttpRequest;

    - in rhino.env.js -
    Rhino = {
        XMLHttpRequest = function()...
    };
    EnvProvider.XMLHttpRequest = RhinoEnv.XMLHttpRequest;

    allows you to include a second script, say 'rhino.env.js' , to keep env.js reusable in spidermonkey?

    Thatcher

    On Thu, Jun 26, 2008 at 11:00 AM, fuzziman <Kenneth.Ko@...> wrote:


    So excited to see that you are actively working on this John! :-)

    I can see you've been concentrating on document parsing behavior, while I've
    just been looking at "automated testing in rhino". From my testing
    perspective, I made a couple of patches:
    - in test(), wrapping fn() and the next lines in try/catch/fail, so tests
    don't fail silently but get logged
    - as part of testrunner's results() method, quit with error code if there
    was a failure, so ant build can stop if a failure occurred.

    I also patched another bug (I'm not sure whether you experience this bug
    too..)
    $.get callback wasn't being called.
    I tracked it down to the setInterval/clearInterval code.
    2 problems:
    - the very first setInterval returns 0, which evaluates to false in jquery,
    and so timer will never be stopped, because in jquery you do    if (ival)
    - as soon as stop() is called, the entire rhino engine stops! not sure
    why..... stop() is deprecated anyway. easy workaround though, I changed it
    to use the standard java runnable stop pattern of checking a local variable
    and returning:


    //--------------
           // Timers

           var timers = [{}];

           window.setTimeout = function(fn, time){
                   var num;
                   return num = setInterval(function(){
                           fn();
                           clearInterval(num);
                   }, time);
           };

           window.setInterval = function(fn, time){
                   var num = timers.length;
                   var isRunning = true;
                   var timerObj = {
                           thread: new java.lang.Thread(new java.lang.Runnable({
                                   run: function(){
                                           while (isRunning){
                                                   java.lang.Thread.currentThread().sleep(time);
                                                   fn();
                                           }
                                   }
                           })),
                           stop: function() {isRunning = false;}
                   };
                   timers[num] = timerObj;
                   timers[num].thread.start();

                   return num;
           };

           window.clearInterval = function(num){
                   if ( timers[num] ) {
                           timers[num].stop();
                           delete timers[num];
                   }
           };

    //--------------

    If you like, I can keep posting my findings on this thread as I find them.
    Once again, good to see you working on env.js, its amazing!
    Keep up the good work John!





    John Resig wrote:
    >
    > I'm working on this (well, trying to get more of the jQuery test suite
    > to pass). I've broken it out into a separate project here:
    > http://github.com/jeresig/env-js/tree/master
    >

    --
    View this message in context: http://www.nabble.com/jQuery-test-suite-and-jsUnit-compatibility-tp15882865s27240p18136064.html
    Sent from the jQuery General Discussion mailing list archive at Nabble.com.




    --
    Christopher Thatcher