Project

General

Profile

Statistics
| Branch: | Revision:

root / docs / www / colonyscout / internal / jeditable / tests / testrunner.js @ f59acf11

History | View | Annotate | Download (10.3 KB)

1
/*
2
 * QUnit - jQuery unit testrunner
3
 * 
4
 * http://docs.jquery.com/QUnit
5
 *
6
 * Copyright (c) 2008 John Resig, Jörn Zaefferer
7
 * Dual licensed under the MIT (MIT-LICENSE.txt)
8
 * and GPL (GPL-LICENSE.txt) licenses.
9
 *
10
 * $Id: testrunner.js 5827 2008-08-13 17:14:48Z joern.zaefferer $
11
 */
12

    
13
var _config = {
14
        fixture: null,
15
        Test: [],
16
        stats: {
17
                all: 0,
18
                bad: 0
19
        },
20
        queue: [],
21
        blocking: true,
22
        timeout: null,
23
        expected: null,
24
        currentModule: null,
25
        asyncTimeout: 2 // seconds for async timeout
26
};
27

    
28
_config.filters = location.search.length > 1 && //restrict modules/tests by get parameters
29
                jQuery.map( location.search.slice(1).split('&'), decodeURIComponent );
30

    
31
var isLocal = !!(window.location.protocol == 'file:');
32

    
33
jQuery(function() {
34
        jQuery('#userAgent').html(navigator.userAgent);
35
        runTest();        
36
});
37

    
38
function synchronize(callback) {
39
        _config.queue[_config.queue.length] = callback;
40
        if(!_config.blocking) {
41
                process();
42
        }
43
}
44

    
45
function process() {
46
        while(_config.queue.length && !_config.blocking) {
47
                var call = _config.queue[0];
48
                _config.queue = _config.queue.slice(1);
49
                call();
50
        }
51
}
52

    
53
function stop(allowFailure) {
54
        _config.blocking = true;
55
        var handler = allowFailure ? start : function() {
56
                ok( false, "Test timed out" );
57
                start();
58
        };
59
        // Disabled, caused too many random errors
60
        //_config.timeout = setTimeout(handler, _config.asyncTimeout * 1000);
61
}
62
function start() {
63
        // A slight delay, to avoid any current callbacks
64
        setTimeout(function(){
65
                if(_config.timeout)
66
                        clearTimeout(_config.timeout);
67
                _config.blocking = false;
68
                process();
69
        }, 13);
70
}
71

    
72
function validTest( name ) {
73
        var filters = _config.filters;
74
        if( !filters )
75
                return true;
76

    
77
        var i = filters.length,
78
                run = false;
79
        while( i-- ){
80
                var filter = filters[i],
81
                        not = filter.charAt(0) == '!';
82
                if( not ) 
83
                        filter = filter.slice(1);
84
                if( name.indexOf(filter) != -1 )
85
                        return !not;
86
                if( not )
87
                        run = true;
88
        }
89
        return run;
90
}
91

    
92
function runTest() {
93
        _config.blocking = false;
94
        var started = +new Date;
95
        _config.fixture = document.getElementById('main').innerHTML;
96
        _config.ajaxSettings = jQuery.ajaxSettings;
97
        synchronize(function() {
98
                jQuery('<p id="testresult" class="result">').html(['Tests completed in ',
99
                        +new Date - started, ' milliseconds.<br/>',
100
                        '<span class="bad">', _config.stats.bad, '</span> tests of <span class="all">', _config.stats.all, '</span> failed.</p>']
101
                        .join(''))
102
                        .appendTo("body");
103
                jQuery("#banner").addClass(_config.stats.bad ? "fail" : "pass");
104
        });
105
}
106

    
107
function test(name, callback, nowait) {
108
        if(_config.currentModule)
109
                name = _config.currentModule + " module: " + name;
110
                
111
        if ( !validTest(name) )
112
                return;
113
                
114
        synchronize(function() {
115
                _config.Test = [];
116
                try {
117
                        callback();
118
                } catch(e) {
119
                        if( typeof console != "undefined" && console.error && console.warn ) {
120
                                console.error("Test " + name + " died, exception and test follows");
121
                                console.error(e);
122
                                console.warn(callback.toString());
123
                        }
124
                        _config.Test.push( [ false, "Died on test #" + (_config.Test.length+1) + ": " + e.message ] );
125
                }
126
        });
127
        synchronize(function() {
128
                try {
129
                        reset();
130
                } catch(e) {
131
                        if( typeof console != "undefined" && console.error && console.warn ) {
132
                                console.error("reset() failed, following Test " + name + ", exception and reset fn follows");
133
                                console.error(e);
134
                                console.warn(reset.toString());
135
                        }
136
                }
137
                
138
                // don't output pause tests
139
                if(nowait) return;
140
                
141
                if(_config.expected && _config.expected != _config.Test.length) {
142
                        _config.Test.push( [ false, "Expected " + _config.expected + " assertions, but " + _config.Test.length + " were run" ] );
143
                }
144
                _config.expected = null;
145
                
146
                var good = 0, bad = 0;
147
                var ol = document.createElement("ol");
148
                ol.style.display = "none";
149
                var li = "", state = "pass";
150
                for ( var i = 0; i < _config.Test.length; i++ ) {
151
                        var li = document.createElement("li");
152
                        li.className = _config.Test[i][0] ? "pass" : "fail";
153
                        li.appendChild( document.createTextNode(_config.Test[i][1]) );
154
                        ol.appendChild( li );
155
                        
156
                        _config.stats.all++;
157
                        if ( !_config.Test[i][0] ) {
158
                                state = "fail";
159
                                bad++;
160
                                _config.stats.bad++;
161
                        } else good++;
162
                }
163
        
164
                var li = document.createElement("li");
165
                li.className = state;
166
        
167
                var b = document.createElement("strong");
168
                b.innerHTML = name + " <b style='color:black;'>(<b class='fail'>" + bad + "</b>, <b class='pass'>" + good + "</b>, " + _config.Test.length + ")</b>";
169
                b.onclick = function(){
170
                        var n = this.nextSibling;
171
                        if ( jQuery.css( n, "display" ) == "none" )
172
                                n.style.display = "block";
173
                        else
174
                                n.style.display = "none";
175
                };
176
                jQuery(b).dblclick(function(event) {
177
                        var target = jQuery(event.target).filter("strong").clone();
178
                        if ( target.length ) {
179
                                target.children().remove();
180
                                location.href = location.href.match(/^(.+?)(\?.*)?$/)[1] + "?" + encodeURIComponent(jQuery.trim(target.text()));
181
                        }
182
                });
183
                li.appendChild( b );
184
                li.appendChild( ol );
185
        
186
                document.getElementById("tests").appendChild( li );                
187
        });
188
}
189

    
190
// call on start of module test to prepend name to all tests
191
function module(moduleName) {
192
        _config.currentModule = moduleName;
193
}
194

    
195
/**
196
 * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
197
 */
