2

I am currently working on an automation test suite for a web application. The web application is really finicky. Recently, we had a UI update, so I ran tests to test out our GUI and buttons, as well as to access that our xpaths were still working.

THE NIGHT BEFORE HALLOWEEN, MY SCRIPT GOT REAL SPOOOOOOOKY~

Ghosts probably in my script

In these suites, I have a set of two tests: yesLogout, noLogout. yesLogout clicks the "Yes" button when you try to logout. noLogout clicks the "No" button when you try to logout.

When you run noLogout in the test script, the script clicks "No" and the logout prompt goes away.

When you run yesLogout in the test script, the script clicks the "Yes" button, but nothing happens. The "Yes" button makes an animation as though it was clicked, but the prompt just remains there.

Manually clicking the button works just fine.

I'm going to share the two methods (noLogout, yesLogout) as they are practically the same, they just call two different xpaths. For the sake of this question, forget that I'm testing at all - tests aren't the problem right now. Pretend I'm some weirdo who just really needs my script to click this button.

Two functions for use in tests (extremely simplified):

public class HiStackOverflow {

    public class yesLogout {
        public static void run(WebDriver driver) throws FileNotFoundException {
            Properties prop = new Properties();
            InputStream selectproductsidebar;

            selectproductsidebar = new FileInputStream(
                "C:/PATH/TO/PROPERTIES");
            try {
                prop.load(selectproductsidebar);
            } catch (IOException e) {
                e.printStackTrace();
            }


            WebElement yesLogout = driver.findElement(By.xpath(prop.getProperty("yeslogout")));
            Actions actions = new Actions(driver);
            actions.moveToElement(yesLogout).build().perform();
            yesLogout.click();
        }
    }

    public class noLogout {
        public static void run(WebDriver driver) throws FileNotFoundException {
            Properties prop = new Properties();
            InputStream selectproductsidebar;

            selectproductsidebar = new FileInputStream(
                "C:/PATH/TO/PROPERTIES");
            try {
                prop.load(selectproductsidebar);
            } catch (IOException e) {
                e.printStackTrace();
            }


            WebElement noLogout = driver.findElement(By.xpath(prop.getProperty("nologout")));
            Actions actions = new Actions(driver);
            actions.moveToElement(noLogout).build().perform();
            noLogout.click();
        }

    }
}

The xpath of the Yes button and the No button in the properties file:

yeslogout = //div[contains(@title,'Enter')]
nologout = //div[contains(@title,'Esc')]

And here is the HTML that relates to the issue:

<div style="transform: translate(0px, 60px) scale(1, 1) rotate(0deg);">
  <div style="transform: translate(10px, 0px) scale(1, 1) rotate(0deg);">
    <div>
      <div tabindex="6" role="button" aria-label="Yes" title="Keyboard shortcut: Enter">
        <div>
        </div>
        <div tabindex="7" role="button" aria-label="No" title="Keyboard shortcut: Esc" style="transform: translate(163.5px, 0px) scale(1, 1) rotate(0deg);">
          <div>
          </div>
        </div>
      </div>
    </div>

tabindex="6" is the yes button. tabindex="7" is the no button. There's a small difference in the two (the no button has some sort of transform: translate magic attached to it), but as far as I'm concerned it shouldn't be acting so strange.

Once again, the actual problem - running the yesLogout method locates, hovers over, and clicks the Yes button, but nothing happens. Manually clicking the yes button works out fine.

I can expand some more <div>s in the html if needed, but I really don't think it will show too much (just some more formatting and <canvas> stuff). I'm really interested in an explanation of what is going on. Thanks in advance.

EDIT: I have attempted to use JavascriptExecutor to click on the element, but alas, it did not work. This has been racking my brain all weekend.

Even doing crazy stuff like:

