Skip to content
This repository was archived by the owner on Jul 29, 2024. It is now read-only.

Commit 21264fd

Browse files
committed
fix(find): fix error when exposed to ng-options element with a default option
Protractor will now ignore elements with the ng-bind class that don't have a proper binding on their data, instead of blowing up when encoutering them. Closes #165, may fix #170
1 parent fb46ec9 commit 21264fd

File tree

5 files changed

+56
-16
lines changed

5 files changed

+56
-16
lines changed

lib/clientsidescripts.js

+28-16
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,11 @@ clientSideScripts.findBinding = function() {
4141
var bindings = using.getElementsByClassName('ng-binding');
4242
var matches = [];
4343
for (var i = 0; i < bindings.length; ++i) {
44-
var bindingName = angular.element(bindings[i]).data().$binding[0].exp ||
45-
angular.element(bindings[i]).data().$binding;
44+
var elemData = angular.element(bindings[i]).data();
45+
if (!elemData || !elemData.$binding) {
46+
continue;
47+
}
48+
var bindingName = elemData.$binding[0].exp || elemData.$binding;
4649
if (bindingName.indexOf(binding) != -1) {
4750
matches.push(bindings[i]);
4851
}
@@ -64,8 +67,11 @@ clientSideScripts.findBindings = function() {
6467
var bindings = using.getElementsByClassName('ng-binding');
6568
var matches = [];
6669
for (var i = 0; i < bindings.length; ++i) {
67-
var bindingName = angular.element(bindings[i]).data().$binding[0].exp ||
68-
angular.element(bindings[i]).data().$binding;
70+
var elemData = angular.element(bindings[i]).data();
71+
if (!elemData || !elemData.$binding) {
72+
continue;
73+
}
74+
var bindingName = elemData.$binding[0].exp || elemData.$binding;
6975
if (bindingName.indexOf(binding) != -1) {
7076
matches.push(bindings[i]);
7177
}
@@ -168,8 +174,11 @@ clientSideScripts.findRepeaterElement = function() {
168174
bindings.push(childBindings[i]);
169175
}
170176
for (var i = 0; i < bindings.length; ++i) {
171-
var bindingName = angular.element(bindings[i]).data().$binding[0].exp ||
172-
angular.element(bindings[i]).data().$binding;
177+
var elemData = angular.element(bindings[i]).data();
178+
if (!elemData || !elemData.$binding) {
179+
continue;
180+
}
181+
var bindingName = elemData.$binding[0].exp || elemData.$binding;
173182
if (bindingName.indexOf(binding) != -1) {
174183
matches.push(bindings[i]);
175184
}
@@ -215,8 +224,11 @@ clientSideScripts.findRepeaterColumn = function() {
215224
bindings.push(childBindings[k]);
216225
}
217226
for (var j = 0; j < bindings.length; ++j) {
218-
var bindingName = angular.element(bindings[j]).data().$binding[0].exp ||
219-
angular.element(bindings[j]).data().$binding;
227+
var elemData = angular.element(bindings[j]).data();
228+
if (!elemData || !elemData.$binding) {
229+
continue;
230+
}
231+
var bindingName = elemData.$binding[0].exp || elemData.$binding;
220232
if (bindingName.indexOf(binding) != -1) {
221233
matches.push(bindings[j]);
222234
}
@@ -226,43 +238,43 @@ clientSideScripts.findRepeaterColumn = function() {
226238
};
227239

228240
/**
229-
* Find an input element by model name.
241+
* Find input element by model name.
230242
*
231243
* arguments[0] {Element} The scope of the search.
232244
* arguments[1] {string} The model name.
233245
*
234-
* @return {Array.<Element?} The matching input elements.
246+
* @return {Element} The first matching input element.
235247
*/
236-
clientSideScripts.findInputs = function() {
248+
clientSideScripts.findInput = function() {
237249
var using = arguments[0] || document;
238250
var model = arguments[1];
239251
var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\:'];
240252
for (var p = 0; p < prefixes.length; ++p) {
241253
var selector = 'input[' + prefixes[p] + 'model="' + model + '"]';
242254
var inputs = using.querySelectorAll(selector);
243255
if (inputs.length) {
244-
return inputs;
256+
return inputs[0];
245257
}
246258
}
247259
};
248260

249261
/**
250-
* Find input elements by model name.
262+
* Find an input elements by model name.
251263
*
252264
* arguments[0] {Element} The scope of the search.
253265
* arguments[1] {string} The model name.
254266
*
255-
* @return {Element} The first matching input element.
267+
* @return {Array.<Element>} The matching input elements.
256268
*/
257-
clientSideScripts.findInput = function() {
269+
clientSideScripts.findInputs = function() {
258270
var using = arguments[0] || document;
259271
var model = arguments[1];
260272
var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\:'];
261273
for (var p = 0; p < prefixes.length; ++p) {
262274
var selector = 'input[' + prefixes[p] + 'model="' + model + '"]';
263275
var inputs = using.querySelectorAll(selector);
264276
if (inputs.length) {
265-
return inputs[0];
277+
return inputs;
266278
}
267279
}
268280
};

lib/locators.js

+5
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,11 @@ ProtractorBy.prototype.repeater = function(repeatDescriptor) {
161161
webdriver.By.js(clientSideScripts.findRepeaterRow),
162162
using, repeatDescriptor, index);
163163
},
164+
findArrayOverride: function(driver, using) {
165+
return driver.findElement(
166+
webdriver.By.js(clientSideScripts.findAllRepeaterRows),
167+
using, repeatDescriptor);
168+
},
164169
column: function(binding) {
165170
return {
166171
findOverride: function(driver, using) {

spec/basic/findelements_spec.js

+13
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,24 @@ describe('locators', function() {
8080
expect(arr.length).toEqual(3);
8181
});
8282
});
83+
});
8384

85+
describe('by select', function() {
8486
it('should find multiple selects', function() {
8587
browser.findElements(by.select('dayColor.color')).then(function(arr) {
8688
expect(arr.length).toEqual(3);
8789
});
8890
});
8991

92+
it('should find the select and concat its options', function() {
93+
expect(element(by.select('fruit')).getText()).
94+
toEqual('applepearpeachbanana');
95+
});
96+
97+
it('should find the selected option', function() {
98+
expect(element(by.selectedOption('fruit')).getText()).toEqual('apple');
99+
});
100+
90101
it('should find multiple selected options', function() {
91102
browser.findElements(
92103
by.selectedOption('dayColor.color')).then(function(arr) {
@@ -96,6 +107,8 @@ describe('locators', function() {
96107
expect(arr[2].getText()).toBe('blue');
97108
});
98109
});
110+
111+
99112
});
100113

101114
describe('by repeater', function() {

testapp/form/form.html

+5
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ <h4>Selects</h4>
3131
<div ng-repeat="dayColor in dayColors">
3232
<select ng-model="dayColor.color" ng-options="c for c in colors"></select>
3333
</div>
34+
35+
<select ng-model="fruit" ng-options="fruit for fruit in fruits">
36+
<option value="">{{defaultFruit}}</option>
37+
</select>
38+
<span>Fruit: {{fruit}}</span>
3439
</div>
3540

3641
<div id="checkboxes">

testapp/form/form.js

+5
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@ function FormCtrl($scope) {
44
$scope.aboutbox = "This is a text box";
55
$scope.color = "blue";
66
$scope.show = true;
7+
78
$scope.colors = ['red', 'green', 'blue'];
89
$scope.dayColors = [{day: 'Mon', color: 'red'}, {day: 'Tue', color: 'green'}, {day: 'Wed', color: 'blue'}];
10+
11+
$scope.fruit = '';
12+
$scope.defaultFruit = 'apple'
13+
$scope.fruits = ['pear', 'peach', 'banana'];
914
}
1015
FormCtrl.$inject = ['$scope'];

0 commit comments

Comments
 (0)