Where is the right place to put Thread in C# test automation - c#

I have used the Thread in the middle of the two coding lines. Is it the correct place to keep
var branch = new SelectElement(webDriver.FindElement(By.Id("CompanyBranchId")));
Thread.Sleep(4000);
branch.SelectByText("Globex Branch Two");

Using a Thread.Sleep() is the last thing you should do when designing selenium tests. It unreliable/inefficient. Make an instance of WebDriverWait (if you don't already have one) and use it's Until() function. Example for what you're trying to do:
IWebDriver webDriver = new ChromeDriver();
WebDriverWait wait = new WebDriverWait(webDriver, TimeSpan.FromMinutes(2));
var branch = new SelectElement(webDriver.FindElement(By.Id("CompanyBranchId")));
wait.Until(driver => driver.FindElement(By.XPath("//*[contains(text(),'Globex Branch Two')]")).Displayed);
branch.SelectByText("Globex Branch Two");

Related

How to stop Selenium to allow manual captcha resolution?

I want to start my Selenium script on a login page, wait for 30 seconds so I can manually resolve a captcha, and once the login is successful, start the actual work automation work.
I'm using the code below, and it works ok up to the line where it enter the email.
I supposed that this code will wait in a sort of pooling until it sees the H4 element with certain text in it (login successful), but it throws an exception when the element is not found.
IWebDriver driver = new ChromeDriver();
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
driver.Navigate().GoToUrl("URL");
var loginEmail = driver.FindElement(By.Id("LOGINTextBTTN"));
loginEmail.SendKeys("myEmail"); //this line works
IWebElement firstResult = wait.Until(ExpectedConditions.ElementExists(By.XPath(#"//h4[text()='H4 Text']"))); //this lines fails with an exception
Console.WriteLine(firstResult.GetAttribute("textContent"));
Write the code
driver.manage().timeouts().implicitlyWait(60,TimeUnit.SECONDS) ; // Wait for 60 Sec.
WebElement firstResult = wait.Until(ExpectedConditions.ElementExists(By.XPath(#"//h4[text()='H4 Text']")));
Or
You can use Fluentwait
Wait wait = new FluentWait(driver).withTimeout(30, TimeUnit.SECONDS)
.pollingEvery(5, TimeUnit.SECONDS).ignoring(NoSuchElementException.class);
I had to deal with this a while back. The way I solved was with sleep:
time.sleep(seconds need to solve) #for me it was around 60ish seconds
Probably something like:
import code
code.interact(local=dict(globals(), **locals()))
Then Ctrl+D out after you solve the captcha

Waiting for render events with Selenium and React

I am getting started with using Selenium to test a React application that I have built.
In most simple JavaScript applications it is trivial to wire up a test where one uses the WebDriverWait class to wait for some event to signal that the test can proceed to the next step.
For example:
using (IWebDriver driver = new ChromeDriver())
{
driver.Navigate().GoToUrl($"{Properties.Settings.Default.ApplicationUrl}/Dashboard");
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until(d => d.Title.StartsWith("dashboard", StringComparison.OrdinalIgnoreCase));
//Can do next thing....
Assert.IsTrue(true);
}
However things get a bit more complicated if we want to test a React application. Given that each component in your React application will each individually invoke their own lifecycle events, in their own time, it is extremely difficult to know when a given control has completed its Render() lifecycle.
I have played with a simple solution like:
//Add something like this to each React component
componentDidMount() {
if (!window.document.hasMyComponentMounted)
window.document.hasMyComponentMounted = true;
}
and then I can do something like this in my tests:
using (IWebDriver driver = new ChromeDriver())
{
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
driver.Navigate().GoToUrl($"{Properties.Settings.Default.ApplicationUrl}/Dashboard");
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until(d => js.ExecuteScript("return window.document.hasHomeMounted"));
//Can do next thing....
Assert.IsTrue(true);
}
but this seems like a kinda sucky solution.
Has anyone encountered the same problem or know of potential workarounds (except for just using Thread.Sleep())?
I have written extensive automation for a React.js application, and as you mentioned, it was a very difficult problem waiting for components to render.
There is no concrete solution that can fix every issue with this. The solution you mentioned, to wait for components to mount, is a good one. You can make it cleaner by wrapping it in with WebDriver calls so that they automatically wait for the components to mount, and you do not have to specify that code in your test cases.
Here's an idea:
public static class WebDriverExtensions()
{
public static void WaitForComponents(this IWebDriver driver)
{
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until(d => js.ExecuteScript("return window.document.hasHomeMounted"));
}
public static void GoToUrl(this IWebDriver driver, string url)
{
driver.Navigate().GoToUrl(url);
driver.WaitForComponents();
}
}
Then, your test case will look like:
using WebDriverExtensions;
using (IWebDriver driver = new ChromeDriver())
{
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
driver.GoToUrl($"{Properties.Settings.Default.ApplicationUrl}/Dashboard");
//Can do next thing....
Assert.IsTrue(true);
}
If the component you are checking is constantly changing, i.e. hasHomeMounted only works on the Home page, the solution is a little uglier. You could try something that takes a component name as a parameter to check if it is mounted:
public static void WaitForComponent(this IWebDriver driver, string componentName)
{
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until(d => js.ExecuteScript($"return window.document.has{componentName}Mounted"));
}
As I mentioned, there is no catch-all way to accomplish this, and using Thread.Sleep() everywhere is not advisable. Your solution which checks the react component mounting is a good solution.
If you do not like the above solution, here's what I specifically used to handle most of my React UI testing:
public static void WaitAndClick(this IWebDriver driver, By by)
{
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until(ExpectedConditions.ElementToBeClickable(by));
driver.FindElement(by).Click();
}
My issues with automating React UI involved elements taking too long to load. Most of the page would load, but the component I was trying to click would not exist sometimes. So I wrapped Click() in a WaitAndClick() method, to ensure the element is clickable before I try to perform the click. This worked for most of my cases.

Wait for element to be clickable by accessibility ID

I am trying to do a wait for element to be visible before I try to click it. My tests fail with NoSuchElementException if I don't wait. Right now I am doing a wait by text but I want to be able to wait for the accessibilityId. I noticed that accessibilityId is not an option in By. How do I handle it?
_driver = new AndroidDriver<IWebElement>(new Uri("http://127.0.0.1:4723/wd/hub"),capability);
var wait = new WebDriverWait(_driver,new TimeSpan(0,0,0,15));
wait.Until(ExpectedConditions.ElementIsVisible(
By.XPath("//android.widget.TextView[#text='Bypass Sign In (Testing Only)']")));
_driver.FindElementByXPath("//android.widget.TextView[#text='Bypass Sign In (Testing Only)']").Click();;
Update: I noticed that there is a MobileBy class with a By strategy for Accessibility Id however when I try to implement the wait with it my test fails immediately with a NoSuchElementException. Once I have waited long enough using the xpath and then do a click by _driver.FindByAccessibilityId it seems to recognize that button and click on it.
Failing Code below.
'var wait = new WebDriverWait(_driver, new TimeSpan(0, 0, 0, 45));
wait.Until(ExpectedConditions.ElementIsVisible(MobileBy.AccessibilityId("Button_SignIn")));
_driver.FindElementByAccessibilityId("Button_SignIn").Click();'
Working Code
`var wait = new WebDriverWait(_driver, new TimeSpan(0, 0, 0, 45));
wait.Until(ExpectedConditions.ElementIsVisible(
By.XPath("//android.widget.TextView[#text='Bypass Sign In (Testing Only)']")));
_driver.FindElementByAccessibilityId("Button_SignIn").Click();`
I just figured out that there is a MobileBy class in C# that has the AccessibilityId locator available as a By type but it didn't really do what I was expecting it to

How to find the absence of elements within the time span set and without modifying the Implicit Time out of the driver in Selenium Webdriver?

My Query is to find the absence of dynamic elements(more spinners) in the page.
For solving this We should use driver.findElements(By by) method which will indirectly wait until the driver's implicit wait time when the elements are not found.
My driver's implicit timeout is 15 secs.
Though reducing the implicit time out of the driver is useful to solve,
Is there any replacements for driver.findElements method in Selenium Webdriver?
Thanks in Advance!
You can WebDriverWait for same. It will wait as per the time you have pass in it
WebDriverWait wait = new WebDriverWait(driver, 5);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
OR
WebElement element = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("myDynamicElement")));
For more details refer below link:-
http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp
You can do something like below ...
Try to put some wait from first place
The code is in java but it is very similar/near to C#, take a reference from it
You can check everytime that your element is present or not in your HTML DOM to prevent from error/failer of script. like below:-
if (driver.findElements(By."YOUR Locator")).size() != 0) {
YOUR FIRST Working code
System.out.println("element exists");
}
else{
System.out.println("element is not exists");
}
Hope it will help you :)
You can use below mentioned method to wait for an element without modifying implicit time
IWebDriver driver = new FirefoxDriver();
driver.Url = "<URL>";
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(15));
IWebElement myDynamicElement = wait.Until<IWebElement>((d) =>
{
return d.FindElement(By.Id("<ELEMENTID>"));
});
Use id of the element instead of <ELEMENTID> and url for "<URL>"

WebDriverWait is not working for DialogFragment - C#, Appium

I'm using Appium .NET driver to write some automated tests for one Android app.
I need to add a wait to find one element as it takes some time to load.
If I use Thread.Sleep it works fine but it nasty way so thought to check with WebDriverWait but using WebDriverWait the test failed and not able to find the element.
Working code:
[TestMethod]
public void TestMethod1()
{
Thread.Sleep(TimeSpan.FromSeconds(10));
IWebElement obj = driver.FindElementByXPath("//android.widget.Button[#text='Get Started']");
obj.Click();
}
Not working:
[TestMethod]
public void TestMethod1()
{
var obj = driver.FindElement(By.XPath("//android.widget.Button[#text='Get Started']"), 15);
obj.Click();
}
FindElement is the extension method written by Loudenvier here
Log: Here is my Appium log from thread sleep and webdriverwait approach. Appreciate your help.
Edit1: the button element I'm trying to find is part of a Android DialogFragment. This DialogFragment comes up when user open the the app for first time, this is a kind of welcome screen.
What I noticed WebDriverWait actually wait in the primary app fragment and trying to search for the element and it fails. But Thread.Sleep works because in that case the DialogFragment get loaded on top of the primary app fragment and then webdriver search the element in the correct fragment. I tried with the ImplicitlyWait and explicitwait but result is same.
Is there any better way to wait for DialogFragment?
Why not using explicit wait and wait for driver to find element? Plus, the find element mechanisms look different in your code above.
[TestMethod]
public void TestMethod1()
{
By byXpath = By.XPath("//android.widget.Button[#text='Get Started']");
IWebElement webElement = new WebDriverWait(driver, TimeSpan.FromSeconds(10)).Until(d=>d.FindElement(byXpath));
webElement.Click();
}

Categories