elynnaie
elynnaie

Reputation: 879

Clicking on Google Maps with Selenium IDE

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

  1. 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.

  2. 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

Answers (3)

Aaron Kreider
Aaron Kreider

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

Will Budreau
Will Budreau

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

elynnaie
elynnaie

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:

  1. Get the left and top positions of my map div.
  2. Get the element that would be clicked on at these coordinates.
  3. Set the id of this element to something unique.
  4. Use the clickAt function with this id.

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 = &quot;selenium-gmap&quot;</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

Related Questions