diff --git a/console/harness/doneprintHandle.js b/console/harness/doneprintHandle.js
new file mode 100644
index 0000000000000000000000000000000000000000..317aa9c4efc29df39db9b31c97da6c5226157b3f
--- /dev/null
+++ b/console/harness/doneprintHandle.js
@@ -0,0 +1,10 @@
+function __consolePrintHandle__(msg){
+	print(msg);
+}
+
+function $DONE(){
+	if(arguments.length === 0)
+		__consolePrintHandle__('Test262:AsyncTestComplete');
+	else
+		__consolePrintHandle__('Error: ' + arguments[0]);
+}
\ No newline at end of file
diff --git a/console/harness/ed.js b/console/harness/ed.js
index 89d0dfc1ca40d3d31b45ba1057d337dbc7662bd5..88e2cecc49ba65601b7cee2fd2618529ed6b5664 100644
--- a/console/harness/ed.js
+++ b/console/harness/ed.js
@@ -8,6 +8,7 @@
 if (this.window!==undefined) {  //for console support
     this.window.onerror = function(errorMsg, url, lineNumber) {
         this.window.iframeError = errorMsg;
+        if(typeof $DONE === 'function') $DONE();
     };
 }
 
diff --git a/console/harness/gs.js b/console/harness/gs.js
index 210c08548f775bbd4fa29adfc5a11b6cf3d31265..855cb85bf40b5bf2527510a280dd151ddfd8b614 100644
--- a/console/harness/gs.js
+++ b/console/harness/gs.js
@@ -5,38 +5,60 @@
 /// copyright and this notice and otherwise comply with the Use Terms.
 
 //Global Scope Test Case Validator