WebElement yesLogout = driver.findElement(By.xpath(prop.getProperty("yeslogout")));
        Actions actions = new Actions(driver);
        actions.moveToElement(yesLogout, 10, 10).build().perform();
        yesLogout.click();
        yesLogout.click();
        yesLogout.click();
        yesLogout.click();
        yesLogout.click();
        yesLogout.click();

Shows the button being clicked over and over and over again, but no actual functionality.

For the sake of completeness and trying to get people to understand the issue, I'll restate, manually clicking the button works wonderfully. As does the Enter shortcut. Selenium .click() commands VISIBLY "work", but do not carry out the functionality of the button itself.

SECOND EDIT: I will include a fully expanded HTML of the concerning divs:

<div style="transform: translate(794px, 202px) scale(1, 1) rotate(0deg);" tabindex="5" role="dialog">
  <div>
    <div>
      <div>
        <div>
          <div>
            <canvas height="106" width="332" style="top: 0px; left: 0px; width: 332px; height: 106px;" />
          </div>
        </div>
        <div style="transform: translate(10px, 10px) scale(1, 1) rotate(0deg);">
          <div>
            <div style="transform: translate(6px, 6px) scale(1, 1) rotate(0deg);">
              <div style="font-family: franklin-gothic-urw; font-weight: 400; font-style: normal; font-size: 14px; opacity: 1; color: rgb(0, 0, 0);">Are you sure you want to logoff?</div>
            </div>
          </div>
        </div>
        <div style="transform: translate(0px, 60px) scale(1, 1) rotate(0deg);">
          <div style="transform: translate(10px, 0px) scale(1, 1) rotate(0deg);">
            <div>
              <div tabindex="6" role="button" aria-label="Yes" title="Keyboard shortcut: Enter">
                <div>
                  <div>
                    <div>
                      <div>
                        <div>
                          <canvas height="36" width="148" style="top: 0px; left: 0px; width: 148.5px; height: 36px;" />
                        </div>
                      </div>
                      <div style="transform: translate(56px, 7px) scale(1, 1) rotate(0deg);">
                        <div style="font-family: proxima-nova; font-weight: 400; font-style: normal; font-size: 17px; opacity: 1; color: rgb(255, 255, 255); transform: translate(5px, 0px) scale(1, 1) rotate(0deg);">Yes</div>
                      </div>
                      <div style="">
                        <div>
                          <div>
                            <canvas height="36" width="148" style="top: 0px; left: 0px; width: 148.5px; height: 36px;" />
                          </div>
                        </div>
                        <div style="display: none;">
                          <div>
                            <canvas height="36" width="148" style="top: 0px; left: 0px; width: 148.5px; height: 36px;" />
                          </div>
                          <div style="transform: translate(56px, 7px) scale(1, 1) rotate(0deg);">
                            <div style="font-family: proxima-nova; font-weight: 400; font-style: normal; font-size: 17px; opacity: 1; color: rgb(255, 255, 255); transform: translate(5px, 0px) scale(1, 1) rotate(0deg);">Yes</div>
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
              <div tabindex="7" role="button" aria-label="No" title="Keyboard shortcut: Esc" style="transform: translate(163.5px, 0px) scale(1, 1) rotate(0deg);">
                <div>
                  <div>
                    <div>
                      <div>
                        <div>
                          <canvas height="36" width="148" style="top: 0px; left: 0px; width: 148.5px; height: 36px;" />
                        </div>
                      </div>
                      <div style="transform: translate(58px, 7px) scale(1, 1) rotate(0deg);">
                        <div style="font-family: proxima-nova; font-weight: 400; font-style: normal; font-size: 17px; opacity: 1; color: rgb(255, 255, 255); transform: translate(5px, 0px) scale(1, 1) rotate(0deg);">No</div>
                      </div>
                      <div style="display: none;">
                        <div>
                          <div>
                            <canvas height="36" width="148" style="top: 0px; left: 0px; width: 148.5px; height: 36px;" />
                          </div>
                        </div>
                        <div style="display: none;">
                          <div>
                            <canvas height="36" width="148" style="top: 0px; left: 0px; width: 148.5px; height: 36px;" />
                          </div>
                          <div style="transform: translate(58px, 7px) scale(1, 1) rotate(0deg);">
                            <div style="font-family: proxima-nova; font-weight: 400; font-style: normal; font-size: 17px; opacity: 1; color: rgb(255, 255, 255); transform: translate(5px, 0px) scale(1, 1) rotate(0deg);">No</div>
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
James Brierley
  • 4,630
  • 1
  • 20
  • 39
