Webdriver C# how to set driver timeouts with multiple browsers - c#

Hoping to find my answer here I have spent the better half of a week trying to figure this out myself and I cannot fix my issue. A little background, I am new to C# and NUnit tests with webdriver, I am attempting to create a regression suit for the company I work for. We have a few products that are heavily integrated with ebay and so for part of the test I need to click on a button which takes me to the ebay login page and then I need to login. Seems simple enough (or so I thought). The issue I am running into is when hitting this ebay login page FF times out each time. I currently have my test setup to run in multiple browsers, chrome and IE are passing (they also hang a little) but FF has never passed.
This is odd to me because earlier in this test I go to ebay and sucessfully login. But when I have to link my company account to the ebay account this login page takes forever. I know we pass some unique token to ebay to link the accounts which is what I think causes the long load times.
So the failure with FF is always the same, timed out after 60 seconds. I have read other questions that seemed to be a similar issue (Selenium WebDriver throws Timeout exceptions sporadically) there are a few solutions the one I am interested in is setting the driver timeout to something greater than 60 seconds. I do not know how to do this with multiple browser setup I have going.
[TestFixture(typeof(FirefoxDriver))]
[TestFixture(typeof(ChromeDriver))]
[TestFixture(typeof(InternetExplorerDriver))]
public class UnitTest1<TWebDriver> where TWebDriver: IWebDriver, new()
{
PTGeneral General;
[TestFixtureSetUp]
public void SetUp()
{
General = new PTGeneral();
General.Driver = new TWebDriver();
}
I would really like to keep this setup as I like how I can test IE, FF, and Chrome, but I do not know how to implement a solution like this then.
new FirefoxDriver("FfBinaryPath", FfProfileInstance, TimeSpan.FromSeconds(180));
Any help would be greatly appreciated, if you would like more information ill be happy to provide, assuming I understand what you are asking ;)
Thank you all for even reading, this community is amazing.
Still struggling with this one. Here is the error message if that helps.
------ Run test started ------
NUnit VS Adapter 2.0.0.0 executing tests is started
Loading tests from C:\Users\jburns\documents\visual studio 2013\Projects\PTTest\PTTest\bin\Debug\PTTest.dll
Run started: C:\Users\jburns\documents\visual studio 2013\Projects\PTTest\PTTest\bin\Debug\PTTest.dll
TearDown failed for test fixture PTTest.UnitTest1<ChromeDriver>
The HTTP request to the remote WebDriver server for URL http://localhost:64706/session/0186901c828d3a1ad7523ecd41dedf9a/element timed out after 60 seconds.
at OpenQA.Selenium.Remote.HttpCommandExecutor.CreateResponse(WebRequest request)
at OpenQA.Selenium.Remote.HttpCommandExecutor.Execute(Command commandToExecute)
at OpenQA.Selenium.Remote.DriverServiceCommandExecutor.Execute(Command commandToExecute)
at OpenQA.Selenium.Remote.RemoteWebDriver.Execute(String driverCommandToExecute, Dictionary`2 parameters)
at OpenQA.Selenium.Remote.RemoteWebDriver.FindElement(String mechanism, String value)
at OpenQA.Selenium.Remote.RemoteWebDriver.FindElementByXPath(String xpath)
at OpenQA.Selenium.By.<>c__DisplayClasse.<XPath>b__c(ISearchContext context)
at OpenQA.Selenium.By.FindElement(ISearchContext context)
at OpenQA.Selenium.Remote.RemoteWebDriver.FindElement(By by)
at PTTest.PTGeneral.IsElementPresent(By by) in c:\Users\jburns\Documents\Visual Studio 2013\Projects\PTTest\PTTest\PTGeneral.cs:line 42
at PTTest.PTGeneral.EmailCleanUP() in c:\Users\jburns\Documents\Visual Studio 2013\Projects\PTTest\PTTest\PTGeneral.cs:line 105
at PTTest.UnitTest1`1.TearDown() in c:\Users\jburns\Documents\Visual Studio 2013\Projects\PTTest\PTTest\UnitTest1.cs:line 29
TearDown failed for test fixture PTTest.UnitTest1<FirefoxDriver>
So I stripped out the multiple browser piece I had in the [TestFixture] and setup so that I could test only against FF and increased the driver timeout to 3m with
General.Driver = new FirefoxDriver(new FirefoxBinary(), new FirefoxProfile(), TimeSpan.FromSeconds(180));
This worked and made my tests pass. But I still need a solution that works when I run against multiple browsers, as I don't want to maintain 2 different projects when there should be a way to

Your problem is that you have to wait till a page is loading.
Then the solution will be to use waiting methods each time when a new page is being opening.
Put this method after navigating to each new page:
public void WaitForPageLoading(int secondsToWait = 600)
{
Stopwatch sw = new Stopwatch();
sw.Start();
try
{
while (sw.Elapsed.TotalSeconds < secondsToWait)
{
var pageIsReady = (bool)((IJavaScriptExecutor)Driver).ExecuteScript("return document.readyState == 'complete'");
if (pageIsReady)
break;
Thread.Sleep(100);
}
}
catch (Exception)
{
Driver.Dispose();
throw new TimeoutException("Page loading time out time has passed " + secondsToWait + " seconds");
}
finally
{
sw.Stop();
}
}

Related

NET5 - How to run numerous web acceptance tests on a single machine

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.

Selenium and PhantomJS takes 30 seconds to open each link

I am trying to open a website and grab some data using Selenium with PhantomJS, however it takes a lot of time to open a website (about 30 second). And every time I open other link I have to wait 30+Seconds. What is wrong with my code ?
static void Main(string[] args)
{
IWebDriver browser = new PhantomJSDriver();
var URL = "http://www.cbssports.com/nba/playerrankings ";
browser.Navigate().GoToUrl(URL);
//Position
var title = browser.FindElements(By.CssSelector(".tableTitle"));
Console.WriteLine(title.First().Text);
Console.Read();
}
Things I have tried to do:
1.Set PhantomJS proxy type to none
2.Disable internet option: automatically detect settings
3.Disable IPv6 protocol
PhantomJS release notes claim, that there are some known issues with network performance on Microsoft Windows. According to release notes, solution is to set proxy type to none, however that doesn't work.
You have to wait 30 seconds because you haven't defined timeouts which are 30 seconds as default. You should use this predefined driver service.
var phantomJSDriverService = PhantomJSDriverService.CreateDefaultService();
IWebDriver browser = new PhantomJSDriver(phantomJSDriverService);
browser.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(0));
The default timeout for Selenium is 30 seconds. You are using browser.FindElements() (the plural version), which will wait the full 30 seconds before continuing!
You can reduce the timeout with browser.manage().timeouts().implicitlyWait(), or you can use explicit timeouts.

