最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Targeting elements within an element directive with Protractor - Stack Overflow

programmeradmin0浏览0评论

Consider the following view model:

$scope.data = {};
$scope.data.person = {};
$scope.data.person.firstname = "";
$scope.data.person.lastname = "";
$scope.data.person.username = "";

and the following element directive:

<custom-form-directive ng-model="data.person"></custom-form-directive>

which contains three input tags to display the data. How do I use protractor to populate the input fields by targeting ng-model="data.person"?

Consider the following view model:

$scope.data = {};
$scope.data.person = {};
$scope.data.person.firstname = "";
$scope.data.person.lastname = "";
$scope.data.person.username = "";

and the following element directive:

<custom-form-directive ng-model="data.person"></custom-form-directive>

which contains three input tags to display the data. How do I use protractor to populate the input fields by targeting ng-model="data.person"?

Share Improve this question edited May 1, 2015 at 18:02 alecxe 474k126 gold badges1.1k silver badges1.2k bronze badges asked Apr 25, 2015 at 18:56 TrazeKTrazeK 8381 gold badge8 silver badges18 bronze badges
Add a comment  | 

4 Answers 4

Reset to default 6

It depends on how you're getting data in/out of the inputs in the directive. However, in all cases you can chain together element(<locator>) calls to search for sub-elements of the directive:

var directive = element(by.model('data.person'));
var subElement = directive.element(by.<something>);

If you're using ng-model in the directive itself on each of the inputs, you can do something like:

var directive = element(by.model('data.person'));

// Assuming the inputs have attributes like `ng-model="firstname"` in the directive template
var firstnameInput = directive.element(by.model('firstname'));
var lastnameInput = directive.element(by.model('lastname'));
var usernameInput = directive.element(by.model('surnamname'));

and then on each call sendKeys

firstnameInput.sendKeys('Peter');
secondnameInput.sendKeys('Piper');
usernameInput.sendKeys('PickledPumpernickle');

If you're not using ng-model in the directive template, you can use other locators to find the sub elements, together with get if needs be, and depend on the order they're in the DOM

var inputs = directive.element(by.css('input'));
var firstnameInput = inputs.get(0);
var secondnameInput = inputs.get(1);
var usernameInput = inputs.get(2);

However, I suspect none of the above will work if you have replace: true specified in the directive, as it depends on the original element, with the ng-model attribute, being in the DOM.

This is exactly what the evaluate method is for: http://angular.github.io/protractor/#/api?view=ElementFinder.prototype.evaluate

element(by.model('data.person')).evaluate('data.person.firstname = "yourvaluehere"');

I assume by "targeting the model" you want to change the controller's value and have the ng-model directive update the view, rather than the other way around.

I think you want to build something like a "pageObject" (see https://github.com/angular/protractor/blob/master/docs/page-objects.md) for your custom-form-directive directive. This object will understand how the directive maps to primitives that Protractor will understand (e.g., specific input fields). It should take a locator so its callers can pass in the how to find the directive on the page, but the object should handle everything after that.

var object = new customFormDirectiveObject(by.model('data.person'));

depending on how your directive works you'd do something like:

object.setName(first, last, user);

or if its more dyanmic maybe something like this:

object.setName({firstname: first, lastname: last, username: user });

With a few helper function you could do it rather easily. The helper object just wraps protractor and makes it a little more sane and safe to use. Especially when running on remote systems.

var helper = {
  getElement: function (selector) {
    return element(by.css(selector));
  },

  resolveSelector: function (selector) {
    var el;
    if (typeof selector === 'string') {
      el = self.getElement(selector);
    } else {
      el = selector;
    }
    return el;
  },

  waitForElementClickable: function (selector) {
    var el = self.resolveSelector(selector);
    var condition = function () {
      return self.waitForElement(el).then(function () {
        return self.isElementEnabled(el);
      });
    };
    return self.wait(condition, 15000, 'Element not clickable. (' + selector + ')');
  },

  setElementValue: function (selector, value) {
    var el = self.resolveSelector(selector);
    return self.waitForElementClickable(el).then(function () {
      el.click().clear().sendKeys(value);
    });
  },

  getElementValue: function (selector) {
    var el = self.resolveSelector(selector);
    return el ? el.getAttribute('value') : '';
  }

}

Then you can just use regular CSS selectors to set your values:

helper.setElementValue('[ng-model="data.person"] input:nth-child(1)', '1st Input Value');
helper.setElementValue('[ng-model="data.person"] input:nth-child(2)', '2nd Input Value');
helper.setElementValue('[ng-model="data.person"] input:nth-child(3)', '3rd Input Value');

And you can check for expected values with something like this:

expect(helper.getElementValue('[ng-model="data.person"] input:nth-child(1)')).toEqual('something')
发布评论

评论列表(0)

  1. 暂无评论