Reputation: 1693
I have an array of webdriver elements, I am trying to iterate over them to delete them all, except the one with index 0. The processes inside this iteration are asynchronous.
I have tried several things, but none seem to work.
My current approach is to use a for of
loop, but I am getting a Failed: stale element reference: element is not attached to the page document
.
const els = await this.el.getElements(this.s.tm.button.remove)
for (let el of els) {
if (els.indexOf(el) >= 1) {
await this.h.waitForSpinner(2147483647)
await el.click()
await EC.isVisible(this.s.tm.deleteModal.container)
await this.h.waitForSpinner(2147483647)
await this.el.clickElement(this.s.tm.deleteModal.confirmButton)
}
}
I have also tried to use:
element.all(by.css('[data-qa="this.s.tm.button.remove"]')).filter((el, i) => {
return i >= 1;
}).each(async (el, i) => {
await el.click()
await EC.isVisible(this.s.tm.deleteModal.container)
await this.h.waitForSpinner(50000)
await this.el.clickElement(this.s.tm.deleteModal.confirmButton)
});
But this second approach is not awaiting for the async code.
Any help will be appreciated!
=================== UPDATED SOLUTION ===================
The solution to iterate over a WebDriver collection of elements by @yong is correct.
However, in my case, the code inside the for loop
is deleting one element each time, so there is a moment in which .get(i)
tries to get an index provided by the loop that no longer exists in the page. Getting the error:
Failed: Index out of bound. Trying to access element at index: 6, but there are only 5 elements that match locator By(css selector, [data-qa=team-members__button-remove])
.
The solution is to use a decremental for loop
. This means, the loop backwards of els_count
will match always the get(i)
. Note that if els_count === 10
, the last index will be 9. So we need to do els_count - 1
.
async deleteAllTeamMembers() {
await EC.isVisible(await this.el.getFirstElement(this.s.tm.button.invite));
const els_count = await this.el.getElements(this.s.tm.button.remove).count();
for (let i = els_count - 1; i >= 1; i--) {
await EC.isVisible(this.el.getElements(this.s.tm.button.remove).get(i))
await this.el.getElements(this.s.tm.button.remove).get(i).click()
await EC.isVisible(this.s.tm.deleteModal.confirmButton, 50000)
await this.el.clickElement(this.s.tm.deleteModal.confirmButton)
await this.h.waitForSpinner(50000)
}
}
Upvotes: 0
Views: 741
Reputation: 13712
const els_cnt = await element.all(by.css('[data-qa="this.s.tm.button.remove"]')).count();
for (let index=1;index<els_cnt;index++) {
await element.all(by.css('[data-qa="this.s.tm.button.remove"]')).get(index).click();
await EC.isVisible(this.s.tm.deleteModal.container)
await this.h.waitForSpinner(50000)
await this.el.clickElement(this.s.tm.deleteModal.confirmButton)
}
Upvotes: 1
Reputation: 186
Try doing this. Hold the elements in the object and you need to access each element asynchronously and perform action as shown below. Dont need to specify waits
this.searchResults = element.all(by.xpath('<xpath>') // this will hold array of elements
function foo(){
this.searchResults.then(function(runTimeResults){
for(i=0; i< runTimeResults.length; i++){
if(i>0){ //click/delete the element if the index > 0
(function(currentElement){
currentElement.click();
});
})(runTimeResults[i]);// Need to hold the current ith element in a variable => currentElement
}
};
});
}
Upvotes: 0