yashaka / NSelene

Consise API to Selenium for .Net (the port of Selene in python / Selenide in Java)
MIT License
68 stars 21 forks source link

ShouldNot does take <timeout> seconds when executed on an element which parent does not exist. #91

Closed wjgerritsen-0001 closed 3 years ago

wjgerritsen-0001 commented 3 years ago

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);
        }
wjgerritsen-0001 commented 3 years ago

Maybe related to #3

yashaka commented 3 years ago

@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)

wjgerritsen-0001 commented 3 years ago

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