diff --git a/TODO b/TODO new file mode 100644 index 0000000..737e6d2 --- /dev/null +++ b/TODO @@ -0,0 +1,2 @@ +need a way to do global before and afters +need to investigate race condition with data store \ No newline at end of file diff --git a/lib/jquery-1.2.3.js b/lib/jquery-1.2.3.js index 2e43a82..a653a71 100644 --- a/lib/jquery-1.2.3.js +++ b/lib/jquery-1.2.3.js @@ -1857,7 +1857,7 @@ jQuery.event = { var val; // Handle the second event of a trigger and when - // an event is called after a page has unloaded + // an event is called after a page has unload if ( typeof jQuery == "undefined" || jQuery.event.triggered ) return val; @@ -2282,7 +2282,7 @@ jQuery.extend({ readyList: [], // Handle when the DOM is ready ready: function() { - // Make sure that the DOM is not already loaded + // Make sure that the DOM is not already load if ( !jQuery.isReady ) { // Remember that the DOM is ready jQuery.isReady = true; @@ -2347,7 +2347,7 @@ function bindReady(){ var numStyles; (function(){ if (jQuery.isReady) return; - if ( document.readyState != "loaded" && document.readyState != "complete" ) { + if ( document.readyState != "load" && document.readyState != "complete" ) { setTimeout( arguments.callee, 0 ); return; } @@ -2641,7 +2641,7 @@ jQuery.extend({ // Attach handlers for all browsers script.onload = script.onreadystatechange = function(){ if ( !done && (!this.readyState || - this.readyState == "loaded" || this.readyState == "complete") ) { + this.readyState == "load" || this.readyState == "complete") ) { done = true; success(); complete(); diff --git a/lib/jquery.print.js b/lib/jquery.print.js index fc081d5..7236cdf 100644 --- a/lib/jquery.print.js +++ b/lib/jquery.print.js @@ -1,13 +1,22 @@ (function($) { - $.fn.print = function() { - var obj = this.get(); + $.print = function(obj) { if (obj instanceof Function) { return obj.toString().match(/^([^\{]*) {/)[1]; } else if(obj instanceof Array) { - return "[" + obj.toString() + "]"; + var result = []; + for (var i = 0; i < obj.length; i++) { + result.push($.print(obj[i])); + } + return "[" + result.join(", ") + "]"; } else if(obj instanceof HTMLElement) { return "<" + obj.tagName + " " + (obj.className != "" ? "class='" + obj.className + "'" : "") + (obj.id != "" ? "id='" + obj.id + "'" : "") + ">"; + } else if(obj instanceof Object) { + var result = []; + for (var k in obj) { + result.push(k + ": " + $.print(obj[k])) + } + return "{" + result.join(", ") + "}" } else { return obj.toString().replace(/\n\s*/g, ""); } diff --git a/lib/screw.behaviors.js b/lib/screw.behaviors.js index 2912af0..09cd37e 100644 --- a/lib/screw.behaviors.js +++ b/lib/screw.behaviors.js @@ -1,83 +1,91 @@ -$(Screw).bind('loaded', function() { - $(Screw).trigger('before'); - $('.status').fn({ - display: function() { - $(this).text( - $('.passed').length + $('.failed').length + ' test(s), ' + $('.failed').length + ' failure(s)' - ); - } - }); - $(Screw).bind('after', function() { - $('.status').fn('display'); - }); - - $('.describe').fn({ - parent: function() { - return $(this).parent('.describes').parent('.describe'); - }, - run_befores: function() { - $(this).fn('parent').fn('run_befores'); - $(this).children('.befores').find('.before').each(function() { - Screw.befores[this.id](); - }); - }, - run_afters: function() { - $(this).fn('parent').fn('run_afters'); - $(this).children('.afters').find('.after').each(function() { - Screw.afters[this.id](); - }); - }, - enqueue: function() { - $(this).children('.its').children('.it').fn('enqueue'); - $(this).children('.describes').children('.describe').fn('enqueue'); - }, - selector: function() { - var parent_selector = $(this).fn('parent').fn('selector'); - if(parent_selector) { - return parent_selector + ' > .describes > .describe:eq(' + $(this).parent('.describes').children('.describe').index(this) + ')'; - } else { - return 'body > .describe'; +(function($) { + $(Screw).bind('load', function() { + $('.status').fn({ + display: function() { + $(this).text( + $('.passed').length + $('.failed').length + ' test(s), ' + $('.failed').length + ' failure(s)' + ); } - } - }); + }); - $('.it').fn({ - parent: function() { - return $(this).parent('.its').parent('.describe'); - }, - run: function() { - try { + $('.describe').fn({ + parent: function() { + return $(this).parent('.describes').parent('.describe'); + }, + + run_befores: function() { + $(this).fn('parent').fn('run_befores'); + $(this).children('.befores').children('.before').fn('run'); + }, + + run_afters: function() { + $(this).fn('parent').fn('run_afters'); + $(this).children('.afters').children('.after').fn('run'); + }, + + enqueue: function() { + $(this).children('.its').children('.it').fn('enqueue'); + $(this).children('.describes').children('.describe').fn('enqueue'); + }, + + selector: function() { + return $(this).fn('parent').fn('selector') + + ' > .describes > .describe:eq(' + $(this).parent('.describes').children('.describe').index(this) + ')'; + } + }); + + $('body > .describe').fn({ + selector: function() { return 'body > .describe' } + }); + + $('.it').fn({ + parent: function() { + return $(this).parent('.its').parent('.describe'); + }, + + run: function() { try { - $(this) - .fn('parent').fn('run_befores'); - - Screw.its[this.id](); - } finally { - $(this).fn('parent').fn('run_afters'); + try { + $(this).fn('parent').fn('run_befores'); + $(this).data('screwunit.run')(); + } finally { + $(this).fn('parent').fn('run_afters'); + } + $(this).trigger('passed'); + } catch(e) { + $(this).trigger('failed', [e]); } - $(this).trigger('passed'); - } catch(e) { - $(this).trigger('failed', [e]); + }, + + enqueue: function() { + var self = $(this).trigger('enqueued'); + $(Screw) + .queue(function() { + self.fn('run'); + setTimeout(function() { $(Screw).dequeue() }, 0); + }); + }, + + selector: function() { + return $(this).fn('parent').fn('selector') + + ' > .its > .it:eq(' + $(this).parent('.its').children('.it').index(this) + ')'; } - }, - enqueue: function() { - var self = $(this).trigger('enqueued'); - $(Screw) - .queue(function() { - self.fn('run'); - setTimeout(function() { $(Screw).dequeue() }, 0); - }); - }, - selector: function() { - return $(this).fn('parent').fn('selector') - + ' > .its > .it:eq(' + $(this).parent('.its').children('.it').index(this) + ')'; - } - }); + }); + + $('.before').fn({ + run: function() { $(this).data('screwunit.run')() } + }); + + $('.after').fn({ + run: function() { $(this).data('screwunit.run')() } + }); - $('.status').text('Running...'); - var to_run = unescape(location.search.slice(1)) || 'body > .describe > .describes > .describe'; - $(to_run) - .focus() - .fn('enqueue'); - $(Screw).queue(function() {$(Screw).trigger('after');}); -}); \ No newline at end of file + $(Screw).trigger('before'); + var to_run = unescape(location.search.slice(1)) || 'body > .describe > .describes > .describe'; + $(to_run) + .focus() + .eq(0).trigger('scroll').end() + .fn('enqueue'); + $(Screw).queue(function() { $(Screw).trigger('after') }); + }) +})(jQuery); diff --git a/lib/screw.builder.js b/lib/screw.builder.js index 679ca98..c39fd0d 100644 --- a/lib/screw.builder.js +++ b/lib/screw.builder.js @@ -1,156 +1,81 @@ -var Screw = { - Unit: function(suite) { - Screw.last_suite = suite; - $("html").ready(function() { - if(!Screw.root_element) { - Screw.root_element = $('
'); - Screw.root_element - .append('

') +var Screw = (function($) { + var screw = { + Unit: function(fn) { + var contents = fn.toString().match(/^[^\{]*{((.*\n*)*)}/m)[1]; + var fn = new Function("matchers", "specifications", + "with (specifications) { with (matchers) { " + contents + " } }" + ); + + $(Screw).queue(function() { + Screw.Specifications.context.push($('body > .describe')); + fn.call(this, Screw.Matchers, Screw.Specifications); + Screw.Specifications.context.pop(); + $(this).dequeue(); + }); + }, + + Specifications: { + context: [], + + describe: function(name, fn) { + var describe = $('
  • '); + $('

    ').text(name).appendTo(describe); + describe .append('
      ') .append('
        ') .append('
          ') .append('
            ') - Screw.Specifications.context.push(Screw.root_element); - } - $(function() { - $('body').append(Screw.root_element); - var contents = suite.toString().match(/^[^\{]*{((.*\n*)*)}/m)[1]; - var eval_suite = new Function("matchers", "specifications", - "with (specifications) { with (matchers) { " + contents + " } }" - ); - eval_suite.call(this, Screw.Matchers, Screw.Specifications); - if(Screw.last_suite == suite) { - $(Screw).trigger('loaded') - } - }); - }); - }, - root_element: null, - last_suite: null, - describes: {}, - befores: {}, - its: {}, - afters: {}, - assign_next_id: function(element) { - Screw.current_id++; - var id = "Screw_" + Screw.current_id; - element.attr('id', id); - return id - }, - current_id: 0, - Specifications: { - context: [], - describe: function(name, fn) { - var describe = $('
          1. '); - Screw.describes[Screw.assign_next_id(describe)] = fn; - $('

            ').text(name).appendTo(describe); - describe - .append('
              ') - .append('
                ') - .append('
                  ') - .append('
                    ') + this.context.push(describe); + fn.call(); + this.context.pop(); - this.context.push(describe); - fn.call(); - this.context.pop(); + this.context[this.context.length-1] + .children('.describes') + .append(describe); + }, - this.context[this.context.length-1] - .children('.describes') - .append(describe); - }, - it: function(name, fn) { - var it = $('
                  1. '); - Screw.its[Screw.assign_next_id(it)] = fn; - $('

                    ').text(name).appendTo(it); + it: function(name, fn) { + var it = $('
                  2. '); + $('

                    ').text(name).appendTo(it); + it.data('screwunit.run', fn); - this.context[this.context.length-1] - .children('.its') - .append(it); - }, - before: function(fn) { - var before = $('
                  3. '); - Screw.befores[Screw.assign_next_id(before)] = fn; - this.context[this.context.length-1] - .children('.befores') - .append(before); - }, - after: function(fn) { - var after = $('
                  4. '); - Screw.afters[Screw.assign_next_id(after)] = fn; - this.context[this.context.length-1] - .children('.afters') - .append(after); - } - }, - Matchers: { - expect: function(actual) { - return { - to: function(matcher, expected, not) { - var matched = matcher.match(expected, actual); - if (not ? matched : !matched) { - throw(matcher.failure_message(expected, actual, not)); - } - }, - to_not: function(matcher, expected) { - this.to(matcher, expected, true); - } - } - }, - equal: { - match: function(expected, actual) { - if (expected instanceof Array) { - return Screw.Matchers.array_equal.match(actual, expected); - } else if(expected instanceof Object) { - for(var key in expected) { - if(expected[key] != actual[key]) { - return false; - } - } - for(var key in actual) { - if(actual[key] != expected[key]) { - return false; - } - } - return true; - } else { - return expected == actual; - } + this.context[this.context.length-1] + .children('.its') + .append(it); }, - failure_message: function(expected, actual, not) { - return 'expected ' + $([actual]).print() + (not ? ' to not equal ' : ' to equal ') + $([expected]).print(); - } - }, - array_equal: { - match: function(expected, actual) { - for(var i = 0; i < actual.length; i++) { - if(!Screw.Matchers.equal.match(expected[i], actual[i])) { return false } - } - return actual.length == expected.length; - } - }, - match: { - match: function(expected, actual) { - if(typeof expected == "string") { - return actual.indexOf(expected) > -1; - } else { - return expected.exec(actual); - } - }, - failure_message: function(expected, actual, not) { - return 'expected ' + $([actual]).print() + (not ? ' to not match ' : ' to match ') + $([expected]).print(); - } - }, - be_empty: { - match: function(expected, actual) { - if(actual.length == undefined) { - throw(actual.toString() + " does not respond to length"); - } - return actual.length == 0; + + before: function(fn) { + var before = $('
                  5. ') + .data('screwunit.run', fn); + + this.context[this.context.length-1] + .children('.befores') + .append(before); }, - failure_message: function(expected, actual, not) { - return 'expected ' + $([actual]).print() + (not ? ' to not be empty' : ' to be empty'); + + after: function(fn) { + var after = $('
                  6. ') + .data('screwunit.run', fn); + + this.context[this.context.length-1] + .children('.afters') + .append(after); } } - } -}; + }; + + $(screw).queue(function() { $(screw).trigger('loading') }); + $(function() { + $('
                    ') + .append('

                    ') + .append('
                      ') + .append('
                        ') + .append('
                          ') + .appendTo('body'); + + $(screw).dequeue(); + $(screw).trigger('load'); + }); + return screw; +})(jQuery); \ No newline at end of file diff --git a/lib/screw.events.js b/lib/screw.events.js index 81ec62f..d48c1c8 100644 --- a/lib/screw.events.js +++ b/lib/screw.events.js @@ -1,28 +1,39 @@ -$(Screw).bind('loaded', function() { - $('.describe, .it') - .click(function() { - document.location = location.href.split('?')[0] + '?' + $(this).fn('selector'); - return false; - }) - .focus(function() { - $('body').get(0).scrollTop = $(this).offset().top; - return $(this).addClass('focused'); - }); +(function($) { + $(Screw) + .bind('load', function() { + $('.describe, .it') + .click(function() { + document.location = location.href.split('?')[0] + '?' + $(this).fn('selector'); + return false; + }) + .focus(function() { + return $(this).addClass('focused'); + }) + .bind('scroll', function() { + document.body.scrollTop = $(this).offset().top; + }); - $('.it') - .bind('enqueued', function() { - $(this).addClass('enqueued'); - }) - .bind('running', function() { - $(this).addClass('running'); + $('.it') + .bind('enqueued', function() { + $(this).addClass('enqueued'); + }) + .bind('running', function() { + $(this).addClass('running'); + }) + .bind('passed', function() { + $(this).addClass('passed'); + }) + .bind('failed', function(e, reason) { + $(this).addClass('failed'); + $('

                          ') + .text(reason.toString()) + .appendTo($(this)); + }) }) - .bind('passed', function() { - $(this).addClass('passed'); + .bind('before', function() { + $('.status').text('Running...'); }) - .bind('failed', function(e, reason) { - $(this).addClass('failed'); - $('

                          ') - .text(reason.toString()) - .appendTo($(this)); + .bind('after', function() { + $('.status').fn('display') }) -}); \ No newline at end of file +})(jQuery); \ No newline at end of file diff --git a/lib/screw.matchers.js b/lib/screw.matchers.js new file mode 100644 index 0000000..a01f17c --- /dev/null +++ b/lib/screw.matchers.js @@ -0,0 +1,65 @@ +Screw.Matchers = (function($) { + return matchers = { + expect: function(actual) { + return { + to: function(matcher, expected, not) { + var matched = matcher.match(expected, actual); + if (not ? matched : !matched) { + throw(matcher.failure_message(expected, actual, not)); + } + }, + + to_not: function(matcher, expected) { + this.to(matcher, expected, true); + } + } + }, + + equal: { + match: function(expected, actual) { + if (expected instanceof Array) { + for (var i = 0; i < actual.length; i++) + if (!Screw.Matchers.equal.match(expected[i], actual[i])) return false; + return actual.length == expected.length; + } else if (expected instanceof Object) { + for (var key in expected) + if (expected[key] != actual[key]) return false; + for (var key in actual) + if (actual[key] != expected[key]) return false; + return true; + } else { + return expected == actual; + } + }, + + failure_message: function(expected, actual, not) { + return 'expected "' + $.print(actual) + (not ? '" to not equal "' : '" to equal "') + $.print(expected) + '"'; + } + }, + + match: { + match: function(expected, actual) { + if (expected.constructor == String) + return actual.indexOf(expected) > -1; + else + return expected.exec(actual); + }, + + failure_message: function(expected, actual, not) { + return 'expected "' + $.print(actual) + (not ? '" to not match "' : '" to match "') + $.print(expected) + '"' + } + }, + + be_empty: { + match: function(expected, actual) { + if (actual.length == undefined) throw(actual.toString() + " does not respond to length"); + + return actual.length == 0; + }, + + failure_message: function(expected, actual, not) { + return 'expected "' + $.print(actual) + (not ? '" to not be empty' : '" to be empty'); + } + } + } +})(jQuery); \ No newline at end of file diff --git a/spec/anotherfile_spec.js b/spec/anotherfile_spec.js deleted file mode 100644 index 177b2e6..0000000 --- a/spec/anotherfile_spec.js +++ /dev/null @@ -1,7 +0,0 @@ -Screw.Unit(function() { - describe("Another file", function() { - it("runs in the same suite", function() { - expect(true).to(equal, true); - }); - }); -}); \ No newline at end of file diff --git a/spec/behaviors_spec.js b/spec/behaviors_spec.js new file mode 100644 index 0000000..9e56eef --- /dev/null +++ b/spec/behaviors_spec.js @@ -0,0 +1,178 @@ +Screw.Unit(function() { + var global_before_invoked = false, global_after_invoked = false; + before(function() { global_before_invoked = true }); + after(function() { global_after_invoked = true }); + + describe('Behaviors', function() { + describe('#run', function() { + describe("a simple [describe]", function() { + it("invokes the global [before] before an [it]", function() { + expect(global_before_invoked).to(equal, true); + global_before_invoked = false; + }); + + it("invokes the global [before] before each [it]", function() { + expect(global_before_invoked).to(equal, true); + global_after_invoked = false; + }); + + it("invokes the global [after] after an [it]", function() { + expect(global_after_invoked).to(equal, true); + }); + }); + + describe("a [describe] with a [before] and [after] block", function() { + var before_invoked = false, after_invoked = false; + before(function() { before_invoked = true }); + after(function() { after_invoked = true }); + + describe('[after] blocks', function() { + it("does not invoke the [after] until after the first [it]", function() { + expect(after_invoked).to(equal, false); + }); + + it("invokes the [after] after the first [it]", function() { + expect(after_invoked).to(equal, true); + after_invoked = false; + }); + + it("invokes the [after] after each [it]", function() { + expect(after_invoked).to(equal, true); + }); + }); + + describe('[before] blocks', function() { + it("invokes the [before] before an it", function() { + expect(before_invoked).to(equal, true); + before_invoked = false; + }); + + it("invokes the [before] before each it", function() { + expect(before_invoked).to(equal, true); + }); + }); + }); + + describe("A [describe] with two [before] and two [after] blocks", function() { + var before_invocations = [], after_invocations = []; + before(function() { before_invocations.push('before 1') }); + before(function() { before_invocations.push('before 2') }); + + after(function() { after_invocations.push('after 1') }); + after(function() { after_invocations.push('after 2') }); + + it("invokes the [before]s in lexical order before each [it]", function() { + expect(before_invocations).to(equal, ['before 1', 'before 2']); + }); + + it("invokes the [afters]s in lexical order after each [it]", function() { + expect(after_invocations).to(equal, ['after 1', 'after 2']); + }); + }); + + describe("A describe with a nested describe", function() { + var before_invocations = [], after_invocations = []; + before(function() { + before_invocations = []; + before_invocations.push("outermost before"); + }); + + after(function() { + after_invocations = []; + after_invocations.push("outermost after"); + }); + + it("outside a nested [describe], does not invoke any of the nested's [before]s", function() { + expect(before_invocations).to(equal, ["outermost before"]); + }); + + it("outside a nested [describe], does not invoke any of the nested's [after]s", function() { + expect(after_invocations).to(equal, ["outermost after"]); + }); + + describe("a nested [describe]", function() { + before(function() { + before_invocations.push("inner before"); + }); + + after(function() { + after_invocations.push("inner after"); + }); + + it("runs [before]s in the parent [describe] before each [it]", function() { + expect(before_invocations).to(equal, ["outermost before", "inner before"]); + }); + + it("runs [after]s in the parent [describe] after each [it]", function() { + expect(after_invocations).to(equal, ["outermost after", "inner after"]); + }); + + describe("a doubly nested [describe]", function() { + before(function() { + before_invocations.push('innermost before'); + }); + + after(function() { + after_invocations.push('innermost after'); + }); + + describe('[before] blocks', function() { + it("runs [before]s in all ancestors before an [it]", function() { + expect(before_invocations).to(equal, ["outermost before", "inner before", "innermost before"]); + }); + + it("runs [before]s in all ancestors before each [it]", function() { + expect(before_invocations).to(equal, ["outermost before", "inner before", "innermost before"]); + }); + }); + + describe('[after] blocks', function() { + it("runs [after]s in all ancestors after an [it]", function() { + expect(after_invocations).to(equal, ["outermost after", "inner after", "innermost after"]); + }); + + it("runs [after]s in all ancestors after each [it]", function() { + expect(after_invocations).to(equal, ["outermost after", "inner after", "innermost after"]); + }); + }); + }); + }); + }); + + describe("A describe block with exceptions", function() { + var after_invoked = false; + after(function() { + after_invoked = true; + }); + + describe("an exception in a test", function() { + it("fails because it throws an exception", function() { + throw('an exception'); + }); + + it("invokes [after]s even if the previous [it] raised an exception", function() { + expect(after_invoked).to(equal, true); + }); + }); + }); + }); + + describe("#selector", function() { + describe('a [describe]', function() { + it('manufactures a CSS selector that uniquely locates the [describe]', function() { + $('.describe').each(function() { + expect($($(this).fn('selector')).get(0)).to(equal, $(this).get(0)) + }); + }); + }); + + describe('an [it]', function() { + it('manufactures a CSS selector that uniquely locates the [it]', function() { + $('.it').each(function() { + expect($($(this).fn('selector')).get(0)).to(equal, $(this).get(0)) + }); + }); + }); + }); + }); +}); \ No newline at end of file diff --git a/spec/matchers_spec.js b/spec/matchers_spec.js new file mode 100644 index 0000000..ebaff67 --- /dev/null +++ b/spec/matchers_spec.js @@ -0,0 +1,86 @@ +Screw.Unit(function() { + describe("Matchers", function() { + describe('#equal', function() { + it("invokes the provided matcher on a call to expect", function() { + expect(true).to(equal, true); + expect(true).to_not(equal, false); + }); + + describe('when given an object', function() { + it("matches Objects with the same keys and values", function() { + expect({a: 'b', c: 'd'}).to(equal, {a: 'b', c: 'd'}); + expect({a: 'b', c: 'd', e: 'f'}).to_not(equal, {a: 'b', c: 'd', e: 'G'}); + }); + + }); + + describe('when given an array', function() { + it("matches Arrays with the same elements", function() { + expect([1, 2, 4]).to(equal, [1, 2, 4]); + expect([1, 2, 3]).to_not(equal, [3, 2, 1]); + }); + + it("recursively applies equality to complex elements", function() { + expect([{a: 'b'}, {c: 'd'}]).to(equal, [{a: 'b'}, {c: 'd'}]); + expect([{a: 'b'}, {c: 'd'}]).to_not(equal, [{a: 'b'}, {c: 'E'}]); + }); + }); + + describe(".failure_message", function() { + it('prints "expected "expected" to (not) be equal "actual""', function() { + var message = null; + try { expect(1).to(equal, 2) } catch(e) { message = e } + expect(message).to(equal, 'expected "1" to equal "2"'); + + try { expect(1).to_not(equal, 1) } catch(e) { message = e } + expect(message).to(equal, 'expected "1" to not equal "1"'); + }); + }); + }); + + describe('#match', function() { + describe('when given a regular expression', function() { + it("matches Strings produced by the grammar", function() { + expect("The wheels of the bus").to(match, /bus/); + expect("The wheels of the bus").to_not(match, /boat/); + }); + }); + + describe('when given a string', function() { + it("matches [expected]s containing [actual]s", function() { + expect("The wheels of the bus").to(match, "wheels"); + expect("The wheels of the bus").to_not(match, "oars"); + }); + }); + + describe(".failure_message", function() { + it('prints "expected "actual" to (not) match "expected"', function() { + var message = null; + try { expect("hello").to(match, "schmello") } catch(e) { message = e } + expect(message).to(equal, 'expected "hello" to match "schmello"'); + + try { expect("hello").to_not(match, "ello") } catch(e) { message = e } + expect(message).to(equal, 'expected "hello" to not match "ello"'); + }); + }); + }); + + describe('#be_empty', function() { + it("matches Arrays with no elements", function() { + expect([]).to(be_empty); + expect([1]).to_not(be_empty); + }); + + describe(".failure_message", function() { + it("prints 'expected [actual] to (not) be empty", function() { + var message = null; + try { expect([1]).to(be_empty) } catch(e) { message = e } + expect(message).to(equal, 'expected "[1]" to be empty'); + + try { expect([]).to_not(be_empty) } catch(e) { message = e } + expect(message).to(equal, 'expected "[]" to not be empty'); + }); + }); + }); + }); +}); \ No newline at end of file diff --git a/spec/screwunit_spec.js b/spec/screwunit_spec.js deleted file mode 100644 index 35d90f6..0000000 --- a/spec/screwunit_spec.js +++ /dev/null @@ -1,394 +0,0 @@ -Screw.Unit(function() { - var global_before_invoked = 0; - var global_after_invoked = 0; - before(function() { - try { - expect(global_before_invoked).to(equal, 0); - } finally { - global_before_invoked++; - global_after_invoked = 0; - } - }); - - after(function() { - try { - expect(global_after_invoked).to(equal, false); - } finally { - global_before_invoked = 0; - global_after_invoked = 1; - } - }); - - describe('Screw.Unit', function() { - describe("Matchers", function() { - describe("#equal", function() { - describe("when actual is a primitive", function() { - describe(".matches", function() { - it("matches when expected == actual", function() { - expect(true).to(equal, true); - expect(true).to_not(equal, false); - }); - }); - - describe(".failure_message", function() { - describe("on a positive failure", function() { - it("prints 'expected [actual] to equal [expected]", function() { - var message = null; - try { - expect(true).to(equal, false); - } catch(e) { - message = e; - } - expect(message).to(equal, "expected [true] to equal [false]"); - }); - }); - - describe("on a negative failure", function() { - it("prints 'expected [actual] to not equal [expected]", function() { - var message = null; - try { - expect(true).to_not(equal, true); - } catch(e) { - message = e; - } - expect(message).to(equal, "expected [true] to not equal [true]"); - }); - }); - }); - }); - - describe("when actual is an Array", function() { - describe("and contents are primitives", function() { - describe(".matches", function() { - it("matches when Arrays the expected and actual have the same contents", function() { - expect([1, 2, 3]).to(equal, [1, 2, 3]); - expect([1, 2, 3]).to_not(equal, [3, 2, 1]); - }); - }); - - describe(".failure_message", function() { - describe("on a positive failure", function() { - it("prints 'expected [actual] to equal [expected]", function() { - var message = null; - try { - expect([1, 2, 3]).to(equal, [1, 2, 4]); - } catch(e) { - message = e; - } - expect(message).to(equal, "expected [1,2,3] to equal [1,2,4]"); - }); - }); - - describe("on a negative failure", function() { - it("prints 'expected [actual] to not equal [expected]", function() { - var message = null; - try { - expect([1, 2, 3]).to_not(equal, [1, 2, 3]); - } catch(e) { - message = e; - } - expect(message).to(equal, "expected [1,2,3] to not equal [1,2,3]"); - }); - }); - }); - }); - - describe("and contents are Objects", function() { - describe(".matches", function() { - it("matches when all the items' expected's keys match all of actual's keys", function() { - expect([{foo: 1, bar: 2}, {foo: 3, bar: 4}]).to(equal, [{foo: 1, bar: 2}, {foo: 3, bar: 4}]); - expect([{foo: 1, bar: 2}, {foo: 3, bar: 4}]).to_not(equal, [{foo: 1, bar: 2}, {foo: 3, bar: 5}]); - }); - }); - - describe(".failure_message", function() { - describe("on a positive failure", function() { - it("prints 'expected [actual] to equal [expected]", function() { - var message = null; - try { - expect([{foo: 1, bar: 2}, {foo: 3, bar: 4}]).to(equal, [{foo: 1, bar: 2}, {foo: 3, bar: 5}]); - } catch(e) { - message = e; - } - expect(message).to(equal, "expected [[object Object],[object Object]] to equal [[object Object],[object Object]]"); - }); - }); - - describe("on a negative failure", function() { - it("prints 'expected [actual] to not equal [expected]", function() { - var message = null; - try { - expect([{foo: 1, bar: 2}, {foo: 3, bar: 4}]).to_not(equal, [{foo: 1, bar: 2}, {foo: 3, bar: 4}]); - } catch(e) { - message = e; - } - expect(message).to(equal, "expected [[object Object],[object Object]] to not equal [[object Object],[object Object]]"); - }); - }); - }); - }); - }); - - describe("when actual is an Object", function() { - describe(".matches", function() { - it("matches when all expected's keys match all of actual's keys", function() { - expect({foo: 1, bar: 2}).to(equal, {foo: 1, bar: 2}); - expect({foo: 1, bar: 2}).to_not(equal, {foo: 1, bar: 3}); - }); - }); - - describe(".failure_message", function() { - describe("on a positive failure", function() { - it("prints 'expected [actual] to equal [expected]", function() { - var message = null; - try { - expect({foo: 1, bar: 2}).to(equal, {foo: 1, bar: 3}); - } catch(e) { - message = e; - } - expect(message).to(equal, "expected [[object Object]] to equal [[object Object]]"); - }); - }); - - describe("on a negative failure", function() { - it("prints 'expected [actual] to not equal [expected]", function() { - var message = null; - try { - expect({foo: 1, bar: 2}).to_not(equal, {foo: 1, bar: 2}); - } catch(e) { - message = e; - } - expect(message).to(equal, "expected [[object Object]] to not equal [[object Object]]"); - }); - }); - }); - }); - }); - - describe("#match", function() { - describe("when passed a Regex", function() { - describe(".matches", function() { - it("matches when expected =~ actual", function() { - expect("The wheels of the bus").to(match, /bus/); - expect("The wheels of the bus").to_not(match, /boat/); - }); - }); - - describe(".failure_message", function() { - describe("on a positive failure", function() { - it("prints 'expected [actual] to match [expected]", function() { - var message = null; - try { - expect("Hello").to(match, /Goodbye/); - } catch(e) { - message = e; - } - expect(message).to(equal, "expected [Hello] to match [/Goodbye/]"); - }); - }); - - describe("on a negative failure", function() { - it("prints 'expected [actual] to not match [expected]", function() { - var message = null; - try { - expect("Hello").to_not(match, /ello/); - } catch(e) { - message = e; - } - expect(message).to(equal, "expected [Hello] to not match [/ello/]"); - }); - }); - }); - }); - - describe("when passed a String", function() { - describe(".matches", function() { - it("matches when expected is included in actual", function() { - expect("The wheels of the bus").to(match, "wheels"); - expect("The wheels of the bus").to_not(match, "oars"); - }); - }); - - describe(".failure_message", function() { - describe("on a positive failure", function() { - it("prints 'expected [actual] to match [expected]", function() { - var message = null; - try { - expect("Hello").to(match, "goodbye"); - } catch(e) { - message = e; - } - expect(message).to(equal, "expected [Hello] to match [goodbye]"); - }); - }); - - describe("on a negative failure", function() { - it("prints 'expected [actual] to not match [expected]", function() { - var message = null; - try { - expect("Hello").to_not(match, "ello"); - } catch(e) { - message = e; - } - expect(message).to(equal, "expected [Hello] to not match [ello]"); - }); - }); - }); - }); - }); - - describe("#be_empty", function() { - describe(".matches", function() { - it("matches when Array#length == 0", function() { - expect([]).to(be_empty); - expect([1]).to_not(be_empty); - }); - }); - - describe(".failure_message", function() { - describe("on a positive failure", function() { - it("prints 'expected ... to be empty'", function() { - var message = null; - try { - expect([1]).to(be_empty); - } catch(e) { - message = e; - } - expect(message).to(equal, "expected [1] to be empty"); - }); - }); - - describe("on a negative failure", function() { - it("prints 'expected ... to not be empty'", function() { - var message = null; - try { - expect([]).to_not(be_empty); - } catch(e) { - message = e; - } - expect(message).to(equal, "expected [] to not be empty"); - }); - }); - }); - }); - }); - - describe('#run', function() { - describe("A describe with a before and after block", function() { - var before_invoked = 0; - var after_invoked = 0; - before(function() { - try { - expect(before_invoked).to(equal, 0); - } finally { - before_invoked++; - after_invoked = 0; - } - }); - after(function() { - try { - expect(after_invoked).to(equal, 0); - } finally { - before_invoked = 0; - after_invoked++; - } - }); - - it("invokes the global before prior to an it", function() { - expect(global_before_invoked).to(equal, 1); - }); - - it("invokes the before prior to an it", function() { - expect(before_invoked).to(equal, 1); - }); - - it("invokes the after callback after an it", function() { - expect(after_invoked).to(equal, 0); - }); - - it("invokes the global after callback after an it", function() { - expect(global_after_invoked).to(equal, 0); - }); - }); - - describe("A describe with two before blocks", function() { - var invocations = []; - before(function() { - invocations.push('before 1'); - }); - - before(function() { - invocations.push('before 2'); - }); - - it("invokes the befores in lexical order prior to each it", function() { - expect(invocations).to(equal, ['before 1', 'before 2']); - }); - }); - - describe("A describe with a nested describe", function() { - var invocations = []; - before(function() { - invocations = []; - invocations.push("outermost before"); - }); - - it("after a nested describe, does not invoke any of its befores", function() { - expect(invocations).to(equal, ["outermost before"]); - }); - - describe("a nested describe", function() { - before(function() { - invocations.push("inner before"); - }); - - describe("a doubly nested describe", function() { - before(function() { - invocations.push('innermost before'); - }) - - it("runs befores in all ancestors prior to an it", function() { - expect(invocations).to(equal, ["outermost before", "inner before", "innermost before"]); - }); - - it("runs befores in all ancestors prior to each it", function() { - expect(invocations).to(equal, ["outermost before", "inner before", "innermost before"]); - }); - }); - - it("runs a before in the parent describe before each it", function() { - expect(invocations).to(equal, ["outermost before", "inner before"]); - }); - }); - }); - - var before_triggered = false; - $(Screw).bind('before', function() { - before_triggered = true; - }); - describe("$(Screw).bind('before')", function() { - it('invokes before bindings before the specs run', function() { - expect(before_triggered).to(equal, true); - }); - }); - }); - - describe("#selector", function() { - describe('a describe', function() { - it('returns a css selector that uniquely locates the describe', function() { - $('.describe').each(function() { - expect($($(this).fn('selector')).get(0)).to(equal, $(this).get(0)) - }); - }); - }); - - describe('an it', function() { - it('returns a css selector that uniquely locates the it', function() { - $('.it').each(function() { - expect($($(this).fn('selector')).get(0)).to(equal, $(this).get(0)) - }); - }); - }); - }); - }); -}); \ No newline at end of file diff --git a/spec/screwunit_spec.html b/spec/suite.html similarity index 58% rename from spec/screwunit_spec.html rename to spec/suite.html index ca05360..142b5b7 100644 --- a/spec/screwunit_spec.html +++ b/spec/suite.html @@ -4,14 +4,14 @@ + - - + + + + + \ No newline at end of file