使用带循环的量角器 [英] Using protractor with loops
问题描述
循环索引 (i
) 不是我在循环中使用量角器时所期望的.
Loop index (i
) is not what I'm expecting when I use Protractor within a loop.
症状:
失败:索引越界.试图访问 index:'x' 处的元素,但只有 'x' 个元素
Failed: Index out of bound. Trying to access element at index:'x', but there are only 'x' elements
或
索引是静态的并且总是等于最后一个值
Index is static and always equal to the last value
我的代码
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"
}
})
}
})
推荐答案
发生这种情况的原因是因为量角器使用了 promise.
The reason this is happening is because protractor uses promises.
阅读https://github.com/angular/protractor/blob/master/docs/control-flow.md
Promises(即 element(by...)
, element.all(by...)
)在以下情况下执行它们的 then
函数基础价值准备就绪.这意味着首先安排所有承诺,然后在结果准备就绪时运行 then
函数.
Promises (i.e. element(by...)
, element.all(by...)
) execute their then
functions when the underlying value becomes ready. What this means is that all the promises are first scheduled and then the then
functions are run as the results become ready.
当你运行这样的东西时:
When you run something like this:
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() {...})
立即返回,在 Promise 准备好之前并且没有执行 then中的函数代码>.所以首先循环运行 3 次,调度所有
getPromise()
调用.然后,随着 promise 的解析,相应的 then
被运行.
What happens is that getPromise().then(function() {...})
returns immediately, before the promise is ready and without executing the function inside the then
. So first the loop runs through 3 times, scheduling all the getPromise()
calls. Then, as the promises resolve, the corresponding then
s are run.
控制台看起来像这样:
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.
那么,你如何在循环中运行量角器?一般的解决方案是关闭.请参阅循环内的 JavaScript 闭包 - 简单实用示例
So, how do you run protractor in loops? The general solution is closure. See JavaScript closure inside loops – simple practical example
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
被修补以接受承诺的事实,以解决这个问题.
But this is not that nice to read. Fortunately, you can also use protractor functions filter(fn)
, get(i)
, first()
, last()
, and the fact that expect
is patched to take promises, to deal with this.
回到之前提供的示例.第一个例子可以改写为:
Going back to the examples provided earlier. The first example can be rewritten as:
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.
}
第二个和第三个例子可以改写为:
The second and third example can be 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 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
,这样你就不需要使用for循环和i
.但是如果你必须使用for循环和i
,你可以使用闭包解决方案.
In other words, protractor has many ways to iterate or access element i
so that you don't need to use for loops and i
. But if you must use for loops and i
, you can use the closure solution.
这篇关于使用带循环的量角器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!