jagdpanzer
  • 693
  • 2
  • 10
  • 35
  • Could you include more of the html that is causing this problem. I noticed that the no button is contained within the yes button, which is a bit weird, and the bug could be caused by something else inside. Also, how are you binding the click event to the yes button? – James Brierley Nov 02 '15 at 16:13
  • Also, are there any other bound events with `return false;`? – James Brierley Nov 02 '15 at 16:15
  • The click event is made with a `WebElement yesLogout = driver.findElement(By.xpath(prop.getProperty("yeslogout")))` which loads the xpath from a properties file, than I use a simple `yesLogout.click()` to click it. I don't believe there are any values returning false. – jagdpanzer Nov 02 '15 at 16:19
  • 1
    I meant in the JavaScript on the actual page. – James Brierley Nov 02 '15 at 16:20
  • The JavaScript on the page is poorly formatted and about 120000+ lines long. I honestly do not know. The entire application is essentially one page of JavaScript. If there are means of singling out the logout function from it, I'll do so, but searches for anything like "logout" yield no results. – jagdpanzer Nov 02 '15 at 16:27
  • 1
    I'm going to make a guess here. Is it possible that the click handler for the button is set dynamically by your JS? When you run it manually it has enough time to be set and the click happens fine, but selenium does things too quickly? Can you try adding like a 5 second wait before clicking and see if things work? You can also run some javascript in the page before clicking and printing the click handler to see if it is set correctly (might help in debugging). See this: http://stackoverflow.com/questions/5327668/calling-tostring-on-a-javascript-function-returns-source-code – AzureMinotaur Nov 02 '15 at 22:34

3 Answers3

2

Try debugging using different options first such as pass keyboard Enter key to see if it works

WebElement.sendKeys(Keys.ENTER);

Other options you can try is using CSS to find the element or Java script methods to click the element

WebElement element = driver.findElement(By.id("gbqfd"));
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("arguments[0].click();", element);

reference: How to click an element in Selenium WebDriver using JavaScript

Community
  • 1
  • 1
Syed
  • 189
  • 1
  • 5
  • 11
  • I'm currently out for the weekend but I'll try that in my scripts on monday. I've never heard of the Javascript executor. If the ENTIRE web application is written in JavaScript, would it be wise to learn all about that? Thanks by the way. – jagdpanzer Oct 30 '15 at 21:25
  • I've had very similar situations like this before where I just have to mess around with xpaths until clicks work. This sounds like a real solution. – jagdpanzer Oct 30 '15 at 21:26
  • 1
    You shouldn't need JSE here and, in general, JSE should not be used. It interacts with the page in a way that the user can't. If you want to simulate a user's interaction with your page, and you should, then don't use JSE. – JeffC Oct 31 '15 at 13:58
  • Back in the office today. It was worth a shot, but this does not seem to be working. – jagdpanzer Nov 02 '15 at 14:55
1

I don't know if it is up to you or not, but I would try to add an id or a more distinctive property for these buttons (since they are important for the application).

On the other hand, do you necessarily need the actions.moveToElement() thing? Can't you just click the element? This could decrease any unexpected behaviors:

WebElement yesLogout = driver.findElement(By.xpath("..."));
yesLogout.click();

One last thing (for a better understanding), I am not sure I understand why would you use a div as a button? Why is the No button, inside the (div) Yes button? This could lead to an issue.

