diff options
| author | Adam Abrons | 2010-01-05 16:36:58 -0800 |
|---|---|---|
| committer | Adam Abrons | 2010-01-05 16:36:58 -0800 |
| commit | c9c176a53b1632ca2b1c6ed27382ab72ac21d45d (patch) | |
| tree | b5f719a095c03ee9f8b2721ffdaf1e5ff8c11b41 /src/test | |
| download | angular.js-c9c176a53b1632ca2b1c6ed27382ab72ac21d45d.tar.bz2 | |
angular.js
Diffstat (limited to 'src/test')
| -rw-r--r-- | src/test/Runner.js | 160 | ||||
| -rw-r--r-- | src/test/Steps.js | 57 | ||||
| -rw-r--r-- | src/test/_namespace.js | 5 |
3 files changed, 222 insertions, 0 deletions
diff --git a/src/test/Runner.js b/src/test/Runner.js new file mode 100644 index 00000000..478ef73e --- /dev/null +++ b/src/test/Runner.js @@ -0,0 +1,160 @@ +nglr.test.ScenarioRunner = function(scenarios, body) { + this.scenarios = scenarios; + this.body = body; +}; + +nglr.test.ScenarioRunner.prototype = { + run:function(){ + this.setUpUI(); + this.runScenarios(); + }, + setUpUI:function(){ + this.body.html( + '<div id="runner">' + + '<div class="console"></div>' + + '</div>' + + '<div id="testView">' + + '<iframe></iframe>' + + '</div>'); + 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 nglr.test.Runner(this.console, this.testFrame); + _.stepper(this.scenarios, function(next, scenario, name){ + new nglr.test.Scenario(name, scenario).run(runner, next); + }, function(){ + } + ); + } +}; + +nglr.test.Runner = function(console, frame){ + this.console = console; + this.current = null; + this.tests = []; + this.frame = frame; +}; +nglr.test.Runner.prototype = { + start:function(name){ + var current = this.current = { + name:name, + start:new Date().getTime(), + scenario:jQuery('<div class="scenario"></div>') + }; + current.run = current.scenario.append( + '<div class="run">' + + '<span class="name">.</span>' + + '<span class="time">.</span>' + + '<span class="state">.</span>' + + '</run>').find(".run"); + current.log = current.scenario.append('<div class="log"></div>').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('<span div="error"></span>').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:nglr.toJson(arg)); + } + var log = jQuery('<div class="' + level + '"></div>'); + log.text(buf.join(" ")); + this.current.log.append(log); + this.console.scrollTop(this.console[0].scrollHeight); + if (level == "error") + this.current.error = buf.join(" "); + } +}; + +nglr.test.Scenario = function(name, scenario){ + this.name = name; + this.scenario = scenario; +}; +nglr.test.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 = angular.test.GIVEN[step.Given]; + else if (step.When) fn = angular.test.WHEN[step.When]; + else if (step.Then) fn = angular.test.THEN[step.Then]; + return fn || function (){ + throw "ERROR: Need Given/When/Then got: " + nglr.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", nglr.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: " + nglr.toJson(e)); + } + } +}; diff --git a/src/test/Steps.js b/src/test/Steps.js new file mode 100644 index 00000000..af4b84d6 --- /dev/null +++ b/src/test/Steps.js @@ -0,0 +1,57 @@ +angular.test.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:" + nglr.toJson({dataset:this.dataset}); + } +}; +angular.test.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.test.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/test/_namespace.js b/src/test/_namespace.js new file mode 100644 index 00000000..78f430f1 --- /dev/null +++ b/src/test/_namespace.js @@ -0,0 +1,5 @@ +if (!angular) angular = {}; +if (!angular.test) angular.test = {}; +if (!angular.test.GIVEN) angular.test.GIVEN = {}; +if (!angular.test.WHEN) angular.test.WHEN = {}; +if (!angular.test.THEN) angular.test.THEN = {}; |
