             if(methodsToRun.length == 0) {
                 warn(">> We were unable to find any test methods in " + currentTestReflection.name + ". Did you set the --keep-as3-metadata flag?");
             }
-            runNextMethod();
+			
+            runNextMethods();
         }
 
         protected function createTestIterator(test:*, testMethodName:String):TestIterator {
             return new TestIterator(test, testMethodName);
         }
 
-        protected function runNextMethod(e:TimerEvent = null):void {
-            if (testCompleted) {
-                onTestCompleted();
-                return;
-            }
-
-            runMethod(methodsToRun.next());
-        }
-        
-        protected function runMethod(method:Method):void {
-            if (!method) return;
+        protected function runNextMethods(e:TimerEvent = null):void {
+			// Loop through as many as possible without hitting asynchronous tests.
+			// This keeps the call stack small.
+			while (methodsToRun.hasNext()) {
+				var hasAsyncPending:Boolean = runMethod(methodsToRun.next());
+				if (hasAsyncPending) return;
+			}
+			
+			onTestCompleted();
+        }
+        
+		/**
+		 * 
+		 * @param	method
+		 * @return	true if asynchronous calls are pending after calling the test method.
+		 */
+        protected function runMethod(method:Method):Boolean {
+            if (!method) return false;
             currentMethod = method;
             methodPassed = true; // innocent until proven guilty by recordFailure()
             
             if (currentMethod.ignore) {
                 result.onTestIgnored(currentMethod);
                 onMethodCompleted();
-                return;
+                return false;
             }
 
             // This is used to prevent async callbacks from triggering onMethodCompleted too early.

			testInjector.mapValue(IAsync, async);
			testInjector.mapValue(Async, async);
            timer = new Timer(0, 1);
            timer.addEventListener(TimerEvent.TIMER, runNextMethod);
            visualInstances = [];
        }

        public function run(testOrSuite:Class, methodName:String=null, visualContext:DisplayObjectContainer=null):void {
            runMethodByName(testOrSuite, methodName, visualContext);
        }

        public function runMethodByName(test:Class, methodName:String=null, visualContext:DisplayObjectContainer=null):void {
            currentTestReflection  = Reflection.create(test);
            this.visualContext     = visualContext;
			testInjector.mapValue(Sprite, visualContext);
            currentMethod          = null;

            
            methodIsExecuting = false;
            
            if (async.hasPending) return true;

            onMethodCompleted();
			return false;
        }

        protected function onMethodCompleted(wasAsync:Boolean = false):void {
            async.cancelPending();
            
            if (currentMethod.isTest && methodPassed && !currentMethod.ignore) {
                result.onTestSuccess(new TestSuccess(currentTest, currentMethod.name));
            }

            if (wasAsync)
				runNextMethods();
            
            // green thread for runNextMethods()
            // This runs much slower in Flash Player 10.1.
            //timer.reset();
            //timer.start();