makeMonday
  • 2,303
  • 4
  • 25
  • 43
  • To answer those questions, honestly: a complete lack of coding standards by our developers, and our application is going on it's 3rd or 4th year I believe. I run into the craziest s*** when trying to automate this thing. I agree with the inclusion of `id`s, not a single one exists in the entire program. – jagdpanzer Nov 02 '15 at 15:56
  • Essentially I don't have a lot of control over the source code, so I have to always find the weird way around doing things all while hard coding nothing. I'm also an intern, so telling the developers we need `id`s probably won't be taken seriously. I can usually get things to work - infact, the script for this button worked about a week ago, but they updated the GUI (made the canvas a little bigger and a different shade of green) and now it doesn't want to listen to me. It knows what I want to do, just refuses to actually carry out the function beyond the button. – jagdpanzer Nov 02 '15 at 15:58
  • @jagdpanzer Ok, I see you're in a lot of trouble :P Did you try simply clicking the element as I suggested? I would replace your `xpath` with this: `"//div[@aria-label=\"Yes\"]"`. Also, try by replacing the `prop.getProperty("yeslogout")` with the `xpath` directly so you avoid any other possible issues. – makeMonday Nov 02 '15 at 16:10
  • 2
    Could you also provide a bit more of the `html` code. In this way, it is not possible to see much of your problem :( – makeMonday Nov 02 '15 at 16:11
  • Added the expanded HTML of the concerning divs at the bottom of my post. If you need more, let me know, but that is everything within the logout prompt. – jagdpanzer Nov 02 '15 at 16:16
  • 1
    I remember having a "*similar*" issue, in the sense that I could manually click an element, but it was not working with `Selenium`. The issue was that the element triggering the "expected action" was not the one I thought. Meaning that, maybe another DOM element is interfering in your click (`Selenium` clicks on an element specifically, a mouse may click in an element over your element). And since the HTML code looks pretty messy, it is likely that there is something like that going on. I hope it helps :) – makeMonday Nov 02 '15 at 16:34
  • It helps a lot man, thank you. Would this be an issue I'd probably have to bring to a developer? How does one nicely say "heyyyyyy buddy, your html sucks"? – jagdpanzer Nov 02 '15 at 16:39
  • 1
    That is certainly not the way, haha... I would try to ask if there is something in the DOM or in the Javascript as @James Brierley mentions in his question. I mean, ask the guys, even if they created a not so readable code, they probably know what could be happening. Something more like: "Hey! There is something weird happening, maybe you could help me figuring out..." :D – makeMonday Nov 02 '15 at 16:50
1

There are a few things that might cause this, but I couldn't be certain without you adding the relevant JavaScript to your question. I'm assuming that somewhere in the JavaScript on your page, there is a function bound to the click event that is actually performing the action you are expecting.

It could be that this event is bound to a child of the yes button. In this case, clicking on the button on the page might trigger the click event when done so in a browser. However because your xpath is targeting the parent, selenium will only trigger a click event against that element, and would therefore not trigger any events on its children. However, the animation might still be triggered if it is attached to the parent. This could be fixed by making the xpath target the specific element that has the click event attached to it.

Unfortunately, finding which element the event is attached to could be a pain if the JavaScript is a mess. One thing that might help you, is that if you inspect an element in Chrome developer tools, there is an event listeners tab. You can see which elements have click events bound to them, but this won't show the specific method if they are using jQuery, and instead one of the jQuery methods.

James Brierley
  • 4,630
  • 1
  • 20
  • 39
  • Thanks James. I'll try the Chrome developer tools right now and see if I can make sense out of any of this. – jagdpanzer Nov 02 '15 at 16:41
  • 1
    Your advice helped a lot, James. I was able to locate where the actual click event was within the script (and man, it is ridiculously placed). I used this method for a couple other similar problems within our scripts - works great. Thankyou. – jagdpanzer Nov 04 '15 at 15:33