I've started using QUnit and discovered that it's support for
asynchronous tests really didn't meet my needs.  After working with it
for a while I figured out what I needed and implemented it as an
extension to the existing testrunner.js:

ok() does not take a function as an assertion, the fix to extend ok()
to accept function callbacks is trivial.

start() and stop() are non-blocking tests in the sense that assertions
that after a stopped test will be run out of order.  My use cases
require that the assertions always be run in order because the
conditions they test for are asynchronous and dependent on each
other.  Also you have to hand code polling every time you use start()/
stop() which is a pain.   Multiple pending stop() are not supported.
Because of the existing tests depend on start()/stop() it is too late
to propose changing their behavior.

I propose a new function called wait(callback, msg, timeout,
increment) that implements a polling test/retest that has adjustable
timeout period and test increment frequency and blocks progress in the
process() function until the assertion passes or the timeout is
exceeded.  Multiple pending wait() are supported.

The only problem I have with this solution is that the assertions are
still reported in the order of callback result processing rather than
the order as declared in the code.  However asynchronous assertion
execution is now properly ordered at run time.  I'm open for
suggestions on how to get the code order of assertions to match the
reporting order with either start()/stop() or my new wait() function.
I'm thinking tagging the assertions order at declaration time and then
sorting the output at report time will be required.

A working proposed implementation of these changes is below.
config.waiting is added, wait() is exported to the global environment,
ok() and process() are modified and the implementation of wait() is
added:

var config = {
        stats: {
                all: 0,
                bad: 0
        },
        queue: [],
        // block until document ready
        blocking: true,
        waiting: [],
        //restrict modules/tests by get parameters
        filters: GETParams,
        isLocal: !!(window.location.protocol == 'file:')
};

// public API as global methods
$.extend(window, {
        test: test,
        module: module,
        expect: expect,
        ok: ok,
        equals: equals,
        start: start,
        stop: stop,
        wait: wait,

...


function ok(a, msg) {
    if (typeof a === "function") {
        a = a();
    }
        config.assertions.push({
                result: !!a,
                message: msg
        });
}

...

function process() {
    var wait, callback, msg, time, increment, test;
    while (config.queue.length && !config.blocking) {
        while (config.waiting.length > 0) {
            wait = config.waiting[0];
            callback = wait[0];
            msg = wait[1];
            time = wait[2];
            increment = wait[3];
            if (time && time < (new Date()).getTime()) {
                test = false;
            } else {
                test = callback();
                if (!test) {
                    setTimeout(function () {
                        process();
                    }, increment);
                    return;
                }
            }
            ok(test, msg);
            config.waiting = config.waiting.slice(1);
        }
        config.queue.shift()();
    }
}

function wait(callback, msg, timeout, increment) {
    if (!increment) {
        increment = 100; // Default increment 1/10 second
    }
    var time = (new Date()).getTime() + timeout;
    config.waiting.push([callback, msg, time, increment]);
}


Here is an example test using the new wait() and ok() with a callback:

    test("Ensure iframe is properly constructed.", function() {
        expect(5);
        wait(function() { return $("#test").attr("contentWindow"); },
            "Wait for contentWindow to exist.", 2500, 250);
        wait(function() { return $("#test").attr
("contentWindow").frames.length === 9; },
            "Wait for 9 Iframes to be loaded in the content window.",
2500, 100);
        ok(function() { return TestSomeThingInsideThe9Frames() },
"Test iframe contents.");
    });


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"jQuery Development" group.
To post to this group, send email to jquery-dev@googlegroups.com
To unsubscribe from this group, send email to 
jquery-dev+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/jquery-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to