Reputation: 838
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"
?
Upvotes: 18
Views: 4667
Reputation: 1919
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.
Upvotes: 5
Reputation: 21512
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')
Upvotes: 0
Reputation: 27012
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.
Upvotes: 6
Reputation: 25177
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 });
Upvotes: 0