1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
3 <meta http-equiv="refresh" content="1200" />
4 <title> Run the testsuite</title>
5 <noscript>Javascript is disabled in your browser. This page cannot be displayed correctly without Javascript. Sorry. <br/> If you want to view this page, please change your browser settings so that Javascript is enabled.</noscript>
7 Test.AnotherWay version 0.5
9 Copyright (c) 2005 Artem Khodush, http://straytree.org
11 Permission is hereby granted, free of charge, to any person obtaining
12 a copy of this software and associated documentation files (the
13 "Software"), to deal in the Software without restriction, including
14 without limitation the rights to use, copy, modify, merge, publish,
15 distribute, sublicense, and/or sell copies of the Software, and to
16 permit persons to whom the Software is furnished to do so, subject to
17 the following conditions:
19 The above copyright notice and this permission notice shall be
20 included in all copies or substantial portions of the Software.
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 <style type="text/css">
31 * { padding: 0; margin: 0; }
33 body { height: 98%; font: normal normal 10pt sans-serif }
34 #col1 { float: left; width: 27em; margin: 0 0 0 1em; overflow: visible; }
35 #col2 { position: relative; height: 98%; margin: 0 0.5em 0 28em; }
36 #col1_header { margin-top: 0.5em; }
37 #scroller { height: 400px; overflow: auto;}
38 #testtable { margin: 0 0 2em 0; width: 97%; }
39 #run_buttons { margin-bottom: 4em; }
41 #right_header { padding-top: 0.8em; }
42 #results_count { float: left; }
43 .active_tab { float: right; padding: 0 1em 0.2em 1em; background: #0af; border: 1px solid #048; border-bottom: none; cursor: pointer; cursor: hand;
44 position: relative; top: -0.2em; }
45 .inactive_tab { float: right; padding: 0 1em 0 1em; background: #9bb; color: #444; border: 1px solid #9bb; border-bottom: none; cursor: pointer; cursor: hand; }
46 .inactive_mouseover_tab { float: right; padding: 0 1em 0 1em; background: #9bb; color: #062; border: 1px solid #062; border-bottom: none; cursor: pointer; cursor: hand; }
48 #right_frame { overflow: auto; position: relative; top: -0.2em; clear: right; height: 95%; border: 1px solid #048; }
50 #debug { display: none; }
51 #debug p { margin: 2px 0 0 5em; text-indent: -4.8em; }
53 #error { display: none; color: #c22; }
55 #results p { margin: 0 0 2px 0; }
56 /* cursor indicating that detailed results may be expanded/contracted */
57 #results p.badtest { cursor: text; }
58 #results p.ok, #results p.fail { cursor: pointer; cursor: hand; }
60 /* colored squares in the results window at the left of test page names */
61 #results p.ok .bullet { background: #6d6; }
62 #results p.fail .bullet { background: #d46; }
63 #results p.badtest .bullet { background: #ea3; }
64 #results p.loading .bullet { background: #48f; }
65 #results p.running .bullet { background: #26e; }
66 #results p.waiting .bullet { background: #04d; }
67 /* highlight in the results line */
68 #results p .warning { background: #ffc; }
70 /* layout of the detailed results */
71 .result_detail { padding-left: 3em; }
72 .result_exception_detail { padding-left: 4em; }
73 .result_exception_stack_detail { padding-left: 5em; }
74 .result_micro_detail { padding-left: 6em; }
75 /* colouring in the detailed results */
76 .result_detail .fail, .result_exception_detail .fail, .result_micro_detail .fail { background: #ffd8d8; }
78 /* "start recording" controls*/
79 #record_div { margin-top: 3em; }
80 #record_div p { margin-bottom: 0.5em; }
81 #record_select { width: 88%; }
82 #record_input { width: 53%; }
84 <script type="text/javascript">
87 function report_results() {
89 // branch for native XMLHttpRequest object
90 if(window.XMLHttpRequest && !(window.ActiveXObject)) {
92 req = new XMLHttpRequest();
96 // branch for IE/Windows ActiveX version
97 } else if(window.ActiveXObject) {
99 req = new ActiveXObject("Msxml2.XMLHTTP");
102 req = new ActiveXObject("Microsoft.XMLHTTP");
108 req.open("POST", "/test/results.cgi");
109 req.setRequestHeader("Content-Type", 'application/x-www-form-urlencoded');
110 var results = document.getElementById('total').innerHTML;
112 if (results.match("fail")) {
113 test_text = document.getElementById("results").innerHTML;
115 req.send("results="+escape(results)+"&test_text="+escape(test_text));
118 if( typeof( Test )=="undefined" ) {
123 Test.AnotherWay._g_test_iframe=null; // frame where to load test pages
124 Test.AnotherWay._g_test_frame_no_clear=false; // true - leave last page displayed after tests end
125 Test.AnotherWay._g_test_page_urls=[]; // array of: { url: url, convention: "anotherway" or "jsan" }
126 Test.AnotherWay._g_test_object_for_jsan=null; // test object for filling by tests that adhere to jsan Test.Simple calling convention
127 Test.AnotherWay._g_pages_to_run=null; // list of pages to run automatically after loading
128 Test.AnotherWay._g_run_on_main_load=false; // special handling for run_pages_to_run when it might be called before onload or before list of test pages is known.
129 Test.AnotherWay._g_run_on_list_load=false;
130 Test.AnotherWay._g_main_loaded=false;
132 Test.AnotherWay._run_pages_to_run=function( called_from_outside )
134 if( !Test.AnotherWay._g_main_loaded ) {
135 Test.AnotherWay._g_run_on_main_load=true;
137 var a_pages=Test.AnotherWay._g_pages_to_run;
138 if( a_pages=="all" ) {
139 for( var i=0; i<Test.AnotherWay._g_test_page_urls.length; ++i ) {
140 Test.AnotherWay._run_test_page( "test"+i );
142 }else if( a_pages!=null ) {
143 for( var run_i=0; run_i<a_pages.length; ++run_i ) {
144 var run_page=a_pages[run_i];
146 for( var all_i=0; all_i<Test.AnotherWay._g_test_page_urls.length; ++all_i ) {
147 if( run_page==Test.AnotherWay._g_test_page_urls[all_i].url ) {
148 Test.AnotherWay._run_test_page( "test"+all_i, called_from_outside );
154 Test.AnotherWay._show_error( "page specified to run is not found in the page list: "+run_page );
162 Test.AnotherWay._add_test_page_url=function( test_url, convention )
164 var table=document.getElementById( "testtable" );
165 var record_select=document.getElementById( "record_select" );
166 var index=Test.AnotherWay._g_test_page_urls.length;
169 if( test_url.match( "^(\\s*)(.*\\S)(\\s*)$" ) ) {
173 Test.AnotherWay._g_test_page_urls[index]={ url: test_url, convention: convention };
174 var row=table.insertRow( -1 );
178 cell=row.insertCell( -1 );
179 cell_child=document.createElement( "input" );
180 cell_child.type="checkbox";
181 cell_child.id="checkbox"+index;
182 cell_child.checked='checked';
183 cell_child.defaultChecked='checked';
184 cell.appendChild( cell_child );
186 cell=row.insertCell( -1 );
187 cell.setAttribute( "width", "75%" );
188 cell.appendChild( document.createTextNode( test_url ) );
190 cell=row.insertCell( -1 );
191 cell_child=document.createElement( "input" );
192 cell_child.type="button";
193 cell_child.id="test"+index;
194 cell_child.value=" run ";
195 cell_child.onclick=Test.AnotherWay._run_one_onclick;
196 cell.appendChild( cell_child );
198 cell=row.insertCell( -1 );
199 cell.setAttribute( "width", "8em" );
200 cell_child=document.createElement( "span" );
201 cell.appendChild( cell_child );
203 var option=document.createElement( "option" );
204 option.appendChild( document.createTextNode( test_url ) );
205 record_select.appendChild( option );
207 Test.AnotherWay._show_error=function( msg )
209 var error_div=document.getElementById( "error" );
210 error_div.innerHTML="";
211 error_div.appendChild( document.createTextNode( msg ) );
212 error_div.style.display="block";
215 // read urls from the list in the html file inside the list_iframe
216 // fill on-screen list with urls and "run" buttons, and fill the g_test_page_urls object.
217 Test.AnotherWay._list_iframe_onload=function()
219 if( window.frames.list_iframe!=null && window.frames.list_iframe.location!="" && window.frames.list_iframe.location!="about:blank" ) {
220 var list_doc=window.frames.list_iframe.document;
221 var list=list_doc.getElementById( "testlist" );
223 for( var i=0; i<list.childNodes.length; ++i ) {
224 var item=list.childNodes[i];
225 if( item.nodeName=="LI" || item.nodeName=="li" ) {
226 var convention="anotherway";
227 if( Test.AnotherWay._get_css_class( item )=="jsan" ) {
230 Test.AnotherWay._add_test_page_url( item.innerHTML, convention );
233 if( Test.AnotherWay._g_run_on_list_load ) {
234 Test.AnotherWay._g_run_on_list_load=false;
235 Test.AnotherWay._run_pages_to_run();
238 Test.AnotherWay._show_error( "no list with id 'testlist' in a list file "+window.frames.list_iframe.location );
243 Test.AnotherWay._map_checkboxes=function( f )
245 var table=document.getElementById( "testtable" );
246 var checks=table.getElementsByTagName( "INPUT" );
247 for( var i=0; i<checks.length; ++i ) {
248 if( checks[i].type=="checkbox" && checks[i].id.match( /^checkbox(\d+)$/ ) ) {
249 f( checks[i], RegExp.$1 );
253 Test.AnotherWay._run_all_onclick=function()
255 Test.AnotherWay._map_checkboxes( function( c, id ) { Test.AnotherWay._run_test_page( "test"+id ); } );
257 Test.AnotherWay._run_selected_onclick=function()
259 Test.AnotherWay._map_checkboxes( function( c, id ) { if( c.checked ) Test.AnotherWay._run_test_page( "test"+id ); } );
261 Test.AnotherWay._unselect_all_onclick=function()
263 Test.AnotherWay._map_checkboxes( function( c, id ) { c.checked=false; } );
265 Test.AnotherWay._run_one_onclick=function()
267 Test.AnotherWay._run_test_page( this.id );
270 // construct an object that will gather results of running one test function
271 Test.AnotherWay._test_object_t=function( fun_name )
273 this.name=fun_name; // name of the test function
274 this.n_plan=null; // planned number of assertions
275 this.n_ok=0; // # of ok assertions
276 this.n_fail=0; // # of failed assertions
277 this.exception=""; // if the function throwed an exception, it's its message
278 this.exception_stack=[]; // strings: function call stack from the exception
279 this.assertions=[]; // assertion results: array of { ok: 1 or 0, name: string }
280 this.wait_result_milliseconds=0; // how long to wait before collecting results from the test
281 this.second_wait_msg=null; // <p> status message (in addition to the page wait_msg)
282 this.delay_actions=[]; // array of actions to be perfomed after the test function returns
283 // action : { acton_kind: "call" | "window" | "replay"
284 // when "call": { call_fn call_delay_milliseconds } call_fn takes nothing
285 // when "window" : { wnd_url wnd_wnd wnd_fn wnd_timeout_milliseconds wnd_dont_close } wnd_fn takes wnd
286 // wnen "replay" : { replay_wnd replay_events replay_event_i replay_checkpoints } checkpoint_fn takes this, wnd
288 this.delay_action_i=null; // index of delay action currently being performed
289 this.delay_prev_timer_time=0; // for counting time while performing delay_actions
290 this.delay_current_milliseconds_left=0; // time left before the next action, runs down
291 this.delay_total_milliseconds_left=0; // for indication: total estimated time for all actions, runs up and down
294 Test.AnotherWay._test_object_t.prototype.ok=function( cond, name )
303 this.assertions.push( { ok: cond, name: name } );
305 Test.AnotherWay._test_object_t.prototype.fail=function( name )
307 this.ok( false, name );
309 Test.AnotherWay._test_object_t.prototype.plan=function( n )
313 Test.AnotherWay._test_object_t.prototype.wait_result=function( seconds )
315 this.wait_result_milliseconds=1000*seconds;
317 Test.AnotherWay._eq_fail_msg=function( path, what, expected, got )
319 return "eq: "+path+" "+what+" differ: got "+got+", but expected "+expected;
321 Test.AnotherWay._array_eq=function( expected, got, path, msg )
323 if( expected.length!=got.length ) {
324 msg.msg=Test.AnotherWay._eq_fail_msg( path, "array length", expected.length, got.length );
327 for( var i=0; i<expected.length; ++i ) {
328 if( !Test.AnotherWay._thing_eq( expected[i], got[i], path+"["+i+"]", msg ) ) {
334 Test.AnotherWay._object_eq=function( expected, got, path, msg )
337 for( v in expected ) {
339 msg.msg=Test.AnotherWay._eq_fail_msg( path+"."+v, "properties", expected[v], "undefined" );
342 if( !Test.AnotherWay._thing_eq( expected[v], got[v], path+"."+v, msg ) ) {
347 if( ! (v in expected) ) {
348 msg.msg=Test.AnotherWay._eq_fail_msg( path+"."+v, "properties", "undefined", got[v] );
354 Test.AnotherWay._constructor_name=function( x )
361 s=typeof( x.constructor );
363 s=x.constructor.toString();
369 // hackish attempt to guess a type
378 return is_array ? "Array" : "Object"; // for empty arrays/objects, this will be wrong half the time
379 }else if( s.match( /^\s*function\s+(\w+)\s*\(/ ) ) {
395 Test.AnotherWay._is_array=function( x )
397 return Test.AnotherWay._constructor_name( x )=="Array";
399 Test.AnotherWay._is_value_type=function( x )
401 cn=Test.AnotherWay._constructor_name( x );
402 return cn=="Number" || cn=="String" || cn=="Boolean" || cn=="Date";
404 Test.AnotherWay._thing_eq=function( expected, got, path, msg )
406 if( expected==null && got==null ) {
408 }else if( (expected==null && got!=null) || (expected!=null && got==null) ) {
409 msg.msg=Test.AnotherWay._eq_fail_msg( path, "values", expected, got );
412 var expected_cn=Test.AnotherWay._constructor_name( expected );
413 var got_cn=Test.AnotherWay._constructor_name( got );
414 if( expected_cn!=got_cn ) {
415 msg.msg=Test.AnotherWay._eq_fail_msg( path, "types", expected_cn, got_cn );
418 if( Test.AnotherWay._is_array( expected ) ) {
419 return Test.AnotherWay._array_eq( expected, got, path, msg );
420 }else if( Test.AnotherWay._is_value_type( expected ) ) {
421 if( expected!=got ) {
422 msg.msg=Test.AnotherWay._eq_fail_msg( path, "values", expected, got );
427 }else { // just a plain object
428 return Test.AnotherWay._object_eq( expected, got, path, msg );
433 Test.AnotherWay._test_object_t.prototype.eq=function( got, expected, name )
436 if( Test.AnotherWay._thing_eq( expected, got, "", msg ) ) {
439 this.fail( name+". "+msg.msg );
442 Test.AnotherWay._test_object_t.prototype.like=function( got, expected, name )
444 if( got.match( expected )!=null ) {
447 this.fail( name+": got "+got+", but expected it to match: "+expected );
450 Test.AnotherWay._g_html_eq_span=null;
451 Test.AnotherWay._html_eq_string_to_node=function( string_or_node, what, msg )
453 if( string_or_node.nodeType!=null ) {
454 string_or_node=Test.AnotherWay._html_eq_node_to_string( string_or_node ); // double trip - to make properties assigned in scripts available as html node attributes
456 if( Test.AnotherWay._g_html_eq_span==null ) {
457 Test.AnotherWay._g_html_eq_span=document.createElement( "span" );
459 Test.AnotherWay._g_html_eq_span.innerHTML=string_or_node;
460 if( Test.AnotherWay._g_html_eq_span.childNodes.length!=1 ) {
461 msg.msg="bad "+what+" html string given (should contain exactly one outermost element): "+string_or_node;
463 return Test.AnotherWay._g_html_eq_span.childNodes[0].cloneNode( true );
465 Test.AnotherWay._html_eq_node_to_string=function( node ) {
466 if( Test.AnotherWay._g_html_eq_span==null ) {
467 Test.AnotherWay._g_html_eq_span=document.createElement( "span" );
469 Test.AnotherWay._g_html_eq_span.innerHTML="";
470 if( node.outerHTML!=null ) {
471 Test.AnotherWay._g_html_eq_span.innerHTML=node.outerHTML;
473 var clone = node.cloneNode(true);
474 var node = Test.AnotherWay._g_html_eq_span;
475 if(node.ownerDocument && node.ownerDocument.importNode) {
476 if(node.ownerDocument != clone.ownerDocument) {
477 clone = node.ownerDocument.importNode(clone, true);
480 node.appendChild(clone);
482 return Test.AnotherWay._g_html_eq_span.innerHTML;
484 Test.AnotherWay._html_eq_path_msg=function( path )
487 for( var i=0; i<path.length; ++i ) {
488 msg+=" [node "+path[i].node;
489 if( path[i].id!=null && path[i].id!="" ) {
490 msg+=" id "+path[i].id;
491 }else if( path[i].index!=null ) {
492 msg+=" at index "+path[i].index;
498 Test.AnotherWay._html_eq_fail_msg=function( path, what, expected, got )
500 return Test.AnotherWay._html_eq_path_msg( path )+": "+what+" differ: got "+got+", but expected "+expected;
502 Test.AnotherWay._html_eq_remove_blank=function( text )
506 }else if( text.match( "^(\\s*)(.*\\S)(\\s*)$" ) ) {
508 }else if( text.match( "\s*" ) ) {
513 Test.AnotherWay._html_eq_remove_blank_nodes=function( node )
516 for( var child=node.firstChild; child!=null; child=child.nextSibling ) {
517 if( child.nodeType==3 ) {
518 var value=Test.AnotherWay._html_eq_remove_blank( child.nodeValue );
520 to_remove.push( child );
522 child.nodeValue=value;
526 for( var i=0; i<to_remove.length; ++i ) {
527 node.removeChild( to_remove[i] );
530 Test.AnotherWay._html_node_type_text=function( node_type )
533 return "1 (html element)";
534 }else if( node_type==3 ) {
540 Test.AnotherWay._html_eq_node=function( expected, got, path, msg, expected_loc_base, got_loc_base )
542 if( expected.nodeType!=got.nodeType ) {
543 msg.msg=Test.AnotherWay._html_eq_fail_msg( path, "node types", Test.AnotherWay._html_node_type_text( expected.nodeType ), Test.AnotherWay._html_node_type_text( got.nodeType ) );
545 }else if( expected.nodeType==3 ) {
546 if( expected.nodeValue!=got.nodeValue ) {
547 msg.msg=Test.AnotherWay._html_eq_fail_msg( path, "text", expected.nodeValue, got.nodeValue );
550 }else if( expected.nodeType==1 ) {
551 if( expected.nodeName!=got.nodeName ) {
552 msg.msg=Test.AnotherWay._html_eq_fail_msg( path, "node names", expected.nodeName, got.nodeName );
555 // compare attributes
556 var expected_attrs={};
560 for( i=0; i<expected.attributes.length; ++i ) {
561 a=expected.attributes[i];
563 expected_attrs[a.name]=1;
566 for( i=0; i<got.attributes.length; ++i ) {
572 for( a in expected_attrs ) {
573 if( ! (a in got_attrs) ) {
574 msg.msg=Test.AnotherWay._html_eq_path_msg( path )+": attribute sets differ: expected attribute "+a+" is missing";
578 for( a in got_attrs ) {
579 if( ! (a in expected_attrs) ) {
580 msg.msg=Test.AnotherWay._html_eq_path_msg( path )+": attribute sets differ: got extra attribute "+a;
584 for( a in expected_attrs ) {
585 var expected_value=expected.getAttribute( a );
586 var got_value=got.getAttribute( a );
587 if( typeof( expected_value )=="string" && typeof( got_value )=="string" ) {
588 expected_value=Test.AnotherWay._html_eq_remove_blank( expected_value );
589 got_value=Test.AnotherWay._html_eq_remove_blank( got_value );
590 var ok=expected_value==got_value;
591 if( !ok && (a=="href" || a=="HREF" ) ) { // try relative hrefs
592 var expected_relative_value=expected_value;
593 if( expected_loc_base!=null && expected_value.substring( 0, expected_loc_base.length )==expected_loc_base ) {
594 expected_relative_value=expected_value.substring( expected_loc_base.length );
596 var got_relative_value=got_value;
597 if( got_loc_base!=null && got_value.substring( 0, got_loc_base.length )==got_loc_base ) {
598 got_relative_value=got_value.substring( got_loc_base.length );
600 ok=expected_relative_value==got_relative_value;
603 msg.msg=Test.AnotherWay._html_eq_fail_msg( path, "attribute "+a+" values", expected_value, got_value );
606 }else if( typeof( expected_value )=="function" && typeof( got_value )=="function" ) {
607 expected_value=expected_value.toString();
608 got_value=got_value.toString();
609 if( expected_value!=got_value ) {
610 msg.msg=Test.AnotherWay._html_eq_fail_msg( path, "attribute "+a+" values", expected_value, got_value );
615 if( !Test.AnotherWay._thing_eq( expected_value, got_value, "", value_msg ) ) {
616 msg.msg=Test.AnotherWay._html_eq_path_msg( path )+": attribute "+a+" values differ: "+value_msg.msg;
621 // compare child nodes
622 Test.AnotherWay._html_eq_remove_blank_nodes( expected );
623 Test.AnotherWay._html_eq_remove_blank_nodes( got );
624 var expected_length=expected.childNodes.length;
625 var got_length=got.childNodes.length;
626 if( expected_length<got_length ) {
627 msg.msg=Test.AnotherWay._html_eq_path_msg( path )+": got "+(got_length-expected_length)+" extra child nodes";
629 }else if( expected_length>got_length ) {
630 msg.msg=Test.AnotherWay._html_eq_path_msg( path )+": expected "+(expected_length-got_length)+" more child nodes";
633 for( i=0; i<expected_length; ++i ) {
634 var expected_node=expected.childNodes[i];
635 path.push( { node: expected_node.nodeName, id: expected_node.id, index: i } );
636 var eq=Test.AnotherWay._html_eq_node( expected_node, got.childNodes[i], path, msg, expected_loc_base, got_loc_base );
646 Test.AnotherWay._html_eq_get_loc_base=function( node )
648 var loc_base=document.location;
649 if( node.ownerDocument!=null ) {
650 loc_base=node.ownerDocument.location;
652 if( loc_base!=null ) {
653 loc_base=loc_base.href;
654 var slash_pos=loc_base.lastIndexOf( "/" );
655 if( slash_pos!=-1 ) {
656 loc_base=loc_base.substring( 0, slash_pos+1 );
661 Test.AnotherWay._test_object_t.prototype.html_eq=function( got, expected, name )
664 var expected_node=Test.AnotherWay._html_eq_string_to_node( expected, "expected", msg );
665 if( msg.msg!=null ) {
666 this.fail( name+" html_eq: "+msg.msg );
668 var got_node=Test.AnotherWay._html_eq_string_to_node( got, "got", msg );
669 if( msg.msg!=null ) {
670 this.fail( name+" html_eq: "+msg.msg );
672 var expected_loc_base=Test.AnotherWay._html_eq_get_loc_base( expected );
673 var got_loc_base=Test.AnotherWay._html_eq_get_loc_base( got );
674 if( Test.AnotherWay._html_eq_node( expected_node, got_node, [], msg, expected_loc_base, got_loc_base ) ) {
677 var msg=name+" html_eq "+msg.msg;
678 var expected_str=Test.AnotherWay._html_eq_node_to_string( expected_node );
679 var got_str=Test.AnotherWay._html_eq_node_to_string( got_node );
680 msg+=".\n got html: "+got_str;
681 msg+=".\n expected html: "+expected_str;
687 Test.AnotherWay._debug_pane_print=function( msg )
690 var p=document.createElement( "p" );
691 p.appendChild( document.createTextNode( d.toLocaleTimeString()+" "+msg ) );
692 var debug_pane=document.getElementById( "debug" );
693 debug_pane.appendChild( p );
694 var debug_tab=document.getElementById( "debug_tab" );
695 var results_tab=document.getElementById( "results_tab" );
696 debug_tab.style.visibility="visible";
697 results_tab.style.visibility="visible";
699 Test.AnotherWay._test_object_t.prototype.debug_print=function( msg )
701 Test.AnotherWay._debug_pane_print( this.name+": "+msg );
703 Test.AnotherWay._test_object_t.prototype.delay_call=function()
706 for( var i=0; i<arguments.length; ++i ) {
707 if( typeof( arguments[i] )!="function" ) {
708 timeout_ms=3000*arguments[i];
710 var action={ action_kind: "call", call_delay_milliseconds: timeout_ms, call_fn: arguments[i] };
711 this.delay_total_milliseconds_left+=Test.AnotherWay._action_estimate_milliseconds( action );
712 this.delay_actions.push( action );
716 Test.AnotherWay._test_object_t.prototype.open_window=function( url, fn, timeout_seconds )
718 if( timeout_seconds==null ) {
721 var no_close=document.getElementById( "dont_close_test_windows" );
722 var action={ action_kind: "window", wnd_url: url.toString(), wnd_wnd: null, wnd_fn: fn, wnd_timeout_milliseconds: timeout_seconds*1000, wnd_no_close: no_close.checked };
723 this.delay_total_milliseconds_left+=Test.AnotherWay._action_estimate_milliseconds( action );
724 this.delay_actions.push( action );
726 Test.AnotherWay._test_object_t.prototype.replay_events=function( wnd, events )
728 if( Test.AnotherWay._g_no_record_msg!=null ) {
729 this.fail( "replay_events: "+Test.AnotherWay._g_no_record_msg );
731 var action={ action_kind: "replay", replay_wnd: wnd, replay_events: events.events, replay_event_i: null, replay_checkpoints: events.checkpoints };
732 this.delay_total_milliseconds_left+=Test.AnotherWay._action_estimate_milliseconds( action );
733 this.delay_actions.push( action );
736 Test.AnotherWay._action_estimate_milliseconds=function( action )
739 if( action.action_kind=="call" ) {
740 ms=action.call_delay_milliseconds;
741 }else if( action.action_kind=="window" ) {
743 }else if( action.action_kind=="replay" ) {
745 for( var i=0; i<action.replay_events.length; ++i ) {
746 ms+=action.replay_events[i]["time"]-0;
752 Test.AnotherWay._g_timeout_granularity=200;
753 Test.AnotherWay._g_tests_queue=[]; // vector of { url: string, test_objects : array of test_object_t, test_object_i: int, wait_msg: <p> object, loading_timeout_milliseconds: int, timeout_id: id }
755 // load one html page, schedule further processing
756 Test.AnotherWay._run_test_page=function( id, called_from_outside )
758 if( id.match( /^test(\d+)/ ) ) {
760 Test.AnotherWay._g_tests_queue.push( {
761 url: Test.AnotherWay._g_test_page_urls[id].url,
762 convention: Test.AnotherWay._g_test_page_urls[id].convention,
765 if( Test.AnotherWay._g_tests_queue.length==1 ) {
766 if( !called_from_outside ) {
767 // Crap. Be careful stepping around.
768 // For Mozilla and Opera, when this file is included into the frameset page that is in another directory (and _g_outside_path_correction!=null)
769 // but the test pages are started from within it (by "run" buttons), then:
770 // depending on whether the page is the first one loaded into the test frame or not,
771 // the base url for relative test pages differs.
772 // Crap, like I said.
773 Test.AnotherWay._g_tests_queue[0].suppress_outside_path_correction=true;
775 Test.AnotherWay._start_loading_page();
779 Test.AnotherWay._load_next_page=function()
781 Test.AnotherWay._g_tests_queue.splice( 0, 1 );
782 if( Test.AnotherWay._g_tests_queue.length>0 ) {
783 Test.AnotherWay._start_loading_page();
785 if( !Test.AnotherWay._g_test_frame_no_clear ) {
786 Test.AnotherWay._g_test_iframe.location.replace( "about:blank" );
791 Test.AnotherWay._g_opera_path_correction=null; // ugly wart to support opera
792 Test.AnotherWay._g_outside_path_correction=null; // ugly wart to accomodate Opera and Mozilla, where relative url relates to the directory where the page that calls this function is located
793 Test.AnotherWay._set_iframe_location=function( iframe, loc, outside_path_correction )
795 // allow to load only locations with the same origin
796 var proto_end=loc.indexOf( "://" );
797 if( proto_end!=-1 ) { // otherwise, it's safe to assume (for Opera, Mozilla and IE ) that loc will be treated as relative
798 var main_loc=window.location.href;
799 var host_end=loc.substring( proto_end+3 ).indexOf( "/" );
802 var loc_origin=loc.substring( 0, proto_end+3+host_end+1 );
803 if( main_loc.length>=loc_origin.length && main_loc.substring( 0, loc_origin.length )==loc_origin ) {
808 return { msg: "test pages may have only urls with the same origin as "+main_loc };
811 // opera cannot handle urls relative to file:// without assistance
812 if( window.opera!=null && window.location.protocol=="file:" && loc.indexOf( ":" )==-1 ) {
813 var base=window.location.href;
814 var q_pos=base.indexOf( "?" );
816 base=base.substring( 0, q_pos );
818 var slash_pos=base.lastIndexOf( "/" );
819 if( slash_pos!=-1 ) {
820 base=base.substring( 0, slash_pos+1 );
821 Test.AnotherWay._g_opera_path_correction=base;
825 // if this function is called from another page, and if that page is in another directory, correction is needed
826 if( outside_path_correction!=null ) {
827 var pos=loc.indexOf( outside_path_correction );
829 loc=loc.substring( outside_path_correction.length+1 );
832 if( iframe.location!=null ) {
833 iframe.location.replace( loc );
839 Test.AnotherWay._start_loading_page=function()
841 var test_page=Test.AnotherWay._g_tests_queue[0];
842 test_page.loading_timeout_milliseconds=20000;
843 test_page.timeout_id=setTimeout( Test.AnotherWay._loading_timeout, Test.AnotherWay._g_timeout_granularity );
844 test_page.wait_msg=Test.AnotherWay._print_counter_result( test_page.url, "loading...", test_page.loading_timeout_milliseconds, "loading" );
845 if( test_page.convention=="jsan" ) {
846 // the tests in that page will run when it's loading, so the test object must be ready
847 Test.AnotherWay._g_test_object_for_jsan=new Test.AnotherWay._test_object_t( test_page.url );
849 var outside_path_correction=null;
850 if( Test.AnotherWay._g_outside_path_correction!=null && !test_page.suppress_outside_path_correction ) {
851 outside_path_correction=Test.AnotherWay._g_outside_path_correction;
853 var result=Test.AnotherWay._set_iframe_location( Test.AnotherWay._g_test_iframe, test_page.url, outside_path_correction );
854 if( result.msg!=null ) {
855 Test.AnotherWay._unprint_result( test_page.wait_msg );
856 Test.AnotherWay._print_result( test_page.url, result.msg, "badtest", null );
857 Test.AnotherWay._load_next_page();
861 Test.AnotherWay._loading_timeout=function()
863 var test_page=Test.AnotherWay._g_tests_queue[0];
864 test_page.loading_timeout_milliseconds-=Test.AnotherWay._g_timeout_granularity;
865 if( test_page.loading_timeout_milliseconds>0 ) {
866 Test.AnotherWay._update_msg_counter( test_page.wait_msg, (test_page.loading_timeout_milliseconds/1000).toFixed() );
867 test_page.timeout_id=setTimeout( Test.AnotherWay._loading_timeout, Test.AnotherWay._g_timeout_granularity );
869 Test.AnotherWay._unprint_result( test_page.wait_msg );
870 Test.AnotherWay._print_result( test_page.url, "Unable to load test page. Timeout expired", "badtest", null );
871 Test.AnotherWay._load_next_page();
875 Test.AnotherWay._strip_query_and_hash=function( s )
877 var i=s.lastIndexOf( "#" );
879 s=s.substring( 0, i );
881 i=s.lastIndexOf( "?" );
883 s=s.substring( 0, i );
887 Test.AnotherWay._is_url_loaded=function( url, wnd )
890 if( wnd!=null && wnd.location!=null ) {
891 // after some popup blocker interference, location may behave strange..
893 location_s+=wnd.location;
894 if( location_s!="" ) {
895 var pathname=wnd.location.pathname;
896 var expected_url=url;
897 var i=expected_url.lastIndexOf( "#" );
899 expected_url=expected_url.substring( 0, i );
901 i=expected_url.lastIndexOf( "?" );
903 expected_url=expected_url.substring( 0, i );
905 i=expected_url.lastIndexOf( "/" );
906 if( i!=-1 && i!=expected_url.length-1 ) {
907 expected_url=expected_url.substring( i+1 );
909 i=pathname.indexOf( expected_url )
910 if( wnd.location.href==url || (i!=-1 && i==pathname.length-expected_url.length) ) {
911 if( /*window.opera==null*/wnd.document.readyState==null || wnd.document.readyState=="complete" ) { // for opera (and IE?), getElementById does not work until..
919 // find and run all test functions in the g_cur_page html page.
920 Test.AnotherWay._test_page_onload=function()
922 if( Test.AnotherWay._g_tests_queue.length==0 ) {
925 var test_page=Test.AnotherWay._g_tests_queue[0];
926 if( !Test.AnotherWay._is_url_loaded( test_page.url, Test.AnotherWay._g_test_iframe ) ) {
929 clearTimeout( test_page.timeout_id );
930 Test.AnotherWay._unprint_result( test_page.wait_msg );
932 if( test_page.convention=="anotherway" ) {
933 // get test function names (those beginning with "test")
934 if( typeof( Test.AnotherWay._g_test_iframe.document.scripts )!='undefined' ) { // IE
935 for( var i=0; i<Test.AnotherWay._g_test_iframe.document.scripts.length; ++i ) {
936 var script_text=Test.AnotherWay._g_test_iframe.document.scripts[i].text;
937 var fun_sig="function test";
938 var fun_start=script_text.indexOf( fun_sig );
940 while( fun_start!=-1 ) {
941 script_text=script_text.substring( fun_start, script_text.length );
942 var fun_end=script_text.indexOf( '(' );
943 var fun_name=script_text.substring( "function ".length, fun_end );
944 var whitespace = fun_name.indexOf( ' ' );
946 fun_name = fun_name.substring( 0, whitespace );
947 test_page.test_objects.push( new Test.AnotherWay._test_object_t( fun_name ) );
948 script_text=script_text.substring( fun_end, script_text.length );
949 fun_start=script_text.indexOf( fun_sig );
952 }else { // otherwise (not IE) it ought to work like this
953 for( var i in Test.AnotherWay._g_test_iframe) {
954 // Hack to prevent failure in FF3.0b1
955 if (i == "innerWidth" || i == "innerHeight") { continue; }
956 if( typeof( Test.AnotherWay._g_test_iframe[i] )=='function' ) {
957 if( i.substring( 0, 4 )=="test" ) {
958 test_page.test_objects.push( new Test.AnotherWay._test_object_t( i ) );
963 }else if( test_page.convention=="jsan" ) {
964 // the test object is already filled with results
965 test_page.test_objects.push( Test.AnotherWay._g_test_object_for_jsan );
968 if( test_page.test_objects.length==0 ) {
969 Test.AnotherWay._print_result( test_page.url, "No test functions defined in the page", "badtest", null );
970 Test.AnotherWay._load_next_page();
974 test_page.wait_msg=Test.AnotherWay._print_result( test_page.url, "running tests..<span class=\"counter\">"+test_page.test_objects.length+"</span>", "running", null );
976 test_page.test_object_i=0;
977 Test.AnotherWay._run_more_tests();
980 Test.AnotherWay._handle_exception=function( o, e, title )
982 var s=title+": "+typeof( e )+": ";
983 if( e.message!=null ) {
985 }else if( e.description!=null ) {
990 // if( e.location!=null ) { // XXX figure out how to display exception location if it's present (like in mozilla)
991 // s+=" location: "+e.location.toString();
996 var lines=e.stack.split( "\n" );
997 for( var i=0; i<lines.length; ++i ) {
998 // format of the line: func_name(args)@file_name:line_no
999 if( lines[i].match( /(\w*)\(([^\)]*)\)@(.*):([^:]*)$/ ) ) {
1000 var func_name=RegExp.$1;
1001 if( func_name.length==0 ) {
1002 func_name="<anonymous>";
1004 s.push( "in "+func_name+"( "+RegExp.$2+") at "+RegExp.$3+" line "+RegExp.$4+"\n" );
1008 o.exception_stack=s;
1011 Test.AnotherWay._run_more_tests=function()
1013 var test_page=Test.AnotherWay._g_tests_queue[0];
1014 while( test_page.test_object_i<test_page.test_objects.length ) {
1015 Test.AnotherWay._update_msg_counter( test_page.wait_msg, (1+test_page.test_object_i)+"/"+test_page.test_objects.length );
1016 var o=test_page.test_objects[test_page.test_object_i];
1017 if( test_page.convention=="anotherway" ) {
1019 Test.AnotherWay._g_test_iframe[o.name]( o );
1021 Test.AnotherWay._handle_exception( o, e, "" );
1023 } // for "jsan" convention, test has run already
1024 if( o.delay_actions.length>0 || o.wait_result_milliseconds>0 ) {
1025 o.delay_total_milliseconds_left+=o.wait_result_milliseconds;
1026 Test.AnotherWay._delay_actions_timeout();
1029 ++test_page.test_object_i;
1031 Test.AnotherWay._unprint_result( test_page.wait_msg );
1032 Test.AnotherWay._print_result( test_page.url, null, null, test_page.test_objects );
1033 Test.AnotherWay._load_next_page();
1036 Test.AnotherWay._delay_actions_timeout=function()
1038 var test_page=Test.AnotherWay._g_tests_queue[0];
1039 var test_object=test_page.test_objects[test_page.test_object_i];
1041 if( test_object.delay_action_i==null ) {
1042 // set up to start first action
1043 test_object.delay_action_i=-1;
1045 // perform current action
1046 var milliseconds_passed=(new Date()).getTime()-test_object.delay_prev_timer_time;
1047 test_object.delay_current_milliseconds_left-=milliseconds_passed;
1048 test_object.delay_total_milliseconds_left-=milliseconds_passed;
1049 finished=Test.AnotherWay._delay_continue_action( test_object, milliseconds_passed );
1051 while( finished && test_object.delay_action_i<test_object.delay_actions.length ) {
1052 ++test_object.delay_action_i; // start next action
1053 finished=Test.AnotherWay._delay_start_action( test_object );
1055 if( test_object.delay_action_i<=test_object.delay_actions.length ) { // any more actions left ?
1056 test_object.delay_prev_timer_time=(new Date()).getTime();
1057 var next_timeout=Test.AnotherWay._g_timeout_granularity;
1058 if( test_object.delay_current_milliseconds_left<next_timeout ) {
1059 next_timeout=test_object.delay_current_milliseconds_left;
1061 if( test_object.second_wait_msg!=null ) {
1062 Test.AnotherWay._update_msg_counter( test_object.second_wait_msg, (test_object.delay_total_milliseconds_left/1000).toFixed() );
1064 setTimeout( Test.AnotherWay._delay_actions_timeout, next_timeout );
1065 }else { // no more actions left. run the next test.
1066 if( test_object.second_wait_msg!=null ) {
1067 Test.AnotherWay._unprint_result( test_object.second_wait_msg );
1068 test_object.second_wait_msg=null;
1070 ++test_page.test_object_i;
1071 Test.AnotherWay._run_more_tests();
1074 Test.AnotherWay._delay_start_action=function( test_object )
1078 if( test_object.delay_action_i==test_object.delay_actions.length ) {
1079 if( test_object.wait_result_milliseconds>0 ) {
1080 test_object.delay_current_milliseconds_left=test_object.wait_result_milliseconds; // wait for result
1081 wait_msg="waiting for results..";
1083 ++test_object.delay_action_i; // dont wait for result
1086 var action=test_object.delay_actions[test_object.delay_action_i];
1087 if( action.action_kind=="call" ) {
1088 test_object.delay_current_milliseconds_left=action.call_delay_milliseconds;
1089 wait_msg="performing delayed calls..";
1090 }else if( action.action_kind=="window" ) {
1091 if( Test.AnotherWay._g_opera_path_correction!=null && action.wnd_url.indexOf( ":" )==-1 ) {
1092 action.wnd_url=Test.AnotherWay._g_opera_path_correction+action.wnd_url;
1094 action.wnd_wnd=window.open( action.wnd_url, "_blank" );
1095 if( action.wnd_wnd==null ) {
1097 test_object.fail( "unable to open window for "+action.wnd_url );
1099 test_object.delay_current_milliseconds_left=action.wnd_timeout_milliseconds;
1100 wait_msg="opening window..";
1102 }else if( action.action_kind=="replay" ) {
1103 if( action.replay_events.length==0 ) {
1106 action.replay_event_i=0;
1107 test_object.delay_current_milliseconds_left=action.replay_events[0]["time"];
1108 wait_msg="replaying events..";
1112 if( test_object.second_wait_msg!=null ) {
1113 Test.AnotherWay._unprint_result( test_object.second_wait_msg );
1115 if( wait_msg!="" ) {
1116 var test_page=Test.AnotherWay._g_tests_queue[0];
1117 test_object.second_wait_msg=Test.AnotherWay._print_counter_result( test_page.url, wait_msg, test_object.delay_total_milliseconds_left, "waiting" );
1119 test_object.second_wait_msg=null;
1123 Test.AnotherWay._delay_continue_action=function( test_object, milliseconds_passed )
1125 var finished=test_object.delay_current_milliseconds_left<=0;
1126 if( test_object.delay_action_i==test_object.delay_actions.length ) { // action is "waiting for results"
1127 if( test_object.n_plan!=null && test_object.n_plan==test_object.n_ok+test_object.n_fail ) {
1128 finished=true; // if all assertions results are recorded, don't wait any more
1131 ++test_object.delay_action_i; // move on to the next test
1134 var action=test_object.delay_actions[test_object.delay_action_i];
1135 if( action.action_kind=="call" ) {
1140 Test.AnotherWay._handle_exception( test_object, e, "in delay_call" );
1143 }else if( action.action_kind=="window" ) {
1144 test_object.delay_total_milliseconds_left+=milliseconds_passed; // for "window", the countdown is suspended since it's unknown how long it will take
1145 if( Test.AnotherWay._is_url_loaded( action.wnd_url, action.wnd_wnd ) ) {
1147 action.wnd_fn( action.wnd_wnd );
1149 Test.AnotherWay._handle_exception( test_object, e, "in open_window function call" );
1152 }else if( finished ) {
1153 test_object.fail( "unable to open window for url '"+action.wnd_url+"'. timeout expired" );
1155 }else if( action.action_kind=="replay" ) {
1158 Test.AnotherWay._delay_replay_event( test_object, action.replay_wnd, action.replay_events[action.replay_event_i], action.replay_checkpoints );
1159 // }catch( e ) { // disabled, until I know how to gel location info from an exception
1160 // Test.AnotherWay._handle_exception( test_object, e, "while replaying event" );
1162 ++action.replay_event_i;
1163 finished=action.replay_event_i==action.replay_events.length;
1165 test_object.delay_current_milliseconds_left=action.replay_events[action.replay_event_i]["time"];
1172 Test.AnotherWay._delay_replay_event=function( test_object, wnd, event, checkpoints )
1174 if( event.type=="_checkpoint" ) {
1175 var checkpoint_n=event.which;
1176 var prev_n_fail=test_object.n_fail;
1177 checkpoints[checkpoint_n]( test_object, wnd );
1178 var flash_color= prev_n_fail==test_object.n_fail ? "#2f2" : "#f22" ;
1179 Test.AnotherWay._record_flash_border( flash_color );
1180 }else if( event.type=="click" || event.type=="mouseover" || event.type=="mouseout" || event.type=="mousemove" || event.type=="mousedown" || event.type=="mouseup" ) {
1181 var target=Test.AnotherWay._record_node_path_to_node( event["target"], wnd.document );
1182 if( target!=null ) {
1183 Test.AnotherWay._record_control_update_highlight( target, "ball", event );
1184 var e=wnd.document.createEvent( "MouseEvents" );
1185 var related_target=Test.AnotherWay._record_node_path_to_node( event["relatedTarget"], wnd.document );
1188 event["cancelable"],
1190 wnd.document.defaultView,
1201 Test.AnotherWay._record_node_path_to_node( event["relatedTarget"], wnd.document )
1203 // Firefox 1.0.6 somehow loses relatedTarget somewhere on the way. Pass through our own, for those who choose to care.
1204 e.passThroughRelatedTarget=related_target;
1205 target.dispatchEvent( e );
1207 }else if( event.type=="keyup" || event.type=="keydown" || event.type=="keypress" ) {
1208 var e=wnd.document.createEvent( "KeyboardEvents" ); // forget it. Apparently it's not supported neither by mozilla nor by opera.
1209 e.initKeyboardEvent(
1211 event["cancelable"],
1213 wnd.document.defaultView,
1222 wnd.document.dispatchEvent( e );
1226 Test.AnotherWay._print_counter_result=function( url, msg, milliseconds, style )
1228 return Test.AnotherWay._print_result( url, msg+"<span class=\"counter\">"+(milliseconds/1000).toFixed()+"</span>", style, null );
1231 Test.AnotherWay._g_result_count=0; // for assigning unique ids to result paragraphs
1233 // number of pages tested
1234 Test.AnotherWay._g_ok_pages=0;
1235 Test.AnotherWay._g_fail_pages=0;
1237 Test.AnotherWay._print_result=function( url, msg, style, test_objects )
1239 var results=document.getElementById( "results" );
1240 var r=results.appendChild( document.createElement( "p" ) );
1241 r.id="result"+Test.AnotherWay._g_result_count;
1242 ++Test.AnotherWay._g_result_count;
1243 r.onclick=Test.AnotherWay._toggle_detail;
1244 var text="<span class=\"bullet\"> </span> ";
1251 if( test_objects!=null ) {
1252 // compose summary and detail texts
1254 var total_detail_ok=0;
1256 var total_detail_fail=0;
1259 var detail=results.appendChild( document.createElement( "div" ) );
1261 if( r.id.match( /^result(\d+)$/ ) ) {
1262 detail.id="result_detail"+RegExp.$1;
1265 for( var i=0; i<test_objects.length; ++i ) {
1266 var o=test_objects[i];
1269 p=document.createElement( "P" );
1270 Test.AnotherWay._set_css_class( p, "result_detail" );
1272 if( o.n_fail>0 || o.exception || (o.n_plan!=null && o.n_plan!=o.n_ok+o.n_fail) || (o.n_plan==null && o.n_ok==0 && o.n_fail==0)) {
1274 p_text+=" <span class=\"fail\">";
1275 if( o.n_plan!=null && o.n_plan!=o.n_ok+o.n_fail) {
1276 p_text+="planned "+o.n_plan+" assertions but got "+(o.n_ok+o.n_fail)+"; ";
1278 if(o.n_plan==null && o.n_ok==0 && o.n_fail==0) {
1279 p_text+="test did not output anything";
1281 p_text+=" fail "+o.n_fail;
1287 p_text+=" ok "+o.n_ok;
1288 if( o.n_plan==null ) {
1290 p_text+=" <span class=\"warning\">no plan</span>";
1293 detail.appendChild( p );
1295 p=document.createElement( "P" );
1296 Test.AnotherWay._set_css_class( p, "result_exception_detail" );
1297 p.innerHTML="<span class=\"fail\">exception:</span> "+o.exception;
1298 detail.appendChild( p );
1299 p=document.createElement( "P" );
1300 Test.AnotherWay._set_css_class( p, "result_exception_stack_detail" );
1301 p.innerHTML=o.exception_stack.join( "<br/>" );
1302 detail.appendChild( p );
1304 for( var ii=0; ii<o.assertions.length; ++ii ) {
1305 var oo=o.assertions[ii];
1306 var status=oo.ok ? "ok" : "<span class=\"fail\">fail</span>";
1307 p=document.createElement( "P" );
1308 Test.AnotherWay._set_css_class( p, "result_micro_detail" );
1310 p.appendChild( document.createTextNode( " "+oo.name ) );
1311 detail.appendChild( p );
1313 total_detail_ok+=o.n_ok;
1314 total_detail_fail+=o.n_fail;
1316 if( total_fail || total_detail_fail ) {
1317 text+=" fail "+total_fail;
1319 text+=" ok "+total_ok+" (detailed:";
1320 if( total_fail || total_detail_fail ) {
1321 text+=" fail "+total_detail_fail;
1323 text+=" ok "+total_detail_ok+")";
1325 text+=" <span class=\"warning\">no plan</span>";
1327 style= total_fail==0 ? "ok" : "fail";
1328 detail.style.display= style=="fail" ? "block" : "none";
1329 detail.style.cursor="text";
1332 Test.AnotherWay._set_css_class( r, style );
1334 ++Test.AnotherWay._g_ok_pages;
1335 }else if( style=="fail" || style=="badtest" ) {
1336 ++Test.AnotherWay._g_fail_pages;
1339 if( Test.AnotherWay._g_fail_pages>0 ) {
1340 pages_total+=" fail "+Test.AnotherWay._g_fail_pages;
1342 pages_total+=" ok "+Test.AnotherWay._g_ok_pages;
1343 Test.AnotherWay._update_results_total( pages_total );
1346 if( results.scrollHeight!=null && results.scrollTop!=null && results.offsetHeight!=null ) {
1347 results.scrollTop=results.scrollHeight-results.offsetHeight;
1349 // when test_objects is not null, the results are final - good time to clean up
1350 if( test_objects!=null ) {
1351 for( var i=0; i<test_objects.length; ++i ) {
1352 var actions=test_objects[i].delay_actions;
1353 for( var action_i=0; action_i<actions.length; ++action_i ) {
1354 var action=actions[action_i];
1355 if( action.action_kind=="window" && action.wnd_wnd!=null && !action.wnd_no_close ) {
1356 action.wnd_wnd.close();
1357 action.wnd_wnd=null;
1364 Test.AnotherWay._unprint_result=function( child )
1366 var results=document.getElementById( "results" );
1367 results.removeChild( child );
1369 Test.AnotherWay._toggle_detail=function()
1371 if( this.id.match( /^result(\d+)$/ ) ) {
1372 var detail=document.getElementById( "result_detail"+RegExp.$1 );
1373 if( detail!=null ) {
1374 if( detail.style.display=="none" ) {
1375 detail.style.display="block";
1376 }else if( detail.style.display=="block" ) {
1377 detail.style.display="none";
1382 Test.AnotherWay._update_msg_counter=function( msg, text )
1384 for( var i=0; i<msg.childNodes.length; ++i ) {
1385 var item=msg.childNodes[i];
1386 if( item.nodeName=="SPAN" && Test.AnotherWay._get_css_class( item )=="counter" ) {
1387 item.innerHTML=text;
1391 Test.AnotherWay._update_results_total=function( msg )
1393 var total=document.getElementById( "total" );
1395 total.innerHTML=msg;
1398 Test.AnotherWay._results_clear_onclick=function()
1400 var results=document.getElementById( "results" );
1401 results.innerHTML="";
1402 Test.AnotherWay._update_results_total( "" );
1403 Test.AnotherWay._g_ok_pages=0;
1404 Test.AnotherWay._g_fail_pages=0;
1405 var debug=document.getElementById( "debug" );
1409 Test.AnotherWay._get_css_class=function( o )
1411 var c=o.getAttribute( "className" );
1412 if( c==null || c=="" ) {
1413 c=o.getAttribute( "class" );
1417 Test.AnotherWay._set_css_class=function( o, css_class )
1419 o.setAttribute( "className", css_class );
1420 o.setAttribute( "class", css_class );
1423 Test.AnotherWay._tab_onclick=function()
1426 var tabs=[ document.getElementById( "debug_tab" ), document.getElementById( "results_tab" ) ];
1427 var panes=[ document.getElementById( "debug" ), document.getElementById( "results" ) ];
1428 for( var i=0; i<tabs.length; ++i ) {
1429 if( tab==tabs[i] ) {
1430 Test.AnotherWay._set_css_class( tabs[i], "active_tab" );
1431 panes[i].style.display="block";
1433 Test.AnotherWay._set_css_class( tabs[i], "inactive_tab" );
1434 panes[i].style.display="none";
1438 Test.AnotherWay._tab_mouseover=function()
1440 if( Test.AnotherWay._get_css_class( this )=="inactive_tab" ) {
1441 Test.AnotherWay._set_css_class( this, "inactive_mouseover_tab" );
1444 Test.AnotherWay._tab_mouseout=function()
1446 if( Test.AnotherWay._get_css_class( this )=="inactive_mouseover_tab" ) {
1447 Test.AnotherWay._set_css_class( this, "inactive_tab" );
1451 // recording mouse input
1452 Test.AnotherWay._record_check_onfocus=function()
1455 var check_select=o.type!="text";
1456 var div=document.getElementById( "record_div" );
1457 var inputs=div.getElementsByTagName( "input" );
1458 for( var i=0; i<inputs.length; ++i ) {
1459 var input=inputs[i];
1460 if( input.type=="radio" ) {
1461 if( input.value=="select" ) {
1462 input.checked=check_select;
1463 }else if( input.value=="input" ) {
1464 input.checked=!check_select;
1470 Test.AnotherWay._g_no_record_msg=null; // not null - recording is unavailable
1471 Test.AnotherWay._g_record_timeout_cnt=0; // opening window for a page for recording
1472 Test.AnotherWay._g_record_url=null;
1473 Test.AnotherWay._g_record_wnd=null;
1474 Test.AnotherWay._g_record_random_id=null; // added to element ids of record_control div so that they do not clash with ids already in the page for which input is recorded
1475 Test.AnotherWay._g_record_keydown=null; // recording control - which key is down
1476 Test.AnotherWay._g_record_ctrl_keydown=false;
1477 Test.AnotherWay._g_record_shift_keydown=false;
1478 Test.AnotherWay._g_record_control_visible=true; // recording control ui state
1479 Test.AnotherWay._g_record_started;
1480 Test.AnotherWay._g_record_paused;
1481 Test.AnotherWay._g_record_include_mousemove=false;
1482 Test.AnotherWay._g_record_start_time; // for time references
1483 Test.AnotherWay._g_record_pause_start_time;
1484 Test.AnotherWay._g_record_update_time_interval; // showing time in the control ui
1485 Test.AnotherWay._g_record_waiting_for_results=false; // waiting for results window to open
1486 Test.AnotherWay._g_record_events; // recorded events
1487 Test.AnotherWay._g_record_under_cursor; // track element under cursor
1488 Test.AnotherWay._g_record_checkpoint_count; // for checkpoint numbering
1489 Test.AnotherWay._g_record_mouse_over_record_control; // for avoiding record control highlight on mouseover
1490 Test.AnotherWay._g_record_highlighted_element={ element: null, x: null, y: null };
1492 Test.AnotherWay._record_control_get_element=function( id )
1494 if( Test.AnotherWay._g_record_wnd!=null && Test.AnotherWay._g_record_wnd.document!=null ) {
1495 return Test.AnotherWay._g_record_wnd.document.getElementById( id+Test.AnotherWay._g_record_random_id );
1500 Test.AnotherWay._record_start_onclick=function() // "record" button on the run_tests.html: open a window for a page for which input is recorded
1502 if( Test.AnotherWay._g_no_record_msg!=null ) {
1503 alert( Test.AnotherWay._g_no_record_msg );
1506 if( Test.AnotherWay._g_record_timeout_cnt>0
1507 || (Test.AnotherWay._g_record_wnd!=null && (Test.AnotherWay._g_record_wnd.closed!=null && !Test.AnotherWay._g_record_wnd.closed)) ) { // in opera, closed is null.
1508 alert( "there is already window opened for recording input for a page "+Test.AnotherWay._g_record_url );
1511 var div=document.getElementById( "record_div" );
1512 var inputs=div.getElementsByTagName( "input" );
1514 for( var i=0; i<inputs.length; ++i ) {
1515 var input=inputs[i];
1516 if( input.type=="radio" ) {
1517 if( input.value=="select" && input.checked ) {
1518 var index=document.getElementById( "record_select" ).selectedIndex;
1520 url=Test.AnotherWay._g_test_page_urls[index-1].url;
1522 }else if( input.value=="input" && input.checked ) {
1523 url=document.getElementById( "record_input" ).value;
1528 Test.AnotherWay._g_record_url=url;
1529 Test.AnotherWay._g_record_wnd=window.open( url, "_blank" );
1530 if( Test.AnotherWay._g_record_wnd==null ) {
1531 alert( "unable to open new window for a page: "+url );
1533 Test.AnotherWay._g_record_timeout_cnt=50;
1534 setTimeout( Test.AnotherWay._record_window_timeout, 100 );
1538 Test.AnotherWay._record_window_timeout=function()
1540 if( Test.AnotherWay._is_url_loaded( Test.AnotherWay._g_record_url, Test.AnotherWay._g_record_wnd ) ) {
1541 Test.AnotherWay._record_window_setup( Test.AnotherWay._g_record_wnd );
1543 if( --Test.AnotherWay._g_record_timeout_cnt>0 ) {
1544 setTimeout( Test.AnotherWay._record_window_timeout, 100 );
1546 alert( "timeout expired while opening new window for a page: "+Test.AnotherWay._g_record_url );
1547 Test.AnotherWay._g_record_wnd=null;
1548 Test.AnotherWay._g_record_url=null;
1549 Test.AnotherWay._g_record_timeout_cnt=0;
1553 Test.AnotherWay._record_control_randomize_id=function( e, r )
1558 for( var c=e.firstChild; c!=null; c=c.nextSibling ) {
1559 Test.AnotherWay._record_control_randomize_id( c, r );
1562 Test.AnotherWay._record_window_setup=function( wnd ) // insert recording control into the page for which input is recorded
1564 Test.AnotherWay._g_record_timeout_cnt=0;
1565 var this_div=document.getElementById( "record_control" );
1566 var record_control=wnd.document.importNode( this_div, true );
1567 Test.AnotherWay._g_record_random_id=(1000*Math.random()).toFixed();
1568 Test.AnotherWay._record_control_randomize_id( record_control, Test.AnotherWay._g_record_random_id );
1569 Test.AnotherWay._g_record_control_visible=true;
1570 Test.AnotherWay._g_record_started=false;
1571 Test.AnotherWay._g_record_paused=false;
1572 Test.AnotherWay._g_record_checkpoint_count=0;
1573 Test.AnotherWay._g_record_mouse_over_record_control=false;
1574 var doc=wnd.document;
1575 doc.body.appendChild( record_control );
1576 // opera sans-serif font is different
1577 if( window.opera ) {
1578 cursor_over_indicator=Test.AnotherWay._record_control_get_element( "record_cursor_over" );
1579 cursor_over_indicator.style.width="18em";
1580 cursor_over_indicator.style.height="2em";
1581 cursor_over_indicator.style.fontSize="7pt";
1583 doc.addEventListener( "keydown", Test.AnotherWay._record_control_keydown, true );
1584 doc.addEventListener( "keyup", Test.AnotherWay._record_control_keyup, true );
1585 // doc.addEventListener( "keypress", Test.AnotherWay._record_event, true ); // replaying is not supported by any known browser
1587 doc.body.addEventListener( "mousemove", Test.AnotherWay._record_on_mousemove, true );
1588 doc.body.addEventListener( "click", Test.AnotherWay._record_event, true );
1589 doc.body.addEventListener( "mouseover", Test.AnotherWay._record_event, true );
1590 doc.body.addEventListener( "mouseout", Test.AnotherWay._record_event, true );
1591 doc.body.addEventListener( "mousedown", Test.AnotherWay._record_event, true );
1592 doc.body.addEventListener( "mouseup", Test.AnotherWay._record_event, true );
1594 Test.AnotherWay._record_control_key_disabled=function( k )
1597 return !Test.AnotherWay._g_record_started;
1598 }else if( k=="p" ) {
1599 return !Test.AnotherWay._g_record_started;
1600 }else if( k=="s" ) {
1601 return Test.AnotherWay._g_record_waiting_for_results;
1607 Test.AnotherWay._record_control_update_ui=function()
1609 var keydown_color="#fff";
1610 var disabled_color="#aaa";
1611 var button_color="#adf";
1612 var active_color="#fdf";
1615 display[false]="none";
1616 display[true]="inline";
1618 var s_button=Test.AnotherWay._record_control_get_element( "record_s" );
1619 var record_on=Test.AnotherWay._record_control_get_element( "record_on" );
1620 var record_off=Test.AnotherWay._record_control_get_element( "record_off" );
1622 s_button.style.backgroundColor= Test.AnotherWay._record_control_key_disabled( "s" ) ? disabled_color
1623 : Test.AnotherWay._g_record_keydown=="s" ? keydown_color : Test.AnotherWay._g_record_started ? active_color : button_color;
1624 record_on.style.display=display[!Test.AnotherWay._g_record_started];
1625 record_off.style.display=display[Test.AnotherWay._g_record_started];
1627 var h_button=Test.AnotherWay._record_control_get_element( "record_h" );
1628 h_button.style.backgroundColor= Test.AnotherWay._g_record_keydown=="h" ? keydown_color : button_color;
1630 var p_button=Test.AnotherWay._record_control_get_element( "record_p" );
1631 var record_pause_on=Test.AnotherWay._record_control_get_element( "record_pause_on" );
1632 var record_pause_off=Test.AnotherWay._record_control_get_element( "record_pause_off" );
1633 p_button.style.backgroundColor= Test.AnotherWay._record_control_key_disabled( "p" ) ? disabled_color
1634 : Test.AnotherWay._g_record_keydown=="p" ? keydown_color : Test.AnotherWay._g_record_paused ? active_color : button_color;
1635 record_pause_on.style.display=display[!Test.AnotherWay._g_record_paused];
1636 record_pause_off.style.display=display[Test.AnotherWay._g_record_paused];
1638 var m_button=Test.AnotherWay._record_control_get_element( "record_m" );
1639 var record_include_mousemove=Test.AnotherWay._record_control_get_element( "record_include_mousemove" );
1640 var record_omit_mousemove=Test.AnotherWay._record_control_get_element( "record_omit_mousemove" );
1641 m_button.style.backgroundColor= Test.AnotherWay._g_record_keydown=="m" ? keydown_color : Test.AnotherWay._g_record_include_mousemove ? active_color : button_color;
1642 record_include_mousemove.style.display=display[!Test.AnotherWay._g_record_include_mousemove];
1643 record_omit_mousemove.style.display=display[Test.AnotherWay._g_record_include_mousemove];
1645 var c_button=Test.AnotherWay._record_control_get_element( "record_c" );
1646 c_button.style.backgroundColor= Test.AnotherWay._record_control_key_disabled( "c" ) ? disabled_color
1647 : Test.AnotherWay._g_record_keydown=="c" ? keydown_color : button_color;
1649 var record_indicator=Test.AnotherWay._record_control_get_element( "record_indicator" );
1650 record_indicator.style.display=display[Test.AnotherWay._g_record_started];
1652 var pause_indicator=Test.AnotherWay._record_control_get_element( "record_pause_indicator" );
1653 pause_indicator.style.display=display[Test.AnotherWay._g_record_paused];
1655 var record_control=Test.AnotherWay._record_control_get_element( "record_control" );
1656 record_control.style.display= Test.AnotherWay._g_record_control_visible ? "block" : "none";
1658 var shift_button=Test.AnotherWay._record_control_get_element( "record_shift_key" );
1659 shift_button.style.backgroundColor= Test.AnotherWay._g_record_shift_keydown ? keydown_color : button_color;
1661 var ctrl_button=Test.AnotherWay._record_control_get_element( "record_ctrl_key" );
1662 ctrl_button.style.backgroundColor= Test.AnotherWay._g_record_ctrl_keydown ? keydown_color : button_color;
1664 Test.AnotherWay._record_format_time=function( t )
1667 var m=t.getMinutes();
1668 var s=t.getSeconds();
1669 var str= m==0 ? "" : m+"m ";
1673 Test.AnotherWay._record_control_update_time=function()
1675 var time_display=Test.AnotherWay._record_control_get_element( "record_time" );
1676 if( time_display!=null ) {
1677 time_display.innerHTML=Test.AnotherWay._record_format_time( (new Date()).getTime()-Test.AnotherWay._g_record_start_time );
1680 Test.AnotherWay._record_control_update_highlight=function( elem, style, event )
1683 Test.AnotherWay._record_highlight_border( null );
1685 var pos=Test.AnotherWay._get_page_coords( elem );
1686 if( style=="ball" || elem!=Test.AnotherWay._g_record_highlighted_element.element || pos.x!=Test.AnotherWay._g_record_highlighted_element.x || pos.y!=Test.AnotherWay._g_record_highlighted_element.y ) {
1687 Test.AnotherWay._g_record_highlighted_element={ element: elem, x: pos.x, y: pos.y };
1688 Test.AnotherWay._record_highlight_border( elem, style, event );
1692 Test.AnotherWay._record_decode_key=function( event )
1696 k=Test.AnotherWay._g_record_wnd.event.keyCode;
1720 }else if( k==123 ) {
1725 Test.AnotherWay._record_control_keydown=function( event )
1728 var k=Test.AnotherWay._record_decode_key( event );
1730 Test.AnotherWay._g_record_shift_keydown=true;
1731 }else if( k=="ctrl" ) {
1732 Test.AnotherWay._g_record_ctrl_keydown=true;
1733 }else if( k!="" && (Test.AnotherWay._g_record_keydown==null || Test.AnotherWay._g_record_keydown==k) ) {
1734 if( Test.AnotherWay._g_record_ctrl_keydown && Test.AnotherWay._g_record_shift_keydown && !Test.AnotherWay._record_control_key_disabled( k ) ) {
1735 Test.AnotherWay._g_record_keydown=k;
1739 Test.AnotherWay._g_record_keydown="";
1741 Test.AnotherWay._record_control_update_ui();
1743 // Test.AnotherWay._record_event( event ); // replaying is not supported in any known browser
1747 Test.AnotherWay._record_control_keyup=function( event )
1750 var k=Test.AnotherWay._record_decode_key( event );
1752 Test.AnotherWay._g_record_shift_keydown=false;
1753 }else if( k=="ctrl" ) {
1754 Test.AnotherWay._g_record_ctrl_keydown=false;
1755 }else if( k!="" && k==Test.AnotherWay._g_record_keydown && Test.AnotherWay._g_record_ctrl_keydown && Test.AnotherWay._g_record_shift_keydown ) {
1757 Test.AnotherWay._g_record_started=!Test.AnotherWay._g_record_started;
1758 if( Test.AnotherWay._g_record_started ) {
1759 Test.AnotherWay._g_record_events=[];
1760 Test.AnotherWay._g_record_start_time=(new Date()).getTime();
1761 Test.AnotherWay._record_control_update_time();
1762 Test.AnotherWay._g_record_update_time_interval=window.setInterval( Test.AnotherWay._record_control_update_time, 200 );
1764 Test.AnotherWay._record_control_update_highlight( null );
1765 if( !Test.AnotherWay._g_record_paused ) {
1766 window.clearInterval( Test.AnotherWay._g_record_update_time_interval );
1768 Test.AnotherWay._g_record_waiting_for_results=true;
1769 // open a new window for self, pass a parameter to dump recorded events as javascript code there
1770 // (the easiest way to obtain a document from the same origin, so it's writable, is to open this same page again)
1771 Test.AnotherWay._g_record_paused=false;
1772 var loc=window.location;
1773 loc=loc.protocol+"//"+loc.host+loc.pathname+"?recording_results="+Test.AnotherWay._g_record_random_id;
1774 if( window.open( loc, "_blank" )==null ) {
1775 alert( "unable to open new window for results" );
1779 }else if( k=="h" ) {
1780 Test.AnotherWay._g_record_control_visible=!Test.AnotherWay._g_record_control_visible;
1782 }else if( k=="p" ) {
1783 Test.AnotherWay._g_record_paused=!Test.AnotherWay._g_record_paused;
1784 if( Test.AnotherWay._g_record_paused ) {
1785 Test.AnotherWay._g_record_pause_start_time=(new Date()).getTime();
1786 if( Test.AnotherWay._g_record_started ) {
1787 window.clearInterval( Test.AnotherWay._g_record_update_time_interval );
1789 Test.AnotherWay._record_control_update_highlight( null );
1791 var pause_duration=(new Date()).getTime()-Test.AnotherWay._g_record_pause_start_time;
1792 Test.AnotherWay._g_record_start_time+=pause_duration;
1793 Test.AnotherWay._g_record_update_time_interval=window.setInterval( Test.AnotherWay._record_control_update_time, 200 );
1796 }else if( k=="m" ) {
1797 Test.AnotherWay._g_record_include_mousemove=!Test.AnotherWay._g_record_include_mousemove;
1799 }else if( k=="c" ) {
1800 var o=Test.AnotherWay._record_checkpoint();
1801 Test.AnotherWay._record_display_checkpoint( o );
1802 Test.AnotherWay._record_flash_border( "#24d" );
1806 Test.AnotherWay._g_record_keydown=null;
1807 Test.AnotherWay._record_control_update_ui();
1809 // Test.AnotherWay._record_event( event ); // replaying is not supported in any known browser
1813 Test.AnotherWay._record_html_node_path=function( node )
1820 if( node.id!=null && node.id!="" ) {
1821 path.unshift( "#"+node.id+" "+node.nodeName );
1824 var parent_node=node.parentNode;
1825 if( parent_node==null ) {
1826 return []; // no BODY up the path - this node is screwed (browsers differ in what's above the body), discard
1830 for( var child=parent_node.firstChild; child!=null; child=child.nextSibling ) {
1835 if( child.nodeType==1 ) { // count only HTML element nodes
1842 path.unshift( i+" "+node.nodeName );
1843 if( parent_node.nodeName=="BODY" || parent_node.nodeName=="body" ) {
1852 Test.AnotherWay._record_node_path_to_string=function( path )
1856 for( var i=0; i<path.length; ++i ) {
1857 s+= i==0 ? "" : ", ";
1858 var elem=path[i].split( " " );
1859 if( elem[0].charAt( 0 )=="#" ) {
1860 s+=elem[1]+" "+elem[0];
1862 s+=elem[1]+" ["+elem[0]+"]";
1868 Test.AnotherWay._record_node_path_to_node=function( path_str, doc )
1870 if( path_str==null ) {
1873 var path=path_str.split( "," );
1875 for( var i=0; i<path.length; ++i ) {
1876 var node_i=path[i].split( " " )[0];
1877 if( node_i.charAt( 0 )=="#" ) {
1878 node=doc.getElementById( node_i.substring( 1 ) );
1880 if( node_i<0 || node_i>=node.childNodes.length ) {
1883 node=node.firstChild;
1884 while( node!=null ) {
1885 if( node.nodeType==1 ) { // count only HTML element nodes
1891 node=node.nextSibling;
1901 Test.AnotherWay._record_control_contains_id=function( s )
1903 return s.match( /^#record_[\w_]+/ ) && s.match( Test.AnotherWay._g_record_random_id );
1905 Test.AnotherWay._record_checkpoint=function()
1907 var o={ type: "_checkpoint", time: (new Date()).getTime()-Test.AnotherWay._g_record_start_time, which: Test.AnotherWay._g_record_checkpoint_count++,
1908 target: Test.AnotherWay._record_html_node_path( Test.AnotherWay._g_record_under_cursor ) };
1909 Test.AnotherWay._g_record_events.push( o );
1912 Test.AnotherWay._record_event=function( event )
1914 var unneeded=["rangeOffset","eventPhase","timeStamp","isTrusted","popupWindowFeatures","rangeOffset"];
1915 if( Test.AnotherWay._g_record_started && !Test.AnotherWay._g_record_paused ) {
1917 for( var n in event ) {
1918 var needed=!n.match( /^[A-Z0-9_]+$/ );
1920 for( var ui=0; ui<unneeded.length; ++ui ) {
1921 if( unneeded[ui]==n ) {
1928 if( typeof( value )!="object" && typeof( value )!="function" ) {
1930 }else if( n=="target" || n=="relatedTarget" ) {
1931 o[n]=Test.AnotherWay._record_html_node_path( value );
1936 o["time"]=(new Date()).getTime()-Test.AnotherWay._g_record_start_time;
1937 var over_record_control= o["target"]!=null && o["target"][0]!=null && Test.AnotherWay._record_control_contains_id( o["target"][0] );
1938 if( !over_record_control ) {
1939 Test.AnotherWay._g_record_events.push( o );
1944 Test.AnotherWay._record_on_mousemove=function( event )
1946 var path=Test.AnotherWay._record_html_node_path( event.target );
1947 var new_mouse_over_record_control= path!=null && path[0]!=null && Test.AnotherWay._record_control_contains_id( path[0] );
1948 if( new_mouse_over_record_control!=Test.AnotherWay._g_record_mouse_over_record_control ) {
1949 Test.AnotherWay._g_record_mouse_over_record_control=new_mouse_over_record_control;
1950 Test.AnotherWay._record_control_update_ui();
1952 if( event.target!=null && event.target!=Test.AnotherWay._g_record_under_cursor ) {
1953 Test.AnotherWay._g_record_under_cursor=event.target;
1955 if( path==null || path[0]==null || !Test.AnotherWay._record_control_contains_id( path[0] ) ) {
1956 s=Test.AnotherWay._record_node_path_to_string( path );
1961 var cursor_over_indicator=Test.AnotherWay._record_control_get_element( "record_cursor_over" );
1962 cursor_over_indicator.innerHTML=s;
1965 var highlight_element=null;
1966 if( !Test.AnotherWay._g_record_mouse_over_record_control && Test.AnotherWay._g_record_started && !Test.AnotherWay._g_record_paused ) {
1967 highlight_element=event.target;
1969 // highlight border disabled on recording - it causes page to scroll, issuing spurious mouseover/mouseout event
1970 //Test.AnotherWay._record_control_update_highlight( highlight_element, "border" );
1972 if( Test.AnotherWay._g_record_include_mousemove ) {
1973 Test.AnotherWay._record_event( event );
1977 Test.AnotherWay._record_display_checkpoint=function( o )
1979 var checkpoints_div=Test.AnotherWay._record_control_get_element( "record_checkpoints" );
1980 var p=checkpoints_div.appendChild( checkpoints_div.ownerDocument.createElement( "div" ) );
1981 p.style.marginTop="3px";
1982 p.style.font="normal normal 8pt sans-serif";
1983 p.style.color="#000";
1984 p.style.textAligh="left";
1985 p.style.position="relative";
1986 p.style.width="100%";
1987 var checkpoint_text="";
1988 checkpoint_text+="#"+(o.which+1);
1989 checkpoint_text+=" "+Test.AnotherWay._record_format_time( o.time );
1990 if( o.target!=null ) {
1991 checkpoint_text+=Test.AnotherWay._record_node_path_to_string( o.target );
1993 p.appendChild( p.ownerDocument.createTextNode( checkpoint_text ) );
1995 Test.AnotherWay._record_save_results=function( doc )
1997 // strange, but DOM-style append does not work here in opera 8.
1998 var append=function( s ) { doc.write( "<div>"+s+"</div>" ); };
1999 append( "/* paste this data into your javascript and pass it as an argument to replay_events method */" );
2000 append( "{ checkpoints: [" );
2001 var first_checkpoint=true;
2002 for( var i=0; i<Test.AnotherWay._g_record_events.length; ++i ) {
2003 var o=Test.AnotherWay._g_record_events[i];
2004 if( o.type=="_checkpoint" ) {
2005 var str= first_checkpoint ? "" : "}, ";
2006 str+="function( tst, wnd ) { // #"+o.which+" time "+Test.AnotherWay._record_format_time( o.time )+" cursor was over "+Test.AnotherWay._record_node_path_to_string( o.target );
2008 first_checkpoint=false;
2011 if( !first_checkpoint ) {
2014 append( "], events: [ " );
2016 for( var i=0; i<Test.AnotherWay._g_record_events.length; ++i ) {
2017 var o=Test.AnotherWay._g_record_events[i];
2022 if( n=="time" ) { // convert to relative time
2023 var cur_time=o[n]-0;
2024 o[n]=cur_time-prev_time;
2027 s+=n_first ? n : ", "+n;
2036 s+= i==Test.AnotherWay._g_record_events.length-1 ? "}" : "},";
2043 Test.AnotherWay._g_record_border; // border highlighting element under cursor
2044 Test.AnotherWay._g_record_border_flashes=[]; // array of { color: color, timeout: milliseconds }
2045 Test.AnotherWay._g_record_border_flashing=false;
2046 Test.AnotherWay._g_record_border_normal_color="#d4b";
2047 Test.AnotherWay._record_flash_border_timeout=function()
2049 var color=Test.AnotherWay._g_record_border_normal_color;
2051 if( Test.AnotherWay._g_record_border_flashes.length!=0 ) {
2052 color=Test.AnotherWay._g_record_border_flashes[0].color;
2053 timeout=Test.AnotherWay._g_record_border_flashes[0].timeout;
2054 Test.AnotherWay._g_record_border_flashes.splice( 0, 1 );
2056 if( Test.AnotherWay._g_record_border!=null ) {
2057 for( var i=0; i<Test.AnotherWay._g_record_border.length; ++i ) {
2058 Test.AnotherWay._g_record_border[i].style.backgroundColor=color;
2061 if( timeout!=null ) {
2062 setTimeout( Test.AnotherWay._record_flash_border_timeout, timeout );
2064 Test.AnotherWay._g_record_border_flashing=false;
2067 Test.AnotherWay._get_page_coords=function( elm )
2069 var point = { x: 0, y: 0 };
2071 point.x+=elm.offsetLeft;
2072 point.y+=elm.offsetTop;
2073 elm=elm.offsetParent;
2077 Test.AnotherWay._set_page_coords=function( elm, x, y )
2079 var parent_coords={ x: 0, y: 0 };
2080 if( elm.offsetParent ) {
2081 parent_coords=Test.AnotherWay._get_page_coords( elm.offsetParent );
2083 var new_x=x-parent_coords.x;
2087 elm.style.left=new_x+'px';
2088 var new_y=y-parent_coords.y;
2092 elm.style.top=new_y+'px';
2094 Test.AnotherWay._record_setup_highlight_positions=function( element, style, coords, positions )
2096 if( style=="border" ) {
2097 var width=element.clientWidth;
2098 var height=element.clientHeight;
2102 positions.push( { x: coords.x-step-thickness, y: coords.y-step-thickness, width: width+2*step+2*thickness+fudge_expand, height: thickness } );
2103 positions.push( { x: coords.x+width+step+fudge_expand, y: coords.y-step-thickness, width: thickness, height: height+2*step+2*thickness+fudge_expand } );
2104 positions.push( { x:positions[0].x, y:positions[0].y, width:positions[0].width, height:positions[0].height } );
2105 positions.push( { x:positions[1].x, y:positions[1].y, width:positions[1].width, height:positions[1].height } );
2106 positions[2].y+=height+thickness+2*step+fudge_expand;
2107 positions[3].x-=width+thickness+2*step+fudge_expand;
2108 }else if( style=="ball" ) {
2109 positions.push( { x: coords.x+2, y: coords.y, width: 2, height: 6 } );
2110 positions.push( { x: coords.x, y: coords.y+2, width: 6, height: 2 } );
2111 positions.push( { x: coords.x+1, y: coords.y+1, width: 4, height: 4 } );
2114 Test.AnotherWay._record_highlight_border=function( element, style, event ) // null - hide border
2116 if( element!=null ) {
2117 if( Test.AnotherWay._g_record_border==null || Test.AnotherWay._g_record_border[0].ownerDocument!=element.ownerDocument ) {
2118 Test.AnotherWay._g_record_border=[];
2119 var n= style=="border" ? 4 : style=="ball" ? 3 : 0;
2120 for( var i=0; i<4; ++i ) {
2121 var b=element.ownerDocument.createElement( "div" );
2122 b.style.position="absolute";
2124 b.style.backgroundColor=Test.AnotherWay._g_record_border_normal_color;
2125 element.ownerDocument.body.appendChild( b );
2126 Test.AnotherWay._g_record_border.push( b );
2130 if( style=="border" ) {
2131 coords=Test.AnotherWay._get_page_coords( element );
2132 }else if( style=="ball" ) {
2134 if( event.pageX!=null && event.pageY!=null ) {
2135 coords={ x: event.pageX-0, y: event.pageY-0 };
2136 }else if( event.clientX!=null && event.clientY!=null ) {
2137 var doc=element.ownerDocument;
2139 coords={ x: (event.clientX-0)+doc.body.scrollLeft, y: (event.clientY-0)+doc.body.scrollTop };
2144 if( coords!=null && element.clientWidth!=null && element.clientHeight!=null ) {
2146 Test.AnotherWay._record_setup_highlight_positions( element, style, coords, positions );
2147 for( var i=0; i<positions.length; ++i ) {
2148 var b=Test.AnotherWay._g_record_border[i];
2150 Test.AnotherWay._set_page_coords( b, p.x, p.y );
2151 b.style.width=p.width+"px";
2152 b.style.height=p.height+"px";
2153 b.style.display="block";
2157 if( Test.AnotherWay._g_record_border!=null ) {
2158 for( var i=0; i<Test.AnotherWay._g_record_border.length; ++i ) {
2159 Test.AnotherWay._g_record_border[i].style.display="none";
2164 Test.AnotherWay._record_flash_border=function( color )
2166 if( Test.AnotherWay._g_record_border_flashing ) { //already
2167 Test.AnotherWay._g_record_border_flashes.push( { color: Test.AnotherWay._g_record_border_normal_color, timeout:300 } );
2168 Test.AnotherWay._g_record_border_flashes.push( { color: color, timeout:600 } );
2170 Test.AnotherWay._g_record_border_flashing=true;
2171 Test.AnotherWay._g_record_border_flashes.push( { color: color, timeout:600 } );
2172 Test.AnotherWay._record_flash_border_timeout();
2175 Test.AnotherWay._record_prepare_doc_for_results=function()
2178 document.write( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">" );
2179 document.write( "<html><head><title> Input recording results</title>" );
2180 document.write( "<style type=\"text/css\">" );
2181 document.write( "body { font: normal normal smaller sans-serif; }" );
2182 document.write( "div { margin-top: 3px; }" );
2183 document.write( "</style></head><body>" );
2184 // opera and mozilla disagree over who the opener is.
2185 if( typeof( window.opener.Test )!="undefined" && typeof( window.opener.Test.AnotherWay )!="undefined" ) {
2186 window.opener.Test.AnotherWay._record_save_results( document );
2187 window.opener.Test.AnotherWay._g_record_waiting_for_results=false;
2188 window.opener.Test.AnotherWay._record_control_update_ui();
2189 }else if( typeof( window.opener.opener.Test )!="undefined" && typeof( window.opener.opener.Test.AnotherWay )!="undefined" ) {
2190 window.opener.opener.Test.AnotherWay._record_save_results( document );
2191 window.opener.opener.Test.AnotherWay._g_record_waiting_for_results=false;
2192 window.opener.opener.Test.AnotherWay._record_control_update_ui();
2194 document.write( "</body>" );
2198 // global initialization
2201 if( window.opera ) {
2202 var good_opera=typeof( window.opera.version )=="function";
2203 good_opera=good_opera && window.opera.version().match( /^\s*(\d+)/ );
2204 good_opera=good_opera && RegExp.$1>=8;
2206 var span=document.createElement( "SPAN" );
2207 span.innerHTML="<!--[if IE]><br /><![endif]-"+"->";
2208 var is_ie=span.getElementsByTagName( "BR" ).length>0;
2210 Test.AnotherWay._g_test_iframe=window.frames.test_iframe;
2212 var query_str=window.location.search;
2213 if( query_str.charAt( 0 )=="?" ) {
2214 query_str=query_str.substring( 1 );
2216 var testlist_page="list-tests.html";
2218 if( query_str!="" ) {
2219 var params=[query_str];
2220 if( query_str.indexOf( ";" )!=-1 ) {
2221 params=query_str.split( ";" );
2222 }else if( query_str.indexOf( "&" )!=-1 ) {
2223 params=query_str.split( "&" );
2225 for( var param_i=0; param_i<params.length; ++param_i ) {
2226 var param=params[param_i].split( "=" );
2227 if( param[0]=="recording_results" ) {
2228 if( window.opener!=null ) {
2229 // we were told to show recording results - replace everything in the document with the results
2230 Test.AnotherWay._record_prepare_doc_for_results();
2233 }else if( param[0]=="testpage" ) {
2234 Test.AnotherWay._add_test_page_url( decodeURIComponent( param[1] ), "anotherway" );
2235 }else if( param[0]=="jsantestpage" ) {
2236 Test.AnotherWay._add_test_page_url( decodeURIComponent( param[1] ), "jsan" );
2237 }else if( param[0]=="testlist" ) {
2238 testlist_page=decodeURIComponent( param[1] );
2239 }else if( param[0]=="testframe" ) {
2240 if( window.opera && !good_opera ) {
2241 Test.AnotherWay._show_error( "testframe parameter does not work in versions of Opera prior to 8.0. Sorry (pathches are welcome)." );
2242 // Opera 7 barfs on attempt to access frame.frameElement.
2243 // if someone knows a way to assign onload handler to that iframe in Opera 7
2244 // without disrupting code that works in other browsers, patches are welcome.
2246 var frame_path=param[1].split( "." );
2248 for( var frame_path_i=0; frame_path_i<frame_path.length; ++frame_path_i ) {
2249 frame=frame[frame_path[frame_path_i]];
2252 Test.AnotherWay._show_error( "unable to find frame specified for loading test pages: "+param[1] );
2254 if( frame.frameElement!=null ) { // for the following assignement to onload to work, frameElement is required
2255 frame=frame.frameElement;
2257 Test.AnotherWay._g_test_iframe=frame;
2260 }else if( param[0]=="testframe_no_clear" ) {
2261 Test.AnotherWay._g_test_frame_no_clear=true;
2262 }else if( param[0]=="windows" ) {
2263 if (param[1] == "none") {
2265 }else if( param[0]=="run" ) {
2267 if( param[1]=="all" ) {
2268 Test.AnotherWay._g_pages_to_run="all";
2270 if( Test.AnotherWay._g_pages_to_run==null || Test.AnotherWay._g_pages_to_run=="all" ) {
2271 Test.AnotherWay._g_pages_to_run=[];
2273 var pages=param[1].split( "," );
2274 for( var i=0; i<pages.length; ++i ) {
2275 Test.AnotherWay._g_pages_to_run.push( pages[i] );
2281 if( Test.AnotherWay._g_test_page_urls.length==0 ) { // if no individual pages were given on the command line, load the list
2282 var result=Test.AnotherWay._set_iframe_location( window.frames["list_iframe"], testlist_page );
2283 if( result.msg!=null ) {
2284 Test.AnotherWay._show_error( result.msg );
2286 Test.AnotherWay._g_run_on_list_load=auto_run;
2288 Test.AnotherWay._g_run_on_main_load=auto_run;
2291 var f=Test.AnotherWay._g_test_iframe;
2293 if( f.attachEvent!=null ) {
2294 f.attachEvent( "onload", Test.AnotherWay._test_page_onload );
2296 f.onload=Test.AnotherWay._test_page_onload;
2298 if( Test.AnotherWay._g_test_iframe.nodeType!=null && Test.AnotherWay._g_test_iframe.contentWindow!=null ) { // it's iframe element, not the iframe. we need iframe.
2299 Test.AnotherWay._g_test_iframe=Test.AnotherWay._g_test_iframe.contentWindow;
2302 // ignore stupid opera error if the frame has onload handler assigned in the inline html
2305 "run_all": { "onclick": Test.AnotherWay._run_all_onclick },
2306 "run_selected": { "onclick": Test.AnotherWay._run_selected_onclick },
2307 "unselect_all": { "onclick": Test.AnotherWay._unselect_all_onclick },
2308 "record_select": { "onfocus": Test.AnotherWay._record_check_onfocus },
2309 "record_input": { "onfocus": Test.AnotherWay._record_check_onfocus },
2310 "record_start": { "onclick": Test.AnotherWay._record_start_onclick },
2311 "clear_btn": { "onclick": Test.AnotherWay._results_clear_onclick },
2312 "results_tab": { "onclick": Test.AnotherWay._tab_onclick, "onmouseover": Test.AnotherWay._tab_mouseover, "onmouseout": Test.AnotherWay._tab_mouseout },
2313 "debug_tab": { "onclick": Test.AnotherWay._tab_onclick, "onmouseover": Test.AnotherWay._tab_mouseover, "onmouseout": Test.AnotherWay._tab_mouseout }
2315 for( var hs in handlers ) {
2316 var o=document.getElementById( hs );
2318 for( var h in handlers[hs] ) {
2319 o[h]=handlers[hs][h];
2322 Test.AnotherWay._show_error( "unable to set "+h+" handler: id "+hs+" not found" );
2326 if( window.opera && !good_opera ) {
2327 Test.AnotherWay._g_no_record_msg="Input events recording and replaying is not available in opera versions prior to 8.0.";
2330 Test.AnotherWay._g_no_record_msg="Input events recording and replaying is not available in internet explorer.";
2332 if( Test.AnotherWay._g_no_record_msg!=null ) {
2333 var no_record_p=document.getElementById( "record_not_supported" );
2334 no_record_p.style.display="block";
2335 no_record_p.appendChild( document.createTextNode( Test.AnotherWay._g_no_record_msg ) );
2338 Test.AnotherWay._g_main_loaded=true;
2339 if( Test.AnotherWay._g_run_on_main_load ) {
2340 Test.AnotherWay._g_run_on_main_load=false;
2341 Test.AnotherWay._run_pages_to_run();
2344 Test.AnotherWay._test_object_t.prototype.open_window=null;
2347 <script type="text/javascript" src="xml_eq.js"></script>
2348 <script type="text/javascript" src="geom_eq.js"></script>
2352 <div id="col1_header">Test pages:</div>
2354 <table id="testtable">
2357 <div id="run_buttons">
2358 <input type="button" value=" clear " id="clear_btn" />
2359 <input type="button" value=" run all " id="run_all" />
2360 <input type="button" value=" run selected " id="run_selected" />
2361 <input type="button" value=" unselect all " id="unselect_all" />
2363 <input type="checkbox" id="dont_close_test_windows" /> do not close windows opened by tests
2364 <div id="error"></div>
2365 <div id="record_div">
2366 <p id="record_not_supported" style="display:none"></p>
2367 <p>Record mouse input for the page:</p>
2368 <p><input type="radio" name="record_choose" value="select" checked="checked" /> <select id="record_select"><option selected="selected">-- select a page: --</option></select></p>
2369 <p><input type="radio" name="record_choose" value="input" /> or enter page url: <input type="text" id="record_input" /></p>
2370 <p><input type="button" value=" record " id="record_start" /></p>
2375 <div id="right_header">
2376 <span id="results_count">Results: <span id="total"></span></span>
2377 <span id="results_tab" class="active_tab" style="visibility:hidden">Results</span>
2378 <span id="debug_tab" class="inactive_tab" style="visibility:hidden">Debug</span>
2380 <div id="right_frame">
2381 <div id="results"></div>
2382 <div id="debug"></div>
2386 <span style="display:none">
2387 <iframe name="list_iframe" onload="Test.AnotherWay._list_iframe_onload();"></iframe>
2388 <iframe name="test_iframe" onload="Test.AnotherWay._test_page_onload();"></iframe>
2390 <!-- record_control div is to be imported into other documents, so all its styles are inline -->
2391 -<div id="record_control" style="position:absolute;bottom:0;left:0;margin:0;padding:0.5em;width:22em;height:22em;border:1px solid;background:#ffd;font: normal normal 8pt sans-serif; color:#000; text-align: left">
2393 <p style="margin:0 0 0 0; padding:0">
2395 <span style="display:none;font-weight:bold;color:#408" id="record_indicator">
2396 recording. <span style="font-weight:normal">time: <span id="record_time"></span></span><span id="record_pause_indicator"> paused</span>
2400 <div id="record_cursor_over" style="margin:0;padding:2px;width:14em;height:1.1em;overflow:hidden;float:right;border:1px solid #777;background:#fff;font: normal normal 8pt sans-serif;position:relative;top:3px;color:#000;text-align:left;"> </div>
2401 <p style="margin:2px 0 0 0; padding:0">
2405 <p style="margin:8px 0 0 0; padding:0;">
2406 keyboard control: press
2407 <span id="record_ctrl_key" style="border:1px solid #226;background:#adf;padding:0 0.5em">ctrl</span> -
2408 <span id="record_shift_key" style="border:1px solid #226;background:#adf;padding:0 0.5em">shift</span> -
2411 <p style="margin:4px 0 0 0; padding:0">
2412 <span id="record_s" style="border:1px solid #226;background:#adf;width:1.2em;float:left;font-weight:bold;text-align:center;margin-right:0.5em">s</span>
2413 <span id="record_on">to <b>start</b> recording</span>
2414 <span id="record_off" style="display:none">to <b>stop</b> recording</span>
2417 <p style="margin:4px 0 0 0; padding:0">
2418 <span id="record_h" style="border:1px solid #226;background:#adf;width:1.2em;float:left;font-weight:bold;text-align:center;margin-right:0.5em">h</span>
2419 <span>to <b>hide/show</b> this window</span>
2422 <p style="margin:4px 0 0 0; padding:0">
2423 <span id="record_m" style="border:1px solid #226;background:#adf;width:1.2em;float:left;font-weight:bold;text-align:center;margin-right:0.5em">m</span>
2424 <span id="record_include_mousemove">to <b> record</b> mousemove</span>
2425 <span id="record_omit_mousemove" style="display:none">to <b>omit</b> mousemove</span>
2428 <p style="margin:4px 0 0 0; padding:0">
2429 <span id="record_p" style="border:1px solid #226;background:#aaa;width:1.2em;float:left;font-weight:bold;text-align:center;margin-right:0.5em">p</span>
2430 <span id="record_pause_on">to <b> pause</b> recording</span>
2431 <span id="record_pause_off" style="display:none">to <b>continue</b> recording</span>
2434 <p style="margin:4px 0 0 0; padding:0">
2435 <span id="record_c" style="border:1px solid #226;background:#aaa;width:1.2em;float:left;font-weight:bold;text-align:center;margin-right:0.5em">c</span>
2436 <span>to add checkpoint</span>
2439 <p style="margin:6px 0 0 0; padding:0">
2442 <div id="record_checkpoints" style="position:relative;width:100%;height:6em;overflow:auto;font: normal normal 8pt sans-serif; color:#000; text-align: left">