Refactored test suite to allow async tests (use stop() before starting an async reque...
[jquery.git] / build / test / data / testrunner.js
1 var asyncTimeout = 2 // seconds for async timeout
2
3 var fixture;
4 var Test;
5 var stats = {
6         all: 0,
7         bad: 0
8 };
9 var queue = [];
10 var blocking = false;
11
12 function synchronize(callback) {
13         queue[queue.length] = callback;
14         if(!blocking) {
15                 process();
16         }
17 }
18
19 function process() {
20         while(queue.length && !blocking) {
21                 var call = queue[0];
22                 queue = queue.slice(1);
23                 call();
24         }
25 }
26
27 function stop() {
28         blocking = true;
29         setTimeout(start, asyncTimeout * 1000);
30 }
31 function start() {
32         blocking = false;
33         process();
34 }
35
36 function runTest(tests) {
37         var startTime = new Date();
38         fixture = document.getElementById('main').innerHTML;
39         tests();
40         synchronize(function() {
41                 var runTime = new Date() - startTime;
42                 var result = document.createElement("div");
43                 result.innerHTML = 'Tests completed in ' + runTime + ' milliseconds.<br/>' +
44                         stats.bad + ' tests of ' + stats.all + ' failed.';
45                 document.getElementsByTagName("body")[0].appendChild(result);
46         });
47 }
48
49 function test(name, callback) {
50         Test = [];
51         synchronize(function() {
52                 try {
53                         callback();
54                 } catch(e) {
55                         if(typeof console != "undefined") {
56                                 console.error("Test " + name + " died, exception and test follows");
57                                 console.error(e);
58                                 console.warn(callback.toString());
59                         }
60                         Test.push( [ false, "Died on test #" + (Test.length+1) + ": " + e ] );
61                 }
62         });
63         synchronize(function() {
64                 reset();
65                 
66                 var good = 0, bad = 0;
67                 var ol = document.createElement("ol");
68         
69                 var li = "", state = "pass";
70                 for ( var i = 0; i < Test.length; i++ ) {
71                         var li = document.createElement("li");
72                         li.className = Test[i][0] ? "pass" : "fail";
73                         li.innerHTML = Test[i][1];
74                         ol.appendChild( li );
75                         
76                         stats.all++;
77                         if ( !Test[i][0] ) {
78                                 state = "fail";
79                                 bad++;
80                                 stats.bad++;
81                         } else good++;
82                 }
83         
84                 var li = document.createElement("li");
85                 li.className = state;
86         
87                 var b = document.createElement("b");
88                 b.innerHTML = name + " <b style='color:black;'>(<b class='fail'>" + bad + "</b>, <b class='pass'>" + good + "</b>, " + Test.length + ")</b>";
89                 b.onclick = function(){
90                         var n = this.nextSibling;
91                         if ( jQuery.css( n, "display" ) == "none" )
92                                 n.style.display = "block";
93                         else
94                                 n.style.display = "none";
95                 };
96                 li.appendChild( b );
97                 li.appendChild( ol );
98         
99                 document.getElementById("tests").appendChild( li );             
100         });
101 }
102
103 /**
104  * Resets the test setup. Useful for tests that modify the DOM.
105  */
106 function reset() {
107         document.getElementById('main').innerHTML = fixture;
108 }
109
110 /**
111  * Asserts true.
112  * @example ok( $("a").size() > 5, "There must be at least 5 anchors" );
113  */
114 function ok(a, msg) {
115         Test.push( [ !!a, msg ] );
116 }
117
118 /**
119  * Asserts that two arrays are the same
120  */
121 function isSet(a, b, msg) {
122         var ret = true;
123         if ( a && b && a.length == b.length ) {
124                 for ( var i in a )
125                         if ( a[i] != b[i] )
126                                 ret = false;
127         } else
128                 ret = false;
129         if ( !ret && console )
130                 console.log( msg, a, b );
131         Test.push( [ ret, msg ] );
132 }
133
134 /**
135  * Returns an array of elements with the given IDs, eg.
136  * @example q("main", "foo", "bar")
137  * @result [<div id="main">, <span id="foo">, <input id="bar">]
138  */
139 function q() {
140         var r = [];
141         for ( var i = 0; i < arguments.length; i++ )
142                 r.push( document.getElementById( arguments[i] ) );
143         return r;
144 }
145
146 /**
147  * Asserts that a select matches the given IDs
148  * @example t("Check for something", "//[a]", ["foo", "baar"]);
149  * @result returns true if "//[a]" return two elements with the IDs 'foo' and 'baar'
150  */
151 function t(a,b,c) {
152         var f = jQuery.find(b);
153         var s = "";
154         for ( var i = 0; i < f.length; i++ )
155                 s += (s && ",") + '"' + f[i].id + '"';
156         isSet(f, q.apply(q,c), a + " (" + b + ")");
157 }