198
function expect(asserts) {
199
        _config.expected = asserts;
200
}
201

    
202
/**
203
 * Resets the test setup. Useful for tests that modify the DOM.
204
 */
205
function reset() {
206
        jQuery("#main").html( _config.fixture );
207
        jQuery.event.global = {};
208
        jQuery.ajaxSettings = jQuery.extend({}, _config.ajaxSettings);
209
}
210

    
211
/**
212
 * Asserts true.
213
 * @example ok( jQuery("a").size() > 5, "There must be at least 5 anchors" );
214
 */
215
function ok(a, msg) {
216
        _config.Test.push( [ !!a, msg ] );
217
}
218

    
219
/**
220
 * Asserts that two arrays are the same
221
 */
222
function isSet(a, b, msg) {
223
        var ret = true;
224
        if ( a && b && a.length != undefined && a.length == b.length ) {
225
                for ( var i = 0; i < a.length; i++ )
226
                        if ( a[i] != b[i] )
227
                                ret = false;
228
        } else
229
                ret = false;
230
        if ( !ret )
231
                _config.Test.push( [ ret, msg + " expected: " + serialArray(b) + " result: " + serialArray(a) ] );
232
        else 
233
                _config.Test.push( [ ret, msg ] );
234
}
235

    
236
/**
237
 * Asserts that two objects are equivalent
238
 */
