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.
Related
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();
}
}
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();
}
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.
I am trying to use the Explicit Waits in page object model to test a single page app , The problem i am facing is that the Explicit wait starts checking for the element as soon the page is called up ,since the page completely dynamic some element only appear after a some action . Since the element is checked even before its created it always troughs a error "No such Element exception"
Sample Code:
public class example
{
private IWebElement ExampleElement = wait.Until<IWebElement>((d) =>
{
return d.FindElement(By.Id("ExampleElement ID"));
});
private IWebElement ExampleElement2 = wait.Until<IWebElement>((d) =>
{
return d.FindElement(By.Id("ExampleElement ID"));
});
public void example1()
{
ExampleElement.click();
ExampleElement2.click();
}
}
public class exampleTest
{
[Test]
public void SomeTest()
{
example.example1();
}
}
The ExampleElement2 only loads after the ExampleElement click but what happens is it keeps checking for the ExampleElement2 even before the click action so it is not able to find it and it gives a exception . The thing is i dont want the element to checked for exsistence even before its called for .
I am completely new , thanks in advance
It seems that you have a pattern issue here. Your WebElements are at class level, so when the instance of the class is initiated webdriver is trying to initialize everything and therefore waiting even for Element2. If Element2 is dynamic then you can't wait for it at class level. Wait for it after the condition you expect it to appear.
I would say just have at class level,
private IWebElement ExampleElement2;
and then, do
public void example1()
{
ExampleElement.click();
ExampleElement2 = wait.Until<IWebElement>((d) =>
{
return d.FindElement(By.Id("ExampleElement ID"));
});
ExampleElement2.click();
}
Also you might want to look at PageFactory. You don't want to repeat driver.findElement all over your code and other obvious advantages which are off this topic :-).
As nilesh mentioned in his answer, it's required to defer the loading of the ExampleElement2. However it should be an explicit wait and you need to wait for relevant expected condition for example you can say wait until ElementIsVisible (in Java API you can put specific conditions like elementToBeClickable based on the element type). Then it makes sure the element satisfies the particular condition you passed.
P.S - I am sorry I couldn't help you through a code snippet. Since I am a Java guy I haven't done any Selenium tests using C#. But the principle is same.
I have written a number of tests for an MVC application using Selenium and the webdriver. These work on my dev machine without problem. We are using the PageFactory design. Currently I have an explicit wait of 3 seconds (although I have tested up to 10 seconds without change) on page load.
A relatively simple test is below:
The Test
[TestMethod]
public void Can_Log_In_With_Valid_Credential()
{
Pages.LoginPage.Goto();
var success = Pages.LoginPage.Login(Properties.Settings.Default.UserName,
Properties.Settings.Default.Password);
Assert.IsTrue(success);
Pages.HeaderPage.LogOut();
}
The Page and Related Logic
public static class Pages
{
public static LoginPage LoginPage
{
get
{
var loginPage = new LoginPage();
PageFactory.InitElements(Browser.Driver, loginPage);
return loginPage;
}
}
}
public class LoginPage : Page
{
public static string Url = Properties.Settings.Default.DomainAddress + "/Account/Logon";
public static string PageTitle = "Log On";
[FindsBy(How = How.Id, Using = "UserName")]
private IWebElement _userNameBox;
[FindsBy(How = How.Id, Using = "Password")]
private IWebElement _passwordBox;
[FindsBy(How = How.ClassName, Using = "validation-summary-errors")]
private IWebElement _validationErrors;
[FindsBy(How = How.CssSelector, Using = "div#LoginSubmit.signin input")]
private IWebElement _submitButton;
public void Goto()
{
Browser.Goto(Url);
}
public bool IsAt()
{
return Browser.Title == PageTitle;
}
public bool Login(string username, string password)
{
try
{
_userNameBox.SendKeys(username);
}
catch (Exception)
{
_userNameBox = ((IWebDriver) Browser.Driver).FindElement(By.Id("UserName"), 10);
_userNameBox.SendKeys(username);
}
_passwordBox.SendKeys(password);
_submitButton.Click();
return Browser.CurrentUrl != Properties.Settings.Default.DomainAddress + "/Account/Logon";
}
}
The problem arises on the build server. All of the tests fail with the following:
Class Initialization method
KepsPortalMvc.UserAccountManagementTests.Initialize threw exception.
OpenQA.Selenium.WebDriverTimeoutException:
OpenQA.Selenium.WebDriverTimeoutException: Timed out after 10 seconds
---> OpenQA.Selenium.NoSuchElementException: Unable to locate element: {"method":"id","selector":"UserName"}.
It appears that Firefox is not even loading the page. I have verified (via Task Manager) that both the webdriver and Firefox are being started by the BuildServiceAccount, however I have not yet found a way of monitoring the network activity (Fiddler is not showing me any HTTP traffic related to that Firefox instance at the very least).
Is there a way (short of putting something like Wireshark on the build server) to let me monitor the WebDriver-Firefox? It doesn't pop-up as it is run as a different account (I am assuming this is why).
Any help would be greatly appreciated.
Clarification
This is working on my Dev machine, but not on the Team Foundation Build server. We are running Team Foundation on a single server. The TFBuild Service account is what is currently running the Webdriver and Firefox. A process entry for Firefox appears in the Task Manager when it runs as does an entry for WebDriver. A WINDOW for Firefox does NOT. Fiddler does not show me any traffic for that Firefox instance (but I am unsure if that is because nothing is being loaded at all or it just doesn't show me traffic that is loaded in another users session).
A bit of an educated guess here, but it might be that your Test Environment is not set for UI tests. Look at this article on MSDN to see how it should be done.
Secondly, from my experience such a behavior might occur if the build agent runs a different version of msbuild. Make sure they are the same. For example building with VS 2010 and VS 2012 will use different assemblies, and thus provoking different results at runtime.
OpenQA.Selenium.NoSuchElementException
I think this error shows no Element is fpund. It can be caused, that FF lost focus in current window?
How many window have you opened ? or maybe after opening the URL adds either sleep or implicite wait until element isVisible ?
If I understand you right, you use Selenium to run UI tests on your local dev machine and want them to be run no TFS build machine.
This is not working by default, because the build process is a service without a UI and while it is running in the TFS Build service "session", you will not be able to see it. Therefore you need to setup TFS build to run as interactive process (http://msdn.microsoft.com/en-us/library/hh691189.aspx#agent_test), but this would mean that the server is always blocked for it. If it is a hardware machine somewhere, it is possible to turn on the monitor and use it with the build credentials, because it is not locked.
I did something similiar with MS Coded UI Tests and to see if it is working I used my account as build account, so I could open a RDP session to the server, which was the same like for the build. So I could see what was happening during the test, but closing the RDP ended up in failing the test. That's why I always waited for the tests to be finished and than restarted the machine.