How to open broswer's tab on remote machine - c#

Scenario: I have configured Grid 2 and multiple tests are now running in parallel. When test starts there is opened browser window (only one tab opened) and some controls filled inside it. After that I open another tab (in the same browser window), switch to it and fill some controls inside it.
Before filling data inside second tab there needs to be done following steps:
1. Open new tab by calling SendKeys(Keys.Ctrl + 't')
2. Before switching to second tab wait for that second tab's handle to be added to driver instance.
3. If handle added to driver instance then switch to it, else 4.
4. Repeat operation 2. and 3. until timeout reached.
Problem:
When debugging I noticed that when opening a new tab, it's handle was not added to driver.WindowHandles. That means, if not checking if handle added and trying to switch to it, the exception will be thrown. In my case it would switch to incorrect tab as I'm calling driver.SwitchTo().Window(handles[handles.Count() -1]);. So I created method that waits for handle to be added. The problem is that, when running in multiple workers, it always times out. I have changed the timeout but nothing changes. The newly opened tab's handle is not added to WindowHandles. If I'm not running in parallel, then it works as expected.
// previousTabCount- browser's tab count before opening new one
public void WaitForTabToOpenAndSwtich(int previousTabCount)
{
int currentTabCount = driver.WindowHandles.Count();
int count = 0;
while(currentTabCount == previousTabCount)
{
// after 20 seconds throw exception
if(count > 20)
throw new Exception("The newly opened tab's handle was not added.");
// update current tab count
currentTabCount = driver.WindowHandles.Count();
count++;
Thread.Sleep(1000);
}
var handles = driver.WindowHandles;
driver.SwitchTo().Window(handles[handles.Count() -1]);
}

I found the solution. The problem was that when using SendKeys(Keys.Ctrl + 't') to open new tab on remote machine it did not work I'm not sure why. Fortunately I found an alternative approach. Instead of using that send keys command I used:
// script that opens a new tab
driver.ExecuteScript("var w = window.open(); w.document.open();");
After running this script the new tab was opened but I could not change its url by using driver.Navigate().GoToUrl("..."); and exception was thrown:
The HTTP request to the remote WebDriver server for URL 'http:
//example.com' timed out after 60 seconds
So I modified that script a bit by adding a page load at the end like this:
// script that opens new tab and reloads it
driver.ExecuteScript("var w = window.open(); w.document.open(); w.location.reload();");
This worked for me. Maybe someone will find this useful.

Related

Close IE specific window with C# using Kill is not working

I am trying to close the most recent window/tab of IE but when I call the Kill method the window relaunches without the content of the page.
This is the code that I use to get the most recent IE process:
var a = System.Diagnostics.Process.GetProcessesByName("iexplore");
DateTime earliestStart = DateTime.Today.Subtract(new TimeSpan(1,0,0,0));
System.Diagnostics.Process youngestProccess = a.FirstOrDefault();
foreach(var b in a){
if (b.StartTime > earliestStart)
{
earliestStart = b.StartTime;
youngestProccess = b;
}
}
youngestProccess.Kill();
The code is working in the way that the most recent window "stop" working but the window is not beeing closed
Any idea?
Hi I just discover how to solve the problem.
The message is being thrown because my IE has the option "Enable automatic crash recovery" checked in the Internet Options Advanced tab.
So if you face this you have 2 options: un-check that option forever (which might work for your case) or like in my case you can change the selection via registry keys and when you finish your testing return the value to be on.
So to do this you need to add this to your code before opening IE.
Registry.SetValue("HKEY_CURRENT_USER\\Software\\Microsoft\\Internet Explorer\\Recovery", "AutoRecover", 2);
To turn back on the option you must do the same but with a 0
Registry.SetValue("HKEY_CURRENT_USER\\Software\\Microsoft\\Internet Explorer\\Recovery", "AutoRecover", 0);

CefSharp offscreen - wait for page for render

I have a problem as below. I use the CefSharp offscreen for webpage automation as follows (I open only one and the same page):
1. Open page and wait untill it renders*.
2. With EvaluateScriptAsync I put on value to input form and then with the same method I click the button on webpage.
3. Then there is some JS on this webpage that check result and displays a message.
4. When the message is displayed I make a screenshot. **
However, I have two problems:
* My sulution has to be Internet speed proof. And As I used BrowserLoadingStateChanged event and IsLoading method, even though that the events fired the webpage did not load completly - when I started the EavluateScriptAsync method it gives back error because the page was not completly loaded. Sure, I can put sth like ThreadSleep but it does not always work - it is strongly dependent on Your internet speed.
** When I try to make a screenshot it does not always contain the result message displayed by JS - sometimes there is a loading circle instead of message. And here again I can use THreadSleep but it does not always work.
Do You have any ideas? Thanks in advance.
private static void BrowserLoadingStateChanged(object sender, LoadingStateChangedEventArgs e)
{
// Check to see if loading is complete - this event is called twice, one when loading starts
// second time when it's finished
// (rather than an iframe within the main frame).
if (!e.IsLoading)
{
// Remove the load event handler, because we only want one snapshot of the initial page.
browser.LoadingStateChanged -= BrowserLoadingStateChanged;
Thread.Sleep(1800); // e. g. but it isn't a solution in fact
var scriptTask = browser.EvaluateScriptAsync("document.getElementById('b-7').value = 'something'");
scriptTask = browser.EvaluateScriptAsync("document.getElementById('b-8').click()");
//scriptTask.Wait();
if (browser.IsLoading == false)
{
scriptTask.ContinueWith(t =>
{
//Give the browser a little time to render
//Thread.Sleep(500);
Thread.Sleep(500); // still not a solution
// Wait for the screenshot to be taken.
var task = browser.ScreenshotAsync();
task.ContinueWith(x =>
{
// Make a file to save it to (e.g. C:\Users\jan\Desktop\CefSharp screenshot.png)
var screenshotPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "CefSharp screenshot.png");
Console.WriteLine();
Console.WriteLine("Screenshot ready. Saving to {0}", screenshotPath);
// Save the Bitmap to the path.
// The image type is auto-detected via the ".png" extension.
task.Result.Save(screenshotPath);
// We no longer need the Bitmap.
// Dispose it to avoid keeping the memory alive. Especially important in 32-bit applications.
task.Result.Dispose();
Console.WriteLine("Screenshot saved. Launching your default image viewer...");
// Tell Windows to launch the saved image.
Process.Start(screenshotPath);
Console.WriteLine("Image viewer launched. Press any key to exit.");
}, TaskScheduler.Default);
});
}
}
}
Ok, so in my case the best sollution was to use javascript to check if element by id exists. If yes then the page is loaded.
I noticed that render time may vary significantly depending on your hardware. It can take up to 5 seconds to render after EvaluateScriptAsync was called. So it always better to do longer delays before calling ScreenshotAsync() if you do not want to get outdated screenshot.
Thread.Sleep(5000);