+function $DONE() {
 
-//An exception is expected
-if (testDescrip.negative !== undefined) {
-    //TODO - come up with a generic way of catching the error type
-    //from this.onerror
-    testDescrip.negative = testDescrip.negative === "NotEarlyError" ?
-            testDescrip.negative :
-        (testDescrip.negative === "^((?!NotEarlyError).)*$" ?
-            testDescrip.negative : ".");
-    if (this.iframeError === undefined) { //no exception was thrown
-        testRun(testDescrip.id,
-                testDescrip.path,
-                testDescrip.description,
-                testDescrip.code,
-                'fail',
-                Error('No exception was thrown; expected an error "message"' +
-                      ' property matching the regular expression "' +
-                      testDescrip.negative + '".'));
-    } else if (!(new RegExp(testDescrip.negative,
-                            "i").test(this.iframeError))) {
-        //wrong type of exception thrown
+    //An exception is expected
+    if (testDescrip.negative !== undefined) {
+        //TODO - come up with a generic way of catching the error type
+        //from this.onerror
+        testDescrip.negative = testDescrip.negative === "NotEarlyError" ?
+                testDescrip.negative :
+            (testDescrip.negative === "^((?!NotEarlyError).)*$" ?
+                testDescrip.negative : ".");
+        if (this.iframeError === undefined) { //no exception was thrown
+            testRun(testDescrip.id,
+                    testDescrip.path,
+                    testDescrip.description,
+                    testDescrip.code,
+                    'fail',
+                    Error('No exception was thrown; expected an error "message"' +
+                          ' property matching the regular expression "' +
+                          testDescrip.negative + '".'));
+        } else if (!(new RegExp(testDescrip.negative,
+                                "i").test(this.iframeError))) {
+            //wrong type of exception thrown
+            testRun(testDescrip.id,
+                    testDescrip.path,
+                    testDescrip.description,
+                    testDescrip.code,
+                    'fail',
+                    Error('Expected an exception with a "message"' +
+                          ' property matching the regular expression "' +
+                          testDescrip.negative +
+                          '" to be thrown; actual was "' +
+                          this.iframeError + '".'));
+        } else {
+            testRun(testDescrip.id,
+                    testDescrip.path,
+                    testDescrip.description,
+                    testDescrip.code,
+                    'pass',
+                    undefined);
+        }
+    }
+
+    //Exception was not expected to be thrown
+    else if (this.iframeError !== undefined) {
         testRun(testDescrip.id,
                 testDescrip.path,
                 testDescrip.description,
                 testDescrip.code,
                 'fail',
-                Error('Expected an exception with a "message"' +
-                      ' property matching the regular expression "' +
-                      testDescrip.negative +
-                      '" to be thrown; actual was "' +
-                      this.iframeError + '".'));
-    } else {
+                Error('Unexpected exception, "' +
+                      this.iframeError + '" was thrown.'));
+    } 
+
+    else {
         testRun(testDescrip.id,
                 testDescrip.path,
                 testDescrip.description,
@@ -44,26 +66,7 @@ if (testDescrip.negative !== undefined) {
                 'pass',
                 undefined);
     }
-}
-
-//Exception was not expected to be thrown
-else if (this.iframeError !== undefined) {
-    testRun(testDescrip.id,
-            testDescrip.path,
-            testDescrip.description,
-            testDescrip.code,
-            'fail',
-            Error('Unexpected exception, "' +
-                  this.iframeError + '" was thrown.'));
-}
-
-else {
-    testRun(testDescrip.id,
-            testDescrip.path,
-            testDescrip.description,
-            testDescrip.code,
-            'pass',
-            undefined);
-}
 
-testFinished();
\ No newline at end of file
+    //teardown
+    testFinished();
+}
\ No newline at end of file
diff --git a/console/harness/sth.js b/console/harness/sth.js
index c2ce493714674c6b4cdf060449e98ea1385899ab..c61b6a7aa5b03b9fba369710d20beee9cb66c459 100644
--- a/console/harness/sth.js
+++ b/console/harness/sth.js
@@ -1,7 +1,7 @@
-/// Copyright (c) 2012 Ecma International.  All rights reserved. 
+/// Copyright (c) 2012 Ecma International.  All rights reserved.
 /// Ecma International makes this code available under the terms and conditions set
-/// forth on http://hg.ecmascript.org/tests/test262/raw-file/tip/LICENSE (the 
-/// "Use Terms").   Any redistribution of this code must retain the above 
+/// forth on http://hg.ecmascript.org/tests/test262/raw-file/tip/LICENSE (the
+/// "Use Terms").   Any redistribution of this code must retain the above
 /// copyright and this notice and otherwise comply with the Use Terms.
 
 // Do not cache any JSON files - see
@@ -27,6 +27,8 @@ function BrowserRunner() {
         errorDetectorFileContents,
         simpleTestAPIContents,
         globalScopeContents,
+        timerContents,
+        startTime,
         harnessDir = "harness/";
 
     $.ajax({async: false,
@@ -44,6 +46,11 @@ function BrowserRunner() {
             success: function(data){globalScopeContents = data;},
             url:harnessDir+"gs.js"});
 
+	$.ajax({async: false,
+		dataType: "text",
+		success: function(data){timerContents = data;},
+		url:harnessDir+"timer.js"});
+
     /* Called by the child window to notify that the test has
      * finished. This function call is put in a separate script block
      * at the end of the page so errors in the test script block
@@ -70,6 +77,8 @@ function BrowserRunner() {
         document.body.removeChild(iframe);
 
         instance.onComplete(currentTest);
+        //update elapsed time
+        controller.testElapsedTime(new Date() - startTime);
     }
 
     /* Called from the child window after the test has run. */
@@ -85,8 +94,8 @@ function BrowserRunner() {
 
     /* Run the test. */
     this.run = function (test, code) {
-        var start = new Date();
-        
+        startTime = new Date();
+
         //--Detect proper window.onerror support
         if (instance.supportsWindowOnerror===undefined) {
             var iframePrereqs = document.createElement("iframe");
@@ -96,25 +105,25 @@ function BrowserRunner() {
             }
             document.body.appendChild(iframePrereqs);
 
-            var iwinPrereqs = iframePrereqs.contentWindow; 
+            var iwinPrereqs = iframePrereqs.contentWindow;
             var idocPrereqs = iwinPrereqs.document;
             idocPrereqs.open();
-    
+
             iwinPrereqs.failCount = 0;
-            
+
             var stuff = [
                          "window.onerror = function(a, b, c) { this.failCount++; }",
                          "va xyz =",
                          "throw Error();"
             ];
-    
+
             for(var i in stuff) {
                 idocPrereqs.writeln("<script type='text/javascript'>");
                 idocPrereqs.writeln(stuff[i]);
                 idocPrereqs.writeln("</script>");
             }
             idocPrereqs.close();
-            
+
             //TODO - 500ms *should* be a sufficient delay
             setTimeout(function() {
                 instance.supportsWindowOnerror = iwinPrereqs.failCount === 2;
@@ -124,7 +133,7 @@ function BrowserRunner() {
             }, 500);
             return 0; // initial config, ignore this timing.
         }
-        
+
         currentTest = {};
         for (var tempIndex in test) {
             if (test.hasOwnProperty(tempIndex)) {
@@ -132,8 +141,6 @@ function BrowserRunner() {
             }
         }
         currentTest.code = code;
-              
-
 
         iframe = document.createElement("iframe");
         iframe.setAttribute("id", "runnerIframe");
@@ -188,11 +195,25 @@ function BrowserRunner() {
         iwin.testDescrip = currentTest;
 
         //Add an error handler capable of catching so-called early errors
-        //idoc.writeln("<script type='text/javascript' src='harness/ed.js'>" + "</script>");
+		//idoc.writeln("<script type='text/javascript' src='harness/ed.js'>" + "</script>")
         idoc.writeln("<script type='text/javascript'>");
         idoc.writeln(errorDetectorFileContents);
         idoc.writeln("</script>");
 
+        //Validate the results
+        //idoc.writeln("<script type='text/javascript' src='harness/gs.js' defer>" + "</script>");
+        idoc.writeln("<script type='text/javascript'>");
+        idoc.writeln(globalScopeContents);
+        idoc.writeln("</script>");
+
+        //this is mainly applicable for consoles that do not have setTimeout support
+		//idoc.writeln("<script type='text/javascript' src='harness/timer.js' defer>" + "</script>");
+        if(setTimeout === undefined && /\$DONE()/.test(code)){
+         idoc.writeln("<script type='text/javascript'>");
+         idoc.writeln(timerContents);
+         idoc.writeln("</script>");
+        }
+
         //Run the code
         idoc.writeln("<script type='text/javascript'>");
         if (! instance.supportsWindowOnerror) {
@@ -201,17 +222,22 @@ function BrowserRunner() {
             idoc.writeln(code);
         }
         idoc.writeln("</script>");
-
-        //Validate the results
-        //idoc.writeln("<script type='text/javascript' src='harness/gs.js' defer>" + "</script>");
+		
         idoc.writeln("<script type='text/javascript'>");
-        idoc.writeln(globalScopeContents);
+		
+
+        if(!/\$DONE()/.test(code))
+        //if the test is synchronous - call $DONE immediately
+            idoc.writeln("if(typeof $DONE === 'function') $DONE()");
+        else{
+        //in case the test does not call $DONE asynchronously then
+        //bailout after 1 min or given bailout time by calling $DONE
+            var asyncval = parseInt(test.timeout);
+            var testTimeout = asyncval !== asyncval ? 2000 : asyncval;
+			idoc.writeln("setTimeout(function() {$ERROR(\" Test Timed Out at " + testTimeout +"\" )} ," + testTimeout + ")");
+        }
         idoc.writeln("</script>");
         idoc.close();
-        
-        var elapsed = new Date() - start;
-
-        return elapsed;
     };
 
     //--Helper functions-------------------------------------------------------
@@ -264,10 +290,10 @@ function TestLoader() {
         else {
             presenter.updateStatus("Loading file: " + testGroups[testGroupIndex].path);
             testGroups[testGroupIndex].onLoaded = getNextXML;
-            
+
         }
     }
-    
+
     /* Get the test list xml */
     function loadTestXML() {
         var testsListLoader = new XMLHttpRequest();
@@ -288,7 +314,7 @@ function TestLoader() {
                     onLoaded: function(){}
                 };
                 presenter.setTestWaiting(i, testSuite[i]);
-                
+
                 var tr = $('#chapterSelector table tr').filter(':nth-child(' + (i+1) + ')');
                 tr.find('img').filter('[alt="Run"]').bind('click', {index:i}, function(event){
                     controller.runIndividualTest(event.data.index);
@@ -298,25 +324,25 @@ function TestLoader() {
             getFile();
         }});
     }
-    
+
     /* Get the test file. Handles all the logic of figuring out the next file to load. */
     function getFile(index) {
         index = (arguments.length == 0) ? -1 : index;
-        
+
         // Look for selected waiting chapters (priority because you'll probably want to run them soon)
         for(var i = 0; index == -1 && i < testGroups.length; i++) {
             if(testGroups[i].status == 'waiting' && testGroups[i].selected) {
                 index = i;
             }
         }
-        
+
         // Look for just chapters waiting to be loaded.
         for(var i = 0; index == -1 && i < testGroups.length; i++) {
             if(testGroups[i].status == 'waiting') {
                 index = i;
             }
         }
-            
+
         if(index == -1) {
             // Still -1? No more tests are waiting to be loaded then.
             if(controller.state == 'loading') {
@@ -324,13 +350,13 @@ function TestLoader() {
             }
             return;
         }
-        
+
         presenter.setTestLoading(index, testGroups[index].path);
         // the only other status that should be set when we get here is 'priorityloading'
         if(testGroups[index].status == 'waiting') {
             testGroups[index].status = 'loading';
         }
-        
+
         loader.onTestStartLoading(index, testGroups[index].path);
         // Create the AJAX call to grab the file.
         $.ajax({
@@ -344,11 +370,11 @@ function TestLoader() {
             },
             error: function(xhr, textStatus, errorThrown) {
                 // TODO: Catch this error and update UI accordingly. Unlikely to happen, but errors would be 404 or 5-- errors.
-                
+
             }
         });
     }
-    
+
     /* Executes when a test file finishes loading. */
     function onTestLoaded(index, name, numTests) {
         presenter.setTestLoaded(index, name, numTests);
@@ -357,7 +383,7 @@ function TestLoader() {
             loader.runningTests += numTests;
             loader.onInitialized( loader.runningTests );
         }
-        
+
         // The loading status is only assigned when downloading files in sequence, otherwise it
         // gets the status of priorityloading. When loading out of order, we only want to download
         // the single file, so we'll only tell it to get the next file when we see a status of
@@ -371,10 +397,10 @@ function TestLoader() {
             testGroups[index].status = 'loaded';
             loader.setChapter(index);
         }
-        
+
         testGroups[index].onLoaded();
     };
-    
+
     function getIdFromPath (path) {
         //path is of the form "a/b/c.js"
 
@@ -420,7 +446,7 @@ function TestLoader() {
                         return;
                     }
                 }
-                // And if 
+                // And if
                 else {
                     // We don't have tests left in this test group, so move on
                     // to the next.
@@ -428,7 +454,7 @@ function TestLoader() {
                 }
                 getNextXML();
             }
-            // 
+            //
             else {
                 // We're done.
                 loader.onTestsExhausted();
@@ -446,18 +472,18 @@ function TestLoader() {
         currentTestIndex = 0;
         testGroupIndex = 0;
     };
-    
+
     /* Begin downloading test files. */
     this.startLoadingTests = function() {
         loadTestXML();
     };
-    
+
     /* Prepare for testing a single chapter. */
     this.setChapter = function(index) {
         currentTestIndex = 0;
         testGroupIndex = index;
         mode = "one";
-        
+
         if(testGroups[index].status == 'loaded') {
             loader.onInitialized(testGroups[index].tests.length);
         }
@@ -467,7 +493,7 @@ function TestLoader() {
             loader.onInitialized(0);
         }
     };
-    
+
     /* Prepare for testing multiple chapters. Returns true if at least one chapter was selected. */
     this.setMultiple = function() {
         // Find the index of the first selection
@@ -481,16 +507,16 @@ function TestLoader() {
         if(firstSelectedIndex == -1) {
             return false;
         }
-        
+
         // Begin loading the file immediately, if necessary
         if(testGroups[firstSelectedIndex].status == 'waiting') {
             getFile(firstSelectedIndex);
         }
-    
+
         mode = "multiple";
         testGroupIndex = firstSelectedIndex; // start at this chapter
         currentTestIndex = 0; // start at test 0
-        
+
         // Count the number of tests
         runningTests = 0;
         for(var i = 0; i < testGroups.length; i++) {
@@ -499,16 +525,16 @@ function TestLoader() {
         loader.onInitialized(runningTests);
         return true;
     };
-    
+
     this.getNumTestFiles = function() {
         return testGroups.length;
     };
-    
+
     /* Toggle the selection of a file. */
     this.toggleSelection = function(index) {
         testGroups[index].selected = !testGroups[index].selected;
     }
-    
+
 }
 
 /* Controls test generation and running, and sends results to the presenter. */
@@ -523,8 +549,8 @@ function Controller() {
     //into this test framework to handle test case failures and passes in their
     //own way (e.g., logging failures to the filesystem)
     this.implementerHook = {
-        //Adds a test result
-        addTestResult: function (test) { },
+        //Adds a test result        
+        addTestResult: function (test) { },            
 
         //Called whenever all tests have finished running.  Provided with the
         //elapsed time in milliseconds.
@@ -550,7 +576,7 @@ function Controller() {
         }
         presenter.setTotalTests(totalTests);
     };
-    
+
     /* Executes when a test file starts loading. */
     loader.onTestStartLoading = function(index, path) {
         presenter.setTestLoading(index, path);
@@ -559,14 +585,14 @@ function Controller() {
     /* Executes when a test is ready to run. */
     loader.onTestReady = function(testObj, testSrc) {
         presenter.updateStatus("Running Test: " + testObj.id);
-        elapsed += runner.run(testObj, testSrc);
+        runner.run(testObj, testSrc);
     };
 
     /* Executes when there are no more tests to run. */
     loader.onTestsExhausted = function() {
         elapsed = elapsed/(1000*60);  //minutes
         elapsed = elapsed.toFixed(3);
-        
+
         state = (loader.loadedFiles == loader.getNumTestFiles()) ? 'loaded' : 'loading';
         presenter.setState(state);
         presenter.finished(elapsed);
@@ -574,7 +600,7 @@ function Controller() {
             controller.implementerHook.finished(elapsed);
         } catch(e) { /*no-op*/}
     };
-    
+
     /* Start the test execution. */
     this.start = function() {
         elapsed = 0;
@@ -594,25 +620,25 @@ function Controller() {
         loader.onInitialized();
         loader.reset();
         presenter.reset();
-        
+
         state = (loader.loadedFiles == loader.getNumTestFiles()) ? 'loaded' : 'loading';
         presenter.setState(state);
     };
-    
+
     /* Start loading tests. */
     this.startLoadingTests = function() {
         state = 'loading';
         presenter.setState(state);
         loader.startLoadingTests();
     }
-    
+
     /* Set the individual chapter in the laoder and start the controller. */
     this.runIndividualTest = function(index) {
         controller.reset();
         loader.setChapter(index);
         controller.start();
     }
-    
+
     /* Compile a list of the selected tests and start the controller. */
     this.runSelected = function() {
         controller.reset();
@@ -620,15 +646,19 @@ function Controller() {
             controller.start();
         }
     }
-    
+
     this.runAll = function() {
         controller.reset();
         controller.start();
     }
-    
+
     this.toggleSelection = function(index) {
         loader.toggleSelection(index);
     }
+
+    this.testElapsedTime = function(time){
+        elapsed += time;
+    }
 }
 
 var controller = new Controller();
@@ -698,7 +728,7 @@ $(function () {
         presenter.setDate(data.date);
     }
     });
-    
+
     // Start loading the files right away.
     controller.startLoadingTests();
 
diff --git a/console/harness/timer.js b/console/harness/timer.js
new file mode 100644
index 0000000000000000000000000000000000000000..69762d83f54479a67962b411f3563688e61204c8
--- /dev/null
+++ b/console/harness/timer.js
@@ -0,0 +1,22 @@
+//setTimeout is not available, hence this script was loaded
+if(Promise === undefined && this.setTimeout === undefined){
+    if(/\$DONE()/.test(code))
+        $ERROR("Async test capability is not supported in your test environment");
+}
+
+if(Promise !== undefined && this.setTimeout === undefined) 
+    (function(that){
+       that.setTimeout = function(callback, delay) {
+            var p = Promise.resolve();
+            var start = Date.now();
+            var end = start + delay;
+            function check(){
+                var timeLeft = end - Date.now();        
+                if(timeLeft)
+                    p.then(check);
+                else
+                    callback();
+            }        
+            p.then(check);
+        }
+    })(this);
\ No newline at end of file
diff --git a/test/harness/doneprintHandle.js b/test/harness/doneprintHandle.js
new file mode 100644
index 0000000000000000000000000000000000000000..317aa9c4efc29df39db9b31c97da6c5226157b3f
--- /dev/null
+++ b/test/harness/doneprintHandle.js
@@ -0,0 +1,10 @@
+function __consolePrintHandle__(msg){
+	print(msg);
+}
+
+function $DONE(){
+	if(arguments.length === 0)
+		__consolePrintHandle__('Test262:AsyncTestComplete');
+	else
+		__consolePrintHandle__('Error: ' + arguments[0]);
+}
\ No newline at end of file
diff --git a/test/harness/ed.js b/test/harness/ed.js
index 89d0dfc1ca40d3d31b45ba1057d337dbc7662bd5..88e2cecc49ba65601b7cee2fd2618529ed6b5664 100644
--- a/test/harness/ed.js
+++ b/test/harness/ed.js
@@ -8,6 +8,7 @@
 if (this.window!==undefined) {  //for console support
     this.window.onerror = function(errorMsg, url, lineNumber) {
         this.window.iframeError = errorMsg;
+        if(typeof $DONE === 'function') $DONE();
     };
 }
 
diff --git a/test/harness/gs.js b/test/harness/gs.js
index 210c08548f775bbd4fa29adfc5a11b6cf3d31265..855cb85bf40b5bf2527510a280dd151ddfd8b614 100644
--- a/test/harness/gs.js
+++ b/test/harness/gs.js
@@ -5,38 +5,60 @@
 /// copyright and this notice and otherwise comply with the Use Terms.
 
 //Global Scope Test Case Validator
+function $DONE() {
 
-//An exception is expected
-if (testDescrip.negative !== undefined) {
-    //TODO - come up with a generic way of catching the error type
-    //from this.onerror
-    testDescrip.negative = testDescrip.negative === "NotEarlyError" ?
-            testDescrip.negative :
-        (testDescrip.negative === "^((?!NotEarlyError).)*$" ?
-            testDescrip.negative : ".");
-    if (this.iframeError === undefined) { //no exception was thrown
-        testRun(testDescrip.id,
-                testDescrip.path,
-                testDescrip.description,
-                testDescrip.code,
-                'fail',
-                Error('No exception was thrown; expected an error "message"' +
-                      ' property matching the regular expression "' +
-                      testDescrip.negative + '".'));
-    } else if (!(new RegExp(testDescrip.negative,
-                            "i").test(this.iframeError))) {
-        //wrong type of exception thrown
+    //An exception is expected
+    if (testDescrip.negative !== undefined) {
+        //TODO - come up with a generic way of catching the error type
+        //from this.onerror
+        testDescrip.negative = testDescrip.negative === "NotEarlyError" ?
+                testDescrip.negative :
+            (testDescrip.negative === "^((?!NotEarlyError).)*$" ?
+                testDescrip.negative : ".");
+        if (this.iframeError === undefined) { //no exception was thrown
+            testRun(testDescrip.id,
+                    testDescrip.path,
+                    testDescrip.description,
+                    testDescrip.code,
+                    'fail',
+                    Error('No exception was thrown; expected an error "message"' +
+                          ' property matching the regular expression "' +
+                          testDescrip.negative + '".'));
+        } else if (!(new RegExp(testDescrip.negative,
+                                "i").test(this.iframeError))) {
+            //wrong type of exception thrown
+            testRun(testDescrip.id,
+                    testDescrip.path,
+                    testDescrip.description,
+                    testDescrip.code,
+                    'fail',
+                    Error('Expected an exception with a "message"' +
+                          ' property matching the regular expression "' +
+                          testDescrip.negative +
+                          '" to be thrown; actual was "' +
+                          this.iframeError + '".'));
+        } else {
+            testRun(testDescrip.id,
+                    testDescrip.path,
+                    testDescrip.description,
+                    testDescrip.code,
+                    'pass',
+                    undefined);
+        }
+    }
+
+    //Exception was not expected to be thrown
+    else if (this.iframeError !== undefined) {
         testRun(testDescrip.id,
                 testDescrip.path,
                 testDescrip.description,
                 testDescrip.code,
                 'fail',
-                Error('Expected an exception with a "message"' +
-                      ' property matching the regular expression "' +
-                      testDescrip.negative +
-                      '" to be thrown; actual was "' +
-                      this.iframeError + '".'));
-    } else {
+                Error('Unexpected exception, "' +
+                      this.iframeError + '" was thrown.'));
+    } 
+
+    else {
         testRun(testDescrip.id,
                 testDescrip.path,
                 testDescrip.description,
@@ -44,26 +66,7 @@ if (testDescrip.negative !== undefined) {
                 'pass',
                 undefined);
     }
-}
-
-//Exception was not expected to be thrown
-else if (this.iframeError !== undefined) {
-    testRun(testDescrip.id,
-            testDescrip.path,
-            testDescrip.description,
-            testDescrip.code,
-            'fail',
-            Error('Unexpected exception, "' +
-                  this.iframeError + '" was thrown.'));
-}
-
-else {
-    testRun(testDescrip.id,
-            testDescrip.path,
-            testDescrip.description,
-            testDescrip.code,
-            'pass',
-            undefined);
-}
 
-testFinished();
\ No newline at end of file
+    //teardown
+    testFinished();
+}
\ No newline at end of file
diff --git a/test/harness/sth.js b/test/harness/sth.js
index c2ce493714674c6b4cdf060449e98ea1385899ab..cd05685e1877a58da7cb3d374151a28705547020 100644
--- a/test/harness/sth.js
+++ b/test/harness/sth.js
@@ -1,7 +1,7 @@
-/// Copyright (c) 2012 Ecma International.  All rights reserved. 
+/// Copyright (c) 2012 Ecma International.  All rights reserved.
 /// Ecma International makes this code available under the terms and conditions set
-/// forth on http://hg.ecmascript.org/tests/test262/raw-file/tip/LICENSE (the 
-/// "Use Terms").   Any redistribution of this code must retain the above 
+/// forth on http://hg.ecmascript.org/tests/test262/raw-file/tip/LICENSE (the
+/// "Use Terms").   Any redistribution of this code must retain the above
 /// copyright and this notice and otherwise comply with the Use Terms.
 
 // Do not cache any JSON files - see
@@ -27,6 +27,8 @@ function BrowserRunner() {
         errorDetectorFileContents,
         simpleTestAPIContents,
         globalScopeContents,
+        timerContents,
+        startTime,
         harnessDir = "harness/";
 
     $.ajax({async: false,
@@ -43,6 +45,11 @@ function BrowserRunner() {
             dataType: "text",
             success: function(data){globalScopeContents = data;},
             url:harnessDir+"gs.js"});
+    
+	$.ajax({async: false,
+		dataType: "text",
+		success: function(data){timerContents = data;},
+		url:harnessDir+"timer.js"});
 
     /* Called by the child window to notify that the test has
      * finished. This function call is put in a separate script block
@@ -70,6 +77,8 @@ function BrowserRunner() {
         document.body.removeChild(iframe);
 
         instance.onComplete(currentTest);
+        //update elapsed time
+        controller.testElapsedTime(new Date() - startTime);
     }
 
     /* Called from the child window after the test has run. */
@@ -85,8 +94,8 @@ function BrowserRunner() {
 
     /* Run the test. */
     this.run = function (test, code) {
-        var start = new Date();
-        
+        startTime = new Date();
+
         //--Detect proper window.onerror support
         if (instance.supportsWindowOnerror===undefined) {
             var iframePrereqs = document.createElement("iframe");
@@ -96,25 +105,25 @@ function BrowserRunner() {
             }
             document.body.appendChild(iframePrereqs);
 
-            var iwinPrereqs = iframePrereqs.contentWindow; 
+            var iwinPrereqs = iframePrereqs.contentWindow;
             var idocPrereqs = iwinPrereqs.document;
             idocPrereqs.open();
-    
+
             iwinPrereqs.failCount = 0;
-            
+
             var stuff = [
                          "window.onerror = function(a, b, c) { this.failCount++; }",
                          "va xyz =",
                          "throw Error();"
             ];
-    
+
             for(var i in stuff) {
                 idocPrereqs.writeln("<script type='text/javascript'>");
                 idocPrereqs.writeln(stuff[i]);
                 idocPrereqs.writeln("</script>");
             }
             idocPrereqs.close();
-            
+
             //TODO - 500ms *should* be a sufficient delay
             setTimeout(function() {
                 instance.supportsWindowOnerror = iwinPrereqs.failCount === 2;
@@ -124,7 +133,7 @@ function BrowserRunner() {
             }, 500);
             return 0; // initial config, ignore this timing.
         }
-        
+
         currentTest = {};
         for (var tempIndex in test) {
             if (test.hasOwnProperty(tempIndex)) {
@@ -132,8 +141,6 @@ function BrowserRunner() {
             }
         }
         currentTest.code = code;
-              
-
 
         iframe = document.createElement("iframe");
         iframe.setAttribute("id", "runnerIframe");
@@ -188,11 +195,25 @@ function BrowserRunner() {
         iwin.testDescrip = currentTest;
 
         //Add an error handler capable of catching so-called early errors
-        //idoc.writeln("<script type='text/javascript' src='harness/ed.js'>" + "</script>");
+		//idoc.writeln("<script type='text/javascript' src='harness/ed.js'>" + "</script>")
         idoc.writeln("<script type='text/javascript'>");
         idoc.writeln(errorDetectorFileContents);
         idoc.writeln("</script>");
 
+        //Validate the results
+        //idoc.writeln("<script type='text/javascript' src='harness/gs.js' defer>" + "</script>");
+        idoc.writeln("<script type='text/javascript'>");
+        idoc.writeln(globalScopeContents);
+        idoc.writeln("</script>");
+
+        //this is mainly applicable for consoles that do not have setTimeout support
+		//idoc.writeln("<script type='text/javascript' src='harness/timer.js' defer>" + "</script>");
+        if(setTimeout === undefined && /\$DONE()/.test(code)){
+         idoc.writeln("<script type='text/javascript'>");
+         idoc.writeln(timerContents);
+         idoc.writeln("</script>");
+        }
+
         //Run the code
         idoc.writeln("<script type='text/javascript'>");
         if (! instance.supportsWindowOnerror) {
@@ -201,17 +222,21 @@ function BrowserRunner() {
             idoc.writeln(code);
         }
         idoc.writeln("</script>");
-
-        //Validate the results
-        //idoc.writeln("<script type='text/javascript' src='harness/gs.js' defer>" + "</script>");
+		
         idoc.writeln("<script type='text/javascript'>");
-        idoc.writeln(globalScopeContents);
+		
+        if(!/\$DONE()/.test(code))
+        //if the test is synchronous - call $DONE immediately
+            idoc.writeln("if(typeof $DONE === 'function') $DONE()");
+        else{
+        //in case the test does not call $DONE asynchronously then
+        //bailout after 1 min or given bailout time by calling $DONE
+            var asyncval = parseInt(test.timeout);
+            var testTimeout = asyncval !== asyncval ? 2000 : asyncval;
+			idoc.writeln("setTimeout(function() {$ERROR(\" Test Timed Out at " + testTimeout +"\" )} ," + testTimeout + ")");
+        }
         idoc.writeln("</script>");
         idoc.close();
-        
-        var elapsed = new Date() - start;
-
-        return elapsed;
     };
 
     //--Helper functions-------------------------------------------------------
@@ -264,10 +289,10 @@ function TestLoader() {
         else {
             presenter.updateStatus("Loading file: " + testGroups[testGroupIndex].path);
             testGroups[testGroupIndex].onLoaded = getNextXML;
-            
+
         }
     }
-    
+
     /* Get the test list xml */
     function loadTestXML() {
         var testsListLoader = new XMLHttpRequest();
@@ -288,7 +313,7 @@ function TestLoader() {
                     onLoaded: function(){}
                 };
                 presenter.setTestWaiting(i, testSuite[i]);
-                
+
                 var tr = $('#chapterSelector table tr').filter(':nth-child(' + (i+1) + ')');
                 tr.find('img').filter('[alt="Run"]').bind('click', {index:i}, function(event){
                     controller.runIndividualTest(event.data.index);
@@ -298,25 +323,25 @@ function TestLoader() {
             getFile();
         }});
     }
-    
+
     /* Get the test file. Handles all the logic of figuring out the next file to load. */
     function getFile(index) {
         index = (arguments.length == 0) ? -1 : index;
-        
+
         // Look for selected waiting chapters (priority because you'll probably want to run them soon)
         for(var i = 0; index == -1 && i < testGroups.length; i++) {
             if(testGroups[i].status == 'waiting' && testGroups[i].selected) {
                 index = i;
             }
         }
-        
+
         // Look for just chapters waiting to be loaded.
         for(var i = 0; index == -1 && i < testGroups.length; i++) {
             if(testGroups[i].status == 'waiting') {
                 index = i;
             }
         }
-            
+
         if(index == -1) {
             // Still -1? No more tests are waiting to be loaded then.
             if(controller.state == 'loading') {
@@ -324,13 +349,13 @@ function TestLoader() {
             }
             return;
         }
-        
+
         presenter.setTestLoading(index, testGroups[index].path);
         // the only other status that should be set when we get here is 'priorityloading'
         if(testGroups[index].status == 'waiting') {
             testGroups[index].status = 'loading';
         }
-        
+
         loader.onTestStartLoading(index, testGroups[index].path);
         // Create the AJAX call to grab the file.
         $.ajax({
@@ -344,11 +369,11 @@ function TestLoader() {
             },
             error: function(xhr, textStatus, errorThrown) {
                 // TODO: Catch this error and update UI accordingly. Unlikely to happen, but errors would be 404 or 5-- errors.
-                
+
             }
         });
     }
-    
+
     /* Executes when a test file finishes loading. */
     function onTestLoaded(index, name, numTests) {
         presenter.setTestLoaded(index, name, numTests);
@@ -357,7 +382,7 @@ function TestLoader() {
             loader.runningTests += numTests;
             loader.onInitialized( loader.runningTests );
         }
-        
+
         // The loading status is only assigned when downloading files in sequence, otherwise it
         // gets the status of priorityloading. When loading out of order, we only want to download
         // the single file, so we'll only tell it to get the next file when we see a status of
@@ -371,10 +396,10 @@ function TestLoader() {
             testGroups[index].status = 'loaded';
             loader.setChapter(index);
         }
-        
+
         testGroups[index].onLoaded();
     };
-    
+
     function getIdFromPath (path) {
         //path is of the form "a/b/c.js"
 
@@ -420,7 +445,7 @@ function TestLoader() {
                         return;
                     }
                 }
-                // And if 
+                // And if
                 else {
                     // We don't have tests left in this test group, so move on
                     // to the next.
@@ -428,7 +453,7 @@ function TestLoader() {
                 }
                 getNextXML();
             }
-            // 
+            //
             else {
                 // We're done.
                 loader.onTestsExhausted();
@@ -446,18 +471,18 @@ function TestLoader() {
         currentTestIndex = 0;
         testGroupIndex = 0;
     };
-    
+
     /* Begin downloading test files. */
     this.startLoadingTests = function() {
         loadTestXML();
     };
-    
+
     /* Prepare for testing a single chapter. */
     this.setChapter = function(index) {
         currentTestIndex = 0;
         testGroupIndex = index;
         mode = "one";
-        
+
         if(testGroups[index].status == 'loaded') {
             loader.onInitialized(testGroups[index].tests.length);
         }
@@ -467,7 +492,7 @@ function TestLoader() {
             loader.onInitialized(0);
         }
     };
-    
+
     /* Prepare for testing multiple chapters. Returns true if at least one chapter was selected. */
     this.setMultiple = function() {
         // Find the index of the first selection
@@ -481,16 +506,16 @@ function TestLoader() {
         if(firstSelectedIndex == -1) {
             return false;
         }
-        
+
         // Begin loading the file immediately, if necessary
         if(testGroups[firstSelectedIndex].status == 'waiting') {
             getFile(firstSelectedIndex);
         }
-    
+
         mode = "multiple";
         testGroupIndex = firstSelectedIndex; // start at this chapter
         currentTestIndex = 0; // start at test 0
-        
+
         // Count the number of tests
         runningTests = 0;
         for(var i = 0; i < testGroups.length; i++) {
@@ -499,16 +524,16 @@ function TestLoader() {
         loader.onInitialized(runningTests);
         return true;
     };
-    
+
     this.getNumTestFiles = function() {
         return testGroups.length;
     };
-    
+
     /* Toggle the selection of a file. */
     this.toggleSelection = function(index) {
         testGroups[index].selected = !testGroups[index].selected;
     }
-    
+
 }
 
 /* Controls test generation and running, and sends results to the presenter. */
@@ -523,8 +548,8 @@ function Controller() {
     //into this test framework to handle test case failures and passes in their
     //own way (e.g., logging failures to the filesystem)
     this.implementerHook = {
-        //Adds a test result
-        addTestResult: function (test) { },
+        //Adds a test result        
+        addTestResult: function (test) { },            
 
         //Called whenever all tests have finished running.  Provided with the
         //elapsed time in milliseconds.
@@ -550,7 +575,7 @@ function Controller() {
         }
         presenter.setTotalTests(totalTests);
     };
-    
+
     /* Executes when a test file starts loading. */
     loader.onTestStartLoading = function(index, path) {
         presenter.setTestLoading(index, path);
@@ -559,14 +584,14 @@ function Controller() {
     /* Executes when a test is ready to run. */
     loader.onTestReady = function(testObj, testSrc) {
         presenter.updateStatus("Running Test: " + testObj.id);
-        elapsed += runner.run(testObj, testSrc);
+        runner.run(testObj, testSrc);
     };
 
     /* Executes when there are no more tests to run. */
     loader.onTestsExhausted = function() {
         elapsed = elapsed/(1000*60);  //minutes
         elapsed = elapsed.toFixed(3);
-        
+
         state = (loader.loadedFiles == loader.getNumTestFiles()) ? 'loaded' : 'loading';
         presenter.setState(state);
         presenter.finished(elapsed);
@@ -574,7 +599,7 @@ function Controller() {
             controller.implementerHook.finished(elapsed);
         } catch(e) { /*no-op*/}
     };
-    
+
     /* Start the test execution. */
     this.start = function() {
         elapsed = 0;
@@ -594,25 +619,25 @@ function Controller() {
         loader.onInitialized();
         loader.reset();
         presenter.reset();
-        
+
         state = (loader.loadedFiles == loader.getNumTestFiles()) ? 'loaded' : 'loading';
         presenter.setState(state);
     };
-    
+
     /* Start loading tests. */
     this.startLoadingTests = function() {
         state = 'loading';
         presenter.setState(state);
         loader.startLoadingTests();
     }
-    
+
     /* Set the individual chapter in the laoder and start the controller. */
     this.runIndividualTest = function(index) {
         controller.reset();
         loader.setChapter(index);
         controller.start();
     }
-    
+
     /* Compile a list of the selected tests and start the controller. */
     this.runSelected = function() {
         controller.reset();
@@ -620,15 +645,19 @@ function Controller() {
             controller.start();
         }
     }
-    
+
     this.runAll = function() {
         controller.reset();
         controller.start();
     }
-    
+
     this.toggleSelection = function(index) {
         loader.toggleSelection(index);
     }
+
+    this.testElapsedTime = function(time){
+        elapsed += time;
+    }
 }
 
 var controller = new Controller();
@@ -698,7 +727,7 @@ $(function () {
         presenter.setDate(data.date);
     }
     });
-    
+
     // Start loading the files right away.
     controller.startLoadingTests();
 
diff --git a/test/harness/timer.js b/test/harness/timer.js
new file mode 100644
index 0000000000000000000000000000000000000000..69762d83f54479a67962b411f3563688e61204c8
--- /dev/null
+++ b/test/harness/timer.js
@@ -0,0 +1,22 @@
+//setTimeout is not available, hence this script was loaded
+if(Promise === undefined && this.setTimeout === undefined){
+    if(/\$DONE()/.test(code))
+        $ERROR("Async test capability is not supported in your test environment");
+}
+
+if(Promise !== undefined && this.setTimeout === undefined) 
+    (function(that){
+       that.setTimeout = function(callback, delay) {
+            var p = Promise.resolve();
+            var start = Date.now();
+            var end = start + delay;
+            function check(){
+                var timeLeft = end - Date.now();        
+                if(timeLeft)
+                    p.then(check);
+                else
+                    callback();
+            }        
+            p.then(check);
+        }
+    })(this);
\ No newline at end of file
diff --git a/tools/packaging/test262.py b/tools/packaging/test262.py
index f9c1fe628c2a4f7710e1121253922e171f741714..b2d43973876e3448e8ab4f3e489788a0d912225c 100755
--- a/tools/packaging/test262.py
+++ b/tools/packaging/test262.py
@@ -73,6 +73,7 @@ def BuildOptions():
   result.add_option("--junitname", help="Filename to save test results in JUnit XML format")
   result.add_option("--loglevel", default="warning",
                     help="sets log level to debug, info, warning, error, or critical") 
+  result.add_option("--print-handle", default="", help="Command to print from console")
   return result
 
 
@@ -193,16 +194,20 @@ class TestResult(object):
        testpackage = testclass
     return(testpackage,testclass,testcase)
   
-  def HasFailed(self):
+  def HasFailed(self):    
     return self.exit_code != 0
 
+  def AsyncHasFailed(self):   
+    return 'Test262:AsyncTestComplete' not in self.stdout
+
   def HasUnexpectedOutcome(self):
-    if self.case.IsNegative():
+    if self.case.IsAsyncTest():		
+	return self.AsyncHasFailed() or self.HasFailed()
+    elif self.case.IsNegative():      
        return not self.HasFailed()
-    else:
+    else:      
        return self.HasFailed()
 
-
 class TestCase(object):
 
   def __init__(self, suite, name, full_path, strict_mode):
@@ -242,6 +247,9 @@ class TestCase(object):
   def IsNoStrict(self):
     return 'noStrict' in self.testRecord
 
+  def IsAsyncTest(self):	
+	return '$DONE' in self.test
+
   def GetSource(self):
     # "var testDescrip = " + str(self.testRecord) + ';\n\n' + \
     source = self.suite.GetInclude("cth.js") + \
@@ -249,6 +257,8 @@ class TestCase(object):
         self.suite.GetInclude("ed.js") + \
         self.suite.GetInclude("testBuiltInObject.js") + \
         self.suite.GetInclude("testIntl.js") + \
+	self.suite.GetInclude("timer.js") + \
+	self.suite.GetInclude("doneprintHandle.js").replace('print', self.suite.print_handle) + \
         self.test + '\n'
 
     if self.strict_mode:
@@ -332,14 +342,16 @@ def MakePlural(n):
 
 class TestSuite(object):
 
-  def __init__(self, root, strict_only, non_strict_only, unmarked_default):
+  def __init__(self, root, strict_only, non_strict_only, unmarked_default, print_handle):
     # TODO: derive from packagerConfig.py
     self.test_root = path.join(root, 'test', 'suite')
     self.lib_root = path.join(root, 'test', 'harness')
     self.strict_only = strict_only
     self.non_strict_only = non_strict_only
     self.unmarked_default = unmarked_default
+    self.print_handle = print_handle
     self.include_cache = { }
+	
 
   def Validate(self):
     if not path.exists(self.test_root):
@@ -536,7 +548,8 @@ def Main():
   test_suite = TestSuite(options.tests, 
                          options.strict_only, 
                          options.non_strict_only,
-                         options.unmarked_default)
+                         options.unmarked_default,
+			 options.print_handle)
   test_suite.Validate()
   if options.loglevel == 'debug':
     logging.basicConfig(level=logging.DEBUG)