Selenium and Internet Explorer Driver

I'm trying to run some tests with C# and InternetExplorerDriver.
This code is executed on Windows Server 2012, 64 bit.
Right after navigation to a new URL, I'm calling a function that waits until a page loads\20 seconds timeout.
private bool waitForPageToLoad()
{
try
{
int timeout = int.Parse(ConfigurationManager.AppSettings["TimeoutForCustomExpression"]);
IWait<IWebDriver> wait = new OpenQA.Selenium.Support.UI.WebDriverWait(m_driver, TimeSpan.FromSeconds(timeout));
wait.Until(driver1 => ((IJavaScriptExecutor)m_driver).ExecuteScript("return document.readyState").Equals("complete"));
}
catch//(Exception e) //timeout
{
log(e.Message + e.StackTrace);
return false;
}
return true;
}
The function works great for every browser other than IE.
On IE, I the following error in my log:
JavaScript error (UnexpectedJavaScriptError) at
OpenQA.Selenium.Support.UI.DefaultWait1.PropagateExceptionIfNotIgnored(Exception
e) in
c:\Projects\WebDriver\trunk\dotnet\src\WebDriver.Support\UI\DefaultWait.cs:line
222 at OpenQA.Selenium.Support.UI.DefaultWait1.Until[TResult](Func`2
condition) in
c:\Projects\WebDriver\trunk\dotnet\src\WebDriver.Support\UI\DefaultWait.cs:line
180 at MainClass.waitForPageToLoad()
I have no idea why it happens.
Could somebody help me out here?
Sincerely,
Adam.
Without seeing all that extra information that Arran requested, it's hard to help you understand the error.
However if you're just looking for a quick fix that works in all browsers, I always just use
Thread.sleep(int milliseconds);
for my Selenium tests in C# that need to wait for a page to load or a certain element to render before continuing.

Selenium and TFBuild - Pages never seem to load

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.

Documents List API client for C# timing out

I'm working on a simple wrapper for the google docs api in c#. The problem I'm running into is my tests are timing out. Sometimes. When I run all of my tests (only 12 of them) then it usually hangs up on the 8th one, which is testing the delete function. After about 6.5 minutes, it continues on, but every test after it also times out after 6.5 minutes for each test. If I run the tests individually then it works fine every time.
Here is the first method that times out:
Updated to show exception handling
[TestMethod]
public void CanDeleteFile()
{
var api = CreateApi();
api.UploadFile("pic.jpg", "..\\..\\..\\pic.jpg", "image/jpeg");
try
{
var files = api.GetDocuments();
api.DeleteFile("pic.jpg");
var lessFiles = api.GetDocuments();
Assert.AreEqual(files.Count - 1, lessFiles.Count);
}
catch (Google.GData.Client.GDataRequestException ex)
{
using (StreamWriter writer = new StreamWriter("..\\..\\..\\errors.log", true))
{
string time = DateTime.Now.ToString();
writer.WriteLine(time + ":\r\n\t" + ex.ResponseString);
}
throw ex;
}
}
It times out on var lessFiles = api.GetDocuments(); The second call to that method. I have other methods that call that method twice, and they don't time out, but this one does.
The method that all the test methods use that times out:
public AtomEntryCollection GetDocuments(DocumentType type = DocumentType.All, bool includeFolders = false)
{
checkToken();
DocumentsListQuery query = getQueryByType(type);
query.ShowFolders = includeFolders;
DocumentsFeed feed = service.Query(query);
return feed.Entries;
}
It times out on this line DocumentsFeed feed = service.Query(query);. This would be closer to acceptable if I was requesting insane numbers of files. I'm not. I'm requesting 5 - 6 depending on what test I'm running.
Things I've tried:
Deleting all files from my google docs account, leaving only 1-2 files depending on the test for it to retrieve.
Running the tests individually (they all pass and nothing times out, but I shouldn't have to do this)
Checking my network speed to make sure it's not horribly slow (15mbps down 4.5mbps up)
I'm out of ideas. If anyone knows why it might start timing out on me? Any suggestions are welcome.
edit
As #gowansg suggested, I implemented exponential backoff in my code. It started failing at the same point with the same exception. I then wrote a test to send 10000 requests for a complete list of all documents in my drive. It passed without any issues without using exponential backoff. Next I modified my test class so it would keep track of how many requests were sent. My tests crash on request 11.
The complete exception:
Google.GData.Client.GDataRequestException was unhandled by user code
Message=Execution of request failed: https://docs.google.com/feeds/default/private/full
Source=GoogleDrive
StackTrace:
at GoogleDrive.GoogleDriveApi.GetDocuments(DocumentType type, Boolean includeFolders) in C:\Users\nlong\Desktop\projects\GoogleDrive\GoogleDrive\GoogleDriveApi.cs:line 105
at GoogleDrive.Test.GoogleDriveTests.CanDeleteFile() in C:\Users\nlong\Desktop\projects\GoogleDrive\GoogleDrive.Test\GoogleDriveTests.cs:line 77
InnerException: System.Net.WebException
Message=The operation has timed out
Source=System
StackTrace:
at System.Net.HttpWebRequest.GetResponse()
at Google.GData.Client.GDataRequest.Execute()
InnerException:
another edit
It seems that I only crash after requesting the number of documents after the second upload. I'm not sure why that is, but I'm definitely going to look into my upload method.
If your tests pass when ran individually, but not when ran consecutively then you may be hitting a request rate limit. I noticed in your comment to JotaBe's answer you mentioned were getting request timeout exceptions. You should take a look at the http status code to figure out what to do. In the case of a 503 you should implement exceptional back off.
Updated Suggestion
Place a try-catch around the line that is throwing the exception and catch the Google.GData.Client.GDataRequestException. According to the source there are two properties that may be of value to you:
/// <summary>
/// this is the error message returned by the server
/// </summary>
public string ResponseString
{ ... }
and
//////////////////////////////////////////////////////////////////////
/// <summary>Read only accessor for response</summary>
//////////////////////////////////////////////////////////////////////
public WebResponse Response
{ ... }
Hopefully these contain some useful information for you, e.g., an HTTP Status Code.
You can explicitly set the time-outs for your unit tests. Here you have extensive information on it:
How to: Set Time Limits for Running Tests
You can include Thread.Sleep(miliseconds) in your unit tests before the offending methods. Probably your requests are being rejected from google docs for being too may in too short a time.

Categories