1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
2 <html><head><title> Run the testsuite</title>
3 <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>
5 Test.AnotherWay version 0.5
7 Copyright (c) 2005 Artem Khodush, http://straytree.org
9 Permission is hereby granted, free of charge, to any person obtaining
10 a copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sublicense, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
17 The above copyright notice and this permission notice shall be
18 included in all copies or substantial portions of the Software.
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 <style type="text/css">
29 * { padding: 0; margin: 0; }
31 body { height: 98%; font: normal normal 10pt sans-serif }
32 #col1 { float: left; width: 27em; margin: 0 0 0 1em; overflow: visible; }
33 #col2 { position: relative; height: 98%; margin: 0 0.5em 0 28em; }
34 #col1_header { margin-top: 0.5em; }
35 #scroller { height: 400px; overflow: auto;}
36 #testtable { margin: 0 0 2em 0; width: 97%; }
37 #run_buttons { margin-bottom: 4em; }
39 #right_header { padding-top: 0.8em; }
40 #results_count { float: left; }
41 .active_tab { float: right; padding: 0 1em 0.2em 1em; background: #0af; border: 1px solid #048; border-bottom: none; cursor: pointer; cursor: hand;
42 position: relative; top: -0.2em; }
43 .inactive_tab { float: right; padding: 0 1em 0 1em; background: #9bb; color: #444; border: 1px solid #9bb; border-bottom: none; cursor: pointer; cursor: hand; }
44 .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; }
46 #right_frame { overflow: auto; position: relative; top: -0.2em; clear: right; height: 95%; border: 1px solid #048; }
48 #debug { display: none; }
49 #debug p { margin: 2px 0 0 5em; text-indent: -4.8em; }
51 #error { display: none; color: #c22; }
53 #results p { margin: 0 0 2px 0; }
54 /* cursor indicating that detailed results may be expanded/contracted */
55 #results p.badtest { cursor: text; }
56 #results p.ok, #results p.fail { cursor: pointer; cursor: hand; }
58 /* colored squares in the results window at the left of test page names */
59 #results p.ok .bullet { background: #6d6; }
60 #results p.fail .bullet { background: #d46; }
61 #results p.badtest .bullet { background: #ea3; }
62 #results p.loading .bullet { background: #48f; }
63 #results p.running .bullet { background: #26e; }
64 #results p.waiting .bullet { background: #04d; }
65 /* highlight in the results line */
66 #results p .warning { background: #ffc; }
68 /* layout of the detailed results */
69 .result_detail { padding-left: 3em; }
70 .result_exception_detail { padding-left: 4em; }
71 .result_exception_stack_detail { padding-left: 5em; }
72 .result_micro_detail { padding-left: 6em; }
73 /* colouring in the detailed results */
74 .result_detail .fail, .result_exception_detail .fail, .result_micro_detail .fail { background: #ffd8d8; }
76 /* "start recording" controls*/
77 #record_div { margin-top: 3em; }
78 #record_div p { margin-bottom: 0.5em; }
79 #record_select { width: 88%; }
80 #record_input { width: 53%; }
82 <script type="text/javascript">
84 if( typeof( Test )=="undefined" ) {
89 Test.AnotherWay._g_test_iframe=null; // frame where to load test pages
90 Test.AnotherWay._g_test_frame_no_clear=false; // true - leave last page displayed after tests end
91 Test.AnotherWay._g_test_page_urls=[]; // array of: { url: url, convention: "anotherway" or "jsan" }
92 Test.AnotherWay._g_test_object_for_jsan=null; // test object for filling by tests that adhere to jsan Test.Simple calling convention
93 Test.AnotherWay._g_pages_to_run=null; // list of pages to run automatically after loading
94 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.
95 Test.AnotherWay._g_run_on_list_load=false;
96 Test.AnotherWay._g_main_loaded=false;
98 Test.AnotherWay._run_pages_to_run=function( called_from_outside )
100 if( !Test.AnotherWay._g_main_loaded ) {
101 Test.AnotherWay._g_run_on_main_load=true;
103 var a_pages=Test.AnotherWay._g_pages_to_run;
104 if( a_pages=="all" ) {
105 for( var i=0; i<Test.AnotherWay._g_test_page_urls.length; ++i ) {
106 Test.AnotherWay._run_test_page( "test"+i );
108 }else if( a_pages!=null ) {
109 for( var run_i=0; run_i<a_pages.length; ++run_i ) {
110 var run_page=a_pages[run_i];
112 for( var all_i=0; all_i<Test.AnotherWay._g_test_page_urls.length; ++all_i ) {
113 if( run_page==Test.AnotherWay._g_test_page_urls[all_i].url ) {
114 Test.AnotherWay._run_test_page( "test"+all_i, called_from_outside );
120 Test.AnotherWay._show_error( "page specified to run is not found in the page list: "+run_page );
128 Test.AnotherWay._add_test_page_url=function( test_url, convention )
130 var table=document.getElementById( "testtable" );
131 var record_select=document.getElementById( "record_select" );
132 var index=Test.AnotherWay._g_test_page_urls.length;
135 if( test_url.match( "^(\\s*)(.*\\S)(\\s*)$" ) ) {
139 Test.AnotherWay._g_test_page_urls[index]={ url: test_url, convention: convention };
140 var row=table.insertRow( -1 );
144 cell=row.insertCell( -1 );
145 cell_child=document.createElement( "input" );
146 cell_child.type="checkbox";
147 cell_child.id="checkbox"+index;
148 cell_child.checked='checked';
149 cell_child.defaultChecked='checked';
150 cell.appendChild( cell_child );
152 cell=row.insertCell( -1 );
153 cell.setAttribute( "width", "75%" );
154 cell.appendChild( document.createTextNode( test_url ) );
156 cell=row.insertCell( -1 );
157 cell_child=document.createElement( "input" );
158 cell_child.type="button";
159 cell_child.id="test"+index;
160 cell_child.value=" run ";
161 cell_child.onclick=Test.AnotherWay._run_one_onclick;
162 cell.appendChild( cell_child );
164 cell=row.insertCell( -1 );
165 cell.setAttribute( "width", "8em" );
166 cell_child=document.createElement( "span" );
167 cell.appendChild( cell_child );
169 var option=document.createElement( "option" );
170 option.appendChild( document.createTextNode( test_url ) );
171 record_select.appendChild( option );
173 Test.AnotherWay._show_error=function( msg )
175 var error_div=document.getElementById( "error" );
176 error_div.innerHTML="";
177 error_div.appendChild( document.createTextNode( msg ) );
178 error_div.style.display="block";
181 // read urls from the list in the html file inside the list_iframe
182 // fill on-screen list with urls and "run" buttons, and fill the g_test_page_urls object.
183 Test.AnotherWay._list_iframe_onload=function()
185 if( window.frames.list_iframe!=null && window.frames.list_iframe.location!="" && window.frames.list_iframe.location!="about:blank" ) {
186 var list_doc=window.frames.list_iframe.document;
187 var list=list_doc.getElementById( "testlist" );
189 for( var i=0; i<list.childNodes.length; ++i ) {
190 var item=list.childNodes[i];
191 if( item.nodeName=="LI" || item.nodeName=="li" ) {
192 var convention="anotherway";
193 if( Test.AnotherWay._get_css_class( item )=="jsan" ) {
196 Test.AnotherWay._add_test_page_url( item.innerHTML, convention );
199 if( Test.AnotherWay._g_run_on_list_load ) {
200 Test.AnotherWay._g_run_on_list_load=false;
201 Test.AnotherWay._run_pages_to_run();
204 Test.AnotherWay._show_error( "no list with id 'testlist' in a list file "+window.frames.list_iframe.location );
209 Test.AnotherWay._map_checkboxes=function( f )
211 var table=document.getElementById( "testtable" );
212 var checks=table.getElementsByTagName( "INPUT" );
213 for( var i=0; i<checks.length; ++i ) {
214 if( checks[i].type=="checkbox" && checks[i].id.match( /^checkbox(\d+)$/ ) ) {
215 f( checks[i], RegExp.$1 );
219 Test.AnotherWay._run_all_onclick=function()
221 Test.AnotherWay._map_checkboxes( function( c, id ) { Test.AnotherWay._run_test_page( "test"+id ); } );
223 Test.AnotherWay._run_selected_onclick=function()
225 Test.AnotherWay._map_checkboxes( function( c, id ) { if( c.checked ) Test.AnotherWay._run_test_page( "test"+id ); } );
227 Test.AnotherWay._unselect_all_onclick=function()
229 Test.AnotherWay._map_checkboxes( function( c, id ) { c.checked=false; } );
231 Test.AnotherWay._run_one_onclick=function()
233 Test.AnotherWay._run_test_page( this.id );
236 // construct an object that will gather results of running one test function
237 Test.AnotherWay._test_object_t=function( fun_name )
239 this.name=fun_name; // name of the test function
240 this.n_plan=null; // planned number of assertions
241 this.n_ok=0; // # of ok assertions
242 this.n_fail=0; // # of failed assertions
243 this.exception=""; // if the function throwed an exception, it's its message
244 this.exception_stack=[]; // strings: function call stack from the exception
245 this.assertions=[]; // assertion results: array of { ok: 1 or 0, name: string }
246 this.wait_result_milliseconds=0; // how long to wait before collecting results from the test
247 this.second_wait_msg=null; // <p> status message (in addition to the page wait_msg)
248 this.delay_actions=[]; // array of actions to be perfomed after the test function returns
249 // action : { acton_kind: "call" | "window" | "replay"
250 // when "call": { call_fn call_delay_milliseconds } call_fn takes nothing
251 // when "window" : { wnd_url wnd_wnd wnd_fn wnd_timeout_milliseconds wnd_dont_close } wnd_fn takes wnd
252 // wnen "replay" : { replay_wnd replay_events replay_event_i replay_checkpoints } checkpoint_fn takes this, wnd
254 this.delay_action_i=null; // index of delay action currently being performed
255 this.delay_prev_timer_time=0; // for counting time while performing delay_actions
256 this.delay_current_milliseconds_left=0; // time left before the next action, runs down
257 this.delay_total_milliseconds_left=0; // for indication: total estimated time for all actions, runs up and down
260 Test.AnotherWay._test_object_t.prototype.ok=function( cond, name )
269 this.assertions.push( { ok: cond, name: name } );
271 Test.AnotherWay._test_object_t.prototype.fail=function( name )
273 this.ok( false, name );
275 Test.AnotherWay._test_object_t.prototype.plan=function( n )
279 Test.AnotherWay._test_object_t.prototype.wait_result=function( seconds )
281 this.wait_result_milliseconds=1000*seconds;
283 Test.AnotherWay._eq_fail_msg=function( path, what, expected, got )
285 return "eq: "+path+" "+what+" differ: got "+got+", but expected "+expected;
287 Test.AnotherWay._array_eq=function( expected, got, path, msg )
289 if( expected.length!=got.length ) {
290 msg.msg=Test.AnotherWay._eq_fail_msg( path, "array length", expected.length, got.length );
293 for( var i=0; i<expected.length; ++i ) {
294 if( !Test.AnotherWay._thing_eq( expected[i], got[i], path+"["+i+"]", msg ) ) {
300 Test.AnotherWay._object_eq=function( expected, got, path, msg )
303 for( v in expected ) {
305 msg.msg=Test.AnotherWay._eq_fail_msg( path+"."+v, "properties", expected[v], "undefined" );
308 if( !Test.AnotherWay._thing_eq( expected[v], got[v], path+"."+v, msg ) ) {
313 if( ! (v in expected) ) {
314 msg.msg=Test.AnotherWay._eq_fail_msg( path+"."+v, "properties", "undefined", got[v] );
320 Test.AnotherWay._constructor_name=function( x )
327 s=typeof( x.constructor );
329 s=x.constructor.toString();
335 // hackish attempt to guess a type
344 return is_array ? "Array" : "Object"; // for empty arrays/objects, this will be wrong half the time
345 }else if( s.match( /^\s*function\s+(\w+)\s*\(/ ) ) {
362 Test.AnotherWay._is_array=function( x )
364 return Test.AnotherWay._constructor_name( x )=="Array";
366 Test.AnotherWay._is_value_type=function( x )
368 cn=Test.AnotherWay._constructor_name( x );
369 return cn=="Number" || cn=="String" || cn=="Boolean" || cn=="Date";
371 Test.AnotherWay._thing_eq=function( expected, got, path, msg )
373 if( expected==null && got==null ) {
375 }else if( (expected==null && got!=null) || (expected!=null && got==null) ) {
376 msg.msg=Test.AnotherWay._eq_fail_msg( path, "values", expected, got );
379 var expected_cn=Test.AnotherWay._constructor_name( expected );
380 var got_cn=Test.AnotherWay._constructor_name( got );
381 if( expected_cn!=got_cn ) {
382 msg.msg=Test.AnotherWay._eq_fail_msg( path, "types", expected_cn, got_cn );
385 if( Test.AnotherWay._is_array( expected ) ) {
386 return Test.AnotherWay._array_eq( expected, got, path, msg );
387 }else if( Test.AnotherWay._is_value_type( expected ) ) {
388 if( expected!=got ) {
389 msg.msg=Test.AnotherWay._eq_fail_msg( path, "values", expected, got );
394 }else { // just a plain object
395 return Test.AnotherWay._object_eq( expected, got, path, msg );
400 Test.AnotherWay._test_object_t.prototype.eq=function( got, expected, name )
403 if( Test.AnotherWay._thing_eq( expected, got, "", msg ) ) {
406 this.fail( name+". "+msg.msg );
409 Test.AnotherWay._test_object_t.prototype.like=function( got, expected, name )
411 if( got.match( expected )!=null ) {
414 this.fail( name+": got "+got+", but expected it to match: "+expected );
417 Test.AnotherWay._g_html_eq_span=null;
418 Test.AnotherWay._html_eq_string_to_node=function( string_or_node, what, msg )
420 if( string_or_node.nodeType!=null ) {
421 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
423 if( Test.AnotherWay._g_html_eq_span==null ) {
424 Test.AnotherWay._g_html_eq_span=document.createElement( "span" );
426 Test.AnotherWay._g_html_eq_span.innerHTML=string_or_node;
427 if( Test.AnotherWay._g_html_eq_span.childNodes.length!=1 ) {
428 msg.msg="bad "+what+" html string given (should contain exactly one outermost element): "+string_or_node;
430 return Test.AnotherWay._g_html_eq_span.childNodes[0].cloneNode( true );
432 Test.AnotherWay._html_eq_node_to_string=function( node ) {
433 if( Test.AnotherWay._g_html_eq_span==null ) {
434 Test.AnotherWay._g_html_eq_span=document.createElement( "span" );
436 Test.AnotherWay._g_html_eq_span.innerHTML="";
437 if( node.outerHTML!=null ) {
438 Test.AnotherWay._g_html_eq_span.innerHTML=node.outerHTML;
440 var clone = node.cloneNode(true);
441 var node = Test.AnotherWay._g_html_eq_span;
442 if(node.ownerDocument && node.ownerDocument.importNode) {
443 if(node.ownerDocument != clone.ownerDocument) {
444 clone = node.ownerDocument.importNode(clone, true);
447 node.appendChild(clone);
449 return Test.AnotherWay._g_html_eq_span.innerHTML;
451 Test.AnotherWay._html_eq_path_msg=function( path )
454 for( var i=0; i<path.length; ++i ) {
455 msg+=" [node "+path[i].node;
456 if( path[i].id!=null && path[i].id!="" ) {
457 msg+=" id "+path[i].id;
458 }else if( path[i].index!=null ) {
459 msg+=" at index "+path[i].index;
465 Test.AnotherWay._html_eq_fail_msg=function( path, what, expected, got )
467 return Test.AnotherWay._html_eq_path_msg( path )+": "+what+" differ: got "+got+", but expected "+expected;
469 Test.AnotherWay._html_eq_remove_blank=function( text )
473 }else if( text.match( "^(\\s*)(.*\\S)(\\s*)$" ) ) {
475 }else if( text.match( "\s*" ) ) {
480 Test.AnotherWay._html_eq_remove_blank_nodes=function( node )
483 for( var child=node.firstChild; child!=null; child=child.nextSibling ) {
484 if( child.nodeType==3 ) {
485 var value=Test.AnotherWay._html_eq_remove_blank( child.nodeValue );
487 to_remove.push( child );
489 child.nodeValue=value;
493 for( var i=0; i<to_remove.length; ++i ) {
494 node.removeChild( to_remove[i] );
497 Test.AnotherWay._html_node_type_text=function( node_type )
500 return "1 (html element)";
501 }else if( node_type==3 ) {
507 Test.AnotherWay._html_eq_node=function( expected, got, path, msg, expected_loc_base, got_loc_base )
509 if( expected.nodeType!=got.nodeType ) {
510 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 ) );
512 }else if( expected.nodeType==3 ) {
513 if( expected.nodeValue!=got.nodeValue ) {
514 msg.msg=Test.AnotherWay._html_eq_fail_msg( path, "text", expected.nodeValue, got.nodeValue );
517 }else if( expected.nodeType==1 ) {
518 if( expected.nodeName!=got.nodeName ) {
519 msg.msg=Test.AnotherWay._html_eq_fail_msg( path, "node names", expected.nodeName, got.nodeName );
522 // compare attributes
523 var expected_attrs={};
527 for( i=0; i<expected.attributes.length; ++i ) {
528 a=expected.attributes[i];
530 expected_attrs[a.name]=1;
533 for( i=0; i<got.attributes.length; ++i ) {
539 for( a in expected_attrs ) {
540 if( ! (a in got_attrs) ) {
541 msg.msg=Test.AnotherWay._html_eq_path_msg( path )+": attribute sets differ: expected attribute "+a+" is missing";
545 for( a in got_attrs ) {
546 if( ! (a in expected_attrs) ) {
547 msg.msg=Test.AnotherWay._html_eq_path_msg( path )+": attribute sets differ: got extra attribute "+a;
551 for( a in expected_attrs ) {
552 var expected_value=expected.getAttribute( a );
553 var got_value=got.getAttribute( a );
554 if( typeof( expected_value )=="string" && typeof( got_value )=="string" ) {
555 expected_value=Test.AnotherWay._html_eq_remove_blank( expected_value );
556 got_value=Test.AnotherWay._html_eq_remove_blank( got_value );
557 var ok=expected_value==got_value;
558 if( !ok && (a=="href" || a=="HREF" ) ) { // try relative hrefs
559 var expected_relative_value=expected_value;
560 if( expected_loc_base!=null && expected_value.substring( 0, expected_loc_base.length )==expected_loc_base ) {
561 expected_relative_value=expected_value.substring( expected_loc_base.length );
563 var got_relative_value=got_value;
564 if( got_loc_base!=null && got_value.substring( 0, got_loc_base.length )==got_loc_base ) {
565 got_relative_value=got_value.substring( got_loc_base.length );
567 ok=expected_relative_value==got_relative_value;
570 msg.msg=Test.AnotherWay._html_eq_fail_msg( path, "attribute "+a+" values", expected_value, got_value );
573 }else if( typeof( expected_value )=="function" && typeof( got_value )=="function" ) {
574 expected_value=expected_value.toString();
575 got_value=got_value.toString();
576 if( expected_value!=got_value ) {
577 msg.msg=Test.AnotherWay._html_eq_fail_msg( path, "attribute "+a+" values", expected_value, got_value );
582 if( !Test.AnotherWay._thing_eq( expected_value, got_value, "", value_msg ) ) {
583 msg.msg=Test.AnotherWay._html_eq_path_msg( path )+": attribute "+a+" values differ: "+value_msg.msg;
588 // compare child nodes
589 Test.AnotherWay._html_eq_remove_blank_nodes( expected );
590 Test.AnotherWay._html_eq_remove_blank_nodes( got );
591 var expected_length=expected.childNodes.length;
592 var got_length=got.childNodes.length;
593 if( expected_length<got_length ) {
594 msg.msg=Test.AnotherWay._html_eq_path_msg( path )+": got "+(got_length-expected_length)+" extra child nodes";
596 }else if( expected_length>got_length ) {
597 msg.msg=Test.AnotherWay._html_eq_path_msg( path )+": expected "+(expected_length-got_length)+" more child nodes";
600 for( i=0; i<expected_length; ++i ) {
601 var expected_node=expected.childNodes[i];
602 path.push( { node: expected_node.nodeName, id: expected_node.id, index: i } );
603 var eq=Test.AnotherWay._html_eq_node( expected_node, got.childNodes[i], path, msg, expected_loc_base, got_loc_base );
613 Test.AnotherWay._html_eq_get_loc_base=function( node )
615 var loc_base=document.location;
616 if( node.ownerDocument!=null ) {
617 loc_base=node.ownerDocument.location;
619 if( loc_base!=null ) {
620 loc_base=loc_base.href;
621 var slash_pos=loc_base.lastIndexOf( "/" );
622 if( slash_pos!=-1 ) {
623 loc_base=loc_base.substring( 0, slash_pos+1 );
628 Test.AnotherWay._test_object_t.prototype.html_eq=function( got, expected, name )
631 var expected_node=Test.AnotherWay._html_eq_string_to_node( expected, "expected", msg );
632 if( msg.msg!=null ) {
633 this.fail( name+" html_eq: "+msg.msg );
635 var got_node=Test.AnotherWay._html_eq_string_to_node( got, "got", msg );
636 if( msg.msg!=null ) {
637 this.fail( name+" html_eq: "+msg.msg );
639 var expected_loc_base=Test.AnotherWay._html_eq_get_loc_base( expected );
640 var got_loc_base=Test.AnotherWay._html_eq_get_loc_base( got );
641 if( Test.AnotherWay._html_eq_node( expected_node, got_node, [], msg, expected_loc_base, got_loc_base ) ) {
644 var msg=name+" html_eq "+msg.msg;
645 var expected_str=Test.AnotherWay._html_eq_node_to_string( expected_node );
646 var got_str=Test.AnotherWay._html_eq_node_to_string( got_node );
647 msg+=".\n got html: "+got_str;
648 msg+=".\n expected html: "+expected_str;
654 Test.AnotherWay._debug_pane_print=function( msg )
657 var p=document.createElement( "p" );
658 p.appendChild( document.createTextNode( d.toLocaleTimeString()+" "+msg ) );
659 var debug_pane=document.getElementById( "debug" );
660 debug_pane.appendChild( p );
661 var debug_tab=document.getElementById( "debug_tab" );
662 var results_tab=document.getElementById( "results_tab" );
663 debug_tab.style.visibility="visible";
664 results_tab.style.visibility="visible";
666 Test.AnotherWay._test_object_t.prototype.debug_print=function( msg )
668 Test.AnotherWay._debug_pane_print( this.name+": "+msg );
670 Test.AnotherWay._test_object_t.prototype.delay_call=function()
673 for( var i=0; i<arguments.length; ++i ) {
674 if( typeof( arguments[i] )!="function" ) {
675 timeout_ms=1000*arguments[i];
677 var action={ action_kind: "call", call_delay_milliseconds: timeout_ms, call_fn: arguments[i] };
678 this.delay_total_milliseconds_left+=Test.AnotherWay._action_estimate_milliseconds( action );
679 this.delay_actions.push( action );
683 Test.AnotherWay._test_object_t.prototype.open_window=function( url, fn, timeout_seconds )
685 if( timeout_seconds==null ) {
688 var no_close=document.getElementById( "dont_close_test_windows" );
689 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 };
690 this.delay_total_milliseconds_left+=Test.AnotherWay._action_estimate_milliseconds( action );
691 this.delay_actions.push( action );
693 Test.AnotherWay._test_object_t.prototype.replay_events=function( wnd, events )
695 if( Test.AnotherWay._g_no_record_msg!=null ) {
696 this.fail( "replay_events: "+Test.AnotherWay._g_no_record_msg );
698 var action={ action_kind: "replay", replay_wnd: wnd, replay_events: events.events, replay_event_i: null, replay_checkpoints: events.checkpoints };
699 this.delay_total_milliseconds_left+=Test.AnotherWay._action_estimate_milliseconds( action );
700 this.delay_actions.push( action );
703 Test.AnotherWay._action_estimate_milliseconds=function( action )
706 if( action.action_kind=="call" ) {
707 ms=action.call_delay_milliseconds;
708 }else if( action.action_kind=="window" ) {
710 }else if( action.action_kind=="replay" ) {
712 for( var i=0; i<action.replay_events.length; ++i ) {
713 ms+=action.replay_events[i]["time"]-0;
719 Test.AnotherWay._g_timeout_granularity=200;
720 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 }
722 // load one html page, schedule further processing
723 Test.AnotherWay._run_test_page=function( id, called_from_outside )
725 if( id.match( /^test(\d+)/ ) ) {
727 Test.AnotherWay._g_tests_queue.push( {
728 url: Test.AnotherWay._g_test_page_urls[id].url,
729 convention: Test.AnotherWay._g_test_page_urls[id].convention,
732 if( Test.AnotherWay._g_tests_queue.length==1 ) {
733 if( !called_from_outside ) {
734 // Crap. Be careful stepping around.
735 // For Mozilla and Opera, when this file is included into the frameset page that is in another directory (and _g_outside_path_correction!=null)
736 // but the test pages are started from within it (by "run" buttons), then:
737 // depending on whether the page is the first one loaded into the test frame or not,
738 // the base url for relative test pages differs.
739 // Crap, like I said.
740 Test.AnotherWay._g_tests_queue[0].suppress_outside_path_correction=true;
742 Test.AnotherWay._start_loading_page();
746 Test.AnotherWay._load_next_page=function()
748 Test.AnotherWay._g_tests_queue.splice( 0, 1 );
749 if( Test.AnotherWay._g_tests_queue.length>0 ) {
750 Test.AnotherWay._start_loading_page();
752 if( !Test.AnotherWay._g_test_frame_no_clear ) {
753 Test.AnotherWay._g_test_iframe.location.replace( "about:blank" );
757 Test.AnotherWay._g_opera_path_correction=null; // ugly wart to support opera
758 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
759 Test.AnotherWay._set_iframe_location=function( iframe, loc, outside_path_correction )
761 // allow to load only locations with the same origin
762 var proto_end=loc.indexOf( "://" );
763 if( proto_end!=-1 ) { // otherwise, it's safe to assume (for Opera, Mozilla and IE ) that loc will be treated as relative
764 var main_loc=window.location.href;
765 var host_end=loc.substring( proto_end+3 ).indexOf( "/" );
768 var loc_origin=loc.substring( 0, proto_end+3+host_end+1 );
769 if( main_loc.length>=loc_origin.length && main_loc.substring( 0, loc_origin.length )==loc_origin ) {
774 return { msg: "test pages may have only urls with the same origin as "+main_loc };
777 // opera cannot handle urls relative to file:// without assistance
778 if( window.opera!=null && window.location.protocol=="file:" && loc.indexOf( ":" )==-1 ) {
779 var base=window.location.href;
780 var q_pos=base.indexOf( "?" );
782 base=base.substring( 0, q_pos );
784 var slash_pos=base.lastIndexOf( "/" );
785 if( slash_pos!=-1 ) {
786 base=base.substring( 0, slash_pos+1 );
787 Test.AnotherWay._g_opera_path_correction=base;
791 // if this function is called from another page, and if that page is in another directory, correction is needed
792 if( outside_path_correction!=null ) {
793 var pos=loc.indexOf( outside_path_correction );
795 loc=loc.substring( outside_path_correction.length+1 );
798 if( iframe.location!=null ) {
799 iframe.location.replace( loc );
805 Test.AnotherWay._start_loading_page=function()
807 var test_page=Test.AnotherWay._g_tests_queue[0];
808 test_page.loading_timeout_milliseconds=12000;
809 test_page.timeout_id=setTimeout( Test.AnotherWay._loading_timeout, Test.AnotherWay._g_timeout_granularity );
810 test_page.wait_msg=Test.AnotherWay._print_counter_result( test_page.url, "loading...", test_page.loading_timeout_milliseconds, "loading" );
811 if( test_page.convention=="jsan" ) {
812 // the tests in that page will run when it's loading, so the test object must be ready
813 Test.AnotherWay._g_test_object_for_jsan=new Test.AnotherWay._test_object_t( test_page.url );
815 var outside_path_correction=null;
816 if( Test.AnotherWay._g_outside_path_correction!=null && !test_page.suppress_outside_path_correction ) {
817 outside_path_correction=Test.AnotherWay._g_outside_path_correction;
819 var result=Test.AnotherWay._set_iframe_location( Test.AnotherWay._g_test_iframe, test_page.url, outside_path_correction );
820 if( result.msg!=null ) {
821 Test.AnotherWay._unprint_result( test_page.wait_msg );
822 Test.AnotherWay._print_result( test_page.url, result.msg, "badtest", null );
823 Test.AnotherWay._load_next_page();
827 Test.AnotherWay._loading_timeout=function()
829 var test_page=Test.AnotherWay._g_tests_queue[0];
830 test_page.loading_timeout_milliseconds-=Test.AnotherWay._g_timeout_granularity;
831 if( test_page.loading_timeout_milliseconds>0 ) {
832 Test.AnotherWay._update_msg_counter( test_page.wait_msg, (test_page.loading_timeout_milliseconds/1000).toFixed() );
833 test_page.timeout_id=setTimeout( Test.AnotherWay._loading_timeout, Test.AnotherWay._g_timeout_granularity );
835 Test.AnotherWay._unprint_result( test_page.wait_msg );
836 Test.AnotherWay._print_result( test_page.url, "Unable to load test page. Timeout expired", "badtest", null );
837 Test.AnotherWay._load_next_page();
841 Test.AnotherWay._strip_query_and_hash=function( s )
843 var i=s.lastIndexOf( "#" );
845 s=s.substring( 0, i );
847 i=s.lastIndexOf( "?" );
849 s=s.substring( 0, i );
853 Test.AnotherWay._is_url_loaded=function( url, wnd )
856 if( wnd!=null && wnd.location!=null ) {
857 // after some popup blocker interference, location may behave strange..
859 location_s+=wnd.location;
860 if( location_s!="" ) {
861 var pathname=wnd.location.pathname;
862 var expected_url=url;
863 var i=expected_url.lastIndexOf( "#" );
865 expected_url=expected_url.substring( 0, i );
867 i=expected_url.lastIndexOf( "?" );
869 expected_url=expected_url.substring( 0, i );
871 i=expected_url.lastIndexOf( "/" );
872 if( i!=-1 && i!=expected_url.length-1 ) {
873 expected_url=expected_url.substring( i+1 );
875 i=pathname.indexOf( expected_url )
876 if( wnd.location.href==url || (i!=-1 && i==pathname.length-expected_url.length) ) {
877 if( /*window.opera==null*/wnd.document.readyState==null || wnd.document.readyState=="complete" ) { // for opera (and IE?), getElementById does not work until..
885 // find and run all test functions in the g_cur_page html page.
886 Test.AnotherWay._test_page_onload=function()
888 if( Test.AnotherWay._g_tests_queue.length==0 ) {
891 var test_page=Test.AnotherWay._g_tests_queue[0];
892 if( !Test.AnotherWay._is_url_loaded( test_page.url, Test.AnotherWay._g_test_iframe ) ) {
895 clearTimeout( test_page.timeout_id );
896 Test.AnotherWay._unprint_result( test_page.wait_msg );
898 if( test_page.convention=="anotherway" ) {
899 // get test function names (those beginning with "test")
900 if( typeof( Test.AnotherWay._g_test_iframe.document.scripts )!='undefined' ) { // IE
901 for( var i=0; i<Test.AnotherWay._g_test_iframe.document.scripts.length; ++i ) {
902 var script_text=Test.AnotherWay._g_test_iframe.document.scripts[i].text;
903 var fun_sig="function test";
904 var fun_start=script_text.indexOf( fun_sig );
906 while( fun_start!=-1 ) {
907 script_text=script_text.substring( fun_start, script_text.length );
908 var fun_end=script_text.indexOf( '(' );
909 var fun_name=script_text.substring( "function ".length, fun_end );
910 var whitespace = fun_name.indexOf( ' ' );
912 fun_name = fun_name.substring( 0, whitespace );
913 test_page.test_objects.push( new Test.AnotherWay._test_object_t( fun_name ) );
914 script_text=script_text.substring( fun_end, script_text.length );
915 fun_start=script_text.indexOf( fun_sig );
918 }else { // otherwise (not IE) it ought to work like this
919 for( var i in Test.AnotherWay._g_test_iframe) {
920 // Hack to prevent failure in FF3.0b1
921 if (i == "innerWidth" || i == "innerHeight") { continue; }
922 if( typeof( Test.AnotherWay._g_test_iframe[i] )=='function' ) {
923 if( i.substring( 0, 4 )=="test" ) {
924 test_page.test_objects.push( new Test.AnotherWay._test_object_t( i ) );
929 }else if( test_page.convention=="jsan" ) {
930 // the test object is already filled with results
931 test_page.test_objects.push( Test.AnotherWay._g_test_object_for_jsan );
934 if( test_page.test_objects.length==0 ) {
935 Test.AnotherWay._print_result( test_page.url, "No test functions defined in the page", "badtest", null );
936 Test.AnotherWay._load_next_page();
940 test_page.wait_msg=Test.AnotherWay._print_result( test_page.url, "running tests..<span class=\"counter\">"+test_page.test_objects.length+"</span>", "running", null );
942 test_page.test_object_i=0;
943 Test.AnotherWay._run_more_tests();
946 Test.AnotherWay._handle_exception=function( o, e, title )
948 var s=title+": "+typeof( e )+": ";
949 if( e.message!=null ) {
951 }else if( e.description!=null ) {
956 // if( e.location!=null ) { // XXX figure out how to display exception location if it's present (like in mozilla)
957 // s+=" location: "+e.location.toString();
962 var lines=e.stack.split( "\n" );
963 for( var i=0; i<lines.length; ++i ) {
964 // format of the line: func_name(args)@file_name:line_no
965 if( lines[i].match( /(\w*)\(([^\)]*)\)@(.*):([^:]*)$/ ) ) {
966 var func_name=RegExp.$1;
967 if( func_name.length==0 ) {
968 func_name="<anonymous>";
970 s.push( "in "+func_name+"( "+RegExp.$2+") at "+RegExp.$3+" line "+RegExp.$4+"\n" );
977 Test.AnotherWay._run_more_tests=function()
979 var test_page=Test.AnotherWay._g_tests_queue[0];
980 while( test_page.test_object_i<test_page.test_objects.length ) {
981 Test.AnotherWay._update_msg_counter( test_page.wait_msg, (1+test_page.test_object_i)+"/"+test_page.test_objects.length );
982 var o=test_page.test_objects[test_page.test_object_i];
983 if( test_page.convention=="anotherway" ) {
985 Test.AnotherWay._g_test_iframe[o.name]( o );
987 Test.AnotherWay._handle_exception( o, e, "" );
989 } // for "jsan" convention, test has run already
990 if( o.delay_actions.length>0 || o.wait_result_milliseconds>0 ) {
991 o.delay_total_milliseconds_left+=o.wait_result_milliseconds;
992 Test.AnotherWay._delay_actions_timeout();
995 ++test_page.test_object_i;
997 Test.AnotherWay._unprint_result( test_page.wait_msg );
998 Test.AnotherWay._print_result( test_page.url, null, null, test_page.test_objects );
999 Test.AnotherWay._load_next_page();
1002 Test.AnotherWay._delay_actions_timeout=function()
1004 var test_page=Test.AnotherWay._g_tests_queue[0];
1005 var test_object=test_page.test_objects[test_page.test_object_i];
1007 if( test_object.delay_action_i==null ) {
1008 // set up to start first action
1009 test_object.delay_action_i=-1;
1011 // perform current action
1012 var milliseconds_passed=(new Date()).getTime()-test_object.delay_prev_timer_time;
1013 test_object.delay_current_milliseconds_left-=milliseconds_passed;
1014 test_object.delay_total_milliseconds_left-=milliseconds_passed;
1015 finished=Test.AnotherWay._delay_continue_action( test_object, milliseconds_passed );
1017 while( finished && test_object.delay_action_i<test_object.delay_actions.length ) {
1018 ++test_object.delay_action_i; // start next action
1019 finished=Test.AnotherWay._delay_start_action( test_object );
1021 if( test_object.delay_action_i<=test_object.delay_actions.length ) { // any more actions left ?
1022 test_object.delay_prev_timer_time=(new Date()).getTime();
1023 var next_timeout=Test.AnotherWay._g_timeout_granularity;
1024 if( test_object.delay_current_milliseconds_left<next_timeout ) {
1025 next_timeout=test_object.delay_current_milliseconds_left;
1027 if( test_object.second_wait_msg!=null ) {
1028 Test.AnotherWay._update_msg_counter( test_object.second_wait_msg, (test_object.delay_total_milliseconds_left/1000).toFixed() );
1030 setTimeout( Test.AnotherWay._delay_actions_timeout, next_timeout );
1031 }else { // no more actions left. run the next test.
1032 if( test_object.second_wait_msg!=null ) {
1033 Test.AnotherWay._unprint_result( test_object.second_wait_msg );
1034 test_object.second_wait_msg=null;
1036 ++test_page.test_object_i;
1037 Test.AnotherWay._run_more_tests();
1040 Test.AnotherWay._delay_start_action=function( test_object )
1044 if( test_object.delay_action_i==test_object.delay_actions.length ) {
1045 if( test_object.wait_result_milliseconds>0 ) {
1046 test_object.delay_current_milliseconds_left=test_object.wait_result_milliseconds; // wait for result
1047 wait_msg="waiting for results..";
1049 ++test_object.delay_action_i; // dont wait for result
1052 var action=test_object.delay_actions[test_object.delay_action_i];
1053 if( action.action_kind=="call" ) {
1054 test_object.delay_current_milliseconds_left=action.call_delay_milliseconds;
1055 wait_msg="performing delayed calls..";
1056 }else if( action.action_kind=="window" ) {
1057 if( Test.AnotherWay._g_opera_path_correction!=null && action.wnd_url.indexOf( ":" )==-1 ) {
1058 action.wnd_url=Test.AnotherWay._g_opera_path_correction+action.wnd_url;
1060 action.wnd_wnd=window.open( action.wnd_url, "_blank" );
1061 if( action.wnd_wnd==null ) {
1063 test_object.fail( "unable to open window for "+action.wnd_url );
1065 test_object.delay_current_milliseconds_left=action.wnd_timeout_milliseconds;
1066 wait_msg="opening window..";
1068 }else if( action.action_kind=="replay" ) {
1069 if( action.replay_events.length==0 ) {
1072 action.replay_event_i=0;
1073 test_object.delay_current_milliseconds_left=action.replay_events[0]["time"];
1074 wait_msg="replaying events..";
1078 if( test_object.second_wait_msg!=null ) {
1079 Test.AnotherWay._unprint_result( test_object.second_wait_msg );
1081 if( wait_msg!="" ) {
1082 var test_page=Test.AnotherWay._g_tests_queue[0];
1083 test_object.second_wait_msg=Test.AnotherWay._print_counter_result( test_page.url, wait_msg, test_object.delay_total_milliseconds_left, "waiting" );
1085 test_object.second_wait_msg=null;
1089 Test.AnotherWay._delay_continue_action=function( test_object, milliseconds_passed )
1091 var finished=test_object.delay_current_milliseconds_left<=0;
1092 if( test_object.delay_action_i==test_object.delay_actions.length ) { // action is "waiting for results"
1093 if( test_object.n_plan!=null && test_object.n_plan==test_object.n_ok+test_object.n_fail ) {
1094 finished=true; // if all assertions results are recorded, don't wait any more
1097 ++test_object.delay_action_i; // move on to the next test
1100 var action=test_object.delay_actions[test_object.delay_action_i];
1101 if( action.action_kind=="call" ) {
1106 Test.AnotherWay._handle_exception( test_object, e, "in delay_call" );
1109 }else if( action.action_kind=="window" ) {
1110 test_object.delay_total_milliseconds_left+=milliseconds_passed; // for "window", the countdown is suspended since it's unknown how long it will take
1111 if( Test.AnotherWay._is_url_loaded( action.wnd_url, action.wnd_wnd ) ) {
1113 action.wnd_fn( action.wnd_wnd );
1115 Test.AnotherWay._handle_exception( test_object, e, "in open_window function call" );
1118 }else if( finished ) {
1119 test_object.fail( "unable to open window for url '"+action.wnd_url+"'. timeout expired" );
1121 }else if( action.action_kind=="replay" ) {
1124 Test.AnotherWay._delay_replay_event( test_object, action.replay_wnd, action.replay_events[action.replay_event_i], action.replay_checkpoints );
1125 // }catch( e ) { // disabled, until I know how to gel location info from an exception
1126 // Test.AnotherWay._handle_exception( test_object, e, "while replaying event" );
1128 ++action.replay_event_i;
1129 finished=action.replay_event_i==action.replay_events.length;
1131 test_object.delay_current_milliseconds_left=action.replay_events[action.replay_event_i]["time"];
1138 Test.AnotherWay._delay_replay_event=function( test_object, wnd, event, checkpoints )
1140 if( event.type=="_checkpoint" ) {
1141 var checkpoint_n=event.which;
1142 var prev_n_fail=test_object.n_fail;
1143 checkpoints[checkpoint_n]( test_object, wnd );
1144 var flash_color= prev_n_fail==test_object.n_fail ? "#2f2" : "#f22" ;
1145 Test.AnotherWay._record_flash_border( flash_color );
1146 }else if( event.type=="click" || event.type=="mouseover" || event.type=="mouseout" || event.type=="mousemove" || event.type=="mousedown" || event.type=="mouseup" ) {
1147 var target=Test.AnotherWay._record_node_path_to_node( event["target"], wnd.document );
1148 if( target!=null ) {
1149 Test.AnotherWay._record_control_update_highlight( target, "ball", event );
1150 var e=wnd.document.createEvent( "MouseEvents" );
1151 var related_target=Test.AnotherWay._record_node_path_to_node( event["relatedTarget"], wnd.document );
1154 event["cancelable"],
1156 wnd.document.defaultView,
1167 Test.AnotherWay._record_node_path_to_node( event["relatedTarget"], wnd.document )
1169 // Firefox 1.0.6 somehow loses relatedTarget somewhere on the way. Pass through our own, for those who choose to care.
1170 e.passThroughRelatedTarget=related_target;
1171 target.dispatchEvent( e );
1173 }else if( event.type=="keyup" || event.type=="keydown" || event.type=="keypress" ) {
1174 var e=wnd.document.createEvent( "KeyboardEvents" ); // forget it. Apparently it's not supported neither by mozilla nor by opera.
1175 e.initKeyboardEvent(
1177 event["cancelable"],
1179 wnd.document.defaultView,
1188 wnd.document.dispatchEvent( e );
1192 Test.AnotherWay._print_counter_result=function( url, msg, milliseconds, style )
1194 return Test.AnotherWay._print_result( url, msg+"<span class=\"counter\">"+(milliseconds/1000).toFixed()+"</span>", style, null );
1197 Test.AnotherWay._g_result_count=0; // for assigning unique ids to result paragraphs
1199 // number of pages tested
1200 Test.AnotherWay._g_ok_pages=0;
1201 Test.AnotherWay._g_fail_pages=0;
1203 Test.AnotherWay._print_result=function( url, msg, style, test_objects )
1205 var results=document.getElementById( "results" );
1206 var r=results.appendChild( document.createElement( "p" ) );
1207 r.id="result"+Test.AnotherWay._g_result_count;
1208 ++Test.AnotherWay._g_result_count;
1209 r.onclick=Test.AnotherWay._toggle_detail;
1210 var text="<span class=\"bullet\"> </span> ";
1217 if( test_objects!=null ) {
1218 // compose summary and detail texts
1220 var total_detail_ok=0;
1222 var total_detail_fail=0;
1225 var detail=results.appendChild( document.createElement( "div" ) );
1227 if( r.id.match( /^result(\d+)$/ ) ) {
1228 detail.id="result_detail"+RegExp.$1;
1231 for( var i=0; i<test_objects.length; ++i ) {
1232 var o=test_objects[i];
1235 p=document.createElement( "P" );
1236 Test.AnotherWay._set_css_class( p, "result_detail" );
1238 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)) {
1240 p_text+=" <span class=\"fail\">";
1241 if( o.n_plan!=null && o.n_plan!=o.n_ok+o.n_fail) {
1242 p_text+="planned "+o.n_plan+" assertions but got "+(o.n_ok+o.n_fail)+"; ";
1244 if(o.n_plan==null && o.n_ok==0 && o.n_fail==0) {
1245 p_text+="test did not output anything";
1247 p_text+=" fail "+o.n_fail;
1253 p_text+=" ok "+o.n_ok;
1254 if( o.n_plan==null ) {
1256 p_text+=" <span class=\"warning\">no plan</span>";
1259 detail.appendChild( p );
1261 p=document.createElement( "P" );
1262 Test.AnotherWay._set_css_class( p, "result_exception_detail" );
1263 p.innerHTML="<span class=\"fail\">exception:</span> "+o.exception;
1264 detail.appendChild( p );
1265 p=document.createElement( "P" );
1266 Test.AnotherWay._set_css_class( p, "result_exception_stack_detail" );
1267 p.innerHTML=o.exception_stack.join( "<br/>" );
1268 detail.appendChild( p );
1270 for( var ii=0; ii<o.assertions.length; ++ii ) {
1271 var oo=o.assertions[ii];
1272 var status=oo.ok ? "ok" : "<span class=\"fail\">fail</span>";
1273 p=document.createElement( "P" );
1274 Test.AnotherWay._set_css_class( p, "result_micro_detail" );
1276 p.appendChild( document.createTextNode( " "+oo.name ) );
1277 detail.appendChild( p );
1279 total_detail_ok+=o.n_ok;
1280 total_detail_fail+=o.n_fail;
1282 if( total_fail || total_detail_fail ) {
1283 text+=" fail "+total_fail;
1285 text+=" ok "+total_ok+" (detailed:";
1286 if( total_fail || total_detail_fail ) {
1287 text+=" fail "+total_detail_fail;
1289 text+=" ok "+total_detail_ok+")";
1291 text+=" <span class=\"warning\">no plan</span>";
1293 style= total_fail==0 ? "ok" : "fail";
1294 detail.style.display= style=="fail" ? "block" : "none";
1295 detail.style.cursor="text";
1298 Test.AnotherWay._set_css_class( r, style );
1300 ++Test.AnotherWay._g_ok_pages;
1301 }else if( style=="fail" || style=="badtest" ) {
1302 ++Test.AnotherWay._g_fail_pages;
1305 if( Test.AnotherWay._g_fail_pages>0 ) {
1306 pages_total+=" fail "+Test.AnotherWay._g_fail_pages;
1308 pages_total+=" ok "+Test.AnotherWay._g_ok_pages;
1309 Test.AnotherWay._update_results_total( pages_total );
1312 if( results.scrollHeight!=null && results.scrollTop!=null && results.offsetHeight!=null ) {
1313 results.scrollTop=results.scrollHeight-results.offsetHeight;
1315 // when test_objects is not null, the results are final - good time to clean up
1316 if( test_objects!=null ) {
1317 for( var i=0; i<test_objects.length; ++i ) {
1318 var actions=test_objects[i].delay_actions;
1319 for( var action_i=0; action_i<actions.length; ++action_i ) {
1320 var action=actions[action_i];
1321 if( action.action_kind=="window" && action.wnd_wnd!=null && !action.wnd_no_close ) {
1322 action.wnd_wnd.close();
1323 action.wnd_wnd=null;
1330 Test.AnotherWay._unprint_result=function( child )
1332 var results=document.getElementById( "results" );
1333 results.removeChild( child );
1335 Test.AnotherWay._toggle_detail=function()
1337 if( this.id.match( /^result(\d+)$/ ) ) {
1338 var detail=document.getElementById( "result_detail"+RegExp.$1 );
1339 if( detail!=null ) {
1340 if( detail.style.display=="none" ) {
1341 detail.style.display="block";
1342 }else if( detail.style.display=="block" ) {
1343 detail.style.display="none";
1348 Test.AnotherWay._update_msg_counter=function( msg, text )
1350 for( var i=0; i<msg.childNodes.length; ++i ) {
1351 var item=msg.childNodes[i];
1352 if( item.nodeName=="SPAN" && Test.AnotherWay._get_css_class( item )=="counter" ) {
1353 item.innerHTML=text;
1357 Test.AnotherWay._update_results_total=function( msg )
1359 var total=document.getElementById( "total" );
1361 total.innerHTML=msg;
1364 Test.AnotherWay._results_clear_onclick=function()
1366 var results=document.getElementById( "results" );
1367 results.innerHTML="";
1368 Test.AnotherWay._update_results_total( "" );
1369 Test.AnotherWay._g_ok_pages=0;
1370 Test.AnotherWay._g_fail_pages=0;
1371 var debug=document.getElementById( "debug" );
1375 Test.AnotherWay._get_css_class=function( o )
1377 var c=o.getAttribute( "className" );
1378 if( c==null || c=="" ) {
1379 c=o.getAttribute( "class" );
1383 Test.AnotherWay._set_css_class=function( o, css_class )
1385 o.setAttribute( "className", css_class );
1386 o.setAttribute( "class", css_class );
1389 Test.AnotherWay._tab_onclick=function()
1392 var tabs=[ document.getElementById( "debug_tab" ), document.getElementById( "results_tab" ) ];
1393 var panes=[ document.getElementById( "debug" ), document.getElementById( "results" ) ];
1394 for( var i=0; i<tabs.length; ++i ) {
1395 if( tab==tabs[i] ) {
1396 Test.AnotherWay._set_css_class( tabs[i], "active_tab" );
1397 panes[i].style.display="block";
1399 Test.AnotherWay._set_css_class( tabs[i], "inactive_tab" );
1400 panes[i].style.display="none";
1404 Test.AnotherWay._tab_mouseover=function()
1406 if( Test.AnotherWay._get_css_class( this )=="inactive_tab" ) {
1407 Test.AnotherWay._set_css_class( this, "inactive_mouseover_tab" );
1410 Test.AnotherWay._tab_mouseout=function()
1412 if( Test.AnotherWay._get_css_class( this )=="inactive_mouseover_tab" ) {
1413 Test.AnotherWay._set_css_class( this, "inactive_tab" );
1417 // recording mouse input
1418 Test.AnotherWay._record_check_onfocus=function()
1421 var check_select=o.type!="text";
1422 var div=document.getElementById( "record_div" );
1423 var inputs=div.getElementsByTagName( "input" );
1424 for( var i=0; i<inputs.length; ++i ) {
1425 var input=inputs[i];
1426 if( input.type=="radio" ) {
1427 if( input.value=="select" ) {
1428 input.checked=check_select;
1429 }else if( input.value=="input" ) {
1430 input.checked=!check_select;
1436 Test.AnotherWay._g_no_record_msg=null; // not null - recording is unavailable
1437 Test.AnotherWay._g_record_timeout_cnt=0; // opening window for a page for recording
1438 Test.AnotherWay._g_record_url=null;
1439 Test.AnotherWay._g_record_wnd=null;
1440 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
1441 Test.AnotherWay._g_record_keydown=null; // recording control - which key is down
1442 Test.AnotherWay._g_record_ctrl_keydown=false;
1443 Test.AnotherWay._g_record_shift_keydown=false;
1444 Test.AnotherWay._g_record_control_visible=true; // recording control ui state
1445 Test.AnotherWay._g_record_started;
1446 Test.AnotherWay._g_record_paused;
1447 Test.AnotherWay._g_record_include_mousemove=false;
1448 Test.AnotherWay._g_record_start_time; // for time references
1449 Test.AnotherWay._g_record_pause_start_time;
1450 Test.AnotherWay._g_record_update_time_interval; // showing time in the control ui
1451 Test.AnotherWay._g_record_waiting_for_results=false; // waiting for results window to open
1452 Test.AnotherWay._g_record_events; // recorded events
1453 Test.AnotherWay._g_record_under_cursor; // track element under cursor
1454 Test.AnotherWay._g_record_checkpoint_count; // for checkpoint numbering
1455 Test.AnotherWay._g_record_mouse_over_record_control; // for avoiding record control highlight on mouseover
1456 Test.AnotherWay._g_record_highlighted_element={ element: null, x: null, y: null };
1458 Test.AnotherWay._record_control_get_element=function( id )
1460 if( Test.AnotherWay._g_record_wnd!=null && Test.AnotherWay._g_record_wnd.document!=null ) {
1461 return Test.AnotherWay._g_record_wnd.document.getElementById( id+Test.AnotherWay._g_record_random_id );
1466 Test.AnotherWay._record_start_onclick=function() // "record" button on the run_tests.html: open a window for a page for which input is recorded
1468 if( Test.AnotherWay._g_no_record_msg!=null ) {
1469 alert( Test.AnotherWay._g_no_record_msg );
1472 if( Test.AnotherWay._g_record_timeout_cnt>0
1473 || (Test.AnotherWay._g_record_wnd!=null && (Test.AnotherWay._g_record_wnd.closed!=null && !Test.AnotherWay._g_record_wnd.closed)) ) { // in opera, closed is null.
1474 alert( "there is already window opened for recording input for a page "+Test.AnotherWay._g_record_url );
1477 var div=document.getElementById( "record_div" );
1478 var inputs=div.getElementsByTagName( "input" );
1480 for( var i=0; i<inputs.length; ++i ) {
1481 var input=inputs[i];
1482 if( input.type=="radio" ) {
1483 if( input.value=="select" && input.checked ) {
1484 var index=document.getElementById( "record_select" ).selectedIndex;
1486 url=Test.AnotherWay._g_test_page_urls[index-1].url;
1488 }else if( input.value=="input" && input.checked ) {
1489 url=document.getElementById( "record_input" ).value;
1494 Test.AnotherWay._g_record_url=url;
1495 Test.AnotherWay._g_record_wnd=window.open( url, "_blank" );
1496 if( Test.AnotherWay._g_record_wnd==null ) {
1497 alert( "unable to open new window for a page: "+url );
1499 Test.AnotherWay._g_record_timeout_cnt=50;
1500 setTimeout( Test.AnotherWay._record_window_timeout, 100 );
1504 Test.AnotherWay._record_window_timeout=function()
1506 if( Test.AnotherWay._is_url_loaded( Test.AnotherWay._g_record_url, Test.AnotherWay._g_record_wnd ) ) {
1507 Test.AnotherWay._record_window_setup( Test.AnotherWay._g_record_wnd );
1509 if( --Test.AnotherWay._g_record_timeout_cnt>0 ) {
1510 setTimeout( Test.AnotherWay._record_window_timeout, 100 );
1512 alert( "timeout expired while opening new window for a page: "+Test.AnotherWay._g_record_url );
1513 Test.AnotherWay._g_record_wnd=null;
1514 Test.AnotherWay._g_record_url=null;
1515 Test.AnotherWay._g_record_timeout_cnt=0;
1519 Test.AnotherWay._record_control_randomize_id=function( e, r )
1524 for( var c=e.firstChild; c!=null; c=c.nextSibling ) {
1525 Test.AnotherWay._record_control_randomize_id( c, r );
1528 Test.AnotherWay._record_window_setup=function( wnd ) // insert recording control into the page for which input is recorded
1530 Test.AnotherWay._g_record_timeout_cnt=0;
1531 var this_div=document.getElementById( "record_control" );
1532 var record_control=wnd.document.importNode( this_div, true );
1533 Test.AnotherWay._g_record_random_id=(1000*Math.random()).toFixed();
1534 Test.AnotherWay._record_control_randomize_id( record_control, Test.AnotherWay._g_record_random_id );
1535 Test.AnotherWay._g_record_control_visible=true;
1536 Test.AnotherWay._g_record_started=false;
1537 Test.AnotherWay._g_record_paused=false;
1538 Test.AnotherWay._g_record_checkpoint_count=0;
1539 Test.AnotherWay._g_record_mouse_over_record_control=false;
1540 var doc=wnd.document;
1541 doc.body.appendChild( record_control );
1542 // opera sans-serif font is different
1543 if( window.opera ) {
1544 cursor_over_indicator=Test.AnotherWay._record_control_get_element( "record_cursor_over" );
1545 cursor_over_indicator.style.width="18em";
1546 cursor_over_indicator.style.height="2em";
1547 cursor_over_indicator.style.fontSize="7pt";
1549 doc.addEventListener( "keydown", Test.AnotherWay._record_control_keydown, true );
1550 doc.addEventListener( "keyup", Test.AnotherWay._record_control_keyup, true );
1551 // doc.addEventListener( "keypress", Test.AnotherWay._record_event, true ); // replaying is not supported by any known browser
1553 doc.body.addEventListener( "mousemove", Test.AnotherWay._record_on_mousemove, true );
1554 doc.body.addEventListener( "click", Test.AnotherWay._record_event, true );
1555 doc.body.addEventListener( "mouseover", Test.AnotherWay._record_event, true );
1556 doc.body.addEventListener( "mouseout", Test.AnotherWay._record_event, true );
1557 doc.body.addEventListener( "mousedown", Test.AnotherWay._record_event, true );
1558 doc.body.addEventListener( "mouseup", Test.AnotherWay._record_event, true );
1560 Test.AnotherWay._record_control_key_disabled=function( k )
1563 return !Test.AnotherWay._g_record_started;
1564 }else if( k=="p" ) {
1565 return !Test.AnotherWay._g_record_started;
1566 }else if( k=="s" ) {
1567 return Test.AnotherWay._g_record_waiting_for_results;
1573 Test.AnotherWay._record_control_update_ui=function()
1575 var keydown_color="#fff";
1576 var disabled_color="#aaa";
1577 var button_color="#adf";
1578 var active_color="#fdf";
1581 display[false]="none";
1582 display[true]="inline";
1584 var s_button=Test.AnotherWay._record_control_get_element( "record_s" );
1585 var record_on=Test.AnotherWay._record_control_get_element( "record_on" );
1586 var record_off=Test.AnotherWay._record_control_get_element( "record_off" );
1588 s_button.style.backgroundColor= Test.AnotherWay._record_control_key_disabled( "s" ) ? disabled_color
1589 : Test.AnotherWay._g_record_keydown=="s" ? keydown_color : Test.AnotherWay._g_record_started ? active_color : button_color;
1590 record_on.style.display=display[!Test.AnotherWay._g_record_started];
1591 record_off.style.display=display[Test.AnotherWay._g_record_started];
1593 var h_button=Test.AnotherWay._record_control_get_element( "record_h" );
1594 h_button.style.backgroundColor= Test.AnotherWay._g_record_keydown=="h" ? keydown_color : button_color;
1596 var p_button=Test.AnotherWay._record_control_get_element( "record_p" );
1597 var record_pause_on=Test.AnotherWay._record_control_get_element( "record_pause_on" );
1598 var record_pause_off=Test.AnotherWay._record_control_get_element( "record_pause_off" );
1599 p_button.style.backgroundColor= Test.AnotherWay._record_control_key_disabled( "p" ) ? disabled_color
1600 : Test.AnotherWay._g_record_keydown=="p" ? keydown_color : Test.AnotherWay._g_record_paused ? active_color : button_color;
1601 record_pause_on.style.display=display[!Test.AnotherWay._g_record_paused];
1602 record_pause_off.style.display=display[Test.AnotherWay._g_record_paused];
1604 var m_button=Test.AnotherWay._record_control_get_element( "record_m" );
1605 var record_include_mousemove=Test.AnotherWay._record_control_get_element( "record_include_mousemove" );
1606 var record_omit_mousemove=Test.AnotherWay._record_control_get_element( "record_omit_mousemove" );
1607 m_button.style.backgroundColor= Test.AnotherWay._g_record_keydown=="m" ? keydown_color : Test.AnotherWay._g_record_include_mousemove ? active_color : button_color;
1608 record_include_mousemove.style.display=display[!Test.AnotherWay._g_record_include_mousemove];
1609 record_omit_mousemove.style.display=display[Test.AnotherWay._g_record_include_mousemove];
1611 var c_button=Test.AnotherWay._record_control_get_element( "record_c" );
1612 c_button.style.backgroundColor= Test.AnotherWay._record_control_key_disabled( "c" ) ? disabled_color
1613 : Test.AnotherWay._g_record_keydown=="c" ? keydown_color : button_color;
1615 var record_indicator=Test.AnotherWay._record_control_get_element( "record_indicator" );
1616 record_indicator.style.display=display[Test.AnotherWay._g_record_started];
1618 var pause_indicator=Test.AnotherWay._record_control_get_element( "record_pause_indicator" );
1619 pause_indicator.style.display=display[Test.AnotherWay._g_record_paused];
1621 var record_control=Test.AnotherWay._record_control_get_element( "record_control" );
1622 record_control.style.display= Test.AnotherWay._g_record_control_visible ? "block" : "none";
1624 var shift_button=Test.AnotherWay._record_control_get_element( "record_shift_key" );
1625 shift_button.style.backgroundColor= Test.AnotherWay._g_record_shift_keydown ? keydown_color : button_color;
1627 var ctrl_button=Test.AnotherWay._record_control_get_element( "record_ctrl_key" );
1628 ctrl_button.style.backgroundColor= Test.AnotherWay._g_record_ctrl_keydown ? keydown_color : button_color;
1630 Test.AnotherWay._record_format_time=function( t )
1633 var m=t.getMinutes();
1634 var s=t.getSeconds();
1635 var str= m==0 ? "" : m+"m ";
1639 Test.AnotherWay._record_control_update_time=function()
1641 var time_display=Test.AnotherWay._record_control_get_element( "record_time" );
1642 if( time_display!=null ) {
1643 time_display.innerHTML=Test.AnotherWay._record_format_time( (new Date()).getTime()-Test.AnotherWay._g_record_start_time );
1646 Test.AnotherWay._record_control_update_highlight=function( elem, style, event )
1649 Test.AnotherWay._record_highlight_border( null );
1651 var pos=Test.AnotherWay._get_page_coords( elem );
1652 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 ) {
1653 Test.AnotherWay._g_record_highlighted_element={ element: elem, x: pos.x, y: pos.y };
1654 Test.AnotherWay._record_highlight_border( elem, style, event );
1658 Test.AnotherWay._record_decode_key=function( event )
1662 k=Test.AnotherWay._g_record_wnd.event.keyCode;
1686 }else if( k==123 ) {
1691 Test.AnotherWay._record_control_keydown=function( event )
1694 var k=Test.AnotherWay._record_decode_key( event );
1696 Test.AnotherWay._g_record_shift_keydown=true;
1697 }else if( k=="ctrl" ) {
1698 Test.AnotherWay._g_record_ctrl_keydown=true;
1699 }else if( k!="" && (Test.AnotherWay._g_record_keydown==null || Test.AnotherWay._g_record_keydown==k) ) {
1700 if( Test.AnotherWay._g_record_ctrl_keydown && Test.AnotherWay._g_record_shift_keydown && !Test.AnotherWay._record_control_key_disabled( k ) ) {
1701 Test.AnotherWay._g_record_keydown=k;
1705 Test.AnotherWay._g_record_keydown="";
1707 Test.AnotherWay._record_control_update_ui();
1709 // Test.AnotherWay._record_event( event ); // replaying is not supported in any known browser
1713 Test.AnotherWay._record_control_keyup=function( event )
1716 var k=Test.AnotherWay._record_decode_key( event );
1718 Test.AnotherWay._g_record_shift_keydown=false;
1719 }else if( k=="ctrl" ) {
1720 Test.AnotherWay._g_record_ctrl_keydown=false;
1721 }else if( k!="" && k==Test.AnotherWay._g_record_keydown && Test.AnotherWay._g_record_ctrl_keydown && Test.AnotherWay._g_record_shift_keydown ) {
1723 Test.AnotherWay._g_record_started=!Test.AnotherWay._g_record_started;
1724 if( Test.AnotherWay._g_record_started ) {
1725 Test.AnotherWay._g_record_events=[];
1726 Test.AnotherWay._g_record_start_time=(new Date()).getTime();
1727 Test.AnotherWay._record_control_update_time();
1728 Test.AnotherWay._g_record_update_time_interval=window.setInterval( Test.AnotherWay._record_control_update_time, 200 );
1730 Test.AnotherWay._record_control_update_highlight( null );
1731 if( !Test.AnotherWay._g_record_paused ) {
1732 window.clearInterval( Test.AnotherWay._g_record_update_time_interval );
1734 Test.AnotherWay._g_record_waiting_for_results=true;
1735 // open a new window for self, pass a parameter to dump recorded events as javascript code there
1736 // (the easiest way to obtain a document from the same origin, so it's writable, is to open this same page again)
1737 Test.AnotherWay._g_record_paused=false;
1738 var loc=window.location;
1739 loc=loc.protocol+"//"+loc.host+loc.pathname+"?recording_results="+Test.AnotherWay._g_record_random_id;
1740 if( window.open( loc, "_blank" )==null ) {
1741 alert( "unable to open new window for results" );
1745 }else if( k=="h" ) {
1746 Test.AnotherWay._g_record_control_visible=!Test.AnotherWay._g_record_control_visible;
1748 }else if( k=="p" ) {
1749 Test.AnotherWay._g_record_paused=!Test.AnotherWay._g_record_paused;
1750 if( Test.AnotherWay._g_record_paused ) {
1751 Test.AnotherWay._g_record_pause_start_time=(new Date()).getTime();
1752 if( Test.AnotherWay._g_record_started ) {
1753 window.clearInterval( Test.AnotherWay._g_record_update_time_interval );
1755 Test.AnotherWay._record_control_update_highlight( null );
1757 var pause_duration=(new Date()).getTime()-Test.AnotherWay._g_record_pause_start_time;
1758 Test.AnotherWay._g_record_start_time+=pause_duration;
1759 Test.AnotherWay._g_record_update_time_interval=window.setInterval( Test.AnotherWay._record_control_update_time, 200 );
1762 }else if( k=="m" ) {
1763 Test.AnotherWay._g_record_include_mousemove=!Test.AnotherWay._g_record_include_mousemove;
1765 }else if( k=="c" ) {
1766 var o=Test.AnotherWay._record_checkpoint();
1767 Test.AnotherWay._record_display_checkpoint( o );
1768 Test.AnotherWay._record_flash_border( "#24d" );
1772 Test.AnotherWay._g_record_keydown=null;
1773 Test.AnotherWay._record_control_update_ui();
1775 // Test.AnotherWay._record_event( event ); // replaying is not supported in any known browser
1779 Test.AnotherWay._record_html_node_path=function( node )
1786 if( node.id!=null && node.id!="" ) {
1787 path.unshift( "#"+node.id+" "+node.nodeName );
1790 var parent_node=node.parentNode;
1791 if( parent_node==null ) {
1792 return []; // no BODY up the path - this node is screwed (browsers differ in what's above the body), discard
1796 for( var child=parent_node.firstChild; child!=null; child=child.nextSibling ) {
1801 if( child.nodeType==1 ) { // count only HTML element nodes
1808 path.unshift( i+" "+node.nodeName );
1809 if( parent_node.nodeName=="BODY" || parent_node.nodeName=="body" ) {
1818 Test.AnotherWay._record_node_path_to_string=function( path )
1822 for( var i=0; i<path.length; ++i ) {
1823 s+= i==0 ? "" : ", ";
1824 var elem=path[i].split( " " );
1825 if( elem[0].charAt( 0 )=="#" ) {
1826 s+=elem[1]+" "+elem[0];
1828 s+=elem[1]+" ["+elem[0]+"]";
1834 Test.AnotherWay._record_node_path_to_node=function( path_str, doc )
1836 if( path_str==null ) {
1839 var path=path_str.split( "," );
1841 for( var i=0; i<path.length; ++i ) {
1842 var node_i=path[i].split( " " )[0];
1843 if( node_i.charAt( 0 )=="#" ) {
1844 node=doc.getElementById( node_i.substring( 1 ) );
1846 if( node_i<0 || node_i>=node.childNodes.length ) {
1849 node=node.firstChild;
1850 while( node!=null ) {
1851 if( node.nodeType==1 ) { // count only HTML element nodes
1857 node=node.nextSibling;
1867 Test.AnotherWay._record_control_contains_id=function( s )
1869 return s.match( /^#record_[\w_]+/ ) && s.match( Test.AnotherWay._g_record_random_id );
1871 Test.AnotherWay._record_checkpoint=function()
1873 var o={ type: "_checkpoint", time: (new Date()).getTime()-Test.AnotherWay._g_record_start_time, which: Test.AnotherWay._g_record_checkpoint_count++,
1874 target: Test.AnotherWay._record_html_node_path( Test.AnotherWay._g_record_under_cursor ) };
1875 Test.AnotherWay._g_record_events.push( o );
1878 Test.AnotherWay._record_event=function( event )
1880 var unneeded=["rangeOffset","eventPhase","timeStamp","isTrusted","popupWindowFeatures","rangeOffset"];
1881 if( Test.AnotherWay._g_record_started && !Test.AnotherWay._g_record_paused ) {
1883 for( var n in event ) {
1884 var needed=!n.match( /^[A-Z0-9_]+$/ );
1886 for( var ui=0; ui<unneeded.length; ++ui ) {
1887 if( unneeded[ui]==n ) {
1894 if( typeof( value )!="object" && typeof( value )!="function" ) {
1896 }else if( n=="target" || n=="relatedTarget" ) {
1897 o[n]=Test.AnotherWay._record_html_node_path( value );
1902 o["time"]=(new Date()).getTime()-Test.AnotherWay._g_record_start_time;
1903 var over_record_control= o["target"]!=null && o["target"][0]!=null && Test.AnotherWay._record_control_contains_id( o["target"][0] );
1904 if( !over_record_control ) {
1905 Test.AnotherWay._g_record_events.push( o );
1910 Test.AnotherWay._record_on_mousemove=function( event )
1912 var path=Test.AnotherWay._record_html_node_path( event.target );
1913 var new_mouse_over_record_control= path!=null && path[0]!=null && Test.AnotherWay._record_control_contains_id( path[0] );
1914 if( new_mouse_over_record_control!=Test.AnotherWay._g_record_mouse_over_record_control ) {
1915 Test.AnotherWay._g_record_mouse_over_record_control=new_mouse_over_record_control;
1916 Test.AnotherWay._record_control_update_ui();
1918 if( event.target!=null && event.target!=Test.AnotherWay._g_record_under_cursor ) {
1919 Test.AnotherWay._g_record_under_cursor=event.target;
1921 if( path==null || path[0]==null || !Test.AnotherWay._record_control_contains_id( path[0] ) ) {
1922 s=Test.AnotherWay._record_node_path_to_string( path );
1927 var cursor_over_indicator=Test.AnotherWay._record_control_get_element( "record_cursor_over" );
1928 cursor_over_indicator.innerHTML=s;
1931 var highlight_element=null;
1932 if( !Test.AnotherWay._g_record_mouse_over_record_control && Test.AnotherWay._g_record_started && !Test.AnotherWay._g_record_paused ) {
1933 highlight_element=event.target;
1935 // highlight border disabled on recording - it causes page to scroll, issuing spurious mouseover/mouseout event
1936 //Test.AnotherWay._record_control_update_highlight( highlight_element, "border" );
1938 if( Test.AnotherWay._g_record_include_mousemove ) {
1939 Test.AnotherWay._record_event( event );
1943 Test.AnotherWay._record_display_checkpoint=function( o )
1945 var checkpoints_div=Test.AnotherWay._record_control_get_element( "record_checkpoints" );
1946 var p=checkpoints_div.appendChild( checkpoints_div.ownerDocument.createElement( "div" ) );
1947 p.style.marginTop="3px";
1948 p.style.font="normal normal 8pt sans-serif";
1949 p.style.color="#000";
1950 p.style.textAligh="left";
1951 p.style.position="relative";
1952 p.style.width="100%";
1953 var checkpoint_text="";
1954 checkpoint_text+="#"+(o.which+1);
1955 checkpoint_text+=" "+Test.AnotherWay._record_format_time( o.time );
1956 if( o.target!=null ) {
1957 checkpoint_text+=Test.AnotherWay._record_node_path_to_string( o.target );
1959 p.appendChild( p.ownerDocument.createTextNode( checkpoint_text ) );
1961 Test.AnotherWay._record_save_results=function( doc )
1963 // strange, but DOM-style append does not work here in opera 8.
1964 var append=function( s ) { doc.write( "<div>"+s+"</div>" ); };
1965 append( "/* paste this data into your javascript and pass it as an argument to replay_events method */" );
1966 append( "{ checkpoints: [" );
1967 var first_checkpoint=true;
1968 for( var i=0; i<Test.AnotherWay._g_record_events.length; ++i ) {
1969 var o=Test.AnotherWay._g_record_events[i];
1970 if( o.type=="_checkpoint" ) {
1971 var str= first_checkpoint ? "" : "}, ";
1972 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 );
1974 first_checkpoint=false;
1977 if( !first_checkpoint ) {
1980 append( "], events: [ " );
1982 for( var i=0; i<Test.AnotherWay._g_record_events.length; ++i ) {
1983 var o=Test.AnotherWay._g_record_events[i];
1988 if( n=="time" ) { // convert to relative time
1989 var cur_time=o[n]-0;
1990 o[n]=cur_time-prev_time;
1993 s+=n_first ? n : ", "+n;
2002 s+= i==Test.AnotherWay._g_record_events.length-1 ? "}" : "},";
2009 Test.AnotherWay._g_record_border; // border highlighting element under cursor
2010 Test.AnotherWay._g_record_border_flashes=[]; // array of { color: color, timeout: milliseconds }
2011 Test.AnotherWay._g_record_border_flashing=false;
2012 Test.AnotherWay._g_record_border_normal_color="#d4b";
2013 Test.AnotherWay._record_flash_border_timeout=function()
2015 var color=Test.AnotherWay._g_record_border_normal_color;
2017 if( Test.AnotherWay._g_record_border_flashes.length!=0 ) {
2018 color=Test.AnotherWay._g_record_border_flashes[0].color;
2019 timeout=Test.AnotherWay._g_record_border_flashes[0].timeout;
2020 Test.AnotherWay._g_record_border_flashes.splice( 0, 1 );
2022 if( Test.AnotherWay._g_record_border!=null ) {
2023 for( var i=0; i<Test.AnotherWay._g_record_border.length; ++i ) {
2024 Test.AnotherWay._g_record_border[i].style.backgroundColor=color;
2027 if( timeout!=null ) {
2028 setTimeout( Test.AnotherWay._record_flash_border_timeout, timeout );
2030 Test.AnotherWay._g_record_border_flashing=false;
2033 Test.AnotherWay._get_page_coords=function( elm )
2035 var point = { x: 0, y: 0 };
2037 point.x+=elm.offsetLeft;
2038 point.y+=elm.offsetTop;
2039 elm=elm.offsetParent;
2043 Test.AnotherWay._set_page_coords=function( elm, x, y )
2045 var parent_coords={ x: 0, y: 0 };
2046 if( elm.offsetParent ) {
2047 parent_coords=Test.AnotherWay._get_page_coords( elm.offsetParent );
2049 var new_x=x-parent_coords.x;
2053 elm.style.left=new_x+'px';
2054 var new_y=y-parent_coords.y;
2058 elm.style.top=new_y+'px';
2060 Test.AnotherWay._record_setup_highlight_positions=function( element, style, coords, positions )
2062 if( style=="border" ) {
2063 var width=element.clientWidth;
2064 var height=element.clientHeight;
2068 positions.push( { x: coords.x-step-thickness, y: coords.y-step-thickness, width: width+2*step+2*thickness+fudge_expand, height: thickness } );
2069 positions.push( { x: coords.x+width+step+fudge_expand, y: coords.y-step-thickness, width: thickness, height: height+2*step+2*thickness+fudge_expand } );
2070 positions.push( { x:positions[0].x, y:positions[0].y, width:positions[0].width, height:positions[0].height } );
2071 positions.push( { x:positions[1].x, y:positions[1].y, width:positions[1].width, height:positions[1].height } );
2072 positions[2].y+=height+thickness+2*step+fudge_expand;
2073 positions[3].x-=width+thickness+2*step+fudge_expand;
2074 }else if( style=="ball" ) {
2075 positions.push( { x: coords.x+2, y: coords.y, width: 2, height: 6 } );
2076 positions.push( { x: coords.x, y: coords.y+2, width: 6, height: 2 } );
2077 positions.push( { x: coords.x+1, y: coords.y+1, width: 4, height: 4 } );
2080 Test.AnotherWay._record_highlight_border=function( element, style, event ) // null - hide border
2082 if( element!=null ) {
2083 if( Test.AnotherWay._g_record_border==null || Test.AnotherWay._g_record_border[0].ownerDocument!=element.ownerDocument ) {
2084 Test.AnotherWay._g_record_border=[];
2085 var n= style=="border" ? 4 : style=="ball" ? 3 : 0;
2086 for( var i=0; i<4; ++i ) {
2087 var b=element.ownerDocument.createElement( "div" );
2088 b.style.position="absolute";
2090 b.style.backgroundColor=Test.AnotherWay._g_record_border_normal_color;
2091 element.ownerDocument.body.appendChild( b );
2092 Test.AnotherWay._g_record_border.push( b );
2096 if( style=="border" ) {
2097 coords=Test.AnotherWay._get_page_coords( element );
2098 }else if( style=="ball" ) {
2100 if( event.pageX!=null && event.pageY!=null ) {
2101 coords={ x: event.pageX-0, y: event.pageY-0 };
2102 }else if( event.clientX!=null && event.clientY!=null ) {
2103 var doc=element.ownerDocument;
2105 coords={ x: (event.clientX-0)+doc.body.scrollLeft, y: (event.clientY-0)+doc.body.scrollTop };
2110 if( coords!=null && element.clientWidth!=null && element.clientHeight!=null ) {
2112 Test.AnotherWay._record_setup_highlight_positions( element, style, coords, positions );
2113 for( var i=0; i<positions.length; ++i ) {
2114 var b=Test.AnotherWay._g_record_border[i];
2116 Test.AnotherWay._set_page_coords( b, p.x, p.y );
2117 b.style.width=p.width+"px";
2118 b.style.height=p.height+"px";
2119 b.style.display="block";
2123 if( Test.AnotherWay._g_record_border!=null ) {
2124 for( var i=0; i<Test.AnotherWay._g_record_border.length; ++i ) {
2125 Test.AnotherWay._g_record_border[i].style.display="none";
2130 Test.AnotherWay._record_flash_border=function( color )
2132 if( Test.AnotherWay._g_record_border_flashing ) { //already
2133 Test.AnotherWay._g_record_border_flashes.push( { color: Test.AnotherWay._g_record_border_normal_color, timeout:300 } );
2134 Test.AnotherWay._g_record_border_flashes.push( { color: color, timeout:600 } );
2136 Test.AnotherWay._g_record_border_flashing=true;
2137 Test.AnotherWay._g_record_border_flashes.push( { color: color, timeout:600 } );
2138 Test.AnotherWay._record_flash_border_timeout();
2141 Test.AnotherWay._record_prepare_doc_for_results=function()
2144 document.write( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">" );
2145 document.write( "<html><head><title> Input recording results</title>" );
2146 document.write( "<style type=\"text/css\">" );
2147 document.write( "body { font: normal normal smaller sans-serif; }" );
2148 document.write( "div { margin-top: 3px; }" );
2149 document.write( "</style></head><body>" );
2150 // opera and mozilla disagree over who the opener is.
2151 if( typeof( window.opener.Test )!="undefined" && typeof( window.opener.Test.AnotherWay )!="undefined" ) {
2152 window.opener.Test.AnotherWay._record_save_results( document );
2153 window.opener.Test.AnotherWay._g_record_waiting_for_results=false;
2154 window.opener.Test.AnotherWay._record_control_update_ui();
2155 }else if( typeof( window.opener.opener.Test )!="undefined" && typeof( window.opener.opener.Test.AnotherWay )!="undefined" ) {
2156 window.opener.opener.Test.AnotherWay._record_save_results( document );
2157 window.opener.opener.Test.AnotherWay._g_record_waiting_for_results=false;
2158 window.opener.opener.Test.AnotherWay._record_control_update_ui();
2160 document.write( "</body>" );
2164 // global initialization
2167 if( window.opera ) {
2168 var good_opera=typeof( window.opera.version )=="function";
2169 good_opera=good_opera && window.opera.version().match( /^\s*(\d+)/ );
2170 good_opera=good_opera && RegExp.$1>=8;
2172 var span=document.createElement( "SPAN" );
2173 span.innerHTML="<!--[if IE]><br /><![endif]-"+"->";
2174 var is_ie=span.getElementsByTagName( "BR" ).length>0;
2176 Test.AnotherWay._g_test_iframe=window.frames.test_iframe;
2178 var query_str=window.location.search;
2179 if( query_str.charAt( 0 )=="?" ) {
2180 query_str=query_str.substring( 1 );
2182 var testlist_page="list-tests.html";
2184 if( query_str!="" ) {
2185 var params=[query_str];
2186 if( query_str.indexOf( ";" )!=-1 ) {
2187 params=query_str.split( ";" );
2188 }else if( query_str.indexOf( "&" )!=-1 ) {
2189 params=query_str.split( "&" );
2191 for( var param_i=0; param_i<params.length; ++param_i ) {
2192 var param=params[param_i].split( "=" );
2193 if( param[0]=="recording_results" ) {
2194 if( window.opener!=null ) {
2195 // we were told to show recording results - replace everything in the document with the results
2196 Test.AnotherWay._record_prepare_doc_for_results();
2199 }else if( param[0]=="testpage" ) {
2200 Test.AnotherWay._add_test_page_url( decodeURIComponent( param[1] ), "anotherway" );
2201 }else if( param[0]=="jsantestpage" ) {
2202 Test.AnotherWay._add_test_page_url( decodeURIComponent( param[1] ), "jsan" );
2203 }else if( param[0]=="testlist" ) {
2204 testlist_page=decodeURIComponent( param[1] );
2205 }else if( param[0]=="testframe" ) {
2206 if( window.opera && !good_opera ) {
2207 Test.AnotherWay._show_error( "testframe parameter does not work in versions of Opera prior to 8.0. Sorry (pathches are welcome)." );
2208 // Opera 7 barfs on attempt to access frame.frameElement.
2209 // if someone knows a way to assign onload handler to that iframe in Opera 7
2210 // without disrupting code that works in other browsers, patches are welcome.
2212 var frame_path=param[1].split( "." );
2214 for( var frame_path_i=0; frame_path_i<frame_path.length; ++frame_path_i ) {
2215 frame=frame[frame_path[frame_path_i]];
2218 Test.AnotherWay._show_error( "unable to find frame specified for loading test pages: "+param[1] );
2220 if( frame.frameElement!=null ) { // for the following assignement to onload to work, frameElement is required
2221 frame=frame.frameElement;
2223 Test.AnotherWay._g_test_iframe=frame;
2226 }else if( param[0]=="testframe_no_clear" ) {
2227 Test.AnotherWay._g_test_frame_no_clear=true;
2228 }else if( param[0]=="windows" ) {
2229 if (param[1] == "none") {
2230 Test.AnotherWay._test_object_t.prototype.open_window=null;
2232 }else if( param[0]=="run" ) {
2234 if( param[1]=="all" ) {
2235 Test.AnotherWay._g_pages_to_run="all";
2237 if( Test.AnotherWay._g_pages_to_run==null || Test.AnotherWay._g_pages_to_run=="all" ) {
2238 Test.AnotherWay._g_pages_to_run=[];
2240 var pages=param[1].split( "," );
2241 for( var i=0; i<pages.length; ++i ) {
2242 Test.AnotherWay._g_pages_to_run.push( pages[i] );
2248 if( Test.AnotherWay._g_test_page_urls.length==0 ) { // if no individual pages were given on the command line, load the list
2249 var result=Test.AnotherWay._set_iframe_location( window.frames["list_iframe"], testlist_page );
2250 if( result.msg!=null ) {
2251 Test.AnotherWay._show_error( result.msg );
2253 Test.AnotherWay._g_run_on_list_load=auto_run;
2255 Test.AnotherWay._g_run_on_main_load=auto_run;
2258 var f=Test.AnotherWay._g_test_iframe;
2260 if( f.attachEvent!=null ) {
2261 f.attachEvent( "onload", Test.AnotherWay._test_page_onload );
2263 f.onload=Test.AnotherWay._test_page_onload;
2265 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.
2266 Test.AnotherWay._g_test_iframe=Test.AnotherWay._g_test_iframe.contentWindow;
2269 // ignore stupid opera error if the frame has onload handler assigned in the inline html
2272 "run_all": { "onclick": Test.AnotherWay._run_all_onclick },
2273 "run_selected": { "onclick": Test.AnotherWay._run_selected_onclick },
2274 "unselect_all": { "onclick": Test.AnotherWay._unselect_all_onclick },
2275 "record_select": { "onfocus": Test.AnotherWay._record_check_onfocus },
2276 "record_input": { "onfocus": Test.AnotherWay._record_check_onfocus },
2277 "record_start": { "onclick": Test.AnotherWay._record_start_onclick },
2278 "clear_btn": { "onclick": Test.AnotherWay._results_clear_onclick },
2279 "results_tab": { "onclick": Test.AnotherWay._tab_onclick, "onmouseover": Test.AnotherWay._tab_mouseover, "onmouseout": Test.AnotherWay._tab_mouseout },
2280 "debug_tab": { "onclick": Test.AnotherWay._tab_onclick, "onmouseover": Test.AnotherWay._tab_mouseover, "onmouseout": Test.AnotherWay._tab_mouseout }
2282 for( var hs in handlers ) {
2283 var o=document.getElementById( hs );
2285 for( var h in handlers[hs] ) {
2286 o[h]=handlers[hs][h];
2289 Test.AnotherWay._show_error( "unable to set "+h+" handler: id "+hs+" not found" );
2293 if( window.opera && !good_opera ) {
2294 Test.AnotherWay._g_no_record_msg="Input events recording and replaying is not available in opera versions prior to 8.0.";
2297 Test.AnotherWay._g_no_record_msg="Input events recording and replaying is not available in internet explorer.";
2299 if( Test.AnotherWay._g_no_record_msg!=null ) {
2300 var no_record_p=document.getElementById( "record_not_supported" );
2301 no_record_p.style.display="block";
2302 no_record_p.appendChild( document.createTextNode( Test.AnotherWay._g_no_record_msg ) );
2305 Test.AnotherWay._g_main_loaded=true;
2306 if( Test.AnotherWay._g_run_on_main_load ) {
2307 Test.AnotherWay._g_run_on_main_load=false;
2308 Test.AnotherWay._run_pages_to_run();
2313 <script type="text/javascript" src="xml_eq.js"></script>
2314 <script type="text/javascript" src="geom_eq.js"></script>
2318 <div id="col1_header">Test pages:</div>
2320 <table id="testtable">
2323 <div id="run_buttons">
2324 <input type="button" value=" clear " id="clear_btn" />
2325 <input type="button" value=" run all " id="run_all" />
2326 <input type="button" value=" run selected " id="run_selected" />
2327 <input type="button" value=" unselect all " id="unselect_all" />
2329 <input type="checkbox" id="dont_close_test_windows" /> do not close windows opened by tests
2330 <div id="error"></div>
2331 <div id="record_div">
2332 <p id="record_not_supported" style="display:none"></p>
2333 <p>Record mouse input for the page:</p>
2334 <p><input type="radio" name="record_choose" value="select" checked="checked" /> <select id="record_select"><option selected="selected">-- select a page: --</option></select></p>
2335 <p><input type="radio" name="record_choose" value="input" /> or enter page url: <input type="text" id="record_input" /></p>
2336 <p><input type="button" value=" record " id="record_start" /></p>
2341 <div id="right_header">
2342 <span id="results_count">Results: <span id="total"></span></span>
2343 <span id="results_tab" class="active_tab" style="visibility:hidden">Results</span>
2344 <span id="debug_tab" class="inactive_tab" style="visibility:hidden">Debug</span>
2346 <div id="right_frame">
2347 <div id="results"></div>
2348 <div id="debug"></div>
2352 <span style="display:none">
2353 <iframe name="list_iframe" onload="Test.AnotherWay._list_iframe_onload();"></iframe>
2354 <iframe name="test_iframe" onload="Test.AnotherWay._test_page_onload();"></iframe>
2356 <!-- record_control div is to be imported into other documents, so all its styles are inline -->
2357 -<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">
2359 <p style="margin:0 0 0 0; padding:0">
2361 <span style="display:none;font-weight:bold;color:#408" id="record_indicator">
2362 recording. <span style="font-weight:normal">time: <span id="record_time"></span></span><span id="record_pause_indicator"> paused</span>
2366 <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>
2367 <p style="margin:2px 0 0 0; padding:0">
2371 <p style="margin:8px 0 0 0; padding:0;">
2372 keyboard control: press
2373 <span id="record_ctrl_key" style="border:1px solid #226;background:#adf;padding:0 0.5em">ctrl</span> -
2374 <span id="record_shift_key" style="border:1px solid #226;background:#adf;padding:0 0.5em">shift</span> -
2377 <p style="margin:4px 0 0 0; padding:0">
2378 <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>
2379 <span id="record_on">to <b>start</b> recording</span>
2380 <span id="record_off" style="display:none">to <b>stop</b> recording</span>
2383 <p style="margin:4px 0 0 0; padding:0">
2384 <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>
2385 <span>to <b>hide/show</b> this window</span>
2388 <p style="margin:4px 0 0 0; padding:0">
2389 <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>
2390 <span id="record_include_mousemove">to <b> record</b> mousemove</span>
2391 <span id="record_omit_mousemove" style="display:none">to <b>omit</b> mousemove</span>
2394 <p style="margin:4px 0 0 0; padding:0">
2395 <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>
2396 <span id="record_pause_on">to <b> pause</b> recording</span>
2397 <span id="record_pause_off" style="display:none">to <b>continue</b> recording</span>
2400 <p style="margin:4px 0 0 0; padding:0">
2401 <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>
2402 <span>to add checkpoint</span>
2405 <p style="margin:6px 0 0 0; padding:0">
2408 <div id="record_checkpoints" style="position:relative;width:100%;height:6em;overflow:auto;font: normal normal 8pt sans-serif; color:#000; text-align: left">