angularjs - Using protractor with loops -
loop index (i
) not i'm expecting when use protractor within loop.
symptoms:
failed: index out of bound. trying access element @ index:'x', there 'x' elements
or
index static , equal last value
my code
for (var = 0; < max; ++i) { getpromise().then(function() { somearray[i] // 'i' takes value of 'max' }) }
for example:
var expected = ['expect1', 'expect2', 'expect3']; var els = element.all(by.css('selector')); (var = 0; < expected.length; ++i) { els.get(i).gettext().then(function(text) { expect(text).toequal(expected[i]); // error: `i` 3. }) }
or
var els = element.all(by.css('selector')); (var = 0; < 3; ++i) { els.get(i).gettext().then(function(text) { if (text === 'should click') { els.get(i).click(); // fails "failed: index out of bound. trying access element @ index:3, there 3 elements" } }) }
or
var els = element.all(by.css('selector')); els.then(function(rawelements) { (var = 0; < rawelements.length; ++i) { rawelements[i].gettext().then(function(text) { if (text === 'should click') { rawelements[i].click(); // fails "failed: index out of bound. trying access element @ index:'rawelements.length', there 'rawelements.length' elements" } }) } })
the reason happening because protractor uses promises.
read https://github.com/angular/protractor/blob/master/docs/control-flow.md
promises (i.e. element(by...)
, element.all(by...)
) execute then
functions when underlying value becomes ready. means promises first scheduled , then
functions run results become ready.
when run this:
for (var = 0; < 3; ++i) { console.log('1) is: ', i); getpromise().then(function() { console.log('2) is: ', i); somearray[i] // 'i' takes value of 3 }) } console.log('* finished looping. is: ', i);
what happens getpromise().then(function() {...})
returns immediately, before promise ready , without executing function inside then
. first loop runs through 3 times, scheduling getpromise()
calls. then, promises resolve, corresponding then
s run.
the console this:
1) is: 0 // schedules first `getpromise()` 1) is: 1 // schedules second `getpromise()` 1) is: 2 // schedules third `getpromise()` * finished looping. is: 3 2) is: 3 // first `then` function runs, 3 now. 2) is: 3 // second `then` function runs, 3 now. 2) is: 3 // third `then` function runs, 3 now.
so, how run protractor in loops? general solution closure. see javascript closure inside loops – simple practical example
for (var = 0; < 3; ++i) { console.log('1) is: ', i); var func = (function() { var j = i; return function() { console.log('2) j is: ', j); somearray[j] // 'j' takes values of 0..2 } })(); getpromise().then(func); } console.log('* finished looping. is: ', i);
but not nice read. fortunately, can use protractor functions filter(fn)
, get(i)
, first()
, last()
, , fact expect
patched take promises, deal this.
going examples provided earlier. first example can rewritten as:
var expected = ['expect1', 'expect2', 'expect3']; var els = element.all(by.css('selector')); (var = 0; < expected.length; ++i) { expect(els.get(i).gettext()).toequal(expected[i]); // note, no longer in `then` function , take correct values. }
the second , third example can rewritten as:
var els = element.all(by.css('selector')); els.filter(function(elem) { return elem.gettext().then(function(text) { return text === 'should click'; }); }).click(); // note here first used 'filter' select appropriate elements, , used fact actions `click` can act on array click matching elements. result can stop using loop altogether.
in other words, protractor has many ways iterate or access element i
don't need use loops , i
. if must use loops , i
, can use closure solution.
Comments
Post a Comment