Centralize QUnit customizations for MediaWiki:
authorKrinkle <krinkle@users.mediawiki.org>
Sun, 10 Jul 2011 19:10:51 +0000 (19:10 +0000)
committerKrinkle <krinkle@users.mediawiki.org>
Sun, 10 Jul 2011 19:10:51 +0000 (19:10 +0000)
- Rename 'awesome.js' to 'defineTestCallback.js' (more descriptive)
- Move all runner customizations into 'testrunner.js'
- Move all customization files into /data
- Fix bug in jquery.qunit.completenesstest that sometimes caused the element to be re-created if it was ran again from the console.
- Centralize additional assertion helpers in testrunner.js

resources/jquery/jquery.qunit.completenessTest.js
tests/qunit/data/defineTestCallback.js [new file with mode: 0644]
tests/qunit/data/testrunner.js [new file with mode: 0644]
tests/qunit/data/testwarm.inject.js [new file with mode: 0644]
tests/qunit/index.html
tests/qunit/jquery.qunit.completenessTest.config.js [deleted file]
tests/qunit/sample/awesome.js [deleted file]
tests/qunit/suites/resources/jquery/jquery.autoEllipsis.js
tests/qunit/suites/resources/mediawiki/mediawiki.js
tests/qunit/testswarm.inject.js [deleted file]

index 7d4f346..2244237 100644 (file)
@@ -67,7 +67,9 @@ var CompletenessTest = function ( masterVariable, ignoreFn ) {
                                html += '<br />' + mw.html.escape(key);
                        });
                        html += '<br /><br /><em>&mdash; CompletenessTest</em>';
