gmail buttons with selenium library

2,519 views
Skip to first unread message

majatalo

unread,
Apr 26, 2013, 5:36:52 AM4/26/13
to robotframe...@googlegroups.com
Hi
I am trying to learn/remember robot, since it's been while when I last time used it.

I am creating script that uses browser to login to gmail and handling emails example all posts from robot-framework groups will be moved to proper folder.

now I tried to create delete function so that
1. open mail from inbox
2. click delete button.

I am using selenium2library, linux(64)

problem at moment is that I cannot click delete button.
email opens but for some reason I cannot click delete button.

here is source part of that delete button(got it from inspect element in firefox)
<div class="T-I J-J5-Ji nX T-I-ax7 T-I-Js-Gs ar7" tabindex="0" role="button" act="10" style="-moz-user-select: none;" data-tooltip="Poista" aria-label="Poista">
<div class="asa">
<span class="J-J5-Ji ask"></span>
<div class="ar9 T-I-J3 J-J5-Ji">
</div>
</div>
</div>

there is no id, name, label or value that I could use.

is it possible to use aria-label instead label?
just an idea that if robot is made so it can use any element defined in html tag.

I tried to use click element + coordinates, but selenium2library does not support coordinates.

and with seleniumlibrary  handlind browser does not work the same.

any recomendations that I could try(when I get home).

Kevin O.

unread,
Apr 26, 2013, 9:37:27 AM4/26/13
to robotframe...@googlegroups.com
You may be tempted to use Click Button, but do not. It is restricted to actual button elements whereas Google is using role='button' to turn a div into a pseudo-button.
I think your proposal to use the aria-label attribute is a good approach. The data-tooltip attribute would work as well.
Here's two ways that should work:

Click Element    css=div[aria-label='Poista']
Click Element    xpath=//div[@aria-label='Poista']

The part in square brackets is called a predicate for XPath and an attribute selector in CSS.
Unfortunately locating the element this way is language-specific.
It is very helpful to user Firebug with the FirePath add-on to test out locators.

Cheers,
Kevin

majatalo

unread,
Apr 26, 2013, 11:37:42 AM4/26/13
to robotframe...@googlegroups.com
I tried both with " and with '
does not recognaise, but I have to reade more about that xpath.

any good ideas are welcome.

I will let you know if I am find working solution.

Kevin O.