Selenium ChromeDriver incrementally becomes slower over a short period of time time

I'm using Selenium with chromedriver to do some pretty basic screen-scraping, but as I loop and wait for elements and then click on links - the process becomes so slow it's unusable. If I dispose of the chromedriver instance and new-up another instance, everything starts out fast again.
Why is this getting slow so quickly? What can I do to speed this up?
Pseudo C# code:
while(true)
{
var dataGridRows = browser.Driver.FindElements(By.XPath(".//*[#class='datadrid-row']"));
foreach (var dataGridRow in dataGridRows)
{
OpenQA.Selenium.Interactions.Actions act = new OpenQA.Selenium.Interactions.Actions(browser.Driver);
//Double click on the grid row. A new dialog (CSS style) will show up.
act.DoubleClick(dataGridRow).Build().Perform();
// This first time I double click the grid row, the dialog pops up within a few miliseconds.
// This gets incrementally slower, about 10 iterations later the popup will take several MINUTES to show up after the double-click.
//This line waits for a "close dialog" button to appear. This is where the delay occurs but this returns as soon as the dialog actually appears.
ReadOnlyCollection<IWebElement> closeButtons = browser.Driver.FindElements(By.XPath(".//*[#class='dilog-close-button']"));
CollectScreenScrapeInformation(...);
}
Sleep(1000 * 60);
}
Driver itself is not eating your memory, it's the browser. Yes, creating new driver instance speeds things up, but it's not new chromedriver.exe instance which speeds it up, it's fresh chrome.exe instance. If you perform your problematic scripts manually (try to click and abuse your page for 10 min and see what happens) you'll find the same issues, browsers will get slower.
But I must admit that in my experience chrome is the fastest and best performing driver, firefoxdriver has more memory issues when the same instance is used a lot, and IEdriver is impossible to use when you have only one instance for a longer time (Multiple tests on the same IEdriver instance - memory issues). Even phantomJS/ghostdriver has this kind of isssues.
tldr; Recreate your driver instance if it gets slower over time.

How to open "Microsoft Edge" from c# and wait for it to be closed?

I'm building a Windows Form application and I want to open "Microsoft Edge" through my app with a specific URL and wait until the user closes the Edge Window.
I tried it with this code:
using (Process p = Process.Start("microsoft-edge:www.mysite.com"))
{
p.WaitForExit();
}
When I execute this code, Edge is launching with the correct URL ... but got a null object reference. The "p" object that I'm getting from Process.Start is null.
I think it's related to the reuse of Windows application.
Does anyone have a workaround/have an idea how I can wait for the user to close Edge?
Finally I did managed to do so:
When you launch Edge (at least) two process get created:
MicrosoftEdge and MicrosoftEdgeCP.
MicrosoftEdgeCP - foreach tab. So we can "wait" on this new tab process that was just created.
//Edge process is "recycled", therefore no new process is returned.
Process.Start("microsoft-edge:www.mysite.com");
//We need to find the most recent MicrosoftEdgeCP process that is active
Process[] edgeProcessList = Process.GetProcessesByName("MicrosoftEdgeCP");
Process newestEdgeProcess = null;
foreach (Process theprocess in edgeProcessList)
{
if (newestEdgeProcess == null || theprocess.StartTime > newestEdgeProcess.StartTime)
{
newestEdgeProcess = theprocess;
}
}
newestEdgeProcess.WaitForExit();
From an older solution - use a WebBrowser control to load the HTML. Once you get the data back, use an ObjectForScripting to call a c# method to notify when done.
See http://www.codeproject.com/Tips/130267/Call-a-C-Method-From-JavaScript-Hosted-in-a-WebBrowser

how to get count of number of opened windows in WPF

I have a requirement that, if one window is opened then user can not allow to open other window, for that I have tried following code.
if(System.Windows.Application.Current.Windows.Count == 0)
{
//My code
}
I am checking for currently opened window count, if it is greater then 1 then user can not open other window and that I will mention inside if statement,
but when I run this code it gives me the error
"Object reference not set to an instance of an object."
Any Solution
You would be probably getting this error because, even for the first windows to be loaded, you would be applying this check. For this you can apply null check in your code.
and for list of loaded windows, you can get it using Application,
var loadedWindows = Application.Current.Windows.Cast<Window>()
.Where(win => win.IsLoaded);
If you want to know how many windows are opened from your application instance, you can do this
l_WindowCount = 0;
foreach(var Window in App.Current.Windows)
{
l_WindowCount += 1
}
if(l_WindowCount > 1)
{
//do what you want to do here
}

Categories

Resources