I'm newbie to C# Selenium. I tried to automate an "sign in" and "sign out" of an LinkedIn Application. For that I have written the below code,
Here the "Sign out" is an hidden element.
My code
IWebDriver driver = new ChromeDriver();
driver.Navigate().GoToUrl("https://www.linkedin.com/");
driver.Manage().Window.Maximize();
driver.FindElement(By.Id("login-email")).SendKeys("valid email ID");
driver.FindElement(By.Id("login-password")).SendKeys("valid password");
driver.FindElement(By.Name("submit")).Click();
Actions action = new Actions(driver);
action.MoveToElement(driver.FindElement(By.XPath("//*[#id='img-defer-id-1-6775']"))).Build().Perform(); // Getting an exception here
Thread.Sleep(3000);
driver.FindElement(By.XPath("//*[#id='account-sub-nav']/div/div[2]/ul/li[1]/div/span/span[3]/a")).Click();
But I'm getting an "No Such Element Exception". Even I tried to find the element by ID but getting the same exception. Not sure what I did wrong.
Can anyone help me.
Hoverable elements I find it's best to use JavaScript. Action Builder tends to have a high rate of failure, and will cause other hoverable elements to become visible as it scrolls through the page, causing the element that you want to become obscured. I've found this method somewhere online (can't remember where) and it works significantly better than any other method I've tried.
String javaScript = "var evObj = document.createEvent('MouseEvents');" +
"evObj.initMouseEvent(\"mouseover\",true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);" +
"arguments[0].dispatchEvent(evObj);";
IJavaScriptExecutor executor = driver as IJavaScriptExecutor;
executor.ExecuteScript(javaScript, webElement);
Try adding a Thread.sleep after clicking submit button.
Here issue is selenium driver is searching for element even before page is loaded.Hence element not found exception is thrown.
Instead of Thread.sleep in your code ,you could use explicit waits.
Try this
IWebDriver driver = new ChromeDriver();
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(60));
driver.Navigate().GoToUrl("https://www.linkedin.com/");
driver.Manage().Window.Maximize();
driver.FindElement(By.Id("login-email")).SendKeys("valid email ID");
driver.FindElement(By.Id("login-password")).SendKeys("valid password");
driver.FindElement(By.Name("submit")).Click();
Actions action = new Actions(driver);
wait.Until(ExpectedConditions.ElementIsVisible(By.XPath("//*[#id='img-defer-id-1-6775']")));
action.MoveToElement(driver.FindElement(By.XPath("//*[#id='img-defer-id-1-6775']"))).Build().Perform();
wait.Until(ExpectedConditions.ElementIsClickable(By.XPath("//*[#id='account-sub-nav']/div/div[2]/ul/li[1]/div/span/span[3]/a"))).Click();
If the element you are trying to click is invisible, you can make it visible trough JavaScript and then click on it:
((IJavaScriptExecutor)Driver).ExecuteScript("THE ELEMENT YOU WANT TO CLICK.hidden = false;", element);
element.click
Related
I am trying to make some tests using selenium based Katalon Studio. In one of my tests I have to write inside a textarea. The problem is that I get the following error:
...Element MyElement is not clickable at point (x, y)... Other element would receive the click...
In fact my element is place inside some other diva that might hide it but how can I make the click event hit my textarea?
Element ... is not clickable at point (x, y). Other element would receive the click" can be caused for different factors. You can address them by either of the following procedures:
Element not getting clicked due to JavaScript or AJAX calls present
Try to use Actions Class:
WebElement element = driver.findElement(By.id("id1"));
Actions actions = new Actions(driver);
actions.moveToElement(element).click().build().perform();
Element not getting clicked as it is not within Viewport
Try to use JavascriptExecutor to bring the element within Viewport:
JavascriptExecutor jse1 = (JavascriptExecutor)driver;
jse1.executeScript("scroll(250, 0)"); // if the element is on top.
jse1.executeScript("scroll(0, 250)"); // if the element is at bottom.
Or
WebElement myelement = driver.findElement(By.id("id1"));
JavascriptExecutor jse2 = (JavascriptExecutor)driver;
jse2.executeScript("arguments[0].scrollIntoView()", myelement);
The page is getting refreshed before the element gets clickable.
In this case induce some wait.
Element is present in the DOM but not clickable.
In this case add some ExplicitWait for the element to be clickable.
WebDriverWait wait2 = new WebDriverWait(driver, 10);
wait2.until(ExpectedConditions.elementToBeClickable(By.id("id1")));
Element is present but having temporary Overlay.
In this case induce ExplicitWait with ExpectedConditions set to invisibilityOfElementLocated for the Overlay to be invisible.
WebDriverWait wait3 = new WebDriverWait(driver, 10);
wait3.until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("ele_to_inv")));
Element is present but having permanent Overlay.
Use JavascriptExecutor to send the click directly on the element.
WebElement ele = driver.findElement(By.xpath("element_xpath"));
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("arguments[0].click();", ele);
I assume, you've checked already that there is no any other component overlapping here (transparent advertisement-iframes or some other component of the DOM => seen quite often such things in input/textfield elements) and, when manually (slowly) stepping your code, it's working smoothly, then ajax calls might cause this behaviour.
To avoid thread.sleep, try sticking with EventFiringWebDriver and register a handle to it.
(Depending on your application's techstack you may work it for Angular, JQuery or wicket in the handler, thus requiring different implementations)
(Btw: This approach also got me rid of "StaleElementException" stuff lots of times)
see:
org.openqa.selenium.support.events.EventFiringWebDriver
org.openqa.selenium.support.events.WebDriverEventListener
driveme = new ChromeDriver();
driver = new EventFiringWebDriver(driveme);
ActivityCapture handle=new ActivityCapture();
driver.register(handle);
=> ActivityCapture implements WebDriverEventListener
e.g. javascriptExecutor to deal with Ajax calls in a wicket/dojo techstack
#Override
public void beforeClickOn(WebElement arg0, WebDriver event1) {
try {
System.out.println("After click "+arg0.toString());
//System.out.println("Start afterClickOn - timestamp: System.currentTimeMillis(): " + System.currentTimeMillis());
JavascriptExecutor executor = (JavascriptExecutor) event1;
StringBuffer javaScript = new StringBuffer();
javaScript.append("for (var c in Wicket.channelManager.channels) {");
javaScript.append(" if (Wicket.channelManager.channels[c].busy) {");
javaScript.append(" return true;");
javaScript.append(" }");
;
;
;
javaScript.append("}");
javaScript.append("return false;");
//Boolean result = (Boolean) executor.executeScript(javaScript.toString());
WebDriverWait wait = new WebDriverWait(event1, 20);
wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
return !(Boolean) executor.executeScript(javaScript.toString());
}
});
//System.out.println("End afterClickOn - timestamp: System.currentTimeMillis(): " + System.currentTimeMillis());
} catch (Exception ex) {
//ex.printStackTrace();
}
}
As #DebanjanB said, your button (or another element) could be temporarily covered by another element, but you can wait and click it even if you don't know which element is covering the button.
To do this, you can define your own ExpectedCondition with the click action:
public class SuccessfulClick implements ExpectedCondition<Boolean> {
private WebElement element;
public SuccessfulClick(WebElement element) { //WebElement element
this.element = element;
}
#Override
public Boolean apply(WebDriver driver) {
try {
element.click();
return true;
} catch (ElementClickInterceptedException | StaleElementReferenceException | NoSuchElementException e) {
return false;
}
}
}
and then use this:
WebDriverWait wait10 = new WebDriverWait(driver, 10);
wait10.until(elementToBeClickable(btn));
wait10.until(new SuccessfulClick(btn));
Try Thread.Sleep()
Implicit - Thread.Sleep()
So this isn’t actually a feature of Selenium WebDriver, it’s a common feature in most programming languages though.
But none of that matter.
Thread.Sleep() does exactly what you think it does, it’s sleeps the thread. So when your program runs, in the majority of your cases that program will be some automated checks, they are running on a thread.
So when we call Thread.Sleep we are instructing our program to do absolutely nothing for a period of time, just sleep.
It doesn’t matter what our application under test is up to, we don’t care, our checks are having a nap time!
Depressingly though, it’s fairly common to see a few instances of Thread.Sleep() in Selenium WebDriver GUI check frameworks.
What tends to happen is a script will be failing or failing sporadically, and someone runs it locally and realises there is a race, that sometimes WedDriver is losing. It could be that an application sometimes takes longer to load, perhaps when it has more data, so to fix it they tell WebDriver to take a nap, to ensure that the application is loaded before the check continues.
Thread.sleep(5000);
The value provided is in milliseconds, so this code would sleep the check for 5 seconds.
I was having this problem, because I had clicked into a menu option that expanded, changing the size of the scrollable area, and the position of the other items. So I just had my program click back on the next level up of the menu, then forward again, to the level of the menu I was trying to access. It put the menu back to the original positioning so this "click intercepted" error would no longer happen.
The error didn't happen every time I clicked an expandable menu, only when the expandable menu option was already all the way at the bottom of its scrollable area.
I have a web page with a login button, to get to the site you simply click the button. This is easily done by writing this:
//Click the Login button
UITestControl Login = new UITestControl(Browser);
Login.TechnologyName = "Web";
Login.SearchProperties.Add("ControlType", "Button");
Login.SearchProperties.Add("Type", "Submit");
Login.SearchProperties.Add("DisplayText", "Log In");
Mouse.Click(Login);
HOWEVER, after you login the first time, you remain logged in for an hour (auto log out if idle for over an hour). If you access the site more than once within an hour, there will be no login button since you are still logged in so everytime I run my test, it will error right away because it won't find the control.
I hope that makes sense, here is a synopsis:
First time to site - Login screen appears, click login button, gain entry
Subsequent times to site - No login screen appears,no login required
so basically I want to say, "If there is a login button, click it then do the next thing, if no login button, then do the next thing"
There is a TryFind() method which you can use.
UITestControl Login = new UITestControl(Browser);
Login.TechnologyName = "Web";
Login.SearchProperties.Add("ControlType", "Button");
Login.SearchProperties.Add("Type", "Submit");
Login.SearchProperties.Add("DisplayText", "Log In");
// TryFind() returns true if it's in the Markup somewhere, even if hidden.
// By testing Width > 0 && Height > 0, we make sure it is visible.
// If it were Hidden and we did not use TryFind() before checking Height
// or Width, there would be an exception thrown.
if(Login.TryFind() && Login.Width > 0 && Login.Height > 0)
{
Mouse.Click(Login);
}
There is also the TryGetClickablePoint method that you can use instead of looking for width and height.
Point p;
if(Login.TryGetClickablePoint(out p))
{
Mouse.Click(Login);
}
There's a .Exists method for all UI controls
var lastPageButton = new HtmlHyperlink(parent);
lastPageButton.SearchProperties[HtmlHyperlink.PropertyNames.Title] = "Login";
lastPageButton.SearchProperties[HtmlHyperlink.PropertyNames.Class] = "YourClassHere";
if (lastPageButton.Exists) Mouse.Click(lastPageButton);
//Other work
I have the following code and I cannot get the driver to click the div. It keeps throwing the error
"Element is not currently visible and so may not be interacted"
when debugging you can clearly see that the element is visible. How can I ignore the warning or the error?
var webdriver = require('selenium-webdriver')
, By = webdriver.By
, until = webdriver.until;
var driver = new webdriver.Builder().forBrowser('firefox').build();
driver.get('http://www.vapeworld.com/');
driver.manage().timeouts().implicitlyWait(10, 10000);
var hrefs = driver.findElements(webdriver.By.tagName("a"));
hrefs.then(function (elements) {
elements.forEach(function (element) {
element.getAttribute('name').then(function (obj) {
if (obj == '1_name') {
console.log(obj);
element.click();
}
});
});
});
Your code is clicking an A tag with the name "1_name". I'm looking at the page right now and that element doesn't exist, hidden or otherwise.
You'd be better served by replacing the bulk of your code with a CSS selector, "a[name='1_name']" or "a[name='" + tagName + "']", that will find the element you want with a single find. You can then click on that element.
The issue you are running into is that the element you are trying to click is not visible, thus the error message. Selenium is designed to only interact with elements that the user can see, which would be visible elements. You will need to find the element you are looking for and figure out how to make it visible. It may be clicking another link on the page or scrolling a panel over, etc.
If you don't care about user scenarios and just want to click the element, visible or not, look into .executeScript().
Looked at the website and used the F12 tool (Chrome) to investigate the page:
var elements = [].slice.call(document.getElementsByTagName("a"));
var elementNames = elements.map(function (x) { return x.getAttribute("name"); });
var filledElementNames = elementNames.filter(function (x) { return x != null; });
console.log(filledElementNames);
The content of the website http://www.vapeworld.com is very dynamic. Depending on the situation you get one or more anchors with "x_name" and not always "1_name": the output of the script in Chrome was ["2_name"] and Edge returns ["1_name", "9_name", "10_name", "17_name", "2_name"]. So "you can clearly see that the element is visible" is not true in all situations. Also there were some driver bugs on this subject so it is worthwhile to update the driver if needed. See also the answers in this SO question explaining all the criteria the driver uses. If you want to ignore this error you can catch this exception:
try {
element.click();
} catch (Exception ex) {
console.log("Error!");
}
See this documentation page for more explanation.
I'm using selenium webdriver Chrome. I'm seeing something so odd. I'm testing a sign up account. Webdriver is going to each field and it looks like it is input-ing text, but nothing is being displayed. There are no text results being displayed in the fields. What am I doing wrong?
#Test
public void testAlreadyUsedEmailSignUp() throws InterruptedException {
driver.findElement(By.cssSelector("html body.oneColFixCtrHdr div.container div#header div#innerHeader div#menu ul div.btn-gr")).click();
Thread.sleep(5000);
// switch to frames inside the webpage
driver.switchTo().frame("GB_frame"); // 1st frame
driver.switchTo().frame(0); // 2nd frame
driver.findElement(By.id("firstName")).click();
driver.findElement(By.id("firstName")).sendKeys("Tester");
driver.findElement(By.id("lastName")).sendKeys("Automater");
driver.findElement(By.id("email")).sendKeys("test11#gmail.com");
driver.findElement(By.id("Ppassword")).sendKeys("prd1");
driver.findElement(By.id("confirmPPassword")).sendKeys("pass7ord1");
driver.findElement(By.id("State")).sendKeys("I");
driver.findElement(By.id("myInput")).sendKeys("Mike Ward");
Thread.sleep(2000);
driver.findElement(By.name("term")).click();
driver.findElement(By.id("formAccSubmit")).click();
assertEquals(driver.findElement(By.id("errorContainer")).getText(),
"The Email field must contain a valid email address.");
Thread.sleep(5000);
}
Use the below code, your problem will solve, remove OR.getProperty and use your attributes.
String txtuserzipID = OR.getProperty("txt_UserZip_ID");
WebElement txtuserZipInput = driver.findElement(By.id(txtuserzipID));
txtuserZipInput.clear();
txtuserZipInput.sendKeys(String.valueOf(79081));
txtuserZipInput = driver.findElement(By.id(txtuserzipID));
new Actions(driver).sendKeys(driver.findElement(By.id(OR.getProperty("txt_UserZip_ID"))),
"").perform();
Hope it will work and resolve your problem.
Thanks
In short:
I want to show a view or action sheet and only continue code execution after the user has dismissed the view / sheet. So: line one shows the view, line two reads some result variable.
In detail why I would need this:
I'm porting a Windows Forms application over to the iPad. The original implementation has a communication class which uses a web service to communicate with the server. It offers a couple of methods to get data. Conveniently it checks prior to each call if the user still has a valid connection or if he has to re-enter his password for security reasons.
If the password is required, the .NET class shows a modal dialog which blocks any further code executio and if the password was entered, retries the last call it has made before showing the dialog.
Now using CocoaTouch I'm facing a problem. I replaced the code that shows the dialog with a UIActionSheet. Works great but code execution continues immediately, whereas in Windows Forms it is blocked (the next line in Windows Forms after showing the dialogs is to read the entered password from the dialog) until the dialog has been closed.
I tried a Thread.Sleep() until the user dismisses the UIActionSheet but the Thread.Sleep() also blocks the main loop and my view won't even be drawn.
The alternative I currently see is to change all methods in the already working class and give them a return value: if password required, handle it, then retry.
But this means that all over my code I will have to add these checks because at any given moment the password might be needed. That's why it is nested in communication class in Windows Forms.
Any other ideas?
René
Yes, it is possible.
To do this, what you can do is to run the mainloop manually. I have not managed to stop the mainloop directly, so I instead run the mainloop for 0.5 seconds and wait until the user responds.
The following function shows how you could implement a modal query with the above approach:
int WaitForClick ()
{
int clicked = -1;
var x = new UIAlertView ("Title", "Message", null, "Cancel", "OK", "Perhaps");
x.Show ();
bool done = false;
x.Clicked += (sender, buttonArgs) => {
Console.WriteLine ("User clicked on {0}", buttonArgs.ButtonIndex);
clicked = buttonArgs.ButtonIndex;
};
while (clicked == -1){
NSRunLoop.Current.RunUntil (NSDate.FromTimeIntervalSinceNow (0.5));
Console.WriteLine ("Waiting for another 0.5 seconds");
}
Console.WriteLine ("The user clicked {0}", clicked);
return clicked;
}
I think this approach using async/await is much better, and doesn't suffer from freezing the app when rotating the device, or when the autoscrolling interferes and leaves you stuck in the RunUntil loop forever without the ability to click a button (at least these problems are easy to reproduce on iOS7).
Modal UIAlertView
Task<int> ShowModalAletViewAsync (string title, string message, params string[] buttons)
{
var alertView = new UIAlertView (title, message, null, null, buttons);
alertView.Show ();
var tsc = new TaskCompletionSource<int> ();
alertView.Clicked += (sender, buttonArgs) => {
Console.WriteLine ("User clicked on {0}", buttonArgs.ButtonIndex);
tsc.TrySetResult(buttonArgs.ButtonIndex);
};
return tsc.Task;
}