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.
Related
Let's say that I want to run so called web acceptance tests on a modern (as of the day of the question) machine, which, let's say, routinely has somewhere between 16 and 128 logical cores. The number could be different in each particular case, but let's stick with this range for now.
By web acceptance test I mean a test, which opens a web page in one of the browsers (Chrome / FireFox / Edge / ... ) using a driver (e.g. chromedriver / geckodriver, etc...), manipulates a web page in whatever way the test wants, and then "collects" some output (e.g. - does the web page has this or that element OR did it navigate to this or that expected page). The actual detail are irrelevant.
Given that such tests naturally spend most of the time waiting (so that to be sure that once they want to manipulate some web page [element] then it has been loaded for sure) it is then seems reasonable to assume that if I have N logical cores on the machine, then I should be able to spawn at least N of such web acceptance tests.
A typical C# code to do that can be summarized as follows:
namespace WebAcceptanceTests
{
public static class Chrome
{
public static async Task Run(
Uri uri,
Func<ChromeDriver, Task> manipulate,
Action<ChromeDriver> validate)
{
var chromeDriverService = ChromeDriverService.CreateDefaultService();
chromeDriverService.HideCommandPromptWindow = true;
var options = new ChromeOptions();
// To make Chrome window invisible.
options.AddArgument("--headless");
using var driver = new ChromeDriver(chromeDriverService, options);
try
{
driver.Manage().Window.Maximize();
driver.Navigate().GoToUrl(uri);
await manipulate(driver);
validate(driver);
}
finally
{
driver.Quit();
}
}
}
}
where manipulate performs some "manipulation" of the page (e.g. attempts to click some buttons / enters some text / etc...) and validate performs some validation (e.g. if manipulate entered user name and password and then clicked login button, then did the site actually transitioned to logged in page). The actual details of what these manipulate and validate do are irrelevant. However, manipulate is a lengthy process because the site needs to load the page and do some "work" here or there. Therefore, we can model it by a method, which just waits and does nothing, e.g.:
public static async Task Manipulate(ChromeDriver driver)
{
// Do some useful stuff here instead of just waiting.
await Task.Delay(60_000);
}
However, if I start spawning such drivers then very quickly (with under 10 drivers created) some of the created drivers start producing weird errors like:
OpenQA.Selenium.WebDriverException : The HTTP request to the remote WebDriver server for URL http://localhost:52382/session timed out after 60 seconds.
The test server machine that I am getting these errors has 16 cores and enough RAM to open hundreds of Chrome tabs without any problems, yet a small number of chrome drivers (less than 10) seems not working in parallel.
Does anyone has any ideas how to make many chrome drivers work in parallel? Ideally I'd want to open (3-4X the number of cores) drivers because they will mostly wait and do nothing.
Thanks.
We achieve this using NUnit parallel run, parakkekuzabke by fixture.
Allocate driver during OneTimeSetup. Do whatever test need in single fixture.
On OneTimeTearDown, dispose driver.
We do this in base class that all web acceptance test fixtures are inherit
[Parallelizable(ParallelScope.Fixtures)]
public abstract class WebDriverTest
{
protected IDriver driver;
[OneTimeSetup]
public void PrepareDriver()
{
// ...
this.driver = new ChromeDriver(chromeDriverService, options);
// ...
}
[OneTimeTearDown]
public void CleanupDriver()
{
this.driver.Dispose();
}
[TearDown]
public void ScreenshotForFailedTest()
{
var testStatus = GetTestStatus();
if (!string.IsNullOrEmpty(testStatus) && testStatus.Equals("Failed"))
{
this.driver.TakeScreenshot(); // extension method with a take screenshot functionality
// log more details if needed
}
}
}
[OneTimeTearDown] is executed even if there is failed tests
As bonus we take screen
Using this snippet we run around 500 smoke tests against chrome in 5-6 minutes on each commit.
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.
I am developing an application using selenium web driver. I am putting a set of task in the 'for' loop. The task is:
Open a URL using driver object of IWebDriver class.
Traverse to different different URLs
At the for loop, I am killing the instance of IWebDriver class with following:
driver.Close(); driver.Quit();
Now when the second iteration starts, the program does not perform the above task, rather it gives an exception.
When I research on the exception, I found the issue is with the driver.Close(); driver.Quit();. It's not even closing the browser, but its also removing the instance of a IWebDriver class. How can I handle this situation?
Here is the Sample code:
class callingfunction
{
public static IWebDriver driver = new ChromeDriver(Cpath);
public void function1()
{
for (int i = 0; i < 10; i++ )
{
driver.Navigate().GoToUrl("http://www.aaa.org");
driver.Navigate().GoToUrl("http://www.aaa.org/contactus");
driver.FindElement(By.Name("contact")).SendKeys(contact);
driver.Navigate().GoToUrl("http://www.aaa.org/aboutus");
//Code logic
driver.Close();
driver.Quit();
}
}
}
You're calling quit() on the WebDriver inside your loop, so on the second iteration you will indeed get errors.
The only place you need it is right at the very end of your test. The close() call is also unnecessary.
Furthermore, you're not waiting for anything to load, so without proper waits your driver.FindElement(By.Name("contact")).SendKeys(contact); will likely fail often.
Finally you're not doing anything with the 1st or 3rd page requests, so - given the lack of waits - those pages are likely never allowed to fully load.
I don't understand the scenario you are trying to accomplish but I'm hoping that in the process of simplifying the code, you've removed the bits that make this scenario make a little more sense. Having said that...
The problem is that you are closing and quitting the browser driver inside the for loop but never instantiate another browser instance. The browser instance is created when you do new ChromeDriver() so you will want that inside the for loop. Something like this should work.
class callingfunction
{
public static IWebDriver driver = null;
public void function1()
{
for (int i = 0; i < 10; i++)
{
driver = new ChromeDriver(Cpath); // launch browser
driver.Navigate().GoToUrl("http://www.aaa.org");
driver.Navigate().GoToUrl("http://www.aaa.org/contactus");
driver.FindElement(By.Name("contact")).SendKeys(contact);
driver.Navigate().GoToUrl("http://www.aaa.org/aboutus");
//Code logic
driver.Close(); // close browser
}
driver.Quit(); // close browser driver
}
}
Is there some reason you need to close the browser between runs? You can't just reuse the existing browser instance? Your test will run much faster... but sometimes there is a need to close it. Only you would know...
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.