239
function isObj(a, b, msg) {
240
        var ret = true;
241
        
242
        if ( a && b ) {
243
                for ( var i in a )
244
                        if ( a[i] != b[i] )
245
                                ret = false;
246

    
247
                for ( i in b )
248
                        if ( a[i] != b[i] )
249
                                ret = false;
250
        } else
251
                ret = false;
252

    
253
    _config.Test.push( [ ret, msg ] );
254
}
255

    
256
function serialArray( a ) {
257
        var r = [];
258
        
259
        if ( a && a.length )
260
        for ( var i = 0; i < a.length; i++ ) {
261
            var str = a[i].nodeName;
262
            if ( str ) {
263
                str = str.toLowerCase();
264
                if ( a[i].id )
265
                    str += "#" + a[i].id;
266
            } else
267
                str = a[i];
268
            r.push( str );
269
        }
270

    
271
        return "[ " + r.join(", ") + " ]";
272
}
273

    
274
function flatMap(a, block) {
275
        var result = [];
276
        $.each(a, function() {
277
                var x = block.apply(this, arguments);
278
                if (x !== false)
279
                        result.push(x);
280
        })
281
        return result;
282
}
283

    
284
function serialObject( a ) {
285
        return "{ " + flatMap(a, function(key, value) {
286
                return key + ": " + value;
287
        }).join(", ") + " }";
288
}
289

    
290
function compare(a, b, msg) {
291
        var ret = true;
292
        if ( a && b && a.length != undefined && a.length == b.length ) {
293
                for ( var i = 0; i < a.length; i++ )
294
                        for(var key in a[i]) {
295
                                if (a[i][key].constructor == Array) {
296
                                        for (var arrayKey in a[i][key]) {
297
                                                if (a[i][key][arrayKey] != b[i][key][arrayKey]) {
298
                                                        ret = false;
299
                                                }
300
                                        }
301
                                } else if (a[i][key] != b[i][key]) {
302
                                        ret = false
303
                                }
304
                        }
305
        } else
306
                ret = false;
307
        ok( ret, msg + " expected: " + serialArray(b) + " result: " + serialArray(a) );
308
}
309

    
310
function compare2(a, b, msg) {
311
        var ret = true;
312
        if ( a && b ) {
313
                for(var key in a) {
314
                        if (a[key].constructor == Array) {
315
                                for (var arrayKey in a[key]) {
316
                                        if (a[key][arrayKey] != b[key][arrayKey]) {
317
                                                ret = false;
318
                                        }
319
                                }
320
                        } else if (a[key] != b[key]) {
321
                                ret = false
322
                        }
323
                }
324
                for(key in b) {
325
                        if (b[key].constructor == Array) {
326
                                for (var arrayKey in b[key]) {
327
                                        if (a[key][arrayKey] != b[key][arrayKey]) {
328
                                                ret = false;
329
                                        }
330
                                }
331
                        } else if (a[key] != b[key]) {
332
                                ret = false
333
                        }
334
                }
335
        } else
336
                ret = false;
337
        ok( ret, msg + " expected: " + serialObject(b) + " result: " + serialObject(a) );
338
}
339

    
340
/**
341
 * Returns an array of elements with the given IDs, eg.
342
 * @example q("main", "foo", "bar")
343
 * @result [<div id="main">, <span id="foo">, <input id="bar">]
344
 */
345
function q() {
346
        var r = [];
347
        for ( var i = 0; i < arguments.length; i++ )
348
                r.push( document.getElementById( arguments[i] ) );
349
        return r;
350
}
351

    
352
/**
353
 * Asserts that a select matches the given IDs
354
 * @example t("Check for something", "//[a]", ["foo", "baar"]);
355
 * @result returns true if "//[a]" return two elements with the IDs 'foo' and 'baar'
356
 */
357
function t(a,b,c) {
358
        var f = jQuery(b);
359
        var s = "";
360
        for ( var i = 0; i < f.length; i++ )
361
                s += (s && ",") + '"' + f[i].id + '"';
362
        isSet(f, q.apply(q,c), a + " (" + b + ")");
363
}
364

    
365
/**
366
 * Add random number to url to stop IE from caching
367
 *
368
 * @example url("data/test.html")
369
 * @result "data/test.html?10538358428943"
370
 *
371
 * @example url("data/test.php?foo=bar")
372
 * @result "data/test.php?foo=bar&10538358345554"
373
 */
374
function url(value) {
375
        return value + (/\?/.test(value) ? "&" : "?") + new Date().getTime() + "" + parseInt(Math.random()*100000);
376
}
377

    
378
/**
379
 * Checks that the first two arguments are equal, with an optional message.
380
 * Prints out both actual and expected values.
381
 *
382
 * Prefered to ok( actual == expected, message )
383
 *
384
 * @example equals( $.format("Received {0} bytes.", 2), "Received 2 bytes." );
385
 *
386
 * @param Object actual
387
 * @param Object expected
388
 * @param String message (optional)
389
 */
390
function equals(actual, expected, message) {
391
        var result = expected == actual;
392
        message = message || (result ? "okay" : "failed");
393
        _config.Test.push( [ result, result ? message + ": " + expected : message + " expected: " + expected + " actual: " + actual ] );
394
}
395

    
396
/**
397
 * Trigger an event on an element.
398
 *
399
 * @example triggerEvent( document.body, "click" );
400
 *
401
 * @param DOMElement elem
402
 * @param String type
403
 */
404
function triggerEvent( elem, type, event ) {
405
        if ( jQuery.browser.mozilla || jQuery.browser.opera ) {
406
                event = document.createEvent("MouseEvents");
407
                event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
408
                        0, 0, 0, 0, 0, false, false, false, false, 0, null);
409
                elem.dispatchEvent( event );
410
        } else if ( jQuery.browser.msie ) {
411
                elem.fireEvent("on"+type);
412
        }
413
}