diff options
| author | Misko Hevery | 2012-03-23 14:03:24 -0700 | 
|---|---|---|
| committer | Misko Hevery | 2012-03-28 11:16:35 -0700 | 
| commit | 2430f52bb97fa9d682e5f028c977c5bf94c5ec38 (patch) | |
| tree | e7529b741d70199f36d52090b430510bad07f233 /src/ngScenario/dsl.js | |
| parent | 944098a4e0f753f06b40c73ca3e79991cec6c2e2 (diff) | |
| download | angular.js-2430f52bb97fa9d682e5f028c977c5bf94c5ec38.tar.bz2 | |
chore(module): move files around in preparation for more modules
Diffstat (limited to 'src/ngScenario/dsl.js')
| -rw-r--r-- | src/ngScenario/dsl.js | 405 | 
1 files changed, 405 insertions, 0 deletions
diff --git a/src/ngScenario/dsl.js b/src/ngScenario/dsl.js new file mode 100644 index 00000000..8a1bccb1 --- /dev/null +++ b/src/ngScenario/dsl.js @@ -0,0 +1,405 @@ +'use strict'; + +/** + * Shared DSL statements that are useful to all scenarios. + */ + + /** + * Usage: + *    pause() pauses until you call resume() in the console + */ +angular.scenario.dsl('pause', function() { +  return function() { +    return this.addFuture('pausing for you to resume', function(done) { +      this.emit('InteractivePause', this.spec, this.step); +      this.$window.resume = function() { done(); }; +    }); +  }; +}); + +/** + * Usage: + *    sleep(seconds) pauses the test for specified number of seconds + */ +angular.scenario.dsl('sleep', function() { +  return function(time) { +    return this.addFuture('sleep for ' + time + ' seconds', function(done) { +      this.$window.setTimeout(function() { done(null, time * 1000); }, time * 1000); +    }); +  }; +}); + +/** + * Usage: + *    browser().navigateTo(url) Loads the url into the frame + *    browser().navigateTo(url, fn) where fn(url) is called and returns the URL to navigate to + *    browser().reload() refresh the page (reload the same URL) + *    browser().window.href() window.location.href + *    browser().window.path() window.location.pathname + *    browser().window.search() window.location.search + *    browser().window.hash() window.location.hash without # prefix + *    browser().location().url() see angular.module.ng.$location#url + *    browser().location().path() see angular.module.ng.$location#path + *    browser().location().search() see angular.module.ng.$location#search + *    browser().location().hash() see angular.module.ng.$location#hash + */ +angular.scenario.dsl('browser', function() { +  var chain = {}; + +  chain.navigateTo = function(url, delegate) { +    var application = this.application; +    return this.addFuture("browser navigate to '" + url + "'", function(done) { +      if (delegate) { +        url = delegate.call(this, url); +      } +      application.navigateTo(url, function() { +        done(null, url); +      }, done); +    }); +  }; + +  chain.reload = function() { +    var application = this.application; +    return this.addFutureAction('browser reload', function($window, $document, done) { +      var href = $window.location.href; +      application.navigateTo(href, function() { +        done(null, href); +      }, done); +    }); +  }; + +  chain.window = function() { +    var api = {}; + +    api.href = function() { +      return this.addFutureAction('window.location.href', function($window, $document, done) { +        done(null, $window.location.href); +      }); +    }; + +    api.path = function() { +      return this.addFutureAction('window.location.path', function($window, $document, done) { +        done(null, $window.location.pathname); +      }); +    }; + +    api.search = function() { +      return this.addFutureAction('window.location.search', function($window, $document, done) { +        done(null, $window.location.search); +      }); +    }; + +    api.hash = function() { +      return this.addFutureAction('window.location.hash', function($window, $document, done) { +        done(null, $window.location.hash.replace('#', '')); +      }); +    }; + +    return api; +  }; + +  chain.location = function() { +    var api = {}; + +    api.url = function() { +      return this.addFutureAction('$location.url()', function($window, $document, done) { +        done(null, $window.angular.injector(['ng']).get('$location').url()); +      }); +    }; + +    api.path = function() { +      return this.addFutureAction('$location.path()', function($window, $document, done) { +        done(null, $window.angular.injector(['ng']).get('$location').path()); +      }); +    }; + +    api.search = function() { +      return this.addFutureAction('$location.search()', function($window, $document, done) { +        done(null, $window.angular.injector(['ng']).get('$location').search()); +      }); +    }; + +    api.hash = function() { +      return this.addFutureAction('$location.hash()', function($window, $document, done) { +        done(null, $window.angular.injector(['ng']).get('$location').hash()); +      }); +    }; + +    return api; +  }; + +  return function(time) { +    return chain; +  }; +}); + +/** + * 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; +  }; +}); + +/** + * Usage: + *    using(selector, label) scopes the next DSL element selection + * + * ex. + *   using('#foo', "'Foo' text field").input('bar') + */ +angular.scenario.dsl('using', function() { +  return function(selector, label) { +    this.selector = _jQuery.trim((this.selector||'') + ' ' + selector); +    if (angular.isString(label) && label.length) { +      this.label = label + ' ( ' + this.selector + ' )'; +    } else { +      this.label = this.selector; +    } +    return this.dsl; +  }; +}); + +/** + * Usage: + *    binding(name) returns the value of the first matching binding + */ +angular.scenario.dsl('binding', function() { +  return function(name) { +    return this.addFutureAction("select binding '" + name + "'", function($window, $document, done) { +      var values = $document.elements().bindings($window.angular.element, name); +      if (!values.length) { +        return done("Binding selector '" + name + "' did not match."); +      } +      done(null, values[0]); +    }); +  }; +}); + +/** + * Usage: + *    input(name).enter(value) enters value in input with specified name + *    input(name).check() checks checkbox + *    input(name).select(value) selects the radio button with specified name/value + *    input(name).val() returns the value of the input. + */ +angular.scenario.dsl('input', function() { +  var chain = {}; + +  chain.enter = function(value, event) { +    return this.addFutureAction("input '" + this.name + "' enter '" + value + "'", function($window, $document, done) { +      var input = $document.elements('[ng\\:model="$1"]', this.name).filter(':input'); +      input.val(value); +      input.trigger(event || 'blur'); +      done(); +    }); +  }; + +  chain.check = function() { +    return this.addFutureAction("checkbox '" + this.name + "' toggle", function($window, $document, done) { +      var input = $document.elements('[ng\\:model="$1"]', this.name).filter(':checkbox'); +      input.trigger('click'); +      done(); +    }); +  }; + +  chain.select = function(value) { +    return this.addFutureAction("radio button '" + this.name + "' toggle '" + value + "'", function($window, $document, done) { +      var input = $document. +        elements('[ng\\:model="$1"][value="$2"]', this.name, value).filter(':radio'); +      input.trigger('click'); +      done(); +    }); +  }; + +  chain.val = function() { +    return this.addFutureAction("return input val", function($window, $document, done) { +      var input = $document.elements('[ng\\:model="$1"]', this.name).filter(':input'); +      done(null,input.val()); +    }); +  }; + +  return function(name) { +    this.name = name; +    return chain; +  }; +}); + + +/** + * Usage: + *    repeater('#products table', 'Product List').count() number of rows + *    repeater('#products table', 'Product List').row(1) all bindings in row as an array + *    repeater('#products table', 'Product List').column('product.name') all values across all rows in an array + */ +angular.scenario.dsl('repeater', function() { +  var chain = {}; + +  chain.count = function() { +    return this.addFutureAction("repeater '" + this.label + "' count", function($window, $document, done) { +      try { +        done(null, $document.elements().length); +      } catch (e) { +        done(null, 0); +      } +    }); +  }; + +  chain.column = function(binding) { +    return this.addFutureAction("repeater '" + this.label + "' column '" + binding + "'", function($window, $document, done) { +      done(null, $document.elements().bindings($window.angular.element, binding)); +    }); +  }; + +  chain.row = function(index) { +    return this.addFutureAction("repeater '" + this.label + "' row '" + index + "'", function($window, $document, done) { +      var matches = $document.elements().slice(index, index + 1); +      if (!matches.length) +        return done('row ' + index + ' out of bounds'); +      done(null, matches.bindings($window.angular.element)); +    }); +  }; + +  return function(selector, label) { +    this.dsl.using(selector, label); +    return chain; +  }; +}); + +/** + * Usage: + *    select(name).option('value') select one option + *    select(name).options('value1', 'value2', ...) select options from a multi select + */ +angular.scenario.dsl('select', function() { +  var chain = {}; + +  chain.option = function(value) { +    return this.addFutureAction("select '" + this.name + "' option '" + value + "'", function($window, $document, done) { +      var select = $document.elements('select[ng\\:model="$1"]', this.name); +      var option = select.find('option[value="' + value + '"]'); +      if (option.length) { +        select.val(value); +      } else { +        option = select.find('option:contains("' + value + '")'); +        if (option.length) { +          select.val(option.val()); +        } +      } +      select.trigger('change'); +      done(); +    }); +  }; + +  chain.options = function() { +    var values = arguments; +    return this.addFutureAction("select '" + this.name + "' options '" + values + "'", function($window, $document, done) { +      var select = $document.elements('select[multiple][ng\\:model="$1"]', this.name); +      select.val(values); +      select.trigger('change'); +      done(); +    }); +  }; + +  return function(name) { +    this.name = name; +    return chain; +  }; +}); + +/** + * Usage: + *    element(selector, label).count() get the number of elements that match selector + *    element(selector, label).click() clicks an element + *    element(selector, label).query(fn) executes fn(selectedElements, done) + *    element(selector, label).{method}() gets the value (as defined by jQuery, ex. val) + *    element(selector, label).{method}(value) sets the value (as defined by jQuery, ex. val) + *    element(selector, label).{method}(key) gets the value (as defined by jQuery, ex. attr) + *    element(selector, label).{method}(key, value) sets the value (as defined by jQuery, ex. attr) + */ +angular.scenario.dsl('element', function() { +  var KEY_VALUE_METHODS = ['attr', 'css', 'prop']; +  var VALUE_METHODS = [ +    'val', 'text', 'html', 'height', 'innerHeight', 'outerHeight', 'width', +    'innerWidth', 'outerWidth', 'position', 'scrollLeft', 'scrollTop', 'offset' +  ]; +  var chain = {}; + +  chain.count = function() { +    return this.addFutureAction("element '" + this.label + "' count", function($window, $document, done) { +      try { +        done(null, $document.elements().length); +      } catch (e) { +        done(null, 0); +      } +    }); +  }; + +  chain.click = function() { +    return this.addFutureAction("element '" + this.label + "' click", function($window, $document, done) { +      var elements = $document.elements(); +      var href = elements.attr('href'); +      var eventProcessDefault = elements.trigger('click')[0]; + +      if (href && elements[0].nodeName.toUpperCase() === 'A' && eventProcessDefault) { +        this.application.navigateTo(href, function() { +          done(); +        }, done); +      } else { +        done(); +      } +    }); +  }; + +  chain.query = function(fn) { +    return this.addFutureAction('element ' + this.label + ' custom query', function($window, $document, done) { +      fn.call(this, $document.elements(), done); +    }); +  }; + +  angular.forEach(KEY_VALUE_METHODS, function(methodName) { +    chain[methodName] = function(name, value) { +      var args = arguments, +          futureName = (args.length == 1) +              ? "element '" + this.label + "' get " + methodName + " '" + name + "'" +              : "element '" + this.label + "' set " + methodName + " '" + name + "' to " + "'" + value + "'"; + +      return this.addFutureAction(futureName, function($window, $document, done) { +        var element = $document.elements(); +        done(null, element[methodName].apply(element, args)); +      }); +    }; +  }); + +  angular.forEach(VALUE_METHODS, function(methodName) { +    chain[methodName] = function(value) { +      var args = arguments, +          futureName = (args.length == 0) +              ? "element '" + this.label + "' " + methodName +              : futureName = "element '" + this.label + "' set " + methodName + " to '" + value + "'"; + +      return this.addFutureAction(futureName, function($window, $document, done) { +        var element = $document.elements(); +        done(null, element[methodName].apply(element, args)); +      }); +    }; +  }); + +  return function(selector, label) { +    this.dsl.using(selector, label); +    return chain; +  }; +});  | 
