ShouldNot does take <timeout> seconds when executed on an element which parent does not exist.
wjgerritsen-0001 opened this issue · 3 comments
In our code we frequently use nested Find() calls; e.g. By.Selene: (By.Selene: (By.Selene: (NSelene.SeleneDriver).Find(By.XPath: .//descendant-or-self::*[@data-ta = 'reports-list'])).Find(By.XPath: .//*[(contains(@class, 'grid-row') or contains(@class, 'row') or contains(@class, 'list-group-item') or @data-ta='grid-row' or self::form) and not (contains(@class, 'grid-header') or @data-ta='header' or @data-ta='grid-header' or contains(@class, 'report-header'))]/self::*[descendant-or-self::*[@data-ta = 'name' and .//text() = 'Inrichtingsjaarrekening 2020 beperkt']])).Find(By.XPath: .//descendant-or-self::*[@data-ta = 'name'])
When such an element is validated with a ShouldNot, then the timeout is only used on the final element of the search expression. I reproduced this in a simple testcase below:
The nested p is commented out, but we check on the nested a. This is valid, but it takes the full timeout to validate this.
[Test]
public void WaitForVisibility_OnElement_WhichParent_DoesNotExist()
{
Given.OpenedPageWithBody(@"
<p>
<h2>Heading 2</h2>
<!--p>
<a>go to Heading 2</a>
</p-->
</p>"
);
DateTime start = DateTime.Now;
S("p").Find("p").Find("a").ShouldNot(Be.Visible);
Assert.Less(DateTime.Now.Subtract(start).TotalSeconds, Configuration.Timeout);
}
Maybe related to #3
@wjgerritsen-0001, Sorry, I did not get what do you mean here:)
I checked this code in my editor:
Given.OpenedPageWithBody(@"
<p>
<h2>Heading 2</h2>
<!--p>
<a>go to Heading 2</a>
</p-->
</p>"
);
DateTime start = DateTime.Now;
S("p").Find("p").Find("a").ShouldNot(Be.Visible);
Assert.Less(DateTime.Now.Subtract(start).TotalSeconds, Configuration.Timeout);
It passes without waiting, and this is as expected. The <a>
element in your html - is not visible. And our assert S("p").Find("p").Find("a").ShouldNot(Be.Visible);
just checks the same, that it is not visible. And it passes. Everything as it should be from the User perspective.
If you change the code so it asserts visibility:
S("p").Find("p").Find("a").Should(Be.Visible);
Then it will fail as expected, telling that the <p>
element is not visible:
Timed out after 4s, while waiting for:
Browser.Element(p).Element(p).Element(a).Should(Be.Visible)
Reason:
no such element: Unable to locate element: {"method":"css selector","selector":"p"}
(Session info: headless chrome=91.0.4472.114)
----> OpenQA.Selenium.NoSuchElementException : no such element: Unable to locate element: {"method":"css selector","selector":"p"}
By the way... this is an interesting case, because we don't see from the error message, which among two "p" elements is not visible... Probably we have to file new issue for this and try to improve...
P.S.
One more thing - the ShouldNot(Be.Visible)
syntax is obsolete now, the recommended way is: Should(Be.Not.Visible)
Thanks for looking into this ticket. Indeed with the latest code base I also experience the same. So we are upgrading now.
The message in the past was like:
OpenQA.Selenium.WebDriverTimeoutException :
Timed out after 4 seconds
while waiting entity with locator: By.Selene: (By.Selene: (By.Selene: (NSelene.SeleneDriver).Find(By.CssSelector: p)).Find(By.CssSelector: p)).Find(By.CssSelector: a)
for condition: Visible
Expected : True
Actual : False
----> OpenQA.Selenium.WebDriverTimeoutException :
Timed out after 4 seconds
while waiting entity with locator: By.Selene: (By.Selene: (NSelene.SeleneDriver).Find(By.CssSelector: p)).Find(By.CssSelector: p)
for condition: Visible
Expected : True
Actual : False
----> OpenQA.Selenium.NoSuchElementException : no such element: Unable to locate element: {"method":"css selector","selector":"p"}
(Session info: chrome=91.0.4472.164)```
Guess the fix came with alpha7: https://github.com/yashaka/NSelene/commit/a7f113b974ee9fd3c5ac3cf67b402d244f552dc3