-                       return $( '<div>' ).css( style ).append( html );
+                       var     $oldResult = $( '#qunit-completenesstest' ),
+                               $result = $oldResult.length ? $oldResult : $( '<div id="qunit-completenesstest"></div>' );
+                       return $result.css( style ).html( html );
                };
 
                if ( $.isEmptyObject( that.missingTests ) ) {
diff --git a/tests/qunit/data/defineTestCallback.js b/tests/qunit/data/defineTestCallback.js
new file mode 100644 (file)
index 0000000..6fcd459
--- /dev/null
@@ -0,0 +1,4 @@
+window.mw.loader.testCallback = function() {
+       start();
+       ok( true, 'Implementing a module, is the callback timed properly ?');
+};
diff --git a/tests/qunit/data/testrunner.js b/tests/qunit/data/testrunner.js
new file mode 100644 (file)
index 0000000..446add1
--- /dev/null
@@ -0,0 +1,96 @@
+( function( $ ) {
+
+/**
+ * Add bogus to url to prevent IE crazy caching
+ *
+ * @param value {String} a relative path (eg. 'data/defineTestCallback.js' or 'data/test.php?foo=bar')
+ * @return {String} Such as 'data/defineTestCallback.js?131031765087663960'
+ */
+QUnit.fixurl = function(value) {
+       return value + (/\?/.test(value) ? "&" : "?") + new Date().getTime() + "" + parseInt(Math.random()*100000);
+};
+
+/**
+ *  Load TestSwarm agent
+ */
+if ( QUnit.urlParams.swarmURL  ) {
+       document.write("<scr" + "ipt src='" + QUnit.fixurl( 'data/testwarm.inject.js' ) + "'></scr" + "ipt>");
+}
+
+/**
+ * Load completenesstest
+ */
+if ( QUnit.urlParams.completenesstest ) {
+
+       // Return true to ignore
+       var mwTestIgnore = function( val, tester, funcPath ) {
+
+               // Don't record methods of the properties of constructors,
+               // to avoid getting into a loop (prototype.constructor.prototype..).
+               // Since we're therefor skipping any injection for
+               // "new mw.Foo()", manually set it to true here.
+               if ( val instanceof mw.Map ) {
+                       tester.methodCallTracker['Map'] = true;
+                       return true;
+               }
+               if ( val instanceof mw.Title ) {
+                       tester.methodCallTracker['Title'] = true;
+                       return true;
+               }
+
+               // Don't record methods of the properties of a jQuery object
+               if ( val instanceof $ ) {
+                       return true;
+               }
+
+               return false;
+       };
+
+       var mwTester = new CompletenessTest( mw, mwTestIgnore );
+}
+
+/**
+ * Add-on assertion helpers
+ */
+// Define the add-ons
+var addons = {
+
+       // Expect boolean true
+       assertTrue: function( actual, message ) {
+               strictEqual( actual, true, message );
+       },
+
+       // Expect boolean false
+       assertFalse: function( actual, message ) {
+               strictEqual( actual, false, message );
+       },
+
+       // Expect numerical value less than X
+       lt: function( actual, expected, message ) {
+               QUnit.push( actual < expected, actual, 'less than ' + expected, message );
+       },
+
+       // Expect numerical value less than or equal to X
+       ltOrEq: function( actual, expected, message ) {
+               QUnit.push( actual <= expected, actual, 'less than or equal to ' + expected, message );
+       },
+
+       // Expect numerical value greater than X
+       gt: function( actual, expected, message ) {
+               QUnit.push( actual > expected, actual, 'greater than ' + expected, message );
+       },
+
+       // Expect numerical value greater than or equal to X
+       gtOrEq: function( actual, expected, message ) {
+               QUnit.push( actual >= expected, actual, 'greater than or equal to ' + expected, message );
+       },
+
+       // Backwards compatible with new verions of QUnit
+       equals: window.equal,
+       same: window.deepEqual
+};
+
+$.extend( QUnit, addons );
+$.extend( window, addons );
+
+})( jQuery );
diff --git a/tests/qunit/data/testwarm.inject.js b/tests/qunit/data/testwarm.inject.js
new file mode 100644 (file)
index 0000000..14ee8f9
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+       Copyright (c) 2009 John Resig
+       
+       Permission is hereby granted, free of charge, to any person
+       obtaining a copy of this software and associated documentation
+       files (the "Software"), to deal in the Software without
+       restriction, including without limitation the rights to use,
+       copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the
+       Software is furnished to do so, subject to the following
+       conditions:
+       
+       The above copyright notice and this permission notice shall be
+       included in all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+       OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+       NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+       HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+       WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+       FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+       OTHER DEALINGS IN THE SOFTWARE.
+
+*/
+(function(){
+
+       var DEBUG = false;
+
+       var doPost = false;
+
+       try {
+               doPost = !!window.top.postMessage;
+       } catch(e){}
+
+       var search = window.location.search,
+               url, index;
+       if( ( index = search.indexOf( "swarmURL=" ) ) != -1 )
+               url = decodeURIComponent( search.slice( index + 9 ) );
+
+       if ( !DEBUG && (!url || url.indexOf("http") !== 0) ) {
+               return;
+       }
+
+       var submitTimeout = 5;
+
+       var curHeartbeat;
+       var beatRate = 20;
+
+       // Expose the TestSwarm API
+       window.TestSwarm = {
+               submit: submit,
+               heartbeat: function(){
+                       if ( curHeartbeat ) {
+                               clearTimeout( curHeartbeat );
+                       }
+
+                       curHeartbeat = setTimeout(function(){
+                               submit({ fail: -1, total: -1 });
+                       }, beatRate * 1000);
+               },
+               serialize: function(){
+                       return trimSerialize();
+               }
+       };
+
+       // Prevent careless things from executing
+       window.print = window.confirm = window.alert = window.open = function(){};
+
+       window.onerror = function(e){
+               document.body.appendChild( document.createTextNode( "ERROR: " + e ));
+               submit({ fail: 0, error: 1, total: 1 });
+               return false;
+       };
+
+       // QUnit (jQuery)
+       // http://docs.jquery.com/QUnit
+       if ( typeof QUnit !== "undefined" ) {
+               QUnit.done = function(results){
+                       submit({
+                               fail: results.failed,
+                               error: 0,
+                               total: results.total
+                       });
+               };
+
+               QUnit.log = window.TestSwarm.heartbeat;
+               window.TestSwarm.heartbeat();
+
+               window.TestSwarm.serialize = function(){
+                       // Clean up the HTML (remove any un-needed test markup)
+                       remove("nothiddendiv");
+                       remove("loadediframe");
+                       remove("dl");
+                       remove("main");
+
+                       // Show any collapsed results
+                       var ol = document.getElementsByTagName("ol");
+                       for ( var i = 0; i < ol.length; i++ ) {
+                               ol[i].style.display = "block";
+                       }
+
+                       return trimSerialize();
+               };
+
+       // UnitTestJS (Prototype, Scriptaculous)
+       // http://github.com/tobie/unittest_js/tree/master
+       } else if ( typeof Test !== "undefined" && Test && Test.Unit && Test.Unit.runners ) {
+               var total_runners = Test.Unit.runners.length, cur_runners = 0;
+               var total = 0, fail = 0, error = 0;
+
+               for (var i = 0; i < Test.Unit.runners.length; i++) (function(i){
+                       var finish = Test.Unit.runners[i].finish;
+                       Test.Unit.runners[i].finish = function(){
+                               finish.call( this );
+
+                               var results = this.getResult();
+                               total += results.assertions;
+                               fail += results.failures;
+                               error += results.errors;
+
+                               if ( ++cur_runners === total_runners ) {
+                                       submit({
+                                               fail: fail,
+                                               error: error,
+                                               total: total
+                                       });
+                               }
+                       };
+               })(i);
+
+       // JSSpec (MooTools)
+       // http://jania.pe.kr/aw/moin.cgi/JSSpec
+       } else if ( typeof JSSpec !== "undefined" && JSSpec && JSSpec.Logger ) {
+               var onRunnerEnd = JSSpec.Logger.prototype.onRunnerEnd;
+               JSSpec.Logger.prototype.onRunnerEnd = function(){
+                       onRunnerEnd.call(this);
+
+                       // Show any collapsed results
+                       var ul = document.getElementsByTagName("ul");
+                       for ( var i = 0; i < ul.length; i++ ) {
+                               ul[i].style.display = "block";
+                       }
+
+                       submit({
+                               fail: JSSpec.runner.getTotalFailures(),
+                               error: JSSpec.runner.getTotalErrors(),
+                               total: JSSpec.runner.totalExamples
+                       });
+               };
+
+               window.TestSwarm.serialize = function(){
+                       // Show any collapsed results
+                       var ul = document.getElementsByTagName("ul");
+                       for ( var i = 0; i < ul.length; i++ ) {
+                               ul[i].style.display = "block";
+                       }
+
+                       return trimSerialize();
+               };
+
+       // JSUnit
+       // http://www.jsunit.net/
+       // Note: Injection file must be included before the frames
+       //       are document.write()d into the page.
+       } else if ( typeof JsUnitTestManager !== "undefined" ) {
+               var _done = JsUnitTestManager.prototype._done;
+               JsUnitTestManager.prototype._done = function(){
+                       _done.call(this);
+
+                       submit({
+                               fail: this.failureCount,
+                               error: this.errorCount,
+                               total: this.totalCount
+                       });
+               };
+
+               window.TestSwarm.serialize = function(){
+                       return "<pre>" + this.log.join("\n") + "</pre>";
+               };
+
+       // Selenium Core
+       // http://seleniumhq.org/projects/core/
+       } else if ( typeof SeleniumTestResult !== "undefined" && typeof LOG !== "undefined" ) {
+               // Completely overwrite the postback
+               SeleniumTestResult.prototype.post = function(){
+                       submit({
+                               fail: this.metrics.numCommandFailures,
+                               error: this.metrics.numCommandErrors,
+                               total: this.metrics.numCommandPasses + this.metrics.numCommandFailures + this.metrics.numCommandErrors
+                       });
+               };
+
+               window.TestSwarm.serialize = function(){
+                       var results = [];
+                       while ( LOG.pendingMessages.length ) {
+                               var msg = LOG.pendingMessages.shift();
+                               results.push( msg.type + ": " + msg.msg );
+                       }
+
+                       return "<pre>" + results.join("\n") + "</pre>";
+               };
+
+       // Dojo Objective Harness
+       // http://docs.dojocampus.org/quickstart/doh
+       } else if ( typeof doh !== "undefined" && doh._report ) {
+               var _report = doh._report;
+               doh._report = function(){
+                       _report.apply(this, arguments);
+
+                       submit({
+                               fail: doh._failureCount,
+                               error: doh._errorCount,
+                               total: doh._testCount
+                       });
+               };
+
+               window.TestSwarm.serialize = function(){
+                       return "<pre>" + document.getElementById("logBody").innerHTML + "</pre>";
+               };
+  // Screw.Unit
+  // git://github.com/nathansobo/screw-unit.git
+       } else if ( typeof Screw !== "undefined" && typeof jQuery !== 'undefined' && Screw && Screw.Unit ) {
+    $(Screw).bind("after", function() {
+     var passed = $('.passed').length;
+     var failed = $('.failed').length;
+     submit({
+        fail: failed,
+        error: 0,
+        total: failed + passed
+      });
+    });
+
+    $(Screw).bind("loaded", function() {
+      $('.it')
+        .bind("passed", window.TestSwarm.heartbeat)
+        .bind("failed", window.TestSwarm.heartbeat);
+      window.TestSwarm.heartbeat();
+    });
+
+    window.TestSwarm.serialize = function(){
+       return trimSerialize();
+    };
+  }
+
+       function trimSerialize(doc) {
+               doc = doc || document;
+
+               var scripts = doc.getElementsByTagName("script");
+               while ( scripts.length ) {
+                       remove( scripts[0] );
+               }
+
+               var root = window.location.href.replace(/(https?:\/\/.*?)\/.*/, "$1");
+               var cur = window.location.href.replace(/[^\/]*$/, "");
+
+               var links = doc.getElementsByTagName("link");
+               for ( var i = 0; i < links.length; i++ ) {
+                       var href = links[i].href;
+                       if ( href.indexOf("/") === 0 ) {
+                               href = root + href;
+                       } else if ( !/^https?:\/\//.test( href ) ) {
+                               href = cur + href;
+                       }
+                       links[i].href = href;
+               }
+
+               return ("<html>" + doc.documentElement.innerHTML + "</html>")
+                       .replace(/\s+/g, " ");
+       }
+
+       function remove(elem){
+               if ( typeof elem === "string" ) {
+                       elem = document.getElementById( elem );
+               }
+
+               if ( elem ) {
+                       elem.parentNode.removeChild( elem );
+               }
+       }
+
+       function submit(params){
+               if ( curHeartbeat ) {
+                       clearTimeout( curHeartbeat );
+               }
+
+               var paramItems = (url.split("?")[1] || "").split("&");
+
+               for ( var i = 0; i < paramItems.length; i++ ) {
+                       if ( paramItems[i] ) {
+                               var parts = paramItems[i].split("=");
+                               if ( !params[ parts[0] ] ) {
+                                       params[ parts[0] ] = parts[1];
+                               }
+                       }
+               }
+
+               if ( !params.state ) {
+                       params.state = "saverun";
+               }
+
+               if ( !params.results ) {
+                       params.results = window.TestSwarm.serialize();
+               }
+
+               if ( doPost ) {
+                       // Build Query String
+                       var query = "";
+
+                       for ( var i in params ) {
+                               query += ( query ? "&" : "" ) + i + "=" +
+                                       encodeURIComponent(params[i]);
+                       }
+
+                       if ( DEBUG ) {
+                               alert( query );
+                       } else {
+                               window.top.postMessage( query, "*" );
+                       }
+
+               } else {
+                       var form = document.createElement("form");
+                       form.action = url;
+                       form.method = "POST";
+
+                       for ( var i in params ) {
+                               var input = document.createElement("input");
+                               input.type = "hidden";
+                               input.name = i;
+                               input.value = params[i];
+                               form.appendChild( input );
+                       }
+
+                       if ( DEBUG ) {
+                               alert( form.innerHTML );
+                       } else {
+
+                               // Watch for the result submission timing out
+                               setTimeout(function(){
+                                       submit( params );
+                               }, submitTimeout * 1000);
+
+                               document.body.appendChild( form );
+                               form.submit();
+                       }
+               }
+       }
+
+})();
index f27aa99..69c5336 100644 (file)
@@ -51,6 +51,8 @@
        <!-- QUnit: Load framework -->
        <link rel="stylesheet" href="../../resources/jquery/jquery.qunit.css" />
        <script src="../../resources/jquery/jquery.qunit.js"></script>
+       <script src="../../resources/jquery/jquery.qunit.completenessTest.js"></script>
+       <script src="data/testrunner.js"></script>
 
        <!-- QUnit: Load test suites (maintain the same order as above please) -->
        <script src="suites/resources/mediawiki/mediawiki.js"></script>
        <script src="suites/resources/jquery/jquery.tablesorter.test.js" charset="UTF-8"></script>
        <script src="suites/resources/mediawiki/mediawiki.Title.js"></script>
        <script src="suites/resources/mediawiki.special/mediawiki.special.recentchanges.js"></script>
-
-       <!-- TestSwarm: If a test swarm is running this,
-            the following script will allow it to extract the results.
-            Harmless otherwise. -->
-       <script src="testswarm.inject.js"></script>
-
-       <!-- CompletenessTest -->
-       <script>
-               if ( QUnit.urlParams.completenesstest ) {
-                       document.write( '\x3Cscript src="../../resources/jquery/jquery.qunit.completenessTest.js">\x3C/script>' );
-                       document.write( '\x3Cscript src="jquery.qunit.completenessTest.config.js">\x3C/script>' );
-               }
-       </script>
 </head>
 <body>
        <h1 id="qunit-header">MediaWiki JavaScript Test Suite</h1>
diff --git a/tests/qunit/jquery.qunit.completenessTest.config.js b/tests/qunit/jquery.qunit.completenessTest.config.js
deleted file mode 100644 (file)
index c03ddc9..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// Return true to ignore
-var mwTestIgnore = function( val, tester, funcPath ) {
-
-       // Don't record methods of the properties of constructors,
-       // to avoid getting into a loop (prototype.constructor.prototype..).
-       // Since we're therefor skipping any injection for
-       // "new mw.Foo()", manually set it to true here.
-       if ( val instanceof mw.Map ) {
-               tester.methodCallTracker['Map'] = true;
-               return true;
-       }
-       if ( val instanceof mw.Title ) {
-               tester.methodCallTracker['Title'] = true;
-               return true;
-       }
-
-       // Don't record methods of the properties of a jQuery object
-       if ( val instanceof $ ) {
-               return true;
-       }
-
-       return false;
-};
-
-var mwTester = new CompletenessTest( mw, mwTestIgnore );
diff --git a/tests/qunit/sample/awesome.js b/tests/qunit/sample/awesome.js
deleted file mode 100644 (file)
index d7852e3..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-window.mw.loader.testCallback = function(){
-       start();
-       ok( true, 'Implementing a module, is the callback timed properly ?');
-};
index 62c94f0..caf5a6f 100644 (file)
@@ -23,27 +23,6 @@ function findDivergenceIndex( a, b ) {
 test( 'Position right', function() {
        expect(4);
 
-       /**
-        * Extra QUnit assertions
-        * Needed in order to include the expected and actual values in the output.
-        * This way we end up with:
-        * "Expected: > 100, Result: 99"
-        * instead of:
-        * "Expected: true, Result: false"
-        */
-       // Expect numerical value less than or equal to X
-       var ltOrEq = function( actual, expected, message ) {
-               QUnit.push( actual <= expected, actual, 'less than or equal to ' + expected, message );
-       };
-       // Expect numerical value greater than X
-       var gt = function( actual, expected, message ) {
-               QUnit.push( actual > expected, actual, 'greater than ' + expected, message );
-       };
-       // Expect numerical value greater than or equal to X
-       var gtOrEq = function( actual, expected, message ) {
-               QUnit.push( actual >= expected, actual, 'greater than or equal to ' + expected, message );
-       };
-
        // We need this thing to be visible, so append it to the DOM
        var origText = 'This is a really long random string and there is no way it fits in 100 pixels.';
        var $wrapper = createWrappedDiv( origText, '100px' );
index 9444dbd..3ebd9ca 100644 (file)
@@ -159,7 +159,7 @@ test( 'mw.loader', function() {
        // Extract path
        var tests_path = rePath.exec( location.href );
 
-       mw.loader.implement( 'is.awesome', [tests_path + 'sample/awesome.js'], {}, {} );
+       mw.loader.implement( 'is.awesome', [QUnit.fixurl( tests_path + 'data/defineTestCallback.js')], {}, {} );
 
        mw.loader.using( 'is.awesome', function() {
 
diff --git a/tests/qunit/testswarm.inject.js b/tests/qunit/testswarm.inject.js
deleted file mode 100644 (file)
index 14ee8f9..0000000
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
-       Copyright (c) 2009 John Resig
-       
-       Permission is hereby granted, free of charge, to any person
-       obtaining a copy of this software and associated documentation
-       files (the "Software"), to deal in the Software without
-       restriction, including without limitation the rights to use,
-       copy, modify, merge, publish, distribute, sublicense, and/or sell
-       copies of the Software, and to permit persons to whom the
-       Software is furnished to do so, subject to the following
-       conditions:
-       
-       The above copyright notice and this permission notice shall be
-       included in all copies or substantial portions of the Software.
-       
-       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-       OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-       NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-       HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-       WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-       FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-       OTHER DEALINGS IN THE SOFTWARE.
-
-*/
-(function(){
-
-       var DEBUG = false;
-
-       var doPost = false;
-
-       try {
-               doPost = !!window.top.postMessage;
-       } catch(e){}
-
-       var search = window.location.search,
-               url, index;
-       if( ( index = search.indexOf( "swarmURL=" ) ) != -1 )
-               url = decodeURIComponent( search.slice( index + 9 ) );
-
-       if ( !DEBUG && (!url || url.indexOf("http") !== 0) ) {
-               return;
-       }
-
-       var submitTimeout = 5;
-
-       var curHeartbeat;
-       var beatRate = 20;
-
-       // Expose the TestSwarm API
-       window.TestSwarm = {
-               submit: submit,
-               heartbeat: function(){
-                       if ( curHeartbeat ) {
-                               clearTimeout( curHeartbeat );
-                       }
-
-                       curHeartbeat = setTimeout(function(){
-                               submit({ fail: -1, total: -1 });
-                       }, beatRate * 1000);
-               },
-               serialize: function(){
-                       return trimSerialize();
-               }
-       };
-
-       // Prevent careless things from executing
-       window.print = window.confirm = window.alert = window.open = function(){};
-
-       window.onerror = function(e){
-               document.body.appendChild( document.createTextNode( "ERROR: " + e ));
-               submit({ fail: 0, error: 1, total: 1 });
-               return false;
-       };
-
-       // QUnit (jQuery)
-       // http://docs.jquery.com/QUnit
-       if ( typeof QUnit !== "undefined" ) {
-               QUnit.done = function(results){
-                       submit({
-                               fail: results.failed,
-                               error: 0,
-                               total: results.total
-                       });
-               };
-
-               QUnit.log = window.TestSwarm.heartbeat;
-               window.TestSwarm.heartbeat();
-
-               window.TestSwarm.serialize = function(){
-                       // Clean up the HTML (remove any un-needed test markup)
-                       remove("nothiddendiv");
-                       remove("loadediframe");
-                       remove("dl");
-                       remove("main");
-
-                       // Show any collapsed results
-                       var ol = document.getElementsByTagName("ol");
-                       for ( var i = 0; i < ol.length; i++ ) {
-                               ol[i].style.display = "block";
-                       }
-
-                       return trimSerialize();
-               };
-
-       // UnitTestJS (Prototype, Scriptaculous)
-       // http://github.com/tobie/unittest_js/tree/master
-       } else if ( typeof Test !== "undefined" && Test && Test.Unit && Test.Unit.runners ) {
-               var total_runners = Test.Unit.runners.length, cur_runners = 0;
-               var total = 0, fail = 0, error = 0;
-
-               for (var i = 0; i < Test.Unit.runners.length; i++) (function(i){
-                       var finish = Test.Unit.runners[i].finish;
-                       Test.Unit.runners[i].finish = function(){
-                               finish.call( this );
-
-                               var results = this.getResult();
-                               total += results.assertions;
-                               fail += results.failures;
-                               error += results.errors;
-
-                               if ( ++cur_runners === total_runners ) {
-                                       submit({
-                                               fail: fail,
-                                               error: error,
-                                               total: total
-                                       });
-                               }
-                       };
-               })(i);
-
-       // JSSpec (MooTools)
-       // http://jania.pe.kr/aw/moin.cgi/JSSpec
-       } else if ( typeof JSSpec !== "undefined" && JSSpec && JSSpec.Logger ) {
-               var onRunnerEnd = JSSpec.Logger.prototype.onRunnerEnd;
-               JSSpec.Logger.prototype.onRunnerEnd = function(){
-                       onRunnerEnd.call(this);
-
-                       // Show any collapsed results
-                       var ul = document.getElementsByTagName("ul");
-                       for ( var i = 0; i < ul.length; i++ ) {
-                               ul[i].style.display = "block";
-                       }
-
-                       submit({
-                               fail: JSSpec.runner.getTotalFailures(),
-                               error: JSSpec.runner.getTotalErrors(),
-                               total: JSSpec.runner.totalExamples
-                       });
-               };
-
-               window.TestSwarm.serialize = function(){
-                       // Show any collapsed results
-                       var ul = document.getElementsByTagName("ul");
-                       for ( var i = 0; i < ul.length; i++ ) {
-                               ul[i].style.display = "block";
-                       }
-
-                       return trimSerialize();
-               };
-
-       // JSUnit
-       // http://www.jsunit.net/
-       // Note: Injection file must be included before the frames
-       //       are document.write()d into the page.
-       } else if ( typeof JsUnitTestManager !== "undefined" ) {
-               var _done = JsUnitTestManager.prototype._done;
-               JsUnitTestManager.prototype._done = function(){
-                       _done.call(this);
-
-                       submit({
-                               fail: this.failureCount,
-                               error: this.errorCount,
-                               total: this.totalCount
-                       });
-               };
-
-               window.TestSwarm.serialize = function(){
-                       return "<pre>" + this.log.join("\n") + "</pre>";
-               };
-
-       // Selenium Core
-       // http://seleniumhq.org/projects/core/
-       } else if ( typeof SeleniumTestResult !== "undefined" && typeof LOG !== "undefined" ) {
-               // Completely overwrite the postback
-               SeleniumTestResult.prototype.post = function(){
-                       submit({
-                               fail: this.metrics.numCommandFailures,
-                               error: this.metrics.numCommandErrors,
-                               total: this.metrics.numCommandPasses + this.metrics.numCommandFailures + this.metrics.numCommandErrors
-                       });
-               };
-
-               window.TestSwarm.serialize = function(){
-                       var results = [];
-                       while ( LOG.pendingMessages.length ) {
-                               var msg = LOG.pendingMessages.shift();
-                               results.push( msg.type + ": " + msg.msg );
-                       }
-
-                       return "<pre>" + results.join("\n") + "</pre>";
-               };
-
-       // Dojo Objective Harness
-       // http://docs.dojocampus.org/quickstart/doh
-       } else if ( typeof doh !== "undefined" && doh._report ) {
-               var _report = doh._report;
-               doh._report = function(){
-                       _report.apply(this, arguments);
-
-                       submit({
-                               fail: doh._failureCount,
-                               error: doh._errorCount,
-                               total: doh._testCount
-                       });
-               };
-
-               window.TestSwarm.serialize = function(){
-                       return "<pre>" + document.getElementById("logBody").innerHTML + "</pre>";
-               };
-  // Screw.Unit
-  // git://github.com/nathansobo/screw-unit.git
-       } else if ( typeof Screw !== "undefined" && typeof jQuery !== 'undefined' && Screw && Screw.Unit ) {
-    $(Screw).bind("after", function() {
-     var passed = $('.passed').length;
-     var failed = $('.failed').length;
-     submit({
-        fail: failed,
-        error: 0,
-        total: failed + passed
-      });
-    });
-
-    $(Screw).bind("loaded", function() {
-      $('.it')
-        .bind("passed", window.TestSwarm.heartbeat)
-        .bind("failed", window.TestSwarm.heartbeat);
-      window.TestSwarm.heartbeat();
-    });
-
-    window.TestSwarm.serialize = function(){
-       return trimSerialize();
-    };
-  }
-
-       function trimSerialize(doc) {
-               doc = doc || document;
-
-               var scripts = doc.getElementsByTagName("script");
-               while ( scripts.length ) {
-                       remove( scripts[0] );
-               }
-
-               var root = window.location.href.replace(/(https?:\/\/.*?)\/.*/, "$1");
-               var cur = window.location.href.replace(/[^\/]*$/, "");
-
-               var links = doc.getElementsByTagName("link");
-               for ( var i = 0; i < links.length; i++ ) {
-                       var href = links[i].href;
-                       if ( href.indexOf("/") === 0 ) {
-                               href = root + href;
-                       } else if ( !/^https?:\/\//.test( href ) ) {
-                               href = cur + href;
-                       }
-                       links[i].href = href;
-               }
-
-               return ("<html>" + doc.documentElement.innerHTML + "</html>")
-                       .replace(/\s+/g, " ");
-       }
-
-       function remove(elem){
-               if ( typeof elem === "string" ) {
-                       elem = document.getElementById( elem );
-               }
-
-               if ( elem ) {
-                       elem.parentNode.removeChild( elem );
-               }
-       }
-
-       function submit(params){
-               if ( curHeartbeat ) {
-                       clearTimeout( curHeartbeat );
-               }
-
-               var paramItems = (url.split("?")[1] || "").split("&");
-
-               for ( var i = 0; i < paramItems.length; i++ ) {
-                       if ( paramItems[i] ) {
-                               var parts = paramItems[i].split("=");
-                               if ( !params[ parts[0] ] ) {
-                                       params[ parts[0] ] = parts[1];
-                               }
-                       }
-               }
-
-               if ( !params.state ) {
-                       params.state = "saverun";
-               }
-
-               if ( !params.results ) {
-                       params.results = window.TestSwarm.serialize();
-               }
-
-               if ( doPost ) {
-                       // Build Query String
-                       var query = "";
-
-                       for ( var i in params ) {
-                               query += ( query ? "&" : "" ) + i + "=" +
-                                       encodeURIComponent(params[i]);
-                       }
-
-                       if ( DEBUG ) {
-                               alert( query );
-                       } else {
-                               window.top.postMessage( query, "*" );
-                       }
-
-               } else {
-                       var form = document.createElement("form");
-                       form.action = url;
-                       form.method = "POST";
-
-                       for ( var i in params ) {
-                               var input = document.createElement("input");
-                               input.type = "hidden";
-                               input.name = i;
-                               input.value = params[i];
-                               form.appendChild( input );
-                       }
-
-                       if ( DEBUG ) {
-                               alert( form.innerHTML );
-                       } else {
-
-                               // Watch for the result submission timing out
-                               setTimeout(function(){
-                                       submit( params );
-                               }, submitTimeout * 1000);
-
-                               document.body.appendChild( form );
-                               form.submit();
-                       }
-               }
-       }
-
-})();