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();
}
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.
Use below XPath :-
//input[#type='file' and contains(#data-bind,'upload: addAttachments')]
You can use javascriptexecutorof 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 :)
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.
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.
Related
I am trying to create this simple test where you head to the URL, enter your login credentials and then click the button to sign in. It is doing everything, except for clicking the button. I am trying to doing it by calling up ClassName. Can anyone look at my test and see what I am doing wrong?
public void test_search()
{
var driver2 = new ChromeDriver(#"C:\Users\MyName\Desktop\NUnitTestProject1\NUnitTestProject1\bin\Debug\netcoreapp2.1");
driver2.Navigate().GoToUrl("https://portal.crushdata.com/");
driver2.FindElement(By.Name("Email")).SendKeys("email#email.com");
driver2.FindElement(By.Name("Password")).SendKeys("Password");
driver2.FindElement(By.ClassName("btn bg-teal btn-block btn-lg waves-effect")).Click();
}
This is my classname for my button.
Use CSS selector as shown below:
By.ClassName("btn.bg-teal.btn-block.btn-lg.waves-effect")
Each dot represents a class.
See this page for more info and here is an example from that page:
.name1.name2
Selects all elements with both name1 and name2 set within its class attribute
To click on the SIGN IN button you have to induce WebDriverWait for the desired ElementToBeClickable() and you can use either of the following Locator Strategies:
CssSelector:
new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.ElementToBeClickable(By.CssSelector("button.btn.bg-teal.btn-block.btn-lg.waves-effect"))).Click();
XPath:
new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.ElementToBeClickable(By.XPath("//button[text()='SIGN IN']"))).Click();
Try making use of the button xpath.
Open the dev tools. Right click on the button you want to be clicked > Select Inspect >Then right click the html in the dev tools window and Copy Xpath from the Copy option.
Then in you code replace FindElement with FindElementByXPath:
driver2.FindElementByXPath("//*xpath/goes/here")).Click();
Given your shared html block, the following XPath will suffice.
//div[contains(#class = "text-center")]//button[contains(#class, 'btn bg-teal btn-block btn-lg waves-effect') and #type = 'submit']
If the driver is still unable to click you should consider the following:
Is the XPath unique? paste the xpath in chrome's devtools search box in the inspect element tab and make sure the provided xpath is targeting the element you are intending. If this is not the case then you should make the xpath more unique.
Is the element in an iframe? if the element is in an iframe the driver won't be able to locate it by default. In such cases you will need to first switch to the iframe and then attempt to locate and interact with the element.
Is the element clickable, visible and enabled? To check these properties first find the element and store in a separate variable and then check the said properties are true.
The click event is not firing in firefox but works ok in chrome.
The test fails with the error: "Element not found on page."
Below is the code and HTML for the button I want to click.
Browser.ElementClickById("ctl00_ContentPlaceHolderBody_lvProducts_ctrl0_ctrl1_btnAddProductToCart_input");
and inside the elementclickbyid i have:
driver.FindElement(By.Id(elementID)).Click();
HTML code is:
event
You could try working around with a Javascript click.
// declare JS executor
var executor = (IJavaScriptExecutor)Driver;
// locate the input
var input = Driver.FindElement(By.XPath("//input[#type='submit']"));
// execute JS to click
executor.ExecuteScript("arguments[0].click();", input);
I've seen cases where regular Click(); does not work across browsers -- these cases are rare, but using JS click usually works across multiple browsers when I run into this issue.
driver.findElement(By.xpath("//input[#type='submit']")).click();
i am sure you are trying to use browser class to keep your methods there, but try to use xpath not id. just use this code to click what you need. don't use page object model or anything else. don't save it in your browser class under click method. just in your main code use this code to click. and before to run it make sure that you have only one type submit. if its gonna show to you 2 types then use this code
driver.findElement(By.xpath("//input[#type='submit'][1]")).click();
number 1 says click to first submit if the button which you need second then follow the logic and change the number to 2
driver.findElement(By.xpath("//input[#type='submit'][2]")).click();
for better answer share your code class and also URL where you are trying to click button and also which element you are trying to click
<div id="crm" class="row gridrow clickable ng-scope" ng-repeat="customer in customerList" ng-click="gotoRecord(customer.id)">
<i class="col m1 s1 tiny fa fa-male"></i>
<div class="col m3 s11 ng-binding"> Allard</div>
<div class="col m2 s12 ng-binding"></div>
</div>
I have this snippet of HTML, it's one row displaying as a result of a search action for a Customer with nameCustomer 'Allard'. I want to click on this customer to continue to the next page but most of the time this results in a StaleElementException.
I tried it two different ways, using Protractor and without Protractor.
First way:
IWebElement elem = driver.FindElement(By.XPath("//*[contains(text(),'" + nameCustomer + "')]//parent::div[contains(#id,'crm')]"));
ExplicitWait.WaitAndClick(driver, elem);
Second way:
var customers = driver.FindElements(NgBy.Repeater("customer in customerList"));
foreach (var customer in customers)
{
if (elem.Text.Equals(nameCustomer))
{
elem.Click();
}
}
The problem (I think)
With StaleReferenceExceptions, an IWebElement that was previously created is no longer attached to the DOM (you probably already know this). What's most likely happening is this:
1: You click search.
2: Selenium executes driver.FindElement(...) and finds a matching element.
3: Then the search function finishes and the DOM updates. The old IWebElement found previously is gone.
4: Then Selenium tries to click on the element (which no longer exists, causing the StaleElementException. There is an element that matches the one that was there before, but it's not the same element in Selenium's eyes.)
Your statement that this happens "most of the time" makes me suspect this is the case even more, because the exception would depend on the order of events, which would vary depending on the relative speeds of Selenium vs. the web-page.
How to resolve (if this is your problem)
You need to find something on the page that will indicate to Selenium that the search action is done. This is where the creativity of writing GUI automation scripts comes in. If there is something on the page that you know will change as a result of the load, craft an explicit wait to ensure that is complete. Maybe there is a loading bar that shows up, or a message that appears when the search is done. You could grab an element that doesn't match your search before clicking search, then do an explicit wait to make sure it disappears before going on to look for the result you do expect to be there.
It would look something like this below.
# Search action performed before this.
WebDriverWait wait= new WebDriverWait(driver, TimeSpan.FromSeconds(secondsToWait));
wait.Until(ExpectedConditions.InvisibilityOfElementLocated(By.XPath( expressionForElementThatWillDissapear )));
IWebElement elem = driver.FindElement(By.XPath("//*[contains(text(),'" + nameCustomer + "')]//parent::div[contains(#id,'crm')]"));
ExplicitWait.WaitAndClick(driver, elem);
I'd recommend making the method to implement the explicit wait above. These situations will come up often.
I'm using Selenium from C# to try and periodically do a search on a website and pull in updated data. Unfortunately the website needs a login I can't make public so I can't actually give any kind of reproducible test case.
Using the Selenium IDE I've made a script that successfully logs in and pulls the data, so the task is possible. However when exporting that script to C#, there's a failure when trying to use an iframe that appears during the process.
By reading around I've discovered I need to add code to explicitly find and switch to the iframe, which I've done;
driver.SwitchTo().Frame(driver.FindElement(By.Id("popup_iframe")));
Inside that frame is an area to the left with items to click. Each item when clicked changes the visible controls to the right. When I break at this point and click manually, everything works as expected. If I call the .Click on the IWebElement representing the object, nothing happens so the next step in the program fails because it gets another object, tries to click it and an exception's thrown because the object isn't visible.
I'm leaving 5s delays between operations in case delays are needed.
The code on the website in this area is;
<div id="ctl00_popup_workarea_left_container" class="popup-workarea-left-container" style="overflow: auto; height: 337px; display: block;">
<a id="LBTN1" class="navbutton navbutton_Disabled_Selected">Basic Search</a>
<a id="LBTN2" class="navbutton">Advanced Search</a>
<a id="LBTN3" class="navbutton">Permit Holder Search</a>
<a id="LBTN4" class="navbutton">Assessor Search</a>
</div>
The code I'm using to get and click the IWebElement is
driver.FindElement(By.Id("LBTN3")).Click();
I've also tried
Actions act = new Actions(driver);
act.MoveToElement(driver.FindElement(By.Id("LBTN3"))).Click().Perform();
Aside from the fact these don't throw exceptions, I've confirmed I'm getting an IWebElement interactively;
driver.FindElement(By.Id("LBTN3"))
{Element (id = f42435b5-139c-4334-be12-4a1f9f48221f)}
Coordinates: {OpenQA.Selenium.Remote.RemoteCoordinates}
Displayed: true
Enabled: true
Id: "f42435b5-139c-4334-be12-4a1f9f48221f"
Location: {X = 0 Y = 112}
LocationOnScreenOnceScrolledIntoView: {X = 0 Y = 112}
Selected: false
Size: {Width = 200 Height = 29}
TagName: "a"
Text: "Permit Holder Search"
WrappedDriver: {OpenQA.Selenium.Firefox.FirefoxDriver}
So I'm getting the element. The HTML appears to show that it really is the element- I'm not accidentally using the ID of something containing it. The original script created in the Selenium IDE works fine- I just can't automate it so it kicks off unattended in the early hours. I know this is vague because I can't give people access to play to reproduce it, but does anyone have an idea of what could be going wrong and how to fix?
For completeness I thought I'd better put an answer here.
I never identified why none of the attempts I made worked, but I discovered that injecting Javascript into the page to click the element I wanted to click did work. So assuming .FindElement() is able to get the element to click, the following snippet worked for me in a number of places where IWebElement.Click() proved uncooperative.
IWebElement ibtn3 = driver.FindElement(By.Id("LBTN3"));
IJavaScriptExecutor executor = (IJavaScriptExecutor)driver;
executor.ExecuteScript("arguments[0].click();", ibtn3);
I want to test for checkbox checked or unchecked condition.
This is the html code for checkbox checked
<div classs="input-control checkbox">
<span class="check">
::before
</span>
</div>
::before is css selector.
when i hoverover to checkbox, it shows webelement as span.check::before
but
driver.FindElement(By.CssSelector("span.check::before"));
throws element not found exception.
Any help will be highly appreciated.
In my case, I have removed the pseudo-element ::before from the CSS selector as seen below and it works
Instead of:
Actions action = new Actions(driver);
action.moveToElement(driver.findElement(By.cssSelector("span.check::before"))).build().perform();
I gave:
Actions action = new Actions(driver);
action.moveToElement(driver.findElement(By.cssSelector("span.check"))).build().perform();
Using pseudo-elements in the selector is actually not supposed to work as mentioned here and here.
I'm not sure of your exact html as the comment mentions there is no ::after in your example html. Based on your description this seems similar to the below, but not sure if that is what your exact situation is.
I have utilized the mouse move and then wait for the element that displays the modified css/class. The mouse would move and hover to the first element and then wait for the second to appear on the screen. This works similarly for click and then wait for element to appear.
Hover code example - needs to match your code language and structure...
[Actions Instance goes here].MoveToElement([IWebElementGoesHere]).Perform();
you can also just do
[Actions Instance].Click([IWebElementGoesHere]).Perform();
Reference for this library: https://code.google.com/p/selenium/wiki/AdvancedUserInteractions
I have faced similar issue with pseudo css selectors (::before alike), I have overcome the issue using "Actions" class of selenium java.
Actions action = new Actions(driver);
action.moveToElement(driver.findElement(By.cssSelector("button[id$='save-button']"))).build().perform();
Hope it helps.
Thanks,
Sampath