<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>example/spec/dom_mocks/simple.html</filename>
    </added>
    <added>
      <filename>lib/screw.mock.js</filename>
    </added>
    <added>
      <filename>mock_docs/files.html</filename>
    </added>
    <added>
      <filename>mock_docs/index.html</filename>
    </added>
    <added>
      <filename>mock_docs/symbols/TH.Ajax.html</filename>
    </added>
    <added>
      <filename>mock_docs/symbols/TH.Mock.html</filename>
    </added>
    <added>
      <filename>mock_docs/symbols/TH.html</filename>
    </added>
    <added>
      <filename>mock_docs/symbols/_global_.html</filename>
    </added>
    <added>
      <filename>mock_docs/symbols/src/_Users_Topper_screw-unit-mock_lib_screw.mock.js.html</filename>
    </added>
    <added>
      <filename>spec/asynchronous_spec.js</filename>
    </added>
    <added>
      <filename>spec/dom_mocks/click_test.html</filename>
    </added>
    <added>
      <filename>spec/dom_mocks/dom_mock_test.html</filename>
    </added>
    <added>
      <filename>spec/mock_spec.js</filename>
    </added>
    <added>
      <filename>spec/skipping_spec.js</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -1,3 +1,93 @@
+# Skipping Tests:
+
+* Skipped has a separate status counter at the top of the page, a new display color, and a reason can be printed to the page.
+* At any time within an test, you can make it show as skipped.  The test will cease to run at that point.  It can no longer pass or fail.
+* If you want to skip multiple tests, the before can do the skip.
+
+Examples:
+
+          it('should be skipped if the browser is IE', function(me){
+            if(this_browser_is_IE){
+              skip(me).because('IE doesn't have some function I am testing, and failed tests make me curl up on the floor and cry');
+            }
+          })
+          
+          describe('', function(){
+           before(function(me){
+             if(this_browser_is_IE){
+               skip(me).because('IE doesn't have some function I am testing, and failed tests make me curl up on the floor and cry');
+             }
+           });
+           
+           it('will never run at all', function(){
+             alert('you won't see this');
+           }); 
+           
+           it('will never _ever_ run at all', function(){
+             alert('you won't see this... ever!');
+           }); 
+           
+          })
+
+
+# Asynchronous testing:
+
+* A jQuery object representing the current test's dom element is now passed to &quot;it&quot; functions
+* Asynchronous testing functions are tracked and displayed with overall status, which updates as tests complete
+* Nested asynchronous testing
+
+Examples:
+        it('tests something after 3 seconds', function(me){
+          var x = false;
+          setTimeout(some_magic_function, 1000);
+          using(me).wait(3).and_then(function(){
+            expect(x).to(be_true);
+          });
+        })
+
+        it('tests something after 3 seconds, and something else 3 seconds after that', function(me){
+          var x = false;
+          setTimeout(some_magic_function, 1000);
+          using(me).wait(3).and_then(function(){
+            expect(x).to(be_true);
+            setTimeout(some_other_magic_function, 1000);
+            using(me).wait(3).and_then(function(){
+              expect(x).to(be_false);
+            });
+          });
+        })
+
+
+# Mocking
+
+* Mock out objects (and have them restored at the next test)
+* insert DOM mocks for each test
+* Mock out Prototype.js AJAX calls using a simple interface
+* JSDoc Toolkit docs (in /mock_docs/index.html)
+
+Docs online at:  [http://toppingdesign.com/mock_docs/](http://toppingdesign.com/mock_docs/)
+    
+Examples:
+        // DOM mocking
+        TH.insertDomMock(&quot;some_mock&quot;); // will insert dom_mocks/some_mock.html into &lt;div id=&quot;dom_test&quot;&gt;&lt;/div&gt;
+        
+        // Object mocking
+        var someObj = {
+            foo: function () { return 'bar' }
+        };
+        someObj.foo() == 'bar';
+        TH.Mock.Obj(&quot;someObj&quot;, {
+            foo: function () { return 'somethingElse' }
+        });
+        someObj.foo() == 'somethingElse'; // BUT!  Only for this test the next test will have a normal someObj;
+        
+        // Ajax mocking (Prototype.js only)
+        TH.Ajax.mock(&quot;/a_url&quot;, &quot;someText&quot;, 200);
+        var ajx = new Ajax.Request(&quot;/a_url&quot;, {
+            onComplete: function (resp) { response = resp }
+        });
+        expect(response.responseText).to(equal, &quot;someText&quot;);
+
 Screw.Unit is a Behavior-Driven Testing Framework for Javascript. It features nested describes. Its goals are to provide:
 
 * a DSL for elegant, readable, organized specs;</diff>
      <filename>README.markdown</filename>
    </modified>
    <modified>
      <diff>@@ -8,8 +8,8 @@ function Man(options) {
     return luck;
   };
   this.render = function() {
-    return $('&lt;ul class=&quot;man&quot;&gt;')
-      .append('&lt;li class=&quot;hair&quot;&gt;')
+    return $('&lt;ul class=&quot;man&quot;&gt;&lt;/ul&gt;')
+      .append('&lt;li class=&quot;hair&quot;&gt;&lt;/li&gt;')
       .click(function() {
         $(this).children('.hair').remove();
       });</diff>
      <filename>example/models/man.js</filename>
    </modified>
    <modified>
      <diff>@@ -1,9 +1,15 @@
+Screw.Defaults = Screw.Defaults || {};
+Screw.Defaults.to_run = 'body &gt; .describe &gt; .describes &gt; .describe';
+
 (function($) {
   $(Screw).bind('loaded', function() {
     $('.status').fn({
       display: function() {
         $(this).text(
-          $('.passed').length + $('.failed').length + ' example(s), ' + $('.failed').length + ' failure(s)'
+          $('.it.passed' ).length + $('.failed').length + $('.skipped').length + ' finished, ' +
+          $('.it.failed' ).length + ' failure(s), ' + 
+          $('.it.skipped').length + ' skipped, ' + 
+          $('.it.async'  ).length + ' running asynchronous test(s)'
         );
       }
     });
@@ -44,10 +50,12 @@
       },
       
       run: function() {
+        if ($(this).hasClass('skipped')){return}
+        
         try {
           try {
             $(this).fn('parent').fn('run_befores');
-            $(this).data('screwunit.run')();
+            $(this).data('screwunit.run')($(this));
           } finally {
             $(this).fn('parent').fn('run_afters');
           }
@@ -73,15 +81,15 @@
     });
     
     $('.before').fn({
-      run: function() { $(this).data('screwunit.run')() }
+      run: function() { $(this).data('screwunit.run')($(this)) }
     }); 
   
     $('.after').fn({
-      run: function() { $(this).data('screwunit.run')() }
+      run: function() { $(this).data('screwunit.run')($(this)) }
     });
 
     $(Screw).trigger('before');
-    var to_run = unescape(location.search.slice(1)) || 'body &gt; .describe &gt; .describes &gt; .describe';
+    var to_run = unescape(location.search.slice(1)) || Screw.Defaults.to_run;
     $(to_run)
       .focus()
       .eq(0).trigger('scroll').end()</diff>
      <filename>lib/screw.behaviors.js</filename>
    </modified>
    <modified>
      <diff>@@ -2,28 +2,80 @@ var Screw = (function($) {
   var screw = {
     Unit: function(fn) {
       var contents = fn.toString().match(/^[^\{]*{((.*\n*)*)}/m)[1];
-      var fn = new Function(&quot;matchers&quot;, &quot;specifications&quot;,
-        &quot;with (specifications) { with (matchers) { &quot; + contents + &quot; } }&quot;
+      var fn = new Function(&quot;matchers&quot;, &quot;specifications&quot;, &quot;utilities&quot;,
+        &quot;with (specifications) { with (matchers) { with (utilities) {&quot; + contents + &quot; } } }&quot;
       );
 
       $(Screw).queue(function() {
         Screw.Specifications.context.push($('body &gt; .describe'));
-        fn.call(this, Screw.Matchers, Screw.Specifications);
+        fn.call(this, Screw.Matchers, Screw.Specifications, Screw.Utilities);
         Screw.Specifications.context.pop();
         $(this).dequeue();
       });
     },
 
+    Utilities: {
+      /*
+       * 'me' is $(this) being passed to the screwunit.run function (see screw.behaviors.js)
+       *   $(this).data('screwunit.run')($(this));
+       */
+       
+      skip: function(me){
+        return {
+          because: function(reason) {
+            me.trigger('skipped', [reason]);
+            throw '';
+          }
+        }
+      },
+      
+      using: function( me ) {
+        return {
+          wait : function( seconds ) {
+            return {
+              and_then: function( fn ) {
+                var f = function() {
+                  var async_count = me.data('async_waiting_count') - 1;
+                  me.data('async_waiting_count', async_count);
+                  if (async_count &lt; 1) {
+                    me.removeClass('async');
+                  }
+
+                  try {
+                    fn(me);
+                  } catch (e) {
+                    me.trigger('failed', [e]);
+                    return;
+                  }
+                  me.trigger('passed');
+                };
+
+                var async_count = me.data('async_waiting_count') ||  0
+                me.data('async_waiting_count', async_count + 1)
+
+                me.addClass('async');
+
+                // allow the &quot;it&quot; we are called from to finish, which will add class &quot;passed&quot;, which we want to remove.
+                setTimeout(function(){ me.trigger('running'); }, 2);
+
+                setTimeout(f, 1000 * parseInt(seconds,10));
+              } 
+            }
+          }
+        }  
+      }
+    },
+
     Specifications: {
       context: [],
 
       describe: function(name, fn) {
-        var describe = $('&lt;li class=&quot;describe&quot;&gt;')
-          .append($('&lt;h1&gt;').text(name))
-          .append('&lt;ol class=&quot;befores&quot;&gt;')
-          .append('&lt;ul class=&quot;its&quot;&gt;')
-          .append('&lt;ul class=&quot;describes&quot;&gt;')
-          .append('&lt;ol class=&quot;afters&quot;&gt;');
+        var describe = $('&lt;li class=&quot;describe&quot;&gt;&lt;/li&gt;')
+          .append($('&lt;h1&gt;&lt;/h1&gt;').text(name))
+          .append('&lt;ol class=&quot;befores&quot;&gt;&lt;/ol&gt;')
+          .append('&lt;ul class=&quot;its&quot;&gt;&lt;/ul&gt;')
+          .append('&lt;ul class=&quot;describes&quot;&gt;&lt;/ul&gt;')
+          .append('&lt;ol class=&quot;afters&quot;&gt;&lt;/ol&gt;');
 
         this.context.push(describe);
         fn.call();
@@ -35,8 +87,8 @@ var Screw = (function($) {
       },
 
       it: function(name, fn) {
-        var it = $('&lt;li class=&quot;it&quot;&gt;')
-          .append($('&lt;h2&gt;').text(name))
+        var it = $('&lt;li class=&quot;it&quot;&gt;&lt;/li&gt;')
+          .append($('&lt;h2&gt;&lt;/h2&gt;').text(name))
           .data('screwunit.run', fn);
 
         this.context[this.context.length-1]
@@ -45,7 +97,7 @@ var Screw = (function($) {
       },
 
       before: function(fn) {
-        var before = $('&lt;li class=&quot;before&quot;&gt;')
+        var before = $('&lt;li class=&quot;before&quot;&gt;&lt;/li&gt;')
           .data('screwunit.run', fn);
 
         this.context[this.context.length-1]
@@ -54,7 +106,7 @@ var Screw = (function($) {
       },
 
       after: function(fn) {
-        var after = $('&lt;li class=&quot;after&quot;&gt;')
+        var after = $('&lt;li class=&quot;after&quot;&gt;&lt;/li&gt;')
           .data('screwunit.run', fn);
 
         this.context[this.context.length-1]
@@ -66,11 +118,11 @@ var Screw = (function($) {
 
   $(screw).queue(function() { $(screw).trigger('loading') });
   $(function() {
-    $('&lt;div class=&quot;describe&quot;&gt;')
-      .append('&lt;h3 class=&quot;status&quot;&gt;')
-      .append('&lt;ol class=&quot;befores&quot;&gt;')
-      .append('&lt;ul class=&quot;describes&quot;&gt;')
-      .append('&lt;ol class=&quot;afters&quot;&gt;')
+    $('&lt;div class=&quot;describe&quot;&gt;&lt;/div&gt;')
+      .append('&lt;h3 class=&quot;status&quot;&gt;&lt;/h3&gt;')
+      .append('&lt;ol class=&quot;befores&quot;&gt;&lt;/ol&gt;')
+      .append('&lt;ul class=&quot;describes&quot;&gt;&lt;/ul&gt;')
+      .append('&lt;ol class=&quot;afters&quot;&gt;&lt;/ol&gt;')
       .appendTo('body');
 
     $(screw).dequeue();</diff>
      <filename>lib/screw.builder.js</filename>
    </modified>
    <modified>
      <diff>@@ -87,4 +87,16 @@ html {
             cursor: pointer;
             color: #000 !important;
             border-bottom: 1px solid #9A8E51;
-          }
\ No newline at end of file
+          }
+          
+          
+          .describes .describe .its .it.skipped h2 {
+            background-color: #8DEEEE;
+            color: #000000 !important;
+          }
+
+          .describes .describe .its .it.skipped p {
+            margin-left: 1em;
+            color: #000000;
+          }
+          
\ No newline at end of file</diff>
      <filename>lib/screw.css</filename>
    </modified>
    <modified>
      <diff>@@ -10,7 +10,9 @@
           return $(this).addClass('focused');
         })
         .bind('scroll', function() {
-          document.body.scrollTop = $(this).offset().top;
+          var sel = $(this).fn('selector');
+          var use_browser_top = $.inArray(sel, [ Screw.Defaults.to_run + ':eq(0)', 'body &gt; .describe']) &gt;= 0;
+          document.body.scrollTop = use_browser_top ? 0 : $(this).offset().top;
         });
 
       $('.it')
@@ -18,25 +20,52 @@
           $(this).addClass('enqueued');
         })
         .bind('running', function() {
-          $(this).addClass('running');
+          $(this)
+            .addClass('running')
+            .removeClass('failed')
+            .removeClass('passed');
         })
         .bind('passed', function() {
-          $(this).addClass('passed');
+          if ($(this).hasClass('skipped')){return}
+          $(this)
+            .addClass('passed')
+            .removeClass('failed');
+          $('.status').fn('display');
         })
         .bind('failed', function(e, reason) {
+          if ($(this).hasClass('skipped')){return}          
+          reason = reason || '';
           $(this)
             .addClass('failed')
-            .append($('&lt;p class=&quot;error&quot;&gt;').text(reason.toString()));
+            .removeClass('passed')
+            .append($('&lt;p class=&quot;error&quot;&gt;&lt;/p&gt;').text(reason.toString()));
+          $('.status').fn('display');
           if (reason.fileName || reason.lineNumber) {
             $(this)
-              .append($('&lt;p class=&quot;error&quot;&gt;').text(reason.fileName + &quot; : &quot; + reason.lineNumber));
+              .append($('&lt;p class=&quot;error&quot;&gt;&lt;/p&gt;').text(reason.fileName + &quot; : &quot; + reason.lineNumber));
           }
         })
+        .bind('skipped', function(e, reason) {
+          $(this)
+            .removeClass('failed')
+            .removeClass('passed')
+            .addClass('skipped')
+            .append($('&lt;p class=&quot;skip_reason&quot;&gt;&lt;/p&gt;').text(&quot;Skipped because: &quot; + reason.toString()));
+          $('.status').fn('display');
+        });
+        
+      $('.before')
+        .bind('skipped', function(e, reason){
+          if ($(this).hasClass('skipped')){ return }
+          $(this)
+            .addClass('skipped')
+            .append($('&lt;p class=&quot;skip_reason&quot;&gt;&lt;/p&gt;').text(&quot;Group Skipped because: &quot; + reason.toString()));
+          $('.it', $(this).parent().parent().get(0))
+            .addClass('skipped');
+          $('.status').fn('display');
+        });
     })
     .bind('before', function() {
-      $('.status').text('Running...');
-    })
-    .bind('after', function() {
-      $('.status').fn('display')
+      $('.status').text('Starting...');
     })
 })(jQuery);
\ No newline at end of file</diff>
      <filename>lib/screw.events.js</filename>
    </modified>
    <modified>
      <diff>@@ -5,6 +5,23 @@ Screw.Unit(function() {
   
   describe('Behaviors', function() {
     describe('#run', function() {
+      describe(&quot;A describe block with exceptions&quot;, function() {
+        var after_invoked = false;
+        after(function() {
+          after_invoked = true;
+        });
+        
+        describe(&quot;an exception in a test&quot;, function() {
+          it(&quot;fails because it throws an exception.  This is the only test that should fail&quot;, function() {
+            throw('an exception');
+          });
+          
+          it(&quot;invokes [after]s even if the previous [it] raised an exception&quot;, function() {
+            expect(after_invoked).to(equal, true);
+          });
+        });
+      });
+      
       describe(&quot;a simple [describe]&quot;, function() {
         it(&quot;invokes the global [before] before an [it]&quot;, function() {
           expect(global_before_invoked).to(equal, true);</diff>
      <filename>spec/behaviors_spec.js</filename>
    </modified>
    <modified>
      <diff>@@ -48,16 +48,16 @@ Screw.Unit(function() {
     
     describe('when given a function', function() {
       it(&quot;returns the function's signature&quot;, function() {
-        expect($.print(function() {})).to(equal, 'function ()');
-        expect($.print(function foo() {})).to(equal, 'function foo()');
-        expect($.print(function foo(bar) {})).to(equal, 'function foo(bar)');
+        expect($.print(function() {})).to(match, /function\s*\(\)/);
+        expect($.print(function foo() {})).to(match, /function\s*foo\(\)/);
+        expect($.print(function foo(bar) {})).to(match, /function\s*foo\(bar\)/);
       });        
     });
 
     describe('when given an element', function() {
       it(&quot;returns the string representation of the element&quot;, function() {
-        expect($.print($('&lt;div&gt;').get(0))).to(equal, '&lt;div&gt;');
-        expect($.print($('&lt;div foo=&quot;bar&quot;&gt;').get(0))).to(equal, '&lt;div&gt;');
+        expect($.print($('&lt;div&gt;&lt;/div&gt;').get(0))).to(equal, '&lt;div&gt;');
+        expect($.print($('&lt;div foo=&quot;bar&quot;&gt;&lt;/div&gt;').get(0))).to(equal, '&lt;div&gt;');
       });
     });
 
@@ -91,7 +91,7 @@ Screw.Unit(function() {
 
     describe('when given a jQuery', function() {
       it(&quot;returns the printed array of elements engirthed in '$()' &quot;, function() {
-        expect($.print($('&lt;div&gt;'))).to(equal, '$([ &lt;div&gt; ])');
+        expect($.print($('&lt;div&gt;&lt;/div&gt;'))).to(equal, '$([ &lt;div&gt; ])');
       });
     });
     </diff>
      <filename>spec/print_spec.js</filename>
    </modified>
    <modified>
      <diff>@@ -7,12 +7,19 @@
     &lt;script src=&quot;../lib/screw.matchers.js&quot;&gt;&lt;/script&gt;
     &lt;script src=&quot;../lib/screw.events.js&quot;&gt;&lt;/script&gt;
     &lt;script src=&quot;../lib/screw.behaviors.js&quot;&gt;&lt;/script&gt;
+    &lt;script src=&quot;../lib/screw.mock.js&quot;&gt;&lt;/script&gt;
+    
     &lt;script src=&quot;spec_helper.js&quot;&gt;&lt;/script&gt;
     &lt;script src=&quot;behaviors_spec.js&quot;&gt;&lt;/script&gt;
     &lt;script src=&quot;matchers_spec.js&quot;&gt;&lt;/script&gt;
     &lt;script src=&quot;print_spec.js&quot;&gt;&lt;/script&gt;
+    &lt;script src=&quot;mock_spec.js&quot;&gt;&lt;/script&gt;
+    &lt;script src=&quot;asynchronous_spec.js&quot;&gt;&lt;/script&gt;
+    &lt;script src=&quot;skipping_spec.js&quot;&gt;&lt;/script&gt;
 
     &lt;link rel=&quot;stylesheet&quot; href=&quot;../lib/screw.css&quot;&gt;
   &lt;/head&gt;
-  &lt;body&gt;&lt;/body&gt;
+  &lt;body&gt;
+    &lt;div id=&quot;dom_test&quot; style=&quot;position: absolute; left: -9999&quot;&gt;&lt;/div&gt;
+  &lt;/body&gt;
 &lt;/html&gt;
\ No newline at end of file</diff>
      <filename>spec/suite.html</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>8cf1662de3b44262251f82508f294e6b2865db25</id>
    </parent>
    <parent>
      <id>babc38c574eac0ad4b4919d930187412237774e8</id>
    </parent>
  </parents>
  <author>
    <name>David Chelimsky</name>
    <email>dchelimsky@gmail.com</email>
  </author>
  <url>http://github.com/dchelimsky/screw-unit/commit/fb1695e2f63ef98859ed65c15a98a29572dee3a9</url>
  <id>fb1695e2f63ef98859ed65c15a98a29572dee3a9</id>
  <committed-date>2008-09-24T11:42:28-07:00</committed-date>
  <authored-date>2008-09-24T11:42:28-07:00</authored-date>
  <message>merged in remote branch tobowers</message>
  <tree>99734158ce3ca9ea09f0d8af651b2924b5b29b9b</tree>
  <committer>
    <name>David Chelimsky</name>
    <email>dchelimsky@gmail.com</email>
  </committer>
</commit>
