루프가 있는 굴절기 사용
루프 인덱스(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결과가 준비되면 기능이 실행됩니다.
다음과 같은 작업을 실행하는 경우:
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가 실행됩니다.
콘솔은 다음과 같습니다.
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 클로징을 참조하십시오.심플한 실용적인 예
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약속을 받아내고 이 문제를 해결할 수 있도록 패치를 적용했습니다.
앞서 설명한 예시로 돌아가 보겠습니다.첫 번째 예는 다음과 같이 고쳐 쓸 수 있습니다.
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단, 루프를 사용할 필요가 있는 경우,i, 클로저 솔루션을 사용할 수 있습니다.
행크는 이 질문에 아주 잘 대답했어요.
나는 또한 이것을 처리하는 또 다른 빠르고 더러운 방법을 알고 싶었다.약속 내용을 외부 기능으로 옮기고 인덱스를 전달하기만 하면 됩니다.
예를 들어 페이지의 모든 목록 항목을 ElementArrayFinder에서 해당 인덱스로 기록하려는 경우 다음과 같은 작업을 수행할 수 있습니다.
var log_at_index = function (matcher, index) {
return $$(matcher).get(index).getText().then(function (item_txt) {
return console.log('item[' + index + '] = ' + item_txt);
});
};
var css_match = 'li';
it('should log all items found with their index and displayed text', function () {
$$(css_match).count().then(function (total) {
for(var i = 0; i < total; i++)
log_at_index(css_match, i); // move promises to external function
});
});
이 기능은 빠른 디버깅과 조정이 필요한 경우에 편리합니다.
나는 위에서 논의하는 훨씬 더 학식 있는 사람들의 논리나 지혜에 대해 논쟁하는 것이 아니다.비동기 함수로 선언된 현재 버전의 Protractor에서는 다음과 같은 for 루프가 (@hetznercloud/protractor-test-helper에서 flowLog를 삽입하여 작성했지만, console.log는 여기서도 동작할 것이라고 생각합니다) 순진하게 동작하고 있음을 지적하기 위해 이 글을 씁니다.
let inputFields = await element.all(by.tagName('input'));
let i: number;
flowLog('count = '+ inputFields.length);
for (i=0; i < inputFields.length; i++){
flowLog(i+' '+await inputFields[i].getAttribute('id')+' '+await inputFields[i].getAttribute('value'));
}
같은 결과를 낳다
count = 44
0 7f7ac149-749f-47fd-a871-e989a5bd378e 1
1 7f7ac149-749f-47fd-a871-e989a5bd3781 2
2 7f7ac149-749f-47fd-a871-e989a5bd3782 3
3 7f7ac149-749f-47fd-a871-e989a5bd3783 4
4 7f7ac149-749f-47fd-a871-e989a5bd3784 5
5 7f7ac149-749f-47fd-a871-e989a5bd3785 6
...
42 7f7ac149-749f-47fd-a871-e989a5bd376a 1
43 7f7ac149-749f-47fd-a871-e989a5bd376b 2
제가 알기로는await).또, 「 」는 「 」입니다( 「 」는 「 。await루프 내의 s는 i가 증가하기 전에 각 약속이 해결되기 때문입니다.
나의 의도는 독자들에게 선택권을 주는 것이지 위에 의문을 제기하는 것이 아니다.
요즘 더 쉬운 방법은
it('test case', async () => {
let elems = element.all(selector)
for (let i=0; i < await elems.count(); i++) {
console.log(await elems.get(i).getText())
}
});
언급URL : https://stackoverflow.com/questions/27910331/using-protractor-with-loops
'programing' 카테고리의 다른 글
| CORS를 통한 Ajax 요청을 사용하는 브라우저의 Set-Cookie (0) | 2023.03.06 |
|---|---|
| React에서 CORS 문제를 해결하는 방법JS (0) | 2023.03.06 |
| Spring Boot 환경 변수 읽기 (0) | 2023.03.06 |
| 스프링 부트 - @ConditionalOnProperty 또는 @ConditionalOnExpression (0) | 2023.03.06 |
| 플러그인 활성화에서 관리 패널에 알림을 표시하는 방법 (0) | 2023.03.06 |