From 39c6c5975bedf6e1610f7328a088acda9ab3406a Mon Sep 17 00:00:00 2001 From: Adam Abrons Date: Mon, 15 Mar 2010 17:02:54 -0700 Subject: get scenarios running again - open Runner.html in a browser to run them --- src/scenario/Runner.js | 171 +++++++++++++++++++++++++++++++++++++++++++++ src/scenario/Steps.js | 57 +++++++++++++++ src/scenario/_namespace.js | 6 ++ src/scenario/bootstrap.js | 47 +++++++++++++ 4 files changed, 281 insertions(+) create mode 100644 src/scenario/Runner.js create mode 100644 src/scenario/Steps.js create mode 100644 src/scenario/_namespace.js create mode 100644 src/scenario/bootstrap.js (limited to 'src/scenario') diff --git a/src/scenario/Runner.js b/src/scenario/Runner.js new file mode 100644 index 00000000..7caddc98 --- /dev/null +++ b/src/scenario/Runner.js @@ -0,0 +1,171 @@ +var scenario = angular.scenario; +scenario.SuiteRunner = function(scenarios, body) { + this.scenarios = scenarios; + this.body = body; +}; + +scenario.SuiteRunner.prototype = { + run:function(){ + this.setUpUI(); + this.runScenarios(); + }, + + + setUpUI:function(){ + this.body.html( + '
' + + '
' + + '
' + + '
' + + '' + + '
'); + this.console = this.body.find(".console"); + this.testFrame = this.body.find("iframe"); + this.console.find(".run").live("click", function(){ + jQuery(this).parent().find('.log').toggle(); + }); + }, + + + runScenarios:function(){ + var runner = new scenario.Runner(this.console, this.testFrame); + _.stepper(this.scenarios, function(next, scenarioObj, name){ + new scenario.Scenario(name, scenarioObj).run(runner, next); + }, function(){ + } + ); + } +}; + +scenario.Runner = function(console, frame){ + this.console = console; + this.current = null; + this.tests = []; + this.frame = frame; +}; +scenario.Runner.prototype = { + start:function(name){ + var current = this.current = { + name:name, + start:new Date().getTime(), + scenario:jQuery('
') + }; + current.run = current.scenario.append( + '
' + + '.' + + '.' + + '.' + + '').find(".run"); + current.log = current.scenario.append('
').find(".log"); + current.run.find(".name").text(name); + this.tests.push(current); + this.console.append(current.scenario); + }, + end:function(name){ + var current = this.current; + var run = current.run; + this.current = null; + current.end = new Date().getTime(); + current.time = current.end - current.start; + run.find(".time").text(current.time); + run.find(".state").text(current.error ? "FAIL" : "PASS"); + run.addClass(current.error ? "fail" : "pass"); + if (current.error) + run.find(".run").append('').text(current.error); + current.scenario.find(".log").hide(); + }, + log:function(level) { + var buf = []; + for ( var i = 1; i < arguments.length; i++) { + var arg = arguments[i]; + buf.push(typeof arg == "string" ?arg:toJson(arg)); + } + var log = jQuery('
'); + log.text(buf.join(" ")); + this.current.log.append(log); + this.console.scrollTop(this.console[0].scrollHeight); + if (level == "error") + this.current.error = buf.join(" "); + } +}; + +scenario.Scenario = function(name, scenario){ + this.name = name; + this.scenario = scenario; +}; +scenario.Scenario.prototype = { + run:function(runner, callback) { + var self = this; + _.stepper(this.scenario, function(next, steps, name){ + if (name.charAt(0) == '$') { + next(); + } else { + runner.start(self.name + "::" + name); + var allSteps = (self.scenario.$before||[]).concat(steps); + _.stepper(allSteps, function(next, step){ + self.executeStep(runner, step, next); + }, function(){ + runner.end(); + next(); + }); + } + }, callback); + }, + + + verb:function(step){ + var fn = null; + if (!step) fn = function (){ throw "Step is null!"; }; + else if (step.Given) fn = scenario.GIVEN[step.Given]; + else if (step.When) fn = scenario.WHEN[step.When]; + else if (step.Then) fn = scenario.THEN[step.Then]; + return fn || function (){ + throw "ERROR: Need Given/When/Then got: " + toJson(step); + }; + }, + + + context: function(runner) { + var frame = runner.frame; + var window = frame[0].contentWindow; + var document; + if (window.jQuery) + document = window.jQuery(window.document); + var context = { + frame:frame, + window:window, + log:_.bind(runner.log, runner, "info"), + document:document, + assert:function(element, path){ + if (element.size() != 1) { + throw "Expected to find '1' found '"+ + element.size()+"' for '"+path+"'."; + } + return element; + }, + element:function(path){ + var exp = path.replace("{{","[ng-bind=").replace("}}", "]"); + var element = document.find(exp); + return context.assert(element, path); + } + }; + return context; + }, + + + executeStep:function(runner, step, callback) { + if (!step) { + callback(); + return; + } + runner.log("info", toJson(step)); + var fn = this.verb(step); + var context = this.context(runner); + _.extend(context, step); + try { + (fn.call(context)||function(c){c();})(callback); + } catch (e) { + runner.log("error", "ERROR: " + toJson(e)); + } + } +}; diff --git a/src/scenario/Steps.js b/src/scenario/Steps.js new file mode 100644 index 00000000..f8ac173f --- /dev/null +++ b/src/scenario/Steps.js @@ -0,0 +1,57 @@ +angular.scenario.GIVEN = { + browser:function(){ + var self = this; + if (jQuery.browser.safari && this.frame.attr('src') == this.at) { + this.window.location.reload(); + } else { + this.frame.attr('src', this.at); + } + return function(done){ + self.frame.load(function(){ + self.frame.unbind(); + done(); + }); + }; + }, + dataset:function(){ + this.frame.name="$DATASET:" + toJson({dataset:this.dataset}); + } +}; +angular.scenario.WHEN = { + enter:function(){ + var element = this.element(this.at); + element.attr('value', this.text); + element.change(); + }, + click:function(){ + var element = this.element(this.at); + var input = element[0]; + // emulate the browser behavior which causes it + // to be overridden at the end. + var checked = input.checked = !input.checked; + element.click(); + input.checked = checked; + }, + select:function(){ + var element = this.element(this.at); + var path = "option[value=" + this.option + "]"; + var option = this.assert(element.find(path)); + option[0].selected = !option[0].selected; + element.change(); + } +}; +angular.scenario.THEN = { + text:function(){ + var element = this.element(this.at); + if (typeof this.should_be != undefined ) { + var should_be = this.should_be; + if (_.isArray(this.should_be)) + should_be = JSON.stringify(should_be); + if (element.text() != should_be) + throw "Expected " + should_be + + " but was " + element.text() + "."; + } + }, + drainRequestQueue:function(){ + } +}; diff --git a/src/scenario/_namespace.js b/src/scenario/_namespace.js new file mode 100644 index 00000000..7da3a5d8 --- /dev/null +++ b/src/scenario/_namespace.js @@ -0,0 +1,6 @@ +if (!angular) var angular = window['angular'] = {}; +if (!angular['scenario']) var angularScenario = angular['scenario'] = {}; +if (!angular['scenarioDef']) var scenarioDef = angular['scenarioDef'] = {}; +if (!angular['scenario']['GIVEN']) angularScenario['GIVEN'] = {}; +if (!angular['scenario']['WHEN']) angularScenario['WHEN'] = {}; +if (!angular['scenario']['THEN']) angularScenario['THEN'] = {}; diff --git a/src/scenario/bootstrap.js b/src/scenario/bootstrap.js new file mode 100644 index 00000000..1d40b9d0 --- /dev/null +++ b/src/scenario/bootstrap.js @@ -0,0 +1,47 @@ +(function(onLoadDelegate){ + var prefix = (function(){ + var filename = /(.*\/)bootstrap.js(#(.*))?/; + var scripts = document.getElementsByTagName("script"); + for(var j = 0; j < scripts.length; j++) { + var src = scripts[j].src; + if (src && src.match(filename)) { + var parts = src.match(filename); + return parts[1]; + } + } + })(); + function addScript(path) { + document.write(''); + }; + function addCSS(path) { + document.write(''); + }; + window.onload = function(){ + if (!_.stepper) { + _.stepper = function(collection, iterator, done){ + var keys = _.keys(collection); + function next() { + if (keys.length) { + var key = keys.shift(); + iterator(next, collection[key], key); + } else { + (done||_.identity)(); + } + } + next(); + }; + } + _.defer(function(){ + new angular.scenario.SuiteRunner(angular.scenarioDef, jQuery(document.body)).run(); + }); + (onLoadDelegate||function(){})(); + }; + addCSS("../../css/angular-scenario.css"); + addScript("../../lib/underscore/underscore.js"); + addScript("../../lib/jquery/jquery-1.3.2.js"); + addScript("../angular-bootstrap.js"); + addScript("_namespace.js"); + addScript("Steps.js"); + addScript("Runner.js"); +})(window.onload); + -- cgit v1.2.3 From 1b976dc27d022c681d764d51a70a1af6a7e35dd6 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Tue, 23 Mar 2010 15:16:44 -0700 Subject: tweeter demo script --- src/scenario/bootstrap.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/scenario') diff --git a/src/scenario/bootstrap.js b/src/scenario/bootstrap.js index 1d40b9d0..b49530df 100644 --- a/src/scenario/bootstrap.js +++ b/src/scenario/bootstrap.js @@ -8,7 +8,7 @@ var parts = src.match(filename); return parts[1]; } - } + } })(); function addScript(path) { document.write(''); @@ -17,7 +17,7 @@ document.write(''); }; window.onload = function(){ - if (!_.stepper) { + if (!_.stepper) { _.stepper = function(collection, iterator, done){ var keys = _.keys(collection); function next() { @@ -38,7 +38,7 @@ }; addCSS("../../css/angular-scenario.css"); addScript("../../lib/underscore/underscore.js"); - addScript("../../lib/jquery/jquery-1.3.2.js"); + addScript("../../lib/jquery/jquery-1.4.2.js"); addScript("../angular-bootstrap.js"); addScript("_namespace.js"); addScript("Steps.js"); -- cgit v1.2.3 From 9f9bdcf3d16de651f85ccfe9e079cb57baca9eb7 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Mon, 19 Apr 2010 14:41:36 -0700 Subject: lint --- src/scenario/bootstrap.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/scenario') diff --git a/src/scenario/bootstrap.js b/src/scenario/bootstrap.js index b49530df..169f1860 100644 --- a/src/scenario/bootstrap.js +++ b/src/scenario/bootstrap.js @@ -12,10 +12,12 @@ })(); function addScript(path) { document.write(''); - }; + } + function addCSS(path) { document.write(''); - }; + } + window.onload = function(){ if (!_.stepper) { _.stepper = function(collection, iterator, done){ -- cgit v1.2.3 From 22d93e0a3bc2a6dc0f64c63c68bc8f8489ea9068 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Tue, 20 Apr 2010 18:14:13 -0700 Subject: fixes to enable ie --- src/scenario/Steps.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/scenario') diff --git a/src/scenario/Steps.js b/src/scenario/Steps.js index f8ac173f..ffe75933 100644 --- a/src/scenario/Steps.js +++ b/src/scenario/Steps.js @@ -29,14 +29,14 @@ angular.scenario.WHEN = { // emulate the browser behavior which causes it // to be overridden at the end. var checked = input.checked = !input.checked; - element.click(); + element.trigger('click'); input.checked = checked; }, select:function(){ var element = this.element(this.at); var path = "option[value=" + this.option + "]"; var option = this.assert(element.find(path)); - option[0].selected = !option[0].selected; + option[0].selected = !option[0].selected; element.change(); } }; @@ -48,7 +48,7 @@ angular.scenario.THEN = { if (_.isArray(this.should_be)) should_be = JSON.stringify(should_be); if (element.text() != should_be) - throw "Expected " + should_be + + throw "Expected " + should_be + " but was " + element.text() + "."; } }, -- cgit v1.2.3 From 5215e2095cfd42a0363eb02eded34e03fa2b0cd3 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Thu, 20 May 2010 15:55:41 -0700 Subject: basic end to end runner --- src/scenario/Runner.js | 250 +++++++++++++++++---------------------------- src/scenario/Steps.js | 57 ----------- src/scenario/_namespace.js | 6 -- src/scenario/bootstrap.js | 19 +--- 4 files changed, 96 insertions(+), 236 deletions(-) delete mode 100644 src/scenario/Steps.js delete mode 100644 src/scenario/_namespace.js (limited to 'src/scenario') diff --git a/src/scenario/Runner.js b/src/scenario/Runner.js index 7caddc98..eeb4330d 100644 --- a/src/scenario/Runner.js +++ b/src/scenario/Runner.js @@ -1,171 +1,109 @@ -var scenario = angular.scenario; -scenario.SuiteRunner = function(scenarios, body) { - this.scenarios = scenarios; - this.body = body; -}; +angular['scenario'] = (angular['scenario'] = {}); -scenario.SuiteRunner.prototype = { - run:function(){ - this.setUpUI(); - this.runScenarios(); - }, +angular.scenario.Runner = function(scope){ + var self = scope.$scenario = this; + this.scope = scope; + var specs = this.specs = {}; + var path = []; + this.scope.describe = function describe(name, body){ + path.push(name); + body(); + path.pop(); + }; + this.scope.it = function it(name, body) { + var specName = path.join(' ') + ': it ' + name; + self.currentSpec = specs[specName] = { + name: specName, + steps:[] + }; + body(); + self.currentSpec = null; + }; + this.beginSpec = function returnNoop(){ + return returnNoop; + }; +}; - setUpUI:function(){ - this.body.html( +angular.scenario.Runner.prototype = { + run: function(body){ + body.append( '
' + - '
' + + '' + '
' + '
' + '' + '
'); - this.console = this.body.find(".console"); - this.testFrame = this.body.find("iframe"); - this.console.find(".run").live("click", function(){ - jQuery(this).parent().find('.log').toggle(); - }); - }, - - - runScenarios:function(){ - var runner = new scenario.Runner(this.console, this.testFrame); - _.stepper(this.scenarios, function(next, scenarioObj, name){ - new scenario.Scenario(name, scenarioObj).run(runner, next); - }, function(){ - } - ); - } -}; - -scenario.Runner = function(console, frame){ - this.console = console; - this.current = null; - this.tests = []; - this.frame = frame; -}; -scenario.Runner.prototype = { - start:function(name){ - var current = this.current = { - name:name, - start:new Date().getTime(), - scenario:jQuery('
') + var console = body.find('#runner .console'); + this.testFrame = body.find('#testView iframe'); + this.testWindow = this.testFrame[0].contentWindow; + this.beginSpec = function(name){ + var specElement = jQuery('
  • '); + var stepContainer = jQuery(''); + console.append(specElement); + specElement.text(name); + specElement.append(stepContainer); + return function(name){ + var stepElement = jQuery('
  • '); + var logContainer = jQuery(''); + stepContainer.append(stepElement); + stepElement.text(name); + stepElement.append(logContainer); + return function(message) { + var logElement = jQuery('
  • '); + logContainer.append(logElement); + logElement.text(message); + }; + }; }; - current.run = current.scenario.append( - '
    ' + - '.' + - '.' + - '.' + - '').find(".run"); - current.log = current.scenario.append('
    ').find(".log"); - current.run.find(".name").text(name); - this.tests.push(current); - this.console.append(current.scenario); - }, - end:function(name){ - var current = this.current; - var run = current.run; - this.current = null; - current.end = new Date().getTime(); - current.time = current.end - current.start; - run.find(".time").text(current.time); - run.find(".state").text(current.error ? "FAIL" : "PASS"); - run.addClass(current.error ? "fail" : "pass"); - if (current.error) - run.find(".run").append('').text(current.error); - current.scenario.find(".log").hide(); + this.execute("widgets: it should verify that basic widgets work"); }, - log:function(level) { - var buf = []; - for ( var i = 1; i < arguments.length; i++) { - var arg = arguments[i]; - buf.push(typeof arg == "string" ?arg:toJson(arg)); - } - var log = jQuery('
    '); - log.text(buf.join(" ")); - this.current.log.append(log); - this.console.scrollTop(this.console[0].scrollHeight); - if (level == "error") - this.current.error = buf.join(" "); - } -}; -scenario.Scenario = function(name, scenario){ - this.name = name; - this.scenario = scenario; -}; -scenario.Scenario.prototype = { - run:function(runner, callback) { - var self = this; - _.stepper(this.scenario, function(next, steps, name){ - if (name.charAt(0) == '$') { - next(); - } else { - runner.start(self.name + "::" + name); - var allSteps = (self.scenario.$before||[]).concat(steps); - _.stepper(allSteps, function(next, step){ - self.executeStep(runner, step, next); - }, function(){ - runner.end(); - next(); - }); - } - }, callback); + addStep: function(name, step) { + this.currentSpec.steps.push({name:name, fn:step}); }, - - verb:function(step){ - var fn = null; - if (!step) fn = function (){ throw "Step is null!"; }; - else if (step.Given) fn = scenario.GIVEN[step.Given]; - else if (step.When) fn = scenario.WHEN[step.When]; - else if (step.Then) fn = scenario.THEN[step.Then]; - return fn || function (){ - throw "ERROR: Need Given/When/Then got: " + toJson(step); + execute: function(name, callback) { + var spec = this.specs[name], + result = { + passed: false, + failed: false, + finished: false, + fail: function(error) { + result.passed = false; + result.failed = true; + result.error = error; + result.log(angular.isString(error) ? error : angular.toJson(error)); + } + }; + specThis = { + result: result, + testWindow: this.testWindow, + testFrame: this.testFrame }; - }, - - - context: function(runner) { - var frame = runner.frame; - var window = frame[0].contentWindow; - var document; - if (window.jQuery) - document = window.jQuery(window.document); - var context = { - frame:frame, - window:window, - log:_.bind(runner.log, runner, "info"), - document:document, - assert:function(element, path){ - if (element.size() != 1) { - throw "Expected to find '1' found '"+ - element.size()+"' for '"+path+"'."; - } - return element; - }, - element:function(path){ - var exp = path.replace("{{","[ng-bind=").replace("}}", "]"); - var element = document.find(exp); - return context.assert(element, path); - } - }; - return context; - }, - - - executeStep:function(runner, step, callback) { - if (!step) { - callback(); - return; - } - runner.log("info", toJson(step)); - var fn = this.verb(step); - var context = this.context(runner); - _.extend(context, step); - try { - (fn.call(context)||function(c){c();})(callback); - } catch (e) { - runner.log("error", "ERROR: " + toJson(e)); - } + var beginStep = this.beginSpec(name); + spec.nextStepIndex = 0; + function done() { + result.finished = true; + (callback||angular.noop).call(specThis); + } + function next(){ + var step = spec.steps[spec.nextStepIndex]; + if (step) { + spec.nextStepIndex ++; + result.log = beginStep(step.name); + try { + step.fn.call(specThis, next); + } catch (e) { + result.fail(e); + done(); + } + } else { + result.passed = !result.failed; + done(); + } + }; + next(); + return specThis; } -}; +}; \ No newline at end of file diff --git a/src/scenario/Steps.js b/src/scenario/Steps.js deleted file mode 100644 index ffe75933..00000000 --- a/src/scenario/Steps.js +++ /dev/null @@ -1,57 +0,0 @@ -angular.scenario.GIVEN = { - browser:function(){ - var self = this; - if (jQuery.browser.safari && this.frame.attr('src') == this.at) { - this.window.location.reload(); - } else { - this.frame.attr('src', this.at); - } - return function(done){ - self.frame.load(function(){ - self.frame.unbind(); - done(); - }); - }; - }, - dataset:function(){ - this.frame.name="$DATASET:" + toJson({dataset:this.dataset}); - } -}; -angular.scenario.WHEN = { - enter:function(){ - var element = this.element(this.at); - element.attr('value', this.text); - element.change(); - }, - click:function(){ - var element = this.element(this.at); - var input = element[0]; - // emulate the browser behavior which causes it - // to be overridden at the end. - var checked = input.checked = !input.checked; - element.trigger('click'); - input.checked = checked; - }, - select:function(){ - var element = this.element(this.at); - var path = "option[value=" + this.option + "]"; - var option = this.assert(element.find(path)); - option[0].selected = !option[0].selected; - element.change(); - } -}; -angular.scenario.THEN = { - text:function(){ - var element = this.element(this.at); - if (typeof this.should_be != undefined ) { - var should_be = this.should_be; - if (_.isArray(this.should_be)) - should_be = JSON.stringify(should_be); - if (element.text() != should_be) - throw "Expected " + should_be + - " but was " + element.text() + "."; - } - }, - drainRequestQueue:function(){ - } -}; diff --git a/src/scenario/_namespace.js b/src/scenario/_namespace.js deleted file mode 100644 index 7da3a5d8..00000000 --- a/src/scenario/_namespace.js +++ /dev/null @@ -1,6 +0,0 @@ -if (!angular) var angular = window['angular'] = {}; -if (!angular['scenario']) var angularScenario = angular['scenario'] = {}; -if (!angular['scenarioDef']) var scenarioDef = angular['scenarioDef'] = {}; -if (!angular['scenario']['GIVEN']) angularScenario['GIVEN'] = {}; -if (!angular['scenario']['WHEN']) angularScenario['WHEN'] = {}; -if (!angular['scenario']['THEN']) angularScenario['THEN'] = {}; diff --git a/src/scenario/bootstrap.js b/src/scenario/bootstrap.js index 169f1860..81272bdd 100644 --- a/src/scenario/bootstrap.js +++ b/src/scenario/bootstrap.js @@ -19,22 +19,8 @@ } window.onload = function(){ - if (!_.stepper) { - _.stepper = function(collection, iterator, done){ - var keys = _.keys(collection); - function next() { - if (keys.length) { - var key = keys.shift(); - iterator(next, collection[key], key); - } else { - (done||_.identity)(); - } - } - next(); - }; - } _.defer(function(){ - new angular.scenario.SuiteRunner(angular.scenarioDef, jQuery(document.body)).run(); + $scenarioRunner.run(jQuery(document.body)); }); (onLoadDelegate||function(){})(); }; @@ -42,8 +28,7 @@ addScript("../../lib/underscore/underscore.js"); addScript("../../lib/jquery/jquery-1.4.2.js"); addScript("../angular-bootstrap.js"); - addScript("_namespace.js"); - addScript("Steps.js"); addScript("Runner.js"); + document.write(''); })(window.onload); -- cgit v1.2.3 From e3368e12a6207706d8a08b18f9958db3b86ca4e5 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Thu, 20 May 2010 16:55:47 -0700 Subject: semi working state --- src/scenario/Runner.js | 63 +++++++++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 24 deletions(-) (limited to 'src/scenario') diff --git a/src/scenario/Runner.js b/src/scenario/Runner.js index eeb4330d..970d0c66 100644 --- a/src/scenario/Runner.js +++ b/src/scenario/Runner.js @@ -20,8 +20,8 @@ angular.scenario.Runner = function(scope){ body(); self.currentSpec = null; }; - this.beginSpec = function returnNoop(){ - return returnNoop; + this.logger = function returnNoop(){ + return angular.extend(returnNoop, {close:angular.noop, fail:angular.noop});; }; }; @@ -29,33 +29,45 @@ angular.scenario.Runner.prototype = { run: function(body){ body.append( '
    ' + - '
      ' + + '
      ' + '
      ' + '
      ' + '' + '
      '); var console = body.find('#runner .console'); + console.find('li').live('click', function(){ + jQuery(this).toggleClass('collapsed'); + }); this.testFrame = body.find('#testView iframe'); this.testWindow = this.testFrame[0].contentWindow; - this.beginSpec = function(name){ - var specElement = jQuery('
    • '); - var stepContainer = jQuery(''); - console.append(specElement); - specElement.text(name); - specElement.append(stepContainer); - return function(name){ - var stepElement = jQuery('
    • '); - var logContainer = jQuery(''); - stepContainer.append(stepElement); - stepElement.text(name); - stepElement.append(logContainer); - return function(message) { - var logElement = jQuery('
    • '); - logContainer.append(logElement); - logElement.text(message); - }; + function logger(parent) { + var container; + return function(type, text) { + if (!container) { + container = jQuery(''); + parent.append(container); + } + var element = jQuery(''); + element.find('span').text(text); + container.append(element); + return angular.extend(logger(element), { + close: function(){ + element.removeClass('running'); + }, + fail: function(){ + element.removeClass('running'); + var current = element; + while (current[0] != console[0]) { + if (current.is('li')) + current.addClass('fail'); + current.removeClass('collapsed'); + current = current.parent(); + } + } + });; }; - }; + } + this.logger = logger(console); this.execute("widgets: it should verify that basic widgets work"); }, @@ -73,7 +85,7 @@ angular.scenario.Runner.prototype = { result.passed = false; result.failed = true; result.error = error; - result.log(angular.isString(error) ? error : angular.toJson(error)); + result.log('fail', angular.isString(error) ? error : angular.toJson(error)).fail(); } }; specThis = { @@ -81,17 +93,20 @@ angular.scenario.Runner.prototype = { testWindow: this.testWindow, testFrame: this.testFrame }; - var beginStep = this.beginSpec(name); + var stepLogger = this.logger('spec', name); spec.nextStepIndex = 0; function done() { result.finished = true; + stepLogger.close(); (callback||angular.noop).call(specThis); } function next(){ var step = spec.steps[spec.nextStepIndex]; + (result.log || {close:angular.noop}).close(); + result.log = null; if (step) { spec.nextStepIndex ++; - result.log = beginStep(step.name); + result.log = stepLogger('step', step.name); try { step.fn.call(specThis, next); } catch (e) { -- cgit v1.2.3 From f6c67e28c94033edf6a16eb6508de54679cb49db Mon Sep 17 00:00:00 2001 From: Andres Ornelas Mesta Date: Mon, 24 May 2010 13:54:32 -0700 Subject: happy --- src/scenario/Runner.js | 44 +++++++++++++++++++++++++++++--------------- src/scenario/bootstrap.js | 6 ++++-- 2 files changed, 33 insertions(+), 17 deletions(-) (limited to 'src/scenario') diff --git a/src/scenario/Runner.js b/src/scenario/Runner.js index 970d0c66..9e20d394 100644 --- a/src/scenario/Runner.js +++ b/src/scenario/Runner.js @@ -1,8 +1,9 @@ angular['scenario'] = (angular['scenario'] = {}); -angular.scenario.Runner = function(scope){ +angular.scenario.Runner = function(scope, jQuery){ var self = scope.$scenario = this; this.scope = scope; + this.jQuery = jQuery; var specs = this.specs = {}; var path = []; @@ -27,6 +28,7 @@ angular.scenario.Runner = function(scope){ angular.scenario.Runner.prototype = { run: function(body){ + var jQuery = this.jQuery; body.append( '
      ' + '
      ' + @@ -68,7 +70,19 @@ angular.scenario.Runner.prototype = { }; } this.logger = logger(console); - this.execute("widgets: it should verify that basic widgets work"); + var specNames = []; + angular.foreach(this.specs, function(spec, name){ + specNames.push(name); + }, this); + specNames.sort(); + var self = this; + function callback(){ + var next = specNames.shift(); + if(next) { + self.execute(next, callback); + } + }; + callback(); }, addStep: function(name, step) { @@ -102,21 +116,21 @@ angular.scenario.Runner.prototype = { } function next(){ var step = spec.steps[spec.nextStepIndex]; - (result.log || {close:angular.noop}).close(); - result.log = null; - if (step) { - spec.nextStepIndex ++; - result.log = stepLogger('step', step.name); - try { - step.fn.call(specThis, next); - } catch (e) { - result.fail(e); - done(); - } - } else { - result.passed = !result.failed; + (result.log || {close:angular.noop}).close(); + result.log = null; + if (step) { + spec.nextStepIndex ++; + result.log = stepLogger('step', step.name); + try { + step.fn.call(specThis, next); + } catch (e) { + result.fail(e); done(); } + } else { + result.passed = !result.failed; + done(); + } }; next(); return specThis; diff --git a/src/scenario/bootstrap.js b/src/scenario/bootstrap.js index 81272bdd..51d24c38 100644 --- a/src/scenario/bootstrap.js +++ b/src/scenario/bootstrap.js @@ -20,7 +20,7 @@ window.onload = function(){ _.defer(function(){ - $scenarioRunner.run(jQuery(document.body)); + $scenarioRunner.run(jQuery(window.document.body)); }); (onLoadDelegate||function(){})(); }; @@ -29,6 +29,8 @@ addScript("../../lib/jquery/jquery-1.4.2.js"); addScript("../angular-bootstrap.js"); addScript("Runner.js"); - document.write(''); + document.write(''); })(window.onload); -- cgit v1.2.3 From 3fab5d9879272b9f991a67c8135754f00c055834 Mon Sep 17 00:00:00 2001 From: Andres Ornelas Date: Mon, 24 May 2010 15:25:30 -0700 Subject: added error handling on scenario definition --- src/scenario/DSL.js | 47 +++++++++++++++++++++++++++++++++++++++++++++++ src/scenario/Runner.js | 15 ++++++++++++--- src/scenario/bootstrap.js | 1 + 3 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 src/scenario/DSL.js (limited to 'src/scenario') diff --git a/src/scenario/DSL.js b/src/scenario/DSL.js new file mode 100644 index 00000000..4bc21d6c --- /dev/null +++ b/src/scenario/DSL.js @@ -0,0 +1,47 @@ +angular.scenario.dsl.browser = { + navigateTo: function(url){ + $scenario.addStep('Navigate to: ' + url, function(done){ + var self = this; + self.testFrame.load(function(){ + self.testFrame.unbind(); + self.testDocument = jQuery(self.testWindow.document); + done(); + }); + if (this.testFrame.attr('src') == url) { + this.testWindow.location.reload(); + } else { + this.testFrame.attr('src', url); + } + }); + } +}; + +angular.scenario.dsl.input = function(selector) { + return { + enter: function(value){ + $scenario.addStep("Set input text of '" + selector + "' to value '" + + value + "'", function(done){ + var input = this.testDocument.find('input[name=' + selector + ']'); + input.val(value); + input.trigger('change'); + this.testWindow.angular.element(input[0]).trigger('change'); + done(); + }); + } + }; +}; + +angular.scenario.dsl.expect = function(selector) { + return { + toEqual: function(expected) { + $scenario.addStep("Expect that " + selector + " equals '" + expected + "'", function(done){ + var attrName = selector.substring(2, selector.length - 2); + var binding = this.testDocument.find('span[ng-bind=' + attrName + ']'); + if (binding.text() != expected) { + this.result.fail("Expected '" + expected + "' but was '" + binding.text() + "'"); + } + done(); + }); + } + }; +}; diff --git a/src/scenario/Runner.js b/src/scenario/Runner.js index 9e20d394..003ce487 100644 --- a/src/scenario/Runner.js +++ b/src/scenario/Runner.js @@ -1,9 +1,11 @@ -angular['scenario'] = (angular['scenario'] = {}); +angular['scenario'] = (angular['scenario'] = {}); +angular.scenario['dsl'] = (angular.scenario['dsl'] = {}); angular.scenario.Runner = function(scope, jQuery){ var self = scope.$scenario = this; this.scope = scope; this.jQuery = jQuery; + angular.extend(scope, angular.scenario.dsl); var specs = this.specs = {}; var path = []; @@ -18,7 +20,13 @@ angular.scenario.Runner = function(scope, jQuery){ name: specName, steps:[] }; - body(); + try { + body(); + } catch(err) { + self.addStep(err.message || 'ERROR', function(){ + throw err; + }); + } self.currentSpec = null; }; this.logger = function returnNoop(){ @@ -55,6 +63,7 @@ angular.scenario.Runner.prototype = { return angular.extend(logger(element), { close: function(){ element.removeClass('running'); + console.scrollTop(console[0].scrollHeight); }, fail: function(){ element.removeClass('running'); @@ -66,7 +75,7 @@ angular.scenario.Runner.prototype = { current = current.parent(); } } - });; + }); }; } this.logger = logger(console); diff --git a/src/scenario/bootstrap.js b/src/scenario/bootstrap.js index 51d24c38..4c9cdc8d 100644 --- a/src/scenario/bootstrap.js +++ b/src/scenario/bootstrap.js @@ -29,6 +29,7 @@ addScript("../../lib/jquery/jquery-1.4.2.js"); addScript("../angular-bootstrap.js"); addScript("Runner.js"); + addScript("DSL.js"); document.write(''); -- cgit v1.2.3 From 55c0767f16e60e77e9d1b4d46698ddbf343ed8b1 Mon Sep 17 00:00:00 2001 From: Andres Ornelas Date: Mon, 24 May 2010 17:48:17 -0700 Subject: added dsl tests and select method --- src/scenario/DSL.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'src/scenario') diff --git a/src/scenario/DSL.js b/src/scenario/DSL.js index 4bc21d6c..842f7c7a 100644 --- a/src/scenario/DSL.js +++ b/src/scenario/DSL.js @@ -19,14 +19,24 @@ angular.scenario.dsl.browser = { angular.scenario.dsl.input = function(selector) { return { enter: function(value){ - $scenario.addStep("Set input text of '" + selector + "' to value '" + + $scenario.addStep("Set input text of '" + selector + "' to '" + value + "'", function(done){ var input = this.testDocument.find('input[name=' + selector + ']'); input.val(value); - input.trigger('change'); this.testWindow.angular.element(input[0]).trigger('change'); done(); }); + }, + select: function(value){ + $scenario.addStep("Select radio '" + selector + "' to '" + + value + "'", function(done){ + var input = this.testDocument. + find(':radio[name$=@' + selector + '][value=' + value + ']'); + var event = this.testWindow.document.createEvent('MouseEvent'); + event.initMouseEvent('click', true, true, this.testWindow, 0,0,0,0,0, false, false, false, false, 0, null); + input[0].dispatchEvent(event); + done(); + }); } }; }; -- cgit v1.2.3 From 2cce1ffc15ae6483da9cf354f7a5d2d26317427e Mon Sep 17 00:00:00 2001 From: Andres Ornelas Date: Tue, 25 May 2010 13:05:23 -0700 Subject: fixed collapsed issue --- src/scenario/Runner.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/scenario') diff --git a/src/scenario/Runner.js b/src/scenario/Runner.js index 003ce487..8669f56b 100644 --- a/src/scenario/Runner.js +++ b/src/scenario/Runner.js @@ -57,12 +57,14 @@ angular.scenario.Runner.prototype = { container = jQuery('
        '); parent.append(container); } - var element = jQuery(''); + var element = jQuery('
      • '); element.find('span').text(text); container.append(element); return angular.extend(logger(element), { close: function(){ element.removeClass('running'); + if(!element.hasClass('fail')) + element.addClass('collapsed'); console.scrollTop(console[0].scrollHeight); }, fail: function(){ @@ -71,7 +73,6 @@ angular.scenario.Runner.prototype = { while (current[0] != console[0]) { if (current.is('li')) current.addClass('fail'); - current.removeClass('collapsed'); current = current.parent(); } } -- cgit v1.2.3 From 5992e81b2e302c3b3375567e347227f6a9496585 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Tue, 25 May 2010 14:23:52 -0700 Subject: added rake task to create a single file for scenario runner --- src/scenario/DSL.js | 1 + src/scenario/Runner.js | 18 +++++++++--------- src/scenario/angular.prefix | 30 ++++++++++++++++++++++++++++++ src/scenario/angular.suffix | 11 +++++++++++ src/scenario/bootstrap.js | 9 ++++++++- 5 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 src/scenario/angular.prefix create mode 100644 src/scenario/angular.suffix (limited to 'src/scenario') diff --git a/src/scenario/DSL.js b/src/scenario/DSL.js index 842f7c7a..8cbb256d 100644 --- a/src/scenario/DSL.js +++ b/src/scenario/DSL.js @@ -5,6 +5,7 @@ angular.scenario.dsl.browser = { self.testFrame.load(function(){ self.testFrame.unbind(); self.testDocument = jQuery(self.testWindow.document); + self.testWindow = self.testFrame[0].contentWindow; done(); }); if (this.testFrame.attr('src') == url) { diff --git a/src/scenario/Runner.js b/src/scenario/Runner.js index 8669f56b..01e16e79 100644 --- a/src/scenario/Runner.js +++ b/src/scenario/Runner.js @@ -1,11 +1,10 @@ -angular['scenario'] = (angular['scenario'] = {}); -angular.scenario['dsl'] = (angular.scenario['dsl'] = {}); +angular['scenario'] = angular['scenario'] || (angular['scenario'] = {}); +angular.scenario['dsl'] = angular.scenario['dsl'] || (angular.scenario['dsl'] = {}); angular.scenario.Runner = function(scope, jQuery){ var self = scope.$scenario = this; this.scope = scope; this.jQuery = jQuery; - angular.extend(scope, angular.scenario.dsl); var specs = this.specs = {}; var path = []; @@ -30,7 +29,7 @@ angular.scenario.Runner = function(scope, jQuery){ self.currentSpec = null; }; this.logger = function returnNoop(){ - return angular.extend(returnNoop, {close:angular.noop, fail:angular.noop});; + return _(returnNoop).extend({close:_.identity, fail:_.identity});; }; }; @@ -60,7 +59,7 @@ angular.scenario.Runner.prototype = { var element = jQuery('
      • '); element.find('span').text(text); container.append(element); - return angular.extend(logger(element), { + return _(logger(element)).extend({ close: function(){ element.removeClass('running'); if(!element.hasClass('fail')) @@ -81,7 +80,7 @@ angular.scenario.Runner.prototype = { } this.logger = logger(console); var specNames = []; - angular.foreach(this.specs, function(spec, name){ + _(this.specs).each(function(spec, name){ specNames.push(name); }, this); specNames.sort(); @@ -109,7 +108,7 @@ angular.scenario.Runner.prototype = { result.passed = false; result.failed = true; result.error = error; - result.log('fail', angular.isString(error) ? error : angular.toJson(error)).fail(); + result.log('fail', _(error).isString() ? error : toJson(error)).fail(); } }; specThis = { @@ -122,11 +121,11 @@ angular.scenario.Runner.prototype = { function done() { result.finished = true; stepLogger.close(); - (callback||angular.noop).call(specThis); + (callback||_.identity).call(specThis); } function next(){ var step = spec.steps[spec.nextStepIndex]; - (result.log || {close:angular.noop}).close(); + (result.log || {close:_.identity}).close(); result.log = null; if (step) { spec.nextStepIndex ++; @@ -134,6 +133,7 @@ angular.scenario.Runner.prototype = { try { step.fn.call(specThis, next); } catch (e) { + console.error(e); result.fail(e); done(); } diff --git a/src/scenario/angular.prefix b/src/scenario/angular.prefix new file mode 100644 index 00000000..5b44e17c --- /dev/null +++ b/src/scenario/angular.prefix @@ -0,0 +1,30 @@ +/** + * The MIT License + * + * Copyright (c) 2010 Adam Abrons and Misko Hevery http://getangular.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +(function(window, document, previousOnLoad){ + window.angular = { + scenario: { + dsl: window + } + }; + diff --git a/src/scenario/angular.suffix b/src/scenario/angular.suffix new file mode 100644 index 00000000..fc861cbf --- /dev/null +++ b/src/scenario/angular.suffix @@ -0,0 +1,11 @@ + + var $scenarioRunner = new angular.scenario.Runner(window, jQuery); + + window.onload = function(){ + try { + if (previousOnLoad) previousOnLoad(); + } catch(e) {} + $scenarioRunner.run(jQuery(window.document.body)); + }; + +})(window, document, window.onload); diff --git a/src/scenario/bootstrap.js b/src/scenario/bootstrap.js index 4c9cdc8d..694d0e97 100644 --- a/src/scenario/bootstrap.js +++ b/src/scenario/bootstrap.js @@ -18,6 +18,12 @@ document.write(''); } + window.angular = { + scenario: { + dsl: window + } + }; + window.onload = function(){ _.defer(function(){ $scenarioRunner.run(jQuery(window.document.body)); @@ -27,8 +33,9 @@ addCSS("../../css/angular-scenario.css"); addScript("../../lib/underscore/underscore.js"); addScript("../../lib/jquery/jquery-1.4.2.js"); - addScript("../angular-bootstrap.js"); addScript("Runner.js"); + addScript("../Angular.js"); + addScript("../JSON.js"); addScript("DSL.js"); document.write('