I am completely new to Selenium, started using it yesterday and I am pretty much done with the first part of my project and I really love the way its going.
Altho I am having one problem, currently I am using Thread.Sleep for pauses until elements get present. There are some animations going on or just slow loading at times, how can I make it wait until the element is present and then interact with it?
For example:
LoginPageElements loginPage = new LoginPageElements();
loginPage.continueLink.Click();
Thread.Sleep(5000); //here it has to wait until the next page loads
ClickDailyBonusPopUp();
Driver.driver.Navigate().GoToUrl(.....);
Thread.Sleep(2000); //here it has to wait until a login form pops up
LoginFormElements loginForm = new LoginFormElements();
loginForm.userPasswordLogin.Click();
Thread.Sleep(2000); //here it has to wait until a different login form pops up
You need to use WebDriverWait class. Here is really good solution for your problem.
If your application uses jQuery, I would make use of Selenium's IJavaScriptExecutor to do something like this:
public void WaitForAjax()
{
if ((bool)((IJavaScriptExecutor)WebDriver).("return window.jQuery != undefined"))
{
while (true)
{
var ajaxIsComplete = (bool)((IJavaScriptExecutor)WebDriver).ExecuteScript("return jQuery.active == 0");
if (ajaxIsComplete)
break;
Thread.Sleep(100);
}
}
}
(More on jQuery.active here.)
The main idea is to find some condition or element to poll for/wait on that is always present when the page isn't ready.
Related
I write auto tests for web app and I have a problem with delay. I don't want to use sleeps in my script, so I wrote the next:
driver.FindElement(By.ClassName("MyClassName")).Displayed
With if it works ok (also, Enabled can be used), but I have few views were loading getting 3-5 seconds, so I received NoSuchElementException, because it tries to find element, and the element is still not loaded.
I know that the problem can be solved by adding simple sleep, but I don't want to do it.
Are there any other solutions, except sleep?
Thanks in advance!
You can try something like this. You can change the method time if you like or even make it a variable and pass a value to it.
call - WaitForElementDisplayed_byXPathTime("//a[#class='myClass");
public static void WaitForElementDisplayed_byXPathTime(string value)
{
try
{
var wait = new WebDriverWait(driver, new TimeSpan(0, 0, 30));
wait.Until(webDriver => webDriver.FindElement(By.XPath(value)).Displayed);
}
catch (Exception)
{
//add error handling;
throw;
}
}
}
Im not sure in C# but in python we had expected conditions and wait untill class.
WebDriverWait(driver, 30).until(EC.element_to_be_clickable((By.XPATH,'//span[contains(text(),"Enter a gift card, voucher or promotional code")]'))).click()
above command will wait for 30 sec before throwing error and check the mentioned element is available to click or not for every 0.5 sec.
Check for EC(expected condition) and wait untill API in c# selenium module
Sometimes, Selenium C# launches chrome as well as the website, but is unable to interact with it.
On close inspection, I noticed that it was because chrome was not in focus and was not loading the UI.
As soon as I focused the chrome, I would see a white screen for half a second, and then UI appeared. And as soon as UI appeared, the test started running well.
I feel like chrome can not get enough system resources without the background. Any help would be appreciated. I never faced the issue in selenium-python.
Website is - web.whatsapp.com
It look like you are not giving enough time for page to load. You can use any of the below wait technique.
Explicit Wait in Selenium C#
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
String ele_xpath = "<xpath of element>"
WebDriverWait wait = new WebDriverWait(driver,30);
IWebElement welcomeMessage =
wait.until(ExpectedConditions.visibilityOfElementLocated(By.XPath(ele_xpath)));
// Here I have assumed first page is having a welcome message, you can use any element present on your page. Your script will wait up to 30 sec for element to appear before it will throw timeoutexception
implicit wait in Selenium C#
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
//Above will make script to wait for each element up to 30 sec
waiting in C#:
You can ask your script to wait for a defined millisecond before executing next line of code:
Thread.Sleep(6000);
# It will for 6 sec
Fluent Wait in Selenium C#
Wait<WebDriver> fluentWait = new FluentWait<WebDriver>(driver)
.withTimeout(30, SECONDS) // this defines the total amount of time to wait for
.pollingEvery(2, SECONDS) // this defines the polling frequency
.ignoring(NoSuchElementException.class); // this defines the exception to ignore
WebElement welcomeMessage= fluentWait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) //in this method defined your own subjected conditions for which we need to wait for
{ return driver.findElement(By.xpath("//*[contains(text(),'Welcome')]"));
}});
Note : You can use any of the above wait method. However each of them have their own advantage/ disadvantage. Please read more about them and difference at below link:
https://www.lambdatest.com/blog/selenium-waits-implicit-explicit-fluent-and-sleep/
Please try the following - it will force focus on Chrome (from the information provided I can assume there a JS event which blocks the page loading or trigger onfocus event).
var driver = new ChromeDriver();
driver.Manage().Window.Maximize(); // will focus or at least bring to front
// other things to try - switch
driver.SwitchTo().DefaultContent();
driver.SwitchTo().ActiveElement();
// other things to try - JavaScript
((IJavaScriptExecutor)driver).ExecuteScript("document.querySelector('body').focus();")
I am new to selenium webdriver and am testing one application. In my application, I have to test about linking Facebook Account. Whenever I click on link the pop up will be displayed where I have to enter credentials. I am able to link sometimes and sometimes the test fails. I know the reason because it takes time to load pop up window and next command is executed so it is not able to find the element. I have used Thread.Sleep but I want to use implicit wait or explicit wait which is always a good practice rather than Thread.Sleep. How to use implicit wait and where to use that command exactly? Please advice. Thanks.
public void SocialFaceBook()
{
string currentWindow = driver.CurrentWindowHandle;
PopupWindowFinder finder = new PopupWindowFinder(driver);
string facebookWindow = finder.Click(driver.FindElement(By.XPath("//div[#id='panelFacebook']/div[2]/div[3]/div[3]/a")));
// Switch To FaceBook Window
driver.SwitchTo().Window(facebookWindow);
System.Threading.Thread.Sleep(3000);
// Link
// Email Address
IWebElement faceBookLinkEmail = driver.FindElement(By.Id("email"));
faceBookLinkEmail.SendKeys(SocialFaceBookEmail);
// Password
IWebElement faceBookLinkPass = driver.FindElement(By.Id("pass"));
faceBookLinkPass.SendKeys(SocialFaceBookPass);
// Log In Button
IWebElement faceBookLinkLogin = driver.FindElement(By.XPath("//input[#id='u_0_1']"));
faceBookLinkLogin.Click();
// Switch To Main Window
driver.SwitchTo().Window(currentWindow);
System.Threading.Thread.Sleep(3000);
// Sync
IWebElement faceBookSync = driver.FindElement(By.XPath("//div[#id='panelFacebook']/div[2]/div[3]/div[2]/a"));
faceBookSync.Click();
// Unlink
IWebElement faceBookUnLink = driver.FindElement(By.XPath("//div[#id='panelFacebook']/div[2]/div[3]/div[1]/a"));
faceBookUnLink.Click();
}
Sometimes it is not able to find the log in details as pop up is not loaded properly and sometimes it is not able to find sync button as facebook account takes time to link. Please advice.
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("locator")));
It will wait for the element to be located for a maximum of 30 seconds if the element is found before that it will execute....
I had to change some small things from #Vicky's answer but this is what I got as a method I could call.
public static void WaitForElementLoad(By by, int timeoutInSeconds)
{
if (timeoutInSeconds > 0)
{
WebDriverWait wait = new WebDriverWait(webDriver, TimeSpan.FromSeconds(timeoutInSeconds));
wait.Until(ExpectedConditions.ElementIsVisible(by));
}
}
and I call it like this:
MyClass.WaitForElementLoad(By.CssSelector("div#div1 div strong a"), 10);
I used to write a function to detect an element exists every second. if find continue, otherwise threw timeout error. but in that function i still use Thread.Sleep.
Expect other good solution.
I use ExpectedCondition.visibilityOf(element) instead of thread sleeps
Implicit wait -- max waiting time to identify object, it will identify the object for every 500 ms. if it fails to identify the object with in maximum time it will throw nosuchelement exception.
Explicit wait -- used for ajax page loads for the same purpose.
maximum waiting time is same as thread.sleep
Wrote a method for a project:
public static void WaitForElementPresentBy(By by)
{
try
{
Wait.Until(ExpectedConditions.ElementIsVisible(by));
}
catch (TimeoutException te)
{
Assert.Fail("The element with selector {0} didn't appear. The exception was:\n {1}", by, te.ToString());
}
}
Wait should have already been defined.
I have the following scenario:
I want to navigate to a page. Then click a button as soon as it appears(not wait for page to load ). I don't want to wait for the initial page to load as it takes a long time. My program currently is stuck until the page loads and then clicks the button.
I basically want to navigate to link and then have no wait for page and continue with my code.
Is there anyway round this?
With the latest version of the .NET bindings, you can set a page load timeout. However, there are some caveats you'll need to be aware of. First, this hasn't been implemented by all browsers. It should work for IE and Firefox, if memory serves. Secondly, you'll need to catch an exception to make that work properly, but it can be done.
// WARNING! Completely untested code written without
// the benefit of an IDE!
IWebDriver driver = new InternetExplorerDriver();
driver.Manage().Timeouts().SetPageLoadTimeout(TimeSpan.FromSeconds(1));
try
{
driver.Url = "http://your.long.loading.page.com";
}
catch (TimeoutException)
{
// NOTE: In 2.26 or later, this will be WebDriverTimeoutException
}
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
IWebElement element = wait.Until<IWebElement>((d) =>
{
return d.FindElement(By.Id("yourId"));
}
IWebDriver driver = new FirefoxDriver();
driver.Url = "http://somedomain/url_that_delays_loading";
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
IWebElement myDynamicElement = wait.Until<IWebElement>((d) =>
{
return d.FindElement(By.Id("someDynamicElement"));
});
It does exactly what you want. It queries the page to find the element, catches exceptions if no element found and returns an element when found.
After that, you can manipulate the button ignoring the fact that page can be not loaded
http://seleniumhq.org/docs/04_webdriver_advanced.html
Short answer: No.
Long answer: Selenium is by default trying to simulate the real user - I know that it kinda sucks, especially at a times you need to test a deploy after deploy after deploy...
But: If real user has to wait for button to appear, then the program has to do it also...
BTW: If the button really appears among first on the page, you can try this:
search for the button by ID, xpath ... the way you do it
Catch exception (I am Java guy, so dont ask me how)
If there was error, wait short time (e.g. 200 milliseconds) and then go to 1
If not, click the button
The cycle should end also if certain amount of time passes (10s) and if so, throw exception
As stated above: Language of my choice is Java. There I can do that. But I dont know how to write that in C#
I have a program where I have to get a SHDocVw.InternetExplorer instance from a running IE8 process. To get the instance the example code below runs. For some reason it won't work without the Thread.Sleep.
The Browser.HWND throws InvalidCastException for all instances in the m_IEFoundBrowsers if the Thread.Sleep is removed. When using the Thread.Sleep it works for the IE8 windows.
Does anyone know how to do this in a way not using Thread.Sleep? (I don't like to use the sleep function, usually it just pushes the problems into the future...)
Example code:
InternetExplorer m_IEBrowser = null;
ShellWindows m_IEFoundBrowsers = new ShellWindowsClass();
Thread.Sleep(10);
foreach (InternetExplorer Browser in m_IEFoundBrowsers)
{
try
{
if (Browser.HWND == (int)m_Proc.MainWindowHandle)
{
m_IEBrowser = Browser;
break;
}
}
catch(InvalidCastException ice)
{
//Do nothing. Browser.HWND could not execute for this item.
}
}
I came across the following link which seems to back up Hans's comment: http://weblogs.asp.net/joberg/archive/2005/05/03/405283.aspx
The article states:
The Internet Controls Library contains
the “ShellWindowsClass” which is
basically a collection of all the
shell windows (e.g.: IE) spawned
across the desktop. That component
provides an event handler called
“Windows Registered” that we are going
to hook up to. Once the process has
been launched, we will wait until the
corresponding window is registered
then we are going to connect our
Internet Explorer control to the shell
window found. To determine if the
window is found, we iterate through
the registered windows and we try to
find a handle that matches the handle
of the process we previously launched.
We will use the “ManualResetEvent”
synchronization primitive to wait a
certain amount of time for the window
to be registered.
I expect you'd be able to map these ideas across to your problem relatively easily.
The article posted by David solved the problem. The first time the code runs in my program it works as described in the article. But if I exit the program, leave the opened IE8 open, open my program again then the the windows_WindowRegistered method got problems with InvalidCastExceptions. Handling these exceptions as shown below made it work as needed.
EXAMPLE CODE:
private void windows_WindowRegistered(int lCookie)
{
if (process == null)
return; // This wasn't our window for sure
for (int i = 0; i < windows.Count; i++)
{
try
{
InternetExplorerLibrary.InternetExplorer ShellWindow = windows.Item(i) as InternetExplorerLibrary.InternetExplorer;
if (ShellWindow != null)
{
IntPtr tmpHWND = (IntPtr)ShellWindow.HWND;
if (tmpHWND == process.MainWindowHandle)
{
IE = ShellWindow;
waitForRegister.Set(); // Signal the constructor that it is safe to go on now.
return;
}
}
}
catch (InvalidCastException ice)
{
//Do nothing. Browser.HWND could not execute for this item.
}
}
}