Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] Iteration over a table's <tr> tags to click and remove them #2034

Closed
thernstig opened this issue Apr 29, 2020 · 5 comments
Closed

Comments

@thernstig
Copy link
Contributor

The below code throws the error NotConnectedError: Element is not attached to the DOM on the second iteration, in case I have two todos. However, the todo.innerText() is printed in the second loop before it throws the error. How could this be possible? And is there a way to work around that? It is possible the below method is a bad idea altogether to clean out a list of todos.

const todos = await page.$$('#todos-list tbody tr');
for await (const todo of todos) {
  console.log(await todo.innerText());
  await todo.click();
  await page.click('#remove-todo-button');
}

This question might be because of tiredness as I've been hammering away with Playwright all day and night now. It's possible some sleep will alleviate this problem.

@pavelfeldman
Copy link
Member

When you click #remove-todo-button, the DOM is likely rebuilt (React page?). So the list now contains new DOM elements. In the second iteration you compute innerText for the element you have in hand, which is ok, you can say element.innerText for a detached element in DOM too. But clicking it tells you that it is not attached to the dom.

For react pages, you should not store stale state, you should query all items and click remove-todo-button on the first one until you run out of the list items.

@thernstig
Copy link
Contributor Author

@pavelfeldman This is not a React page, but it is as you say very likely it is re-built. What happens is that an API call is made when clicking #remove-todo-button so there is a delay before the element is removed from the list. So I cannot immediately poll the list again since I cannot be sure the exact timing for when the list has been updated. I've got a few ideas on how to solve this, but I'd very much be interested in knowing your suggestion here?

One thing I tried was the new page.waitForLoadState() but I believe that only works for actual navigations, not to check network requests while no navigation is being done.

A second option is to on the first iteration actually get numb of elements, click remove, and poll for :nth-child(i) to be gone.

But I find neither of them appealing.

@ZMarouani
Copy link

ZMarouani commented Oct 12, 2021

was this resolved ? I'm dealing with the exact same problem as @thernstig and it's not a react page ... how to solve this ?

Edit : One workaround is iterating directly through the childs of the element without creating the todos const list , because mostly they have similaire xpath that will allow you to loop through them . That solved things for me in many other examples

@jkohlin
Copy link

jkohlin commented Mar 2, 2023

This is what worked for me:

async function removePills(pills: Locator) {
    const pillButtons = await pills.all();
    if (pillButtons.length > 0) {
        await pillButtons[0].click();
        await removePills(pills);
    }
}
await removePills(
    this.iframe.getByTestId("pw-provider-pill").getByRole("button")
);

A loop will not work unfortunately since Playwright internally uses nth(0), nth(1)... to click elements. And if the button deletes the element at nth(0) then nth(1), if there are two elements, will not be there

@thernstig
Copy link
Contributor Author

@jkohlin could you re-write a new issue? Considering this was closed.

You can then reference this, and add the information you have regarding the loop behavior you found.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants