Clicking at coordinates without identifying element
Asked Answered
C

19

53

As part of my Selenium test for a login function, I would like to click a button by identifying its coordinates and instructing Selenium to click at those coordinates. This would be done without identifying the element itself (via id, xpath, etc).

I understand there are other more efficient ways to run a click command, but I'm looking to specifically use this approach to best match the user experience.

Capello answered 21/7, 2011 at 11:33 Comment(0)
L
-36

Selenium won't let you do this.

Loo answered 25/7, 2011 at 16:28 Comment(10)
Is there another testing framework that would allow for this? Or maybe a user extension to Selenium? Thanks for your response.Capello
What you're suggesting is generally a bad idea for testing a web application, for more reasons than will fit in a comment. Since you're adamant about doing so, you must have a good reason, but I'm at a loss to think of one. Anyway, you'll have to look for a much-less-sophisticated system than Selenium, probably focused on testing native apps. For Windows, that often means AutoIt (autoitscript.com/site/autoit).Loo
Hi Ross. Thanks for the response, on this and my other Selenium question. I am going to take a look at Selenium 2 Webdriver, which may circumvent my problem as it seems to use native browser actions.Capello
I think this is misleading, it is possible using Actions (see below).Knotts
@ChrisRaastad The OP said "click at those coordinates. This would be done without actually identifying the element itself (via id, xpath, etc)". I stand by my answer.Loo
This is possible in selenium using moveToElement method of Actions class in javaIndiscrete
@user3374242 No, moveToElement() does exactly what the original poster didn't want: identify the element by something other than its coordinates. Almost 6 years later, I still don't understand why the OP would want that, but it still isn't possible with Selenium.Loo
@RossPatterson WebGL, for example: we need to emulate user events with specific coordinates.Octillion
@RossPatterson don't you love it when your answer is accepted (and correct) and the whole of SO decides to beat you up? 🙄Infallibilism
@seesharper And it was the correct answer, 10 years ago 😂Loo
B
92

There is a way to do this. Using the ActionChains API you can move the mouse over a containing element, adjust by some offset (relative to the middle of that element) to put the "cursor" over the desired button (or other element), and then click at that location. Here's how to do it using webdriver in Python:

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome()
elem = browser.find_element_by_selector(".some > selector")
ac = ActionChains(browser)
ac.move_to_element(elem).move_by_offset(x_offset, y_offset).click().perform()

Y'all are much to quick to dismiss the question. There are a number of reasons one might to need to click at a specific location, rather than on an element. In my case I have an SVG bar chart with an overlay element that catches all the clicks. I want to simulate a click over one of the bars, but since the overlay is there Selenium can't click on the element itself. This technique would also be valuable for imagemaps.

Bitterroot answered 15/2, 2013 at 2:1 Comment(8)
As noted in another answer, you can click at a position within an element this way. It's not what the OP asked for, but it would work for another use case.Loo
You are identifying an element in the first line of your code, the OP explicitly asked how to do it without identifying an element.Abey
But wouldn't this make it possible to click at an arbitrary point in the page? ActionChains(browser).move_to_element(find_element_by_tag_name('html')).move_by_offset(x, y).click().perform()?Ego
I just tried the idea from my previous comment; doesn't work. Apparently the click() event being generated for the <html> element doesn't propagate the click event down the dom to the actual element.Ego
@Abey The person asking said "the element itself". This isn't the element he wants to click.Rigmarole
is there an equivalent of this in NodeJS selenium-webdriver?Barbaric
@RossPatterson But it's the web, there's always some element. F.e. document.body, or document.head, etc. So there's always a way to click at some coordinate based on some element. The OP probably meant without selecting a specific deeply nested element. There's always root elements anyone can access.Octillion
from selenium.webdriver.common.action_chains import ActionChainsMononuclear
K
23

In C# API you use actions

var element = driver.FindElement(By...);
new Actions(driver).moveToElement(element).moveByOffset(dx, dy).click().perform();

Although it is best to just use simple Id, CSS, Xpath selectors when possible. But the functionality is there when needed (i.e. clicking elements in certain geographic places for functionality).

Knotts answered 13/5, 2013 at 10:30 Comment(3)
Indeed, you can click at a position within an element this way. It's not what the OP asked for, but it would work for another use case.Loo
Yes, also you can get the xy of a Flash game then use offset to click a custom button, as flash is usually fixed px dimensions.Torrid
The code above will only work if the mouse has not been touched, to reset the mouse coordinates need additionally perform moveToElement(element, 0, 0). Code will be the next: var element = driver.FindElement(By...); new Actions(driver).moveToElement(element, 0, 0).moveByOffset(dx, dy).click().perform();Sherrill
B
22

I first used the JavaScript code, it worked amazingly until a website did not click.

So I've found this solution:

First, import ActionChains for Python & active it:

from selenium.webdriver.common.action_chains import ActionChains
actions = ActionChains(driver)

To click on a specific point in your sessions use this:

actions.move_by_offset(X coordinates, Y coordinates).click().perform()

NOTE: The code above will only work if the mouse has not been touched, to reset the mouse coordinates use this:

actions.move_to_element_with_offset(driver.find_element_by_tag_name('body'), 0,0))

In Full:

actions.move_to_element_with_offset(driver.find_element_by_tag_name('body'), 0,0)
actions.move_by_offset(X coordinates, Y coordinates).click().perform()
Biafra answered 1/8, 2018 at 15:50 Comment(0)
A
14

This can be done using Actions class in java

Use following code -

new Actions(driver).moveByOffset(x coordinate, y coordinate).click().build().perform(); 

Note: Selenium 3 doesn't support Actions class for geckodriver

Also, note that x and y co-ordinates are relative values from current mouse position. Assuming mouse co-ordinates are at (0,0) to start with, if you want to use absolute values, you can perform the below action immediately after you clicked on it using the above code.

new Actions(driver).moveByOffset(-x coordinate, -y coordinate).perform();

Antung answered 10/2, 2017 at 5:47 Comment(1)
Ideally this should be the answer with latest version of selenium.Monochord
E
6

If using a commercial add-on to Selenium is an option for you, this is possible: Suppose your button is at coordinates x=123, y=456. Then you can use Helium to click on the element at these coordinates as follows:

from helium.api import *
# Tell Helium about your WebDriver instance:
set_driver(driver)
click(Point(123, 456))

(I am one of Helium's authors.)

Ego answered 23/1, 2014 at 8:13 Comment(0)
P
5

This worked for me in Java for clicking on coordinates irrespective on any elements.

Actions actions = new Actions(driver);
actions.moveToElement(driver.findElement(By.tagName("body")), 0, 0);
actions.moveByOffset(xCoordinate, yCoordinate).click().build().perform();

Second line of code will reset your cursor to the top left corner of the browser view and last line will click on the x,y coordinates provided as parameter.

Pris answered 27/12, 2018 at 13:38 Comment(0)
K
3

Action chains can be a little finicky. You could also achieve this by executing javascript.

self.driver.execute_script('el = document.elementFromPoint(440, 120); el.click();')
Kendrickkendricks answered 10/2, 2017 at 0:6 Comment(0)
K
3

In Selenium Java, you can try it using Javascript:

WebDriver driver = new ChromeDriver();

if (driver instanceof JavascriptExecutor) {
	((JavascriptExecutor) driver).executeScript("el = document.elementFromPoint(x-cordinate, y-cordinate); el.click();");
}
Kore answered 25/7, 2017 at 0:31 Comment(0)
H
2

If all other methods mentioned on this page failed and you are using python, I suggest you use the mouse module to do it in a more native way instead. The code would be as simple as

import mouse
mouse.move("547", "508")
mouse.click(button='left')

You can also use the keyboard module to simulate keyboard actions

import keyboard
keyboard.write('The quick brown fox jumps over the lazy dog.')

To find the coordinate of the mouse, you can use the follow JavaScript Code.

document.onclick=function(event) {
    var x = event.screenX ;
    var y = event.screenY;
    console.log(x, y) 
}

If you don't like screenX, you can use pageX or clientX. More on here

P.S. I come across a website that prevents programmatic interactions with JavaScript/DOM/Selenium. This is probably a robot prevention mechanism. However, there is no way for them to ban OS actions.

Hale answered 4/7, 2021 at 21:1 Comment(0)
C
1

I used the Actions Class like many listed above, but what I found helpful was if I need find a relative position from the element I used Firefox Add-On Measurit to get the relative coordinates. For example:

        IWebDriver driver = new FirefoxDriver();
        driver.Url = @"https://scm.commerceinterface.com/accounts/login/?next=/remittance_center/";
        var target = driver.FindElement(By.Id("loginAsEU"));
        Actions builder = new Actions(driver);            
        builder.MoveToElement(target , -375  , -436).Click().Build().Perform();

I got the -375, -436 from clicking on an element and then dragging backwards until I reached the point I needed to click. The coordinates that MeasureIT said I just subtracted. In my example above, the only element I had on the page that was clickable was the "loginAsEu" link. So I started from there.

Cystitis answered 4/8, 2017 at 17:4 Comment(0)
C
0
    WebElement button = driver.findElement(By.xpath("//button[@type='submit']"));
    int height = button.getSize().getHeight();
    int width = button.getSize().getWidth();
    Actions act = new Actions(driver);
    act.moveToElement(button).moveByOffset((width/2)+2,(height/2)+2).click();
Critta answered 15/2, 2018 at 12:3 Comment(2)
You may want to bracket your code post with explanation as to why it fits the querant's request.Aerodyne
is this nodeJS? How do you get the [Actions] library?Barbaric
F
0
import pyautogui
from selenium import webdriver

driver = webdriver.Chrome(chrome_options=options)
driver.maximize_window() #maximize the browser window
driver.implicitly_wait(30)
driver.get(url)
height=driver.get_window_size()['height']

#get browser navigation panel height
browser_navigation_panel_height = driver.execute_script('return window.outerHeight - window.innerHeight;')

act_y=y%height
scroll_Y=y/height

#scroll down page until y_off is visible
try:
    driver.execute_script("window.scrollTo(0, "+str(scroll_Y*height)+")")
except Exception as e:
    print "Exception"
#pyautogui used to generate click by passing x,y coordinates
pyautogui.FAILSAFE=False
pyautogui.moveTo(x,act_y+browser_navigation_panel_height)
pyautogui.click(x,act_y+browser_navigation_panel_height,clicks=1,interval=0.0,button="left")

This is worked for me. Hope, It will work for you guys :)...

Filemon answered 5/10, 2018 at 12:15 Comment(1)
Welcome to SO! Although this might answer the question, adding links and additional data to support your answer while describing the involved steps would add more credibility.Pinery
P
0

I used AutoIt to do it.

using AutoIt;
AutoItX.MouseClick("LEFT",150,150,1,0);//1: click once, 0: Move instantaneous
  1. Pro:
    • simple
    • regardless of mouse movement
  2. Con:
    • since coordinate is screen-based, there should be some caution if the app scales.
    • the drive won't know when the app finish with clicking consequence actions. There should be a waiting period.
Papaveraceous answered 25/2, 2020 at 2:20 Comment(0)
D
0

To add to this because I was struggling with this for a while. These are the steps I took:

  1. Find the coordinates you need to click. Use the code below in your console and it will display and alert of the coordinates you need.
document.onclick = function(e)
{
    var x = e.pageX;
    var y = e.pageY;
    alert("User clicked at position (" + x + "," + y + ")")
};
  1. Make sure the element is actually visible on the screen and click it using Actionchains
WebDriverWait(DRIVER GOES HERE, 10).until(EC.element_to_be_clickable(YOUR ELEMENT LOCATOR GOES HERE)) 
        actions = ActionChains(DRIVER GOES HERE)
        actions.move_by_offset(X, Y).click().perform() 
Draft answered 1/3, 2021 at 17:34 Comment(0)
C
0

Selenium::WebDriver has PointerActions module which includes a number of actions you can chain and/or trigger without specifying the element, eg. move_to_location or move_by. See detailed specs here. As you can see, you can only use actual coordinates. I am sure this interface is implemented in other languages / libraries accordingly.

My short reply may echo some other comments here, but I just wanted to provide a link for reference.

Chemotherapy answered 1/8, 2021 at 5:56 Comment(0)
G
0

You could use the html tag as the element and then use the coordinates you want, in this example below I am using Javascript. But I am able to click on the top left of the screen.

async function clickOnTopLeft() {
    const html = driver.wait(
        until.elementLocated(By.xpath('/html')),
        10000)
    const { width, height } = await html.getRect()
    const offSetX = - Math.floor(width / 2)
    const offsetY = - Math.floor(height / 2)
    await driver.actions().move(
        { origin: html, x: offSetX, y: offsetY })
        .click().perform()
}
Glaswegian answered 11/8, 2022 at 22:13 Comment(0)
D
0

I tried this solution, and it works.

Lang: Kotlin

Click:

fun WebDriver.clickToPoint(point: Point) {
Actions(this).moveByOffset(point.x, point.y)
    .doubleClick()
    .perform()

Actions(this).moveByOffset(-point.x, -point.y)
    .perform()
}

Drag:

fun WebDriver.dragFromPointToPoint(start: Point, end: Point) {
Actions(this)
    .moveByOffset(start.x, start.y)
    .clickAndHold()
    .perform();

Actions(this)
    .moveByOffset(end.x - start.x, end.y - start.y)
    .release()
    .perform()

Actions(this)
    .moveByOffset(-end.x, -end.y)
    .perform()
}

Important: I tried other answers and it doesn't work without moving back. As I understood, after performing coordinates don't reset. It means that next execution after click, will drag from wrong coordinates. So this small modification, with force resetting coords helped me.

Doralynne answered 17/4, 2023 at 17:25 Comment(0)
H
-3

If you can see the source code of page, its always the best option to refer to the button by its id or NAME attribute. For example you have button "Login" looking like this:

 <input type="submit" name="login" id="login" />

In that case is best way to do

selenium.click(id="login");

Just out of the curiosity - isnt that HTTP basic authentification? In that case maybe look at this: http://code.google.com/p/selenium/issues/detail?id=34

Hellraiser answered 21/7, 2011 at 11:48 Comment(1)
Thanks, but this is not what I am looking for. I know selenium can simply click a button via id. However I am looking to simulate the user experience as close as possible, and thus would like to click on the button in the method I explained above.Capello
L
-36

Selenium won't let you do this.

Loo answered 25/7, 2011 at 16:28 Comment(10)
Is there another testing framework that would allow for this? Or maybe a user extension to Selenium? Thanks for your response.Capello
What you're suggesting is generally a bad idea for testing a web application, for more reasons than will fit in a comment. Since you're adamant about doing so, you must have a good reason, but I'm at a loss to think of one. Anyway, you'll have to look for a much-less-sophisticated system than Selenium, probably focused on testing native apps. For Windows, that often means AutoIt (autoitscript.com/site/autoit).Loo
Hi Ross. Thanks for the response, on this and my other Selenium question. I am going to take a look at Selenium 2 Webdriver, which may circumvent my problem as it seems to use native browser actions.Capello
I think this is misleading, it is possible using Actions (see below).Knotts
@ChrisRaastad The OP said "click at those coordinates. This would be done without actually identifying the element itself (via id, xpath, etc)". I stand by my answer.Loo
This is possible in selenium using moveToElement method of Actions class in javaIndiscrete
@user3374242 No, moveToElement() does exactly what the original poster didn't want: identify the element by something other than its coordinates. Almost 6 years later, I still don't understand why the OP would want that, but it still isn't possible with Selenium.Loo
@RossPatterson WebGL, for example: we need to emulate user events with specific coordinates.Octillion
@RossPatterson don't you love it when your answer is accepted (and correct) and the whole of SO decides to beat you up? 🙄Infallibilism
@seesharper And it was the correct answer, 10 years ago 😂Loo

© 2022 - 2024 — McMap. All rights reserved.