i当我在循环中使用Protractor时,循环索引()不是我期望的。
i
症状:
失败:索引超出范围。尝试访问索引为’x’的元素,但是只有’x’个元素
要么
索引是静态的,并且始终等于最后一个值
我的密码
for (var i = 0; i < MAX; ++i) { getPromise().then(function() { someArray[i] // 'i' always takes the value of 'MAX' }) }
例如:
var expected = ['expect1', 'expect2', 'expect3']; var els = element.all(by.css('selector')); for (var i = 0; i < expected.length; ++i) { els.get(i).getText().then(function(text) { expect(text).toEqual(expected[i]); // Error: `i` is always 3. }) }
var els = element.all(by.css('selector')); for (var i = 0; i < 3; ++i) { els.get(i).getText().then(function(text) { if (text === 'should click') { els.get(i).click(); // fails with "Failed: Index out of bound. Trying to access element at index:3, but there are only 3 elements" } }) }
var els = element.all(by.css('selector')); els.then(function(rawelements) { for (var i = 0; i < rawelements.length; ++i) { rawelements[i].getText().then(function(text) { if (text === 'should click') { rawelements[i].click(); // fails with "Failed: Index out of bound. Trying to access element at index:'rawelements.length', but there are only 'rawelements.length' elements" } }) } })
发生这种情况的原因是因为量角器使用了诺言。
阅读https://github.com/angular/protractor/blob/master/docs/control- flow.md
当基础值准备就绪时element(by...),承诺(即element.all(by...))执行其then功能。这意味着首先对所有承诺进行调度,然后then在结果准备就绪时运行功能。
element(by...)
element.all(by...)
then
当您运行以下命令时:
for (var i = 0; i < 3; ++i) { console.log('1) i is: ', i); getPromise().then(function() { console.log('2) i is: ', i); someArray[i] // 'i' always takes the value of 3 }) } console.log('* finished looping. i is: ', i);
发生的情况是getPromise().then(function() {...}),在答应准备就绪之前立即返回,而没有在内部执行函数then。因此,首先循环运行3次,调度所有getPromise()调用。然后,随着承诺解决,将then运行相应的。
getPromise().then(function() {...})
getPromise()
控制台看起来像这样:
1) i is: 0 // schedules first `getPromise()` 1) i is: 1 // schedules second `getPromise()` 1) i is: 2 // schedules third `getPromise()` * finished looping. i is: 3 2) i is: 3 // first `then` function runs, but i is already 3 now. 2) i is: 3 // second `then` function runs, but i is already 3 now. 2) i is: 3 // third `then` function runs, but i is already 3 now.
那么,如何循环运行量角器?通用的解决方案是关闭。
for (var i = 0; i < 3; ++i) { console.log('1) i is: ', i); var func = (function() { var j = i; return function() { console.log('2) j is: ', j); someArray[j] // 'j' takes the values of 0..2 } })(); getPromise().then(func); } console.log('* finished looping. i is: ', i);
但这不是那么好读。幸运的是,你还可以用量角器功能filter(fn),get(i),first(),last(),和这样一个事实expect修补采取的承诺,来处理这个。
filter(fn)
get(i)
first()
last()
expect
回到前面提供的示例。第一个示例可以重写为:
var expected = ['expect1', 'expect2', 'expect3']; var els = element.all(by.css('selector')); for (var i = 0; i < expected.length; ++i) { expect(els.get(i).getText()).toEqual(expected[i]); // note, the i is no longer in a `then` function and take the correct values. }
第二个和第三个示例可以重写为:
var els = element.all(by.css('selector')); els.filter(function(elem) { return elem.getText().then(function(text) { return text === 'should click'; }); }).click(); // note here we first used a 'filter' to select the appropriate elements, and used the fact that actions like `click` can act on an array to click all matching elements. The result is that we can stop using a for loop altogether.
换句话说,量角器有很多方法可以迭代或访问元素,i因此您无需使用循环和i。但是,如果必须使用for循环和i,则可以使用闭包解决方案。