From 03df6cbddbb80186caf571e29957370b2ef9881c Mon Sep 17 00:00:00 2001 From: Elliott Sprehn Date: Fri, 8 Oct 2010 16:43:40 -0700 Subject: New Angular Scenario runner and DSL system with redesigned HTML UI. Uses the Jasmine syntax for tests, ex: describe('widgets', function() { it('should verify that basic widgets work', function(){ navigateTo('widgets.html'); input('text.basic').enter('Carlos'); expect(binding('text.basic')).toEqual('Carlos'); input('text.basic').enter('Carlos Santana'); expect(binding('text.basic')).not().toEqual('Carlos Boozer'); input('text.password').enter('secret'); expect(binding('text.password')).toEqual('secret'); expect(binding('text.hidden')).toEqual('hiddenValue'); expect(binding('gender')).toEqual('male'); input('gender').select('female'); expect(binding('gender')).toEqual('female'); }); }); Note: To create new UI's implement the interface shown in angular.scenario.ui.Html. --- src/scenario/DSL.js | 249 ++++++++++++++++++++++++++-------------------------- 1 file changed, 126 insertions(+), 123 deletions(-) (limited to 'src/scenario/DSL.js') diff --git a/src/scenario/DSL.js b/src/scenario/DSL.js index dc85ea45..a7571afe 100644 --- a/src/scenario/DSL.js +++ b/src/scenario/DSL.js @@ -1,131 +1,134 @@ -angular.scenario.dsl.browser = { - navigateTo: function(url){ - var location = this.location; - return $scenario.addFuture('Navigate to: ' + url, function(done){ - var self = this; - this.testFrame.load(function(){ - self.testFrame.unbind(); - self.testWindow = self.testFrame[0].contentWindow; - self.testDocument = self.jQuery(self.testWindow.document); - self.$browser = self.testWindow.angular.service.$browser(); - self.notifyWhenNoOutstandingRequests = - bind(self.$browser, self.$browser.notifyWhenNoOutstandingRequests); - self.notifyWhenNoOutstandingRequests(done); - }); - if (this.testFrame.attr('src') == url) { - this.testFrame[0].contentWindow.location.reload(); - } else { - this.testFrame.attr('src', url); - location.setLocation(url); - } - }); - }, - location: { - href: "", - hash: "", - toEqual: function(url) { - return (this.hash === "" ? (url == this.href) : - (url == (this.href + "/#/" + this.hash))); - }, - setLocation: function(url) { - var urlParts = url.split("/#/"); - this.href = urlParts[0] || ""; - this.hash = urlParts[1] || ""; - } - } -}; - -angular.scenario.dsl.input = function(selector) { - var namePrefix = "input '" + selector + "'"; - return { - enter: function(value) { - return $scenario.addFuture(namePrefix + " enter '" + value + "'", function(done) { - var input = this.testDocument.find('input[name=' + selector + ']'); - input.val(value); - this.testWindow.angular.element(input[0]).trigger('change'); - done(); - }); - }, - select: function(value) { - return $scenario.addFuture(namePrefix + " select '" + value + "'", function(done) { - var input = this.testDocument. - find(':radio[name$=@' + selector + '][value=' + value + ']'); - jqLiteWrap(input[0]).trigger('click'); - input[0].checked = true; - done(); - }); - } - }; -}; +/** + * Shared DSL statements that are useful to all scenarios. + */ -angular.scenario.dsl.NG_BIND_PATTERN =/\{\{[^\}]+\}\}/; +/** +* Usage: +* pause(seconds) pauses the test for specified number of seconds +*/ +angular.scenario.dsl('pause', function() { + return function(time) { + return this.addFuture('pause for ' + time + ' seconds', function(done) { + this.setTimeout(function() { done(null, time * 1000); }, time * 1000); + }); + }; +}); -angular.scenario.dsl.repeater = function(selector) { - var namePrefix = "repeater '" + selector + "'"; - return { - count: function() { - return $scenario.addFuture(namePrefix + ' count', function(done) { - done(this.testDocument.find(selector).size()); - }); - }, - collect: function(collectSelector) { - return $scenario.addFuture( - namePrefix + " collect '" + collectSelector + "'", - function(done) { - var self = this; - var doCollect = bind(this, function() { - var repeaterArray = [], ngBindPattern; - var startIndex = collectSelector.search( - angular.scenario.dsl.NG_BIND_PATTERN); - if (startIndex >= 0) { - ngBindPattern = collectSelector.substring( - startIndex + 2, collectSelector.length - 2); - collectSelector = '*'; - - } - this.testDocument.find(selector).each(function() { - var element = self.jQuery(this); - element.find(collectSelector). - each(function() { - var foundElem = self.jQuery(this); - if (foundElem.attr('ng:bind') == ngBindPattern) { - repeaterArray.push(foundElem.text()); - } - }); - }); - return repeaterArray; - }); - done(doCollect()); - }); - } +/** + * Usage: + * expect(future).{matcher} where matcher is one of the matchers defined + * with angular.scenario.matcher + * + * ex. expect(binding("name")).toEqual("Elliott") + */ +angular.scenario.dsl('expect', function() { + var chain = angular.extend({}, angular.scenario.matcher); + + chain.not = function() { + this.inverse = true; + return chain; + }; + + return function(future) { + this.future = future; + return chain; }; -}; +}); -angular.scenario.dsl.element = function(selector) { - var namePrefix = "Element '" + selector + "'"; - var futureJquery = {}; - for (key in (jQuery || _jQuery).fn) { - (function(){ - var jqFnName = key; - var jqFn = (jQuery || _jQuery).fn[key]; - futureJquery[key] = function() { - var jqArgs = arguments; - return $scenario.addFuture(namePrefix + "." + jqFnName + "()", - function(done) { - var self = this, repeaterArray = [], ngBindPattern; - var startIndex = selector.search(angular.scenario.dsl.NG_BIND_PATTERN); - if (startIndex >= 0) { - ngBindPattern = selector.substring(startIndex + 2, selector.length - 2); - var element = this.testDocument.find('*').filter(function() { - return self.jQuery(this).attr('ng:bind') == ngBindPattern; +/** + * Usage: + * navigateTo(future|string) where url a string or future with a value + * of a URL to navigate to + */ +angular.scenario.dsl('navigateTo', function() { + return function(url) { + var application = this.application; + var name = url; + if (url.name) { + name = ' value of ' + url.name; + } + return this.addFuture('navigate to ' + name, function(done) { + application.navigateTo(url.value || url, function() { + application.executeAction(function() { + if (this.angular) { + var $browser = this.angular.service.$browser(); + $browser.poll(); + $browser.notifyWhenNoOutstandingRequests(function() { + done(null, url.value || url); }); - done(jqFn.apply(element, jqArgs)); } else { - done(jqFn.apply(this.testDocument.find(selector), jqArgs)); + done(null, url.value || url); } }); - }; - })(); - } - return futureJquery; -}; + }); + }); + }; +}); + +/** + * Usage: + * input(name).enter(value) enters value in input with specified name + * input(name).check() checks checkbox + * input(name).select(value) selects the readio button with specified name/value + */ +angular.scenario.dsl('input', function() { + var chain = {}; + + chain.enter = function(value) { + var spec = this; + return this.addFutureAction("input '" + this.name + "' enter '" + value + "'", function(done) { + var input = _jQuery(this.document).find('input[name=' + spec.name + ']'); + if (!input.length) + return done("Input named '" + spec.name + "' does not exist."); + input.val(value); + this.angular.element(input[0]).trigger('change'); + done(); + }); + }; + + chain.check = function() { + var spec = this; + return this.addFutureAction("checkbox '" + this.name + "' toggle", function(done) { + var input = _jQuery(this.document). + find('input:checkbox[name=' + spec.name + ']'); + if (!input.length) + return done("Input named '" + spec.name + "' does not exist."); + this.angular.element(input[0]).trigger('click'); + input.attr('checked', !input.attr('checked')); + done(); + }); + }; + + chain.select = function(value) { + var spec = this; + return this.addFutureAction("radio button '" + this.name + "' toggle '" + value + "'", function(done) { + var input = _jQuery(this.document). + find('input:radio[name$="@' + spec.name + '"][value="' + value + '"]'); + if (!input.length) + return done("Input named '" + spec.name + "' does not exist."); + this.angular.element(input[0]).trigger('click'); + input.attr('checked', !input.attr('checked')); + done(); + }); + }; + + return function(name) { + this.name = name; + return chain; + }; +}); + +/** + * Usage: + * binding(name) returns the value of a binding + */ +angular.scenario.dsl('binding', function() { + return function(name) { + return this.addFutureAction("select binding '" + name + "'", function(done) { + var element = _jQuery(this.document).find('[ng\\:bind="' + name + '"]'); + if (!element.length) + return done("Binding named '" + name + "' does not exist."); + done(null, element.text()); + }); + }; +}); -- cgit v1.2.3