SeleniumLibrary
SeleniumLibrary copied to clipboard
`Wait until does not contain element` always waits for full amount of wait time
Hello,
A colleague of mine stumbled upon this, and I found it to be worthy of creating an issue.
Let's say implicit wait is set to 20s, and suppose I want to wait for the disappearance of the element iDontExist:
*** Settings ***
Library SeleniumLibrary implicit_wait=20.0
*** Test Cases ***
Testing implicit wait
Open browser http://www.google.com chrome
Wait until page does not contain element //iDontExist
This will result in a full 20 seconds wait until it returns successfully. I inspected the code responsible, and indeed, it reflects the finding exactly:
@keyword
def wait_until_page_does_not_contain_element(self, locator, timeout=None,
error=None):
"""Waits until element ``locator`` disappears from current page.
Fails if ``timeout`` expires before the element disappears. See
the `Timeouts` section for more information about using timeouts and
their default value and the `Locating elements` section for details
about the locator syntax.
``error`` can be used to override the default error message.
"""
self._wait_until(
lambda: self.find_element(locator, required=False) is None,
"Element '%s' did not disappear in <TIMEOUT>." % locator,
timeout, error
)
In my opinion that is not intuitive. I would expect this keyword to return as soon as the element is not found. Maybe there's use cases for the current implementation also, in which case maybe a parameter can distinguish between both behaviors or something?
I just wanted to bring this to your attention and I'm curious to the clarification.
Thanks, Bart
My environment:
Browser: Chrome 73.0.3683.86 (64 bits) Browser driver: ChromeDriver version 73.0.3683.68 (47787ec04b6e38e22703e856e101e840b65afe72) Operating System: Windows 10 version 1703 (build 15063.1631) Libraries
- Robot Framework: 3.1.1
- Selenium: 3.141.0
- SeleniumLibrary: 3.3.1
- Interpreter: Python 2.7.16 (v2.7.16:413a49145e) (64 bits)
PS Judging by the implementation I would expect this to occur regardless of using implicit or explicit wait.
I agree that it is not very intuitive, but there is logical explanation. SeleniumLibrary supports two type of timeouts. There is timeout which is SeleniumLibrary level timeout and there is implicit wait which is Selenium level timeout. The implicit wait will control how long Selenium will wait element to appear and by defining implicit wait, user/SeleniumLibrary gives waiting control to Selenium how long is waited to the element to appear. This will overrule the timeout which is SeleniumLibrary level timeout.
Selenium API does not contain a method which would allow to ask that element is not in the page, in the Selenium API there is only way to ask that element is in the page. Now because you are waiting that element does not appear in the page, then Selenium will always wait the implicit wait amount to element to appear.
If only timeout is defined, which is by default 5 seconds, keyword will return immediately when the element is not in the DOM.
I am aware of these differences between timeout and implicit_wait, but I'm surprised about the implementation of the keyword:
# ...
lambda: self.find_element(locator, required=False) is None,
# ...
But I can imagine this is not easily changed perhaps, because of the central role of the find_element method.
Okay, the most important thing to take away here is that you're saying this problem only occurs with the implicit wait, not with the timeout value? So the advice is to strategically avoid the use of implicit wait in situations where you want to wait until some element is not contained?
Maybe this should at least be documented somewhere, preferably in the keyword documentation.
1 Implementation
The find_element eventually points to ElementFinder which basically maps locator strategy to the correct Selenium API method. Just one way to for code segregation.
But I do not understand why you are surprised, could you tell more? What did you expect and why the line you see surprising?
2 timeout
Yes, you are correct, implicit wait will give control to Selenium for element waiting and only for that. And therefore keywords execution time can be longer than what is defined by the timeout argument (In the SeleniumLibrary import or by individual keywords.)
3 documentation Documentation can be always improved, currently it is documented in here: http://robotframework.org/SeleniumLibrary/SeleniumLibrary.html#Timeouts%2C%20waits%20and%20delays How you would like to improve it?
At least link in the: See Selenium documentation for more does not anymore exist and defaults to https://www.seleniumhq.org/ which is wrong and at least that should be fixed.
1. Implementation
I think I understand what tripped my brain. I didn't understand why you locate the element that way, which would indeed force you to wait for the full implicit_wait seconds, but of course you have to, since you have to check for its presence and the atomic time this takes (by definition) is the implicit_wait. So I guess I understand now :).
3. Documentation
I was referring to this specific counter-intuitive caveat of the Wait until ... not ... keywords subset. Maybe a line such as: "Bear in mind that when using Wait keywords that wait for some element or text to disappear or not be present, this will internally involve locating the element and therefore this check will never return earlier than the duration of implicit_wait." or something like that. Hope I'm putting/understanding that correctly.
Thanks :)
1 Implementation No worries, I am many times blind to these kinds of details. It is always good to discuss and have a second opinion. Also this is a thing that get's asked now and then.
3 Documentation It would be possible to say:
The implicit wait his higher priority than
timeout, because it is Selenium level timeout and thereforeimplicit_waitmay increase the keywords execution time to be longer than thetimeoutargument defines.
But I am not sure which one would be better, need to give a some tough. Pointers and pull request are always welcomed.
Ah yes, I like how your explanation takes into account both possible waiting parameters. That's crucial!
Personally I would still find it to be clarifying if there's explicit mentioning of this counter-intuitive effect when using those Wait until ... not ... keywords, like my example explanation above. People, like I did, might not realize there's an internal call to find_element going on which adheres to the implicit_wait value (if set). They might think, like I did, that maybe some custom logic has been applied and not be aware of the effects of implicit_wait in this context.
But I think I stated my case. At the least I learned something, thanks for explanation.
I've noticed similar behaviour for Alert Should Not Be Present - without timeout argument, it now wait the full time.
This has changed since v4.4.0, and now the v5.1.3 implementatiton doesn't match the documentation for this keyword, in particular (section in bold):
timeout specifies how long to wait for the alert to appear. By default, is not waited for the alert at all, but a custom time can be given if alert may be delayed. See the time format section for information about the syntax.
I don't follow what are you saying. Could you explain your problem with an example, which shows the timeouts too?