13 asyncTimeout
: 2 // seconds for async timeout
16 var isLocal
= !!(window
.location
.protocol
== 'file:');
19 $('#userAgent').html(navigator
.userAgent
);
23 function synchronize(callback
) {
24 _config
.queue
[_config
.queue
.length
] = callback
;
25 if(!_config
.blocking
) {
31 while(_config
.queue
.length
&& !_config
.blocking
) {
32 var call
= _config
.queue
[0];
33 _config
.queue
= _config
.queue
.slice(1);
38 function stop(allowFailure
) {
39 _config
.blocking
= true;
40 var handler
= allowFailure
? start : function() {
41 ok( false, "Test timed out" );
44 // Disabled, caused too many random errors
45 //_config.timeout = setTimeout(handler, _config.asyncTimeout * 1000);
48 // A slight delay, to avoid any current callbacks
49 setTimeout(function(){
51 clearTimeout(_config
.timeout
);
52 _config
.blocking
= false;
58 _config
.blocking
= false;
59 var time
= new Date();
60 _config
.fixture
= document
.getElementById('main').innerHTML
;
61 synchronize(function() {
62 time
= new Date() - time
;
63 $("<div>").html(['<p class="result">Tests completed in ',
64 time
, ' milliseconds.<br/>',
65 _config
.stats
.bad
, ' tests of ', _config
.stats
.all
, ' failed.</p>']
68 $("#banner").addClass(_config
.stats
.bad
? "fail" : "pass");
72 function test(name
, callback
, nowait
) {
73 if(_config
.currentModule
)
74 name
= _config
.currentModule
+ " module: " + name
;
76 var filter
= location
.search
.slice(1);
77 if ( filter
&& encodeURIComponent(name
).indexOf(filter
) == -1 )
80 synchronize(function() {
85 if( typeof console
!= "undefined" && console
.error
&& console
.warn
) {
86 console
.error("Test " + name
+ " died, exception and test follows");
88 console
.warn(callback
.toString());
90 _config
.Test
.push( [ false, "Died on test #" + (_config
.Test
.length
+1) + ": " + e
] );
93 synchronize(function() {
96 // don't output pause tests
99 if(_config
.expected
&& _config
.expected
!= _config
.Test
.length
) {
100 _config
.Test
.push( [ false, "Expected " + _config
.expected
+ " assertions, but " + _config
.Test
.length
+ " were run" ] );
102 _config
.expected
= null;
104 var good
= 0, bad
= 0;
105 var ol
= document
.createElement("ol");
106 ol
.style
.display
= "none";
107 var li
= "", state
= "pass";
108 for ( var i
= 0; i
< _config
.Test
.length
; i
++ ) {
109 var li
= document
.createElement("li");
110 li
.className
= _config
.Test
[i
][0] ? "pass" : "fail";
111 li
.innerHTML
= _config
.Test
[i
][1];
112 ol
.appendChild( li
);
115 if ( !_config
.Test
[i
][0] ) {
122 var li
= document
.createElement("li");
123 li
.className
= state
;
125 var b
= document
.createElement("strong");
126 b
.innerHTML
= name
+ " <b style='color:black;'>(<b class='fail'>" + bad
+ "</b>, <b class='pass'>" + good
+ "</b>, " + _config
.Test
.length
+ ")</b>";
127 b
.onclick = function(){
128 var n
= this.nextSibling
;
129 if ( jQuery
.css( n
, "display" ) == "none" )
130 n
.style
.display
= "block";
132 n
.style
.display
= "none";
134 $(b
).dblclick(function(event
) {
135 var target
= jQuery(event
.target
).filter("strong").clone();
136 if ( target
.length
) {
137 target
.children().remove();
138 location
.href
= location
.href
.match(/^(.+?)(\?.*)?$/)[1] + "?" + encodeURIComponent($.trim(target
.text()));
142 li
.appendChild( ol
);
144 document
.getElementById("tests").appendChild( li
);
148 // call on start of module test to prepend name to all tests
149 function module(moduleName
) {
150 _config
.currentModule
= moduleName
;
154 * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
156 function expect(asserts
) {
157 _config
.expected
= asserts
;
161 * Resets the test setup. Useful for tests that modify the DOM.
164 $("#main").html( _config
.fixture
);
169 * @example ok( $("a").size() > 5, "There must be at least 5 anchors" );
171 function ok(a
, msg
) {
172 _config
.Test
.push( [ !!a
, msg
] );
176 * Asserts that two arrays are the same
178 function isSet(a
, b
, msg
) {
180 if ( a
&& b
&& a
.length
!= undefined && a
.length
== b
.length
) {
181 for ( var i
= 0; i
< a
.length
; i
++ )
187 _config
.Test
.push( [ ret
, msg
+ " expected: " + serialArray(b
) + " result: " + serialArray(a
) ] );
189 _config
.Test
.push( [ ret
, msg
] );
193 * Asserts that two objects are equivalent
195 function isObj(a
, b
, msg
) {
209 _config
.Test
.push( [ ret
, msg
] );
212 function serialArray( a
) {
216 for ( var i
= 0; i
< a
.length
; i
++ ) {
217 var str
= a
[i
].nodeName
;
219 str
= str
.toLowerCase();
221 str
+= "#" + a
[i
].id
;
227 return "[ " + r
.join(", ") + " ]"
231 * Returns an array of elements with the given IDs, eg.
232 * @example q("main", "foo", "bar")
233 * @result [<div id="main">, <span id="foo">, <input id="bar">]
237 for ( var i
= 0; i
< arguments
.length
; i
++ )
238 r
.push( document
.getElementById( arguments
[i
] ) );
243 * Asserts that a select matches the given IDs
244 * @example t("Check for something", "//[a]", ["foo", "baar"]);
245 * @result returns true if "//[a]" return two elements with the IDs 'foo' and 'baar'
250 for ( var i
= 0; i
< f
.length
; i
++ )
251 s
+= (s
&& ",") + '"' + f
[i
].id
+ '"';
252 isSet(f
, q
.apply(q
,c
), a
+ " (" + b
+ ")");
256 * Add random number to url to stop IE from caching
258 * @example url("data/test.html")
259 * @result "data/test.html?10538358428943"
261 * @example url("data/test.php?foo=bar")
262 * @result "data/test.php?foo=bar&10538358345554"
264 function url(value
) {
265 return value
+ (/\?/.test(value
) ? "&" : "?") + new Date().getTime() + "" + parseInt(Math
.random()*100000);
269 * Checks that the first two arguments are equal, with an optional message.
270 * Prints out both expected and actual values on failure.
272 * Prefered to ok( expected == actual, message )
274 * @example equals( "Expected 2 characters.", v.formatMessage("Expected {0} characters.", 2) );
276 * @param Object expected
277 * @param Object actual
278 * @param String message (optional)
280 function equals(actual
, expected
, message
) {
281 var result
= expected
== actual
;
282 message
= message
|| (result
? "okay" : "failed");
283 _config
.Test
.push( [ result
, result
? message
+ ": " + expected
: message
+ " expected: " + expected
+ " actual: " + actual
] );
287 * Trigger an event on an element.
289 * @example triggerEvent( document.body, "click" );
291 * @param DOMElement elem
294 function triggerEvent( elem
, type
, event
) {
295 if ( jQuery
.browser
.mozilla
|| jQuery
.browser
.opera
) {
296 event
= document
.createEvent("MouseEvents");
297 event
.initMouseEvent(type
, true, true, elem
.ownerDocument
.defaultView
,
298 0, 0, 0, 0, 0, false, false, false, false, 0, null);
299 elem
.dispatchEvent( event
);
300 } else if ( jQuery
.browser
.msie
) {
301 elem
.fireEvent("on"+type
);