WebDriverWait is not working for DialogFragment - C#, Appium - c#

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();
}

Related

Can't verify a modal is showing with Selenium in C#

I'm making some automated tests with Selenium in C#. It's an ASP.NET MVC Core 3 application, using xUnit for the Unit Tests and we are using Bootstrap as the UI framework. I have a problem with verifying that a modal is showing on screen.
When I run this test:
// HomePageAutomatedUITests.cs
[Fact]
public void Try_Open_Arkivskaber_Modal()
{
_page.ClickArkivskaberNyButton();
string modalValue = _page.GetArkivskaberModalAttribute("class");
Assert.Contains("show", modalValue);
}
It always fails, telling me that the Assert.Contains() is never true. The Class string is normally modal fade but when the button is pressed its supposed to add the class "show" so it becomes modal fade show. This works when a user does it on the website, but for some reason I can't make it work in this test. The test tells me that the "modalValue" reads modal fade so it is at least reading the correct place.
The _page variable is a Page Object Model and the following two properties and methods are used in the test:
// HomePage.cs
private IWebElement ArkivskaberNyButton => _driver.FindElement(By.Id("arkivskaber-ny"));
public void ClickArkivskaberNyButton() => ArkivskaberNyButton.Click();
private IWebElement ArkivskaberModalWindow => _driver.FindElement(By.Id("opretArkivskaber"));
public string GetArkivskaberModalAttribute(string attrName) => ArkivskaberModalWindow.GetAttribute(attrName);
I have checked the id arkivskaber-ny I am passing is correct.
I'm running all the tests I do Headless using the Chrome Driver. What might be wrong here?
If anyone else runs into this issue then here is the solution:
Use the WebDriverWait class from the OpenQA.Selenium.Support.UI namespace. You'll also need to get the DotNetSeleniumExtras.WaitHelpers package from NPM or Github.
Then in your code you can do this:
// HomePageAutomatedUITests.cs
public void Arkivskaber_Open_NyArkivskaber_Modal()
{
WebDriverWait waitDriver = new WebDriverWait(_driver, TimeSpan.FromSeconds(2));
_page.ClickArkivskaberNyButton();
waitDriver.Until(_page.GetArkivskaberModalWaitFunc());
string modalValue = _page.GetArkivskaberModalAttribute("class");
Assert.Contains("show", modalValue);
}
In your POM (if you use those) you do this:
// HomePage.cs
using ExpectedConditions = SeleniumExtras.WaitHelpers.ExpectedConditions;
...
public Func<IWebDriver, IWebElement> GetArkivskaberModalWaitFunc() => ExpectedConditions.ElementIsVisible(By.XPath("//div[#id='modal-window-id-here']"));
If you don't use a POM, then you can just make the ExpectedConditions.ElementIsVisible() call straight in your Test function. The key here is how long you wait for the modal to appear after clicking. If you set this too low, it might not have time to appear after you click.
Hope this helps others.

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.

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>"

How to Launch URL in CodedUI testing in Mozilla Firefox 36.0.4

I am testing gmail login page in CodedUI testing and completed recording all actions.
Now i want to first launch login page of google page and i have implemented code as shown below.
BrowserWindow.CurrentBrowser = "IE";
this.UIMap.UIAdminloginMozillaFirWindow.LaunchUrl(new Uri("https://www.google.com"));
But Error is:
You can use the Selenium components for Coded UI Cross Browser Testing (https://visualstudiogallery.msdn.microsoft.com/11cfc881-f8c9-4f96-b303-a2780156628d), a set of extensions that translate Coded UI calls to WebDriver calls, and hence enabling support for Firefox and Chrome.
Download the installer and run it. If you build your tests using the test recorder, record as usual with Internet Explorer (recording does not work in Firefox or Chrome). In your code, before calling BrowserWindow.Launch("url"), set the browser type as follows:
BrowserWindow.CurrentBrowser = "Firefox"; // or "Chrome" or "IE"
Use almost all of the normal properties and methods of HtmlControl and its descendants. I know from experience that accessing HtmlControl.ControlDefinition will throw a NotSupportedException, and Mouse.StartDragging()/StopDragging() also does not work. Debugging can sometimes be interesting as well.
Add in Selenium for testing in Firefox.
[TestClass]
public class UnitTest1
{
FirefoxDriver firefox;
// This is the test to be carried out.
[TestMethod]
public void TestMethod1()
{
firefox = new FirefoxDriver();
firefox.Navigate().GoToUrl("http://www.google.com/");
IWebElement element = firefox.FindElement(By.Id("lst-ib"));
element.SendKeys("Google\n");
}
// This closes the driver down after the test has finished.
[TestCleanup]
public void TearDown()
{
firefox.Quit();
}
}

C# Webdriver - Page Title assert fails before page loads

This issue began when I switched from testing on the www website to my localhost version of it. Working in VS 2012, I will begin debugging so the localhost is active, detach the process so I can test on it, then run any test I like. For a very basic example:
[Test]
public void CanGoToHomePage()
{
Pages.HomePage.Goto();
Assert.IsTrue(Pages.HomePage.IsAt());
}
And the functions it references are here:
public class HomePage
{
const string Url = "http://localhost:3738";
const string HomepageTitle = "FunnelFire - Home Page";
public void Goto()
{
Browser.Goto(Url);
}
public bool IsAt()
{
return Browser.Title == HomepageTitle;
}
}
And the actual selenium code here:
public static class Browser
{
static IWebDriver webDriver = new FirefoxDriver();
public static void Goto(string url)
{
webDriver.Manage().Window.Maximize();
webDriver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(10));
webDriver.Url = url;
}
}
Now the issue. The 10 second implicit wait that I added in Browser does successfully wait at most 10 seconds after loading a page to see if it can locate whatever information I want it to find, that is not the problem.
As I said earlier, after I switched to testing on localhost, suddenly I ran into a strange issue where a page would begin to load (i.e. screen still totally white, nothing finished) or even sometimes the next page would JUST barely finish loading and suddenly the test would just up and fail, pointing to the Assert of IsAt returning false even though the page it was loading was the correct one. I could run that test immediately once more and it would pass without a problem. Run it a third time and it could randomly fail again. I'm honestly not sure what is causing the issue and any help would be appreciated!
Implicit waits work only for finding elements. For waiting on the title of the page to be a certain value, you'll want to use an explicit wait. You can write your own version of this pattern, but in the .NET bindings, the WebDriver.Support.dll assembly has a WebDriverWait class to help with this. Its use would look something like this:
// WARNING! Untested code written from memory below. It has not
// been tested or even compiled in an IDE, so may be syntactically
// incorrect. The concept, however, should still be valid.
public void WaitForTitle(IWebDriver driver, string title, TimeSpan timeout)
{
WebDriverWait wait = new WebDriverWait(driver, timeout);
wait.Until((d) => { return d.Title == title; });
}
You could even modify your IsAt method to use this pattern, catching the WebDriverTimeoutException and returning false if the wait function times out.

Categories