Reputation: 879
I am not able to create a Selenium test case to automate clicking on Google Maps (specifically, creating markers by single-clicking on the map).
Record function in IDE
The "Record" function records my mouse click as
<tr>
<td>click</td>
<td>//div[@id='map_canvas']/div[3]/div/div/div[4]/div/div/div[5]</td>
<td></td>
</tr>
When executing the command, this not only places the marker way outside the visible map view, but it is also not reliable on page refresh because the GMap nested div structure changes every time.
clickAt
Here it was suggested to use clickAt with the outside div's div, like so:
<tr>
<td>clickAt</td>
<td>//div[@id='map_canvas']/div/div[1]</td>
<td>(400,300)</td>
</tr>
This does not work at all. I have tried every variation of click, clickAt, and mouseDown/mouseUp that I can think of, but nothing seems to register.
I do know that Google has released their Selenium test suites, but I cannot figure out how to use it to my advantage. Any help would be appreciated!
Edit: It seems to be that the reason Google's approach (and all the other approaches that I've found) don't work is because I am using v3 of Google's Maps API. Google's own Selenium tests seem to be using v2.
Upvotes: 3
Views: 11097
Reputation: 1819
For your test environment (or a small number of markers), you can set marker option optimized to "false". Then you can use the Xpath selector. There is a performance cost.
See the answers to this question: Selenium tests for Google maps
Upvotes: 1
Reputation: 45
The suggestion using elementFromPoint on id=map does not work for me (Maps API 3 and FireFox 15), as the map_canvas element that is returned does not respond to the click events.
The best approximation I found was to use IDE click recording to get the very specific canvas element and then position within it. Using the clickAt extension simplified getting the position as well.
The cleaned xpath with hard-coded reference to the tiled div/canvas, which successfully triggers the click actions I am looking for:
<tr>
<td>clickAt</td>
<td>//div[@id='map_canvas']//div[8]/canvas</td>
<td>150,131</td>
</tr>
<tr>
<td>clickAt</td>
<td>//div[@id='map_canvas']//div[4]/canvas</td>
<td>90,42</td>
</tr>
<tr>
<td>clickAt</td>
<td>//div[@id='map_canvas']//div[16]/canvas</td>
<td>108,53</td>
</tr>
Upvotes: 2
Reputation: 879
After much fussing around, I think I found a solution that is moderately elegant and robust enough to at least handle page refreshes.
First, I figured that since I can run arbitrary JS with the storeEval command, perhaps I could leverage the power of JS to find what element needed clicking on. My first thought was searching for the actual image and clicking on it:
var imgs = window.document.getElementsByTagName("img");
str = "";
for (var i = 0; i<imgs.length; i++) {
if (imgs[i].src.match("GetMapImage")) {
str = imgs[i].src;
break;
}
}
str;
The above code searches all images for an image source that contains "GetMapImage", which is special to Google's image retrieval. I would then store this in a Selenium variable and use the exact src to clickAt. Unfortunately, this was hit-or-miss, because the same image gets repeated in three separate divs, and there is no telling which one will actually be on top.
Then I found this post: How to simulate a click by using x,y coordinates in JavaScript?
Since I can figure out the X and Y offset of my map using Selenium functions, I could simply run document.elementFromPoint() to get (I assume) whatever element you would have naturally clicked on had you clicked on that x and y location. My steps now are:
My successful selenium code looks like:
<tr>
<td>storeElementPositionLeft</td>
<td>id=map</td>
<td>left</td>
</tr>
<tr>
<td>storeElementPositionTop</td>
<td>id=map</td>
<td>top</td>
</tr>
<tr>
<td>storeEval</td>
<td>window.document.elementFromPoint(${left}, ${top}).id = "selenium-gmap"</td>
<td>dummy</td>
</tr>
<tr>
<td>clickAt</td>
<td>id=selenium-gmap</td>
<td>200,100</td>
</tr>
This, at the very least, works in Firefox 9.0.1, which is good enough for me. Note that this solution hinges upon availability of the document.elementFromPoint function.
Upvotes: 4