SeleniumHQ / selenium

A browser automation framework and ecosystem.
https://selenium.dev
Apache License 2.0
30.47k stars 8.15k forks source link

Click() action unable to perform action on different elements #5072

Closed curtisy1 closed 6 years ago

curtisy1 commented 6 years ago

Meta -

OS: Windows 10, Fall update Selenium Version: .NET 3.7.0 Browser: Firefox

Browser Version: 59.0a1 (2017-11-16) (64-Bit)

Expected Behavior -

Actions should be capable of performing actions to different elements in one go, as documented in the Python reference here.

Actual Behavior -

Calling Click() with different elements results in a StaleElementReference Exception

Steps to reproduce -

Note: I didn't test if this example works as well, but it generally should. I simply changed my selectors and adjusted them to match those of the test case.

Actions cutpaste = new Actions(Driver);
            cutpaste.ContextClick(Driver.FindElement(By.XPath("//tbody/tr[2]/td[5]")))
                .Build()
                .Perform();
                        // this popup is a child of //tbody/tr[2]
            var popup = Driver.FindElements(By.CssSelector("ul.ui-menu"));
            Actions click = new Actions(Driver);
            click.Click(popup[0]).Build().Perform();
                        // this works fine, although the value changed
            cutpaste.ContextClick(Driver.FindElement(By.XPath("//tbody/tr[3]/td[5]")))
                .Build()
                .Perform();
                        // this popup is now a child of //tbody/tr[3]
            popup = Driver.FindElements(By.CssSelector("ul.ui-menu"));
                        // this fails with a staleelementreference exception, although it's the same procedue as contectClick()
            click.Click(popup[0]).Build().Perform();

For an example that should be able to reproduce this, see here.

lmtierney commented 6 years ago

Duplicate of #4724

lmtierney commented 6 years ago

Specifically, this is the intended behavior. https://github.com/SeleniumHQ/selenium/issues/4724#issuecomment-330862710

curtisy1 commented 6 years ago

@lmtierney It's actually a completely different issue. What I described in the one you referred to is that the same Action can only keep its 'state' and do the same action over and over again. (as an example, using a click.SendKeys(Keys.Enter).Build().Perform(); and a click.SendKeys(Keys.Delete).Build().Perform(); after another would reproduce #4724.

What I'm describing here is that by making use of that exact feature by calling click.Click(Element1).Build().Perform(); and then click.Click(Element2).Build().Perform(); the click Action should remember only the Click() event (as it's the same action sequence). This is the case with the cutpaste Action (or rather Contextclick), so even if it would be a duplicate, something on this is inconsisten it seems.

jimevans commented 6 years ago

@curtisy1 I'm sorry, you're mistaken. It is a duplicate. The action sequence doesn't just consist of the actions added to it, but also the specific element references used to create the action sequence. In effect, what you've asked the click Action to do is the following:

Then, at some later time, since the click action is not reset, you ask it to do the following:

This is exactly what's described by the other element. Since the Actions class is lightweight to create, you should create a new one for the second click.

curtisy1 commented 6 years ago

@jimevans Thanks for the detailed explanation. However I'm still a bit short on why the cutpaste Action in my code snippet works fine. Any idea why this doesn't produce a StaleElementReference Exception?

jimevans commented 6 years ago

Because the elements the cutpaste action refers to (and it refers to multiple elements at the end, so it right-clicks on two elements the second time Perform is called), aren’t stale. The elements referred to in the DOM haven’t been removed and replaced, as they have on the pop up menu.

curtisy1 commented 6 years ago
and it refers to multiple elements at the end, so it right-clicks on two elements the second time Perform is called

Ohh that makes a lot more sense.

Thanks for taking the time to explain this :)