-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
Fix selector visible and hidden #2203
Fix selector visible and hidden #2203
Conversation
…e elements function fails if multiple elements have same selector and not same visibilty
…e elements function fails if multiple elements have same selector and not same visibility
…e elements function fails if multiple elements have same selector and not same visibility
Great PR, thank you for sending it out! Implementation looks good to me. Could you please share more details on the specific scenario where this is useful? I am not sure that existing semantic is better or worse than the proposed one. Since this would be on the edge of a breaking change, we need stronger evidence to go this way. |
Hi @dgozman, I apologize in advance if my answer is quite long... I think there might be a simpler example... but I will give one that is similar to the one I encountered: And I have many many users, and each one has different options in the navigation bar. The subnav in the link would look something like this:
where all the primary buttons have a similar data-test-id (e.g. "Menu-button-Home"), and all the subMenu Buttons also have a similar data-test-id(e.g. "subMenu-option-Bring"); when I map the navbar dynamically I do not know the full data test, so I query something like this:
and then, after I know it is visible, I use an eval to get all the subMenu options. the problem occurs when I move from "About", to "Services": I wait for all the subMenus from the About option to turn hidden:
which work fine, but afterwards when I do the same query I did before in order to reveal the new subMenu:
I receive a timeout.(this is the bug) obviously if there is a visible element that answers to my selector, and I am waiting for a visible element, the function should not fail because there is a different hidden element that answers to the same selector. my implementation checks that there is at least one element that answers to the requested condition, whereas the current implementation checks only if the first arbitrary element with this selector answers to the requested condition. once again, sorry if it was quite long :-) |
Thank you for the details. It seems like your usecase is "wait until at least one element matching the selector is visible". I am still not sure that logic will work for everyone. Here are a few ideas:
await page.waitForSelector('[data-test-id*="subMenu-option"]:nth-child(5)', { state: 'visible' })
await page.waitForFunction(() => {
const submenus = Array.from(document.querySelector('[data-test-id*="subMenu-option"]'));
return submenus.map(e => e.getBoundingClientRect()).some(r => r.width > 0 && r.height > 0);
});
await page.waitForSelectors('[data-test-id*="subMenu-option"]',
elements => elements.map(e => e.getBoundingClientRect()).some(r => r.width > 0 && r.height > 0);
});
await page.waitForSelectors('[data-test-id*="subMenu-option"]',
elements => elements.length > 0,
{ state: 'visible' }
); Let me know what you think. |
What might be a nice way of dealing with it is just giving the developer more information - if a method is called that expects one selector but find multiple elements you could just output a warning with a list of all the matched elements in the terminal. Debugged in a few seconds, job done. |
Hi @dgozman, Thank you for your elaborate answer, I have to admit I still think that there is a very major problem in the basic of the usage of the "visible" in playwright. Hidden elements are a nuisance, they stray you away from the happy path of testing, and in the current implementation they remain quite a very big problem. Basically, I think my main point is that usage of {state:”visible”} should be as an additional selector, because it is such a powerful one, and a much needed one in an automation framework. let’s say I have 2 forms in my browser window, both of them have a "submit form" with data-test-id of "submit_form". If one of them is hidden, and I try to click a data-test-id that matches both of them, I will always want to click the visible element.. Always. In a case like that, creating a more specific selector is time consuming, code consuming and creates a flakier test. With my suggested implementation: With current implementation(using waitForFunction):
Or even worse than that, let’s say I had a solid test running for 2 years with the same form. And just because an invisible form was added, my test will start failing because my system timed out waiting for a new invisible element.. It creates a much less reliable automation framework. I understand that currently all the single element functions are implemented in the same fashion: they do document.querySelector and continue from there.. But I think it makes much more sense to use the visibility as an extension of the selector criteria, and not as something I check on one specific element. I know that both of the answers are possible, but I have the distinct feeling that the way that I expect the system to behave is much more common and makes much more sense. Anyway, in a way of looking for the middle ground, maybe it is possible to add another option? I think it should be something like “elementIndex” or “elementDOMIndex” , this will still enable the same old functionality with Obviously I’m sure no one is keen on adding extra options, but I think this one is very much justified. |
Thank you for the detailed response. We discussed this and decided to continue with out predictable model. It is easy to understand and consistent:
I have drafted a proposal in #2370 to address some usecases mentioned in this PR - comments and different proposals are welcome! Again, thank you for the fantastic PR! |
my pleasure.. |
fix(waitForSelector): waiting for visible or hidden fail with multiple elements
function fails if multiple elements have same selector and not same visibility