unread,
Apr 26, 2013, 3:53:35 PM4/26/13
to robotframe...@googlegroups.com
I investigated further. div[aria-label='Poista'] is a valid locator and works in FirePath, but does not work when Selenium uses it.
I did Log Source as well as looking at the HTML in IE's developer tools.
The HTML being displayed in Firebug is different and I'm not sure how exactly...Google's stuff is AJAX-heavy.
I have more experience with IE.
By changing the locators to be based on the code logged with Log Source (//div[@title='Delete']), I was able locate an element.
The problem I ran into was that GMail's HTML is a pile of randomness and there is a hidden div with the same contents as the visible one that app appears before it in the DOM.
If you try Click Element    xpath=//div[@title='Delete'], you get ElementNotVisibleException because the hidden delete div is first.
Selenium2Library is written assuming the element to work with is the first one or only one returned in an element search.
I tried and could not come up with a locator that only selected the second (visible) div for the delete button. I'm not saying its not possible, but I couldn't.
Perhaps when jQuery support is released that might help.
My workaround was to use Selenium2Library's private methods to get a list of web elements and pick the second one.
This is not the preferred way, but I could find no other.
I have attached a suite file, report and log for a test that successfully deleted an email.
It is not usually this hard to automate a web app.
log.html
report.html
UserGroup.txt

Ed Manlove

unread,
Apr 26, 2013, 8:29:02 PM4/26/13
to robotframe...@googlegroups.com
Kevin,

If you come up with a suggestion on how to handle two seemingly
identical elements add it to the issue tracker and thanks for you work
on helping majatalo.

Ed

Kevin O.

unread,
Apr 27, 2013, 1:00:54 AM4/27/13
to robotframe...@googlegroups.com
Ed,

I cannot think of any solution that could be implemented in an acceptable way.
Let us hope this is a very uncommon conundrum.
I do have a selector that selects the last div with the desired attribute value.
Using it would mean not using any private functions or interacting with WebElements, but it is really ugly:

Click Element    dom=(function() {var del; var divs = document.getElementsByTagName('div'); for (var i = 0; i < divs.length; i++) {if(divs[i].title=='Delete') del = divs[i];} return del;})()

'Delete' should be 'Poista' for the language in the OP.
Filtering on visibility in the JS instead of returning the last match would be even uglier due to differences in browsers.
I feel like maybe I am missing a simpler solution. The one time I ran into a similar situation with similar elements hidden and visible they fortunately had different IDs.

Kevin

Kevin O.

unread,
Apr 27, 2013, 1:22:34 AM4/27/13
to robotframe...@googlegroups.com
FYI there is always the possibility of using a locator based on the exact position in the DOM like:

xpath=html/body/div/div/div/div/div/div/div/div/div/div/div/div/div/div/div[3][@title='Delete']

It is hard to suggest doing that, though, since locators like that are brittle. Wow that is a lot of nested DIVs.

Markus Bernhardt

unread,
Apr 27, 2013, 2:59:34 AM4/27/13
to korm...@gmail.com, robotframe...@googlegroups.com
Couldnt you use:

xpath=(//div[@title='Delete'])[3]

Von meinem iPhone gesendet
--
You received this message because you are subscribed to the Google Groups "robotframework-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to robotframework-u...@googlegroups.com.
To post to this group, send email to robotframe...@googlegroups.com.
Visit this group at http://groups.google.com/group/robotframework-users?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

majatalo

unread,
Apr 27, 2013, 8:02:43 AM4/27/13
to robotframe...@googlegroups.com
Thanks your code made it working.
placed this part
 ${s2l}=    Get Library Instance    Selenium2Library
    ${elems}=    Call Method    ${s2l}    _element_find    xpath=//div[@title='Poista']    ${False}    ${True}
    Call Method    ${elems[1]}    click
    Sleep    3s

and it worked.

So huge thanks, for solving this.

ps. Poista is delete or actually remove in Finnish language.

Kevin O.

unread,
Apr 28, 2013, 10:28:37 AM4/28/13
to robotframe...@googlegroups.com, korm...@gmail.com
The invisible copy of the structure appears first in the DOM, so that locator picks the invisible delete button.
The only reason the big locator with all the DIVs works is because the invisible structure appears at a different depth of DIVs.
Thanks for the suggestion.

Markus Bernhardt

unread,
Apr 28, 2013, 11:47:20 AM4/28/13
to kir...@gmail.com, robotframe...@googlegroups.com
Wouldn't it be more readable to use the following:

Click Element    xpath=(//div[@title='Poista'])[2]

This should do exactly the same.
We are using that quite often.

Kevin O.

unread,
Apr 29, 2013, 1:34:52 AM4/29/13
to robotframe...@googlegroups.com, kir...@gmail.com
I think you are missing what I said. Both the invisible and visible div elements with the attribute title with value Poista are the 3rd child div of their parents. With the selector you are suggesting, you would still have to dig down to the list of elements selected and pick the second one.
It's as if there is a shadow copy of the toolbar that is invisble via CSS and it appears first in the DOM, however at a slightly different depth of DIVs. I'm sure it would make sense if we knew the framework that GMail is based on.
I am curious what Google's acceptance tests look like since they run over 1000 Selenium tests a day.
I have tested web apps based on JSP, ASP.net, & JSF and have'nt had such trouble with uniquely locating elements. Usually there are more static names, IDs, or classes to base a selector on.
Thanks Markus.

theheadofabroom

unread,
Apr 29, 2013, 4:29:44 AM4/29/13
to robotframe...@googlegroups.com
Unless you are looking to use selenium to test a Single Page Application like Gmail, I suggest you might want to start with something a little more simple, as there is quite a lot of "magic" used to make a single web page act like a full application, and this may get in the way of the basics. If you're just trying to access your gmail and perform some automated tasks, you may wish to use imaplib and email from the standard library to implement an object with methods suitable for your test script.

If you are actually trying to test a SPA I suggest you might want to still create a python class which handles the SPA's state and offers methods for interaction - I find that the keywords offered by robotframework-selenium2library to be more than enough for simple prototyping, but that it can get a bit messy as you try to scale.

Markus Bernhardt

unread,
Apr 29, 2013, 5:24:24 AM4/29/13
to korm...@gmail.com, robotframe...@googlegroups.com, kir...@gmail.com
Hi Kevin,

I think you are missing what I said. Both the invisible and visible div elements with the attribute title with value Poista are the 3rd child div of their parents. With the selector you are suggesting, you would still have to dig down to the list of elements selected and pick the second one.

I do not think you are correct here.

This pick every div with the title Poista independent of their position in the DOM.
xpath=//div[@title='Poista']

This pick every div with the title Poista independent of their position in the DOM and then selects the second found element.
xpath=(//div[@title='Poista'])[2]

I do not say this is a good or pretty solution, but;
Click Element    xpath=(//div[@title='Poista'])[2]

is exactly the same than:
${s2l}=    Get Library Instance    Selenium2Library
${elems}=    Call Method    ${s2l}    _element_find    xpath=//div[@title='Poista']    ${False}    ${True}
Call Method    ${elems[1]}    click

The only difference I can see is the first is using a WebDriver click and the second a JavaScript click.

Or am I completely wrong here?
Cheers,
Markus

majatalo

unread,
Apr 29, 2013, 2:58:01 PM4/29/13
to robotframe...@googlegroups.com, korm...@gmail.com, kir...@gmail.com
Hi
I tested both and it seems that they work equaly well.
So from my point of view no difference.

Kevin O.

unread,
Apr 30, 2013, 11:34:24 AM4/30/13
to robotframe...@googlegroups.com, korm...@gmail.com, kir...@gmail.com
Ahh, I see. Thank you so much Markus. I knew there had to be a simpler way. I haven't had experience with apps with generated classes and IDs like GMail. Whenever there were multiple copies of similar structures, they would have or their parents would have IDs or names like item2, order3, etc.
The key in Markus' locator is in the parenthesis.

@majatalo - Markus' solution is better in several ways:
* less code/lines
* does not require accessing private method
* does not call methods directly, bypassing the on failure code in Selenium2Library

@Markus - calling click on the WebElement is exactly what Selenium2Library does.

Gratefully and slightly more informed,
Kevin

majatalo

unread,
May 3, 2013, 12:01:58 AM5/3/13
to robotframe...@googlegroups.com, korm...@gmail.com, kir...@gmail.com
Ok, again I am back here asking questions about this.
delete button work well, but....

i have loop that goes thru emails and delete button works ok in first time, but for second email it does not work.
I checked source and there is difference in button code.

first time code is this:
<div tabindex="0" role="button" title="Poista" act="10" class="T-I J-J5-Ji nX T-I-ax7 T-I-Js-Gs ar7">

second time it is this:
<div tabindex="0" role="button" act="10" class="T-I J-J5-Ji nX T-I-ax7 T-I-Js-Gs ar7" style="-moz-user-select: none;" data-tooltip="Poista" aria-label="Poista">

error message I get in second time is:
Element locator 'xpath=(//div[@title='Poista'])[2]' did not match any elements.

how can I click that button on second run?

Markus Bernhardt

unread,
May 3, 2013, 2:31:26 AM5/3/13
to kir...@gmail.com, robotframe...@googlegroups.com, korm...@gmail.com
Hi,

generally spoken you have to build your test to match your application.
If the website behaves that way you have to take that into account.

In this case it should be something like: xpath=//div[@aria-label='Poista']

For us finding the correct locators is the most time consuming part in developing testcases.

We are using the following firefox plugins to develop the testcases:
- firebug to look into the page source
- firepath to check css and xpath locators
- xpathchecker to play around with xpath statements

Hope that helps somehow.
Markus

Kevin O.

unread,
May 3, 2013, 9:17:11 AM5/3/13
to robotframe...@googlegroups.com, korm...@gmail.com, kir...@gmail.com
First time there are two elements that match the XPath in the parenthesis and the second time there is only one, so if we always match the last one, it doesn't matter how many there are.
I verified this locator worked when deleting multiple emails: xpath=(//div[@title='Poista'])[last()]
I second everything Markus said.

Kevin

Kevin O.

unread,
May 17, 2013, 8:56:25 AM5/17/13
to robotframe...@googlegroups.com
A reasonable suggestion. IE did not support getElementsByClass until 9 unfortunately.
Also the classes appear to be random. Here is an example of the class attribute value for the delete button: "T-I J-J5-Ji nX T-I-ax7 T-I-Js-Gs ar7"
If you do go the route of JavaScript, I would recommend using it to locate the element only, that way you aren't forcing synthetic events.
Here is an example of that:
Click Button    dom=document.getElementsByClass("xxx").item(number)

Kevin

wxy...@gmail.com

unread,
May 20, 2013, 6:04:28 AM5/20/13
to robotframe...@googlegroups.com
I see the function assign_id under Call Selenium Api, maybe you can assert a  temp ID to it then use the temp ID to do what you want to do.

Aditi Rajpurohit

unread,
Jun 18, 2015, 1:31:35 AM6/18/15
to robotframe...@googlegroups.com


Hi Majatalo,

I tried this and it did give an error at first but then I tried the following, It worked !

First I applied an explicit wait and then I used the visibilityOfElementLocated function.

Check this 

WebDriverWait wait = new WebDriverWait(d, 50);

wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[@id=':5']/div/div[1]/div[1]/div/div/div[2]/div[3]"))); 

inty inty

unread,
Feb 4, 2017, 1:17:12 PM2/4/17
to robotframework-users, kir...@gmail.com

I had exactly same problem.
I added -"maximize broswer window".  and "sleep for 2seconds"  before --click element---
this solved my problem.
Reply all
Reply to author
Forward
0 new messages