Reputation:
I know there are existing questions on this topic, but none of them seems to help me with this:
I've got a lightbox with several elements. I can find and access all of these elements, except ONE, using the XPath.
These are the items:
Text header: No problem
Text: No problem
Input field: No problem
Text: No problem
Text: No problem
Button (upload file): THIS IS SEEMINGLY IMPOSSIBLE FOR Selenium TO FIND
Button (cancel): No problem
Button (send): No problem
The XPaths for all the elements:
.//*[@id='overlays']/overlay--master/div/div/overlay-lightbox/div/div[1] /content-placeholder/h1
.//*[@id='overlays']/overlay--master/div/div/overlay-lightbox/div/div[3]/content-placeholder/ul[1]/li[1]/label/span
.//*[@id='overlays']/overlay--master/div/div/overlay-lightbox/div/div[3]/content-placeholder/ul[1]/li[1]/div/div/input
.//*[@id='overlays']/overlay--master/div/div/overlay-lightbox/div/div[3]/content-placeholder/label
.//*[@id='overlays']/overlay--master/div/div/overlay-lightbox/div/div[3]/content-placeholder/span
.//*[@id='overlays']/overlay--master/div/div/overlay-lightbox/div/div[3]/content-placeholder/a/input
.//*[@id='overlays']/overlay--master/div/div/overlay-lightbox/div/div[5]/content-placeholder/button[1]
.//*[@id='overlays']/overlay--master/div/div/overlay-lightbox/div/div[5]/content-placeholder/button[2]
The problematic element is this:
.//*[@id='overlays']/overlay--master/div/div/overlay-lightbox/div/div[3]/content-placeholder/a/input
As far as I can see, there's no reason why it should be different from the other elements (textfield, button, text)?
I'm accessing all these elements with an implicit wait, to check that they've all loaded before continuing.
GCDriver.WaitForVisible("//*[@id='overlays']/overlay--master/div/div/overlay-lightbox/div/div[3]/content-placeholder/a/input");
From the GCDriver (Selenium Driver) class:
public static void WaitForVisible (string xpath) {
var wait = new WebDriverWait(GCDriver.Instance,
TimeSpan.FromSeconds(10));
wait.Until(driver =>
driver.FindElement(By.XPath(xpath)).Displayed);
}
Now, as mentioned, this works for all the other elements, as well as accessing them directly. For this, the wait times out with WebDriverTimeoutEsception:
Result Message:
Test method Tests.Regression_tests.VerifyOverlays.Verify_Update_Ticket_OverlayContent threw exception:
OpenQA.Selenium.WebDriverTimeoutException: Timed out after 10 seconds
Also, of course, trying to ACCESS the button with .Click() also fails:
GCDriver.Instance.FindElement(By.XPath(".//*[@id='overlays']/overlay--master/div/div/overlay-lightbox/div/div[3]/content-placeholder/a/input")).Click();
Result Message:
Test method Tests.Regression_tests.VerifyOverlays.Verify_Update_Ticket_OverlayContent threw exception:
System.InvalidOperationException: unknown error: Element is not clickable at point (-208, 307)
Here's the html code for the element:
<a class="btn btn-grey file-input-container btn-small" data-bind="enable: !uploading() "
style="margin-top: 10px; padding: 7px 12px; "data-tooltipped=""
aria-describedby="tippy-tooltip-32"
data-original-title="Add Attachment">
<i class="fa fa-cloud-upload"/>
<span class="mq-for-small-hide">
<span localize-me="">Add Attachment</span>
</span>
<input data-bind="upload: addAttachments,
enable: !uploading()" type="file"/>
</a>
I've tried some other ways of getting the element, but since this is quite (imo) "messy" html, with no unique ID's or good class names, I've been unable to figure out how.
And it REALLY bugs me that I cannot find it by the XPath. There are 8 elements on the page, all visible and accessible, but this ONE element is impossible to find with Selenium.
The element is there; I can manually click the button on the page while Selenium runs it.
UPDATE: I also tried using .Enabled instead of .Displayed. Same result.
UPDATE 2: There are two answers below, and I have to select one as the "winner".
Shubham Jain gives an answer that, while not the exact thing I was trying to to, is a very good work-around. By using JavaScriptExecutor to try clicking the button, it also checks if the button is visible. However, the answer given doesn't do what it tries to do; Clicking doesn't work quite that way. See Solution below to see the correct/working code to click a button using JavaScriptExectutor.
smit9234's answer is exactly what I'm trying to do, although clicking doesn't work that way. To click the button, JS is necessary in this case. However, the question was how to check .Displayed, and that works with the modified XPath he gave me from the code excerpt.
Solution
The XPath of the element (button) is, according to FirePath:
.//*[@id='overlays']/overlay--master/div/div/overlay-lightbox/div/div[3]/content-placeholder/a/input
This, however, doesn't work. Selenium simply cannot find it, even though it's clearly there.
THIS XPath, however, does work:
.//*[@id='overlays']/overlay--master/div/div/overlay-lightbox/div/div[3]/content-placeholder/a/span/span
However, it works with reagards to the .Displayed check. It does NOT work with Click(). To be able to click the button, I began with Shubham Jain's code example and created this method in the Driver class, to be able to use JavaScript (with Selenium's JavaScriptExecutor) to click the button:
using OpenQA.Selenium.Interactions;
public static void JSClick (string xpath) {
IWebElement icon = Instance.FindElement(By.XPath(xpath));
Actions ob = new Actions(Instance);
ob.Click(icon);
IAction action = ob.Build();
action.Perform();
}
Upvotes: 1
Views: 782
Reputation: 361
Looking at the html snippet you posted, it seems like this is a file attachment function. Based on the html structure of the snippet, try using the following xpath:
.//*[@id='overlays']/overlay--master/div/div/overlay-lightbox/div/div[3]/content-placeholder/a/span/span
You should then be able to use the click(); method to click the "Add Attachments"
I assume that clicking on the input doesn't do anything, however you should be able to use the sendKeys(); method for sending the "file path" to the input element.
Upvotes: 1
Reputation: 1149
It seems like it's not clickable. It looks like there's some javascript on the page with a function called "uploading()".
since you're button has this on it
enable: !uploading()
just a test to verify if this is actually the cause, put a breakpoint before your click. on the browser dev tools stick a breakpoint in the uploading() function on the javascript file and see what it's returning.
If this is the case you'll have to use the javascript executor to bypass this.
Upvotes: 0
Reputation: 17593
Use below XPath :-
//input[@type='file' and contains(@data-bind,'upload: addAttachments')]
You can use javascriptexecutor
of selenium to click on button. It operated directly on JS of page.
In java :-
WebElement element = driver.findElement(By.id("gbqfd"));
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("arguments[0].click();", element);
I don't know more about c# but I believe it something like
IWebElement clicks = driver.FindElement(By.Id("gbqfq"));
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
js.ExecuteScript("arguments[0].click();", clicks);
Change the locator in above elements as per your convenience.
Below you will find more details of javascriptexecutor
https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/JavascriptExecutor.html
Hope it will help you :)
Upvotes: 1
Reputation: 5347
May be input element is not visible on the page. you may not use displayed function for that element and try with enabled as given below.
public static void WaitForEnabled (string xpath) {
var wait = new WebDriverWait(GCDriver.Instance,
TimeSpan.FromSeconds(10));
wait.Until(driver =>
driver.FindElement(By.XPath(xpath)).Enabled);
}
if the above is not working, you try to click on anchor tag instead of input.
Upvotes: 0