Can't send keys in Selenium C# - c#

I want to open a new tab and close the first one in Selenium.
So, I was using the SendKeys method to do this.
But my problem is when I open the new tab, I can't continue using the SendKeys method to switch to my first tab and close the current one.
When entering the while loop, both SendKeys and ExecuteJS are not working.
I tried using this javascript code:
browser.ExecuteJS("window.close();");
but it is also not working.
My code is like this:
IWebElement body = browser.FindElementByTagName("body");
//browser.ExecuteJS("window.open();");
body.SendKeys(OpenQA.Selenium.Keys.Control + 't');
browser.DeleteAllCookies();
Thread.Sleep(50);
while (browser.GetWindowNum() > 1)
{
body.SendKeys(OpenQA.Selenium.Keys.Control + OpenQA.Selenium.Keys.Tab);
body.SendKeys(OpenQA.Selenium.Keys.Control + 'w');
//browser.ExecuteJS("window.close();");
_tmExcute = DateTime.Now;
}
browser.GoToUrl(link);
browser.WaitForPageToLoad();
I use the method GetWindowNum() to check if the number of tabs is more than 1.
Here is my code to check the number of tabs in the browser:
public int GetWindowNum()
{
return wd.WindowHandles.Count;
}

You can simply switch the first window and close it using the driver and WindowHandles
ReadOnlyCollection<string> windowHandles = wd.WindowHandles;
string firstWindow = windowHandles.ElementAt(0); //first window handle at 0 index
foreach (string handle in windowHandles) { //Gets the new window handle
if(handle == firstWindow) {
wd.switchTo().window(handle); // switch focus of WebDriver to the first window
wd.close(); //close that window
break;
}
}

Related

Check if a web is open in Chrome (C#)

I am programming a .NET Framework application that open a website in Chrome and change it to full screen.
The problem I am facing is to determine if the web is already open (I don't want to open multiple pages unnecessary), In that case the program should just switch the current active window to the correct tab and switch to full screen.
The problem is only the active tab is visible to the C# program at a time, so the program needs to check each tab manually (by switching the active tab and check is title).
I don't care if the screen is flickering throw all the tabs.
I found this solution online:
private void GetCaptionOfActiveWindow()
{
Process[] procs = Process.GetProcessesByName("Chrome");
// to find the tabs we first need to locate something reliable - the 'New Tab' button
if (procs.Length == 0)
{
//some code to open chrome with the correct web site and change to full screen
return;
}
IntPtr hWnd = IntPtr.Zero;
int id = 0;
int numTabs = procs.Length;
foreach (Process p in procs)
{
if (p.MainWindowTitle.Length > 0)
{
hWnd = p.MainWindowHandle;
id = p.Id;
break;
}
}
SetForegroundWindow(hWnd);
SendKeys.SendWait("^1"); // change focus to first tab
Thread.Sleep(100);
int next = 1;
string title;
while (next <= numTabs)
{
try
{
title = Process.GetProcessById(id).MainWindowTitle.Replace(" - Google Chrome", "");
//richTextBox1.Text += title + "\n";
if (title.ToLower().Contains("some web site name"))
{
// some code to change the current active tab and change to full screen.
return;
}
next++;
SendKeys.SendWait("^{TAB}"); // change focus to next tab
Thread.Sleep(100);
}
catch (Exception ex)
{
// Chrome internal process, doesn't have tab.
}
}
//richTextBox1.Text += "web not exists\n";
//some code to open new tab with the correct web site and change to full screen
}
This solution works fine if all the Chrome tabs are open in the same window.
My problem is to figure out what to do if the tabs are scatterd across multiple Chrome Windows.

Condition Process.Start to the number of Instances of a given Process

In a WPF C# app, users can launch the "explorer.exe" process from a given menu.
This is achieved as usual, with
Process.Start("explorer.exe");
However, I need to restrict the explorer quantity of simultaneous processes to one instance, instead of as many instances as the user starts by clicking on a button.
So the usual way is to count how many instance of the given process, "explorer.exe" are actually running and if there is more than one, then block the Process.Start().
The issue is that I'm stucked in the counting function. here is what I wrote:
static bool CountProcess(string name) {
return false; // by defualt it returns false.
int counter = 0;
while(true) {
counter = Process.GetProcessesByName(name).length; // get the quantity of processes for a given name.
if(counter > 1) {
return true;
break;
}
}
}
Then I invoke the function as this:
if(countProcess("explorer")) {
// Do nothing.
} else {
Process p = Process.Start("explorer.exe");
}
However after build and execute, the app gets stucked when opening the given process. Indeed, Visual Studio does not give any debug feedback.
How can this function be refactored to be 1) operational, 2) efficient.
Why there is while loop in CountProcess method? It should be simple if.
if(Process.GetProcessByName("explorer").Length == 0)
{
Process.Start("explorer.exe");
}
=== UPDATE ===
Ok, I'm starting to realize what is your problem.
If this wasn't explorer.exe - this code should work:
private static Process proc { get; set; }
private void button1_Click(object sender, EventArgs e)
{
if (proc == null || proc.HasExited)
{
proc = Process.Start("explorer.exe");
}
}
It checks whether Process was ever created (if first time - allow processing, if not - deny starting a new one) If he clicks for the second time, the process is not null but it SHOULD BE as proc.HasExited == false (if you didn't close it)
But if you run this code - probably starting new explorer window will be possible because this newly created process is being closed immediately. And this is because:
The reason that WaitForSingleObject returns immediately is that Explorer is a single-instance program (well, limited-instance)
You can try modifying the registry as proposed here :
Open explorer window and wait for it to close
But if this to be client application to be installed on others computer, I wouldn't advise changing programmatically someone registry.
=== UPDATE 2 ====
This solution below works - but with some restrictions (You must add com reference: "Microsoft Internet Controls") It allows to open one explorer window - and then checks whether window with the same "start folder path" as the base is already opened (watch out for slash and backslash difference in two different places of the code)
using SHDocVw;
public bool ExistOpenedWindow()
{
ShellWindows _shellWindows = new SHDocVw.ShellWindows();
string processType;
foreach (InternetExplorer ie in _shellWindows)
{
//this parses the name of the process
processType = Path.GetFileNameWithoutExtension(ie.FullName).ToLower();
//this could also be used for IE windows with processType of "iexplore"
if (processType.Equals("explorer") && ie.LocationURL.Contains("C:/"))
{
return true;
}
}
return false;
}
private void button1_Click(object sender, EventArgs e)
{
if (proc == null || !ExistOpenedWindow())
{
proc = Process.Start("explorer.exe", #"C:\");
}
}
So if you choose your base path (which will be sent as argument to explorer.exe") to be C:/, after clicking button once again, it will check whether there is ANY explorer window containing such path (opened by you or not)
Compare here: Start explorer.exe without creating a window C#
And here: Is there a way to close a particular instance of explorer with C#?
=== UPDATE 3 ====
After some thoughts - i've managed to come to working solution:
public bool ExistOpenedWindow()
{
var currentlyOpenedWindows = GetAllOpenedExplorerWindow();
return currentlyOpenedWindows.Any(t => t.HWND == ActiveOpenedWindowHwnd);
}
public List<InternetExplorer> GetAllOpenedExplorerWindow()
{
List<InternetExplorer> windows = new List<InternetExplorer>();
ShellWindows _shellWindows = new SHDocVw.ShellWindows();
string processType;
foreach (InternetExplorer ie in _shellWindows)
{
//this parses the name of the process
processType = Path.GetFileNameWithoutExtension(ie.FullName).ToLower();
//this could also be used for IE windows with processType of "iexplore"
if (processType.Equals("explorer"))
{
windows.Add(ie);
}
}
return windows;
}
public static int ActiveOpenedWindowHwnd;
private void button1_Click(object sender, EventArgs e)
{
var currentlyOpenedWindows = GetAllOpenedExplorerWindow();
if (ActiveOpenedWindowHwnd == 0 || !ExistOpenedWindow())
{
Process.Start("explorer.exe");
ShellWindows windows;
while ((windows = new SHDocVw.ShellWindows()).Count <= currentlyOpenedWindows.Count)
{
Thread.Sleep(50);
}
var currentlyOpenedWindowsNew = GetAllOpenedExplorerWindow();
var openedWindow = currentlyOpenedWindowsNew.Except(currentlyOpenedWindows).Single();
ActiveOpenedWindowHwnd = openedWindow.HWND;
}
}

ASP.NET How to open a second popup on close() event of first

I want to open a popup window with some parameters inside and then open a new one (or even more than one) with different parameters, after the user closes the first.
It should be like a foreach loop where it waits for the closing event before opening a new window.
I'm using .NET Framework v3.5.
foreach (object o in ObjectsList)
{
// Do some stuff...
// Set query string for popup
string queryString = string.Format("Page.aspx?doc={0}, o.ID);
string urlDownload = Page.ResolveClientUrl(string.Format("~/Path/To/Folder/{0}", queryString));
string script = string.Format("loadDownload('{0}','_blank',600,600);", urlDownload);
// Open popup window
ScriptManager.RegisterStartupScript(Page, Page.GetType(), "DocID" + o.ID, script, true);
// Wait for popup close event before proceeding...
}
These links might be of good use to you.
http://aspdotnetcodebook.blogspot.com.au/2009/03/how-to-open-modalpopup-inside.html
http://www.codeproject.com/Articles/546817/ASP-NET-Popup-Control-Displaying-as-multiple-neste
I would have registered to the Closed/disposed event and handle all there, that means
ObjectsList
will be an instance of your class, where you have an indexer, let say i which tells you in which you are:
int i
void frm_disposed(object sender, EventArgs e)
{
showFrm(ObjectsList[++i];
}

Selenium WaitDriver doesn't wait for element to be clickable

When I click on a button it displays me a form with another buttons and I want to click on one of them. Here is a video with this (really short one), please watch http://screencast.com/t/zyliSemW1s1
So I click on button "Buy Tickets" simply like that:
button.Click();
And then I wait for the next button to be clickable.
I use the next code:
WebDriverWait wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(15));
IWebElement element = wait.Until(ExpectedConditions.ElementToBeClickable(myButton));
After that I click on button that I waited for:
element.Click();
And I get error: Element is not clickable at that point.
As I know, the method ExpectedConditions.ElementToBeClickable() waits for 2 conditions: element is visible and element is enabled.
When I use Thread.Sleep(3000) before clicking on the second button the code works and button is clickable.
I saw similar issue and the solution was to wait for handlers of this button:Selenium Wait doesn't wait for Element to be Clickable
But what to do if I don't know what handles it? I think it handles by jQuery and I use the next code to wait till it stops executing:
var ajaxIsComplete = (bool)
((IJavaScriptExecutor)Driver).ExecuteScript("return jQuery.active == 0");
If it returns "false" I wait and check again.
But it still doesn't work.
So for now my flow goes like that:
I click on button "Buy Tickets"
I wait till jQuery stops executing
I wait till element is clickable using ExpectedConditions.ElementToBeClickable() method
I click on the element and it returns me an error that it is not clickable.
Please guys tell me what is wrong in my flow and how to manage it correct.
Update:
I'm adding HTML code of buttons:
I click to this one:
<button class="btn btn-warning play-now" name="button" type="submit">Buy Tickets</button>
And wait for this one:
<img alt="Credit Card" class="merchant" src="https://numgames-production.s3.amazonaws.com/uploads/merchant/image/21/CC_Offline.png?AWSAccessKeyId=AKIAJ2Q64HPERGHAJJUA&Expires=1470984765&Signature=Qj%2BFSQ3ElctkY6KTMfzp%2FedPjPo%3D">
Denis,
As mentioned in comments to OP, here are a few little extension methods that may help your quest:
public static void WaitForAjax(this IWebDriver driver, int timeoutSecs = 10, bool throwException = false)
{
for (var i = 0; i < (timeoutSecs*10); i++)
{
var javaScriptExecutor = driver as IJavaScriptExecutor;
var ajaxIsComplete = javaScriptExecutor != null && (bool)javaScriptExecutor.ExecuteScript("return jQuery.active == 0");
if (ajaxIsComplete) return;
Thread.Sleep(100);
}
if (throwException)
{
throw new Exception("WebDriver timed out waiting for AJAX call to complete");
}
}
public static bool ElementExists(this IWebDriver driver, By condition)
{
return ElementExists(driver, condition, new TimeSpan());
}
public static bool ElementExists(this IWebDriver driver, By condition, TimeSpan timeSpan)
{
bool isElementPresent = false;
if (timeSpan == default(TimeSpan))
{
timeSpan = TimeSpan.FromMilliseconds(15000);
}
var driverWait = new WebDriverWait(driver, (TimeSpan)timeSpan);
driverWait.IgnoreExceptionTypes(typeof(WebDriverTimeoutException));
isElementPresent = driverWait.Until(x => x.FindElements(condition).Any());
return isElementPresent;
}
public static IWebElement FindElementAfterWait(this IWebDriver driver, By condition, int fromSeconds = 90)
{
bool isElementPresent = false;
IWebElement singleElement = null;
var driverWait = new WebDriverWait(driver, TimeSpan.FromSeconds(fromSeconds));
driverWait.IgnoreExceptionTypes(typeof(WebDriverTimeoutException));
try
{
isElementPresent = driverWait.Until(ExpectedConditions.ElementExists(condition)) != null;
if (isElementPresent)
{
singleElement = driver.FindElement(condition);
}
}
catch
{
// log any errors
}
return singleElement;
}
usages:
bool elementExists = _driver.ElementExists(By.Id("submitButton"));
var submitButton = _driver.FindElementAfterWait(By.Id("submitButton"));
submitButton.Click();
_driver.WaitForAjax();
// then do other code stuff...
Hopefully, a combo of these may get you out of the fix.
This is a typical problem of working with any asynchronous (AJAX) page.
You don't need to use any "magic" methods like sleeps, jquery.active and expected conditions.
Web pages are usually built that way that user would see when operation ends - like some message appears, or some button become enabled. I believe in your case something like this also happens after you click "Buy Tickets" - you need to notice this and wait for this in your code.
That wait needs to be performed using Explicit wait for your specific case. This is the only reliable way to manage asynchronous pages (including elements not yet clickable).
You can see more detailed overview in my blog post - Approaches to handling AJAX in Web Automation (Selenium)
Instead of using ElementToBeClickable, try using presenceOfElementLocated. I think your expected element is not present on DOM, so try using presenceOfElementLocated first. Once it is present on DOM, then use ElementToBeClickable.
// public void test()
{
IWebDriver driver = new ChromeDriver();
ClickSaveButton(driver,"MyButton",10); //Wait for 10 seconds
}
//Customized wait block
public void ClickSaveButton(IWebDriver driver,String ElementID = "" int TimeOut)
{
Console.Error.WriteLine("Waiting....");
try
{
driver.FindElement(By.Id(ElementID)).Click();
}
catch (Exception exception)
{
Thread.Sleep(1000);
if (TimeOut > 0) ClickSaveButton(driver, TimeOut - 1);
}
}
I was facing this problem and checking if the element is clickable, visible, located (or their combinations) etc was not enough. Selenium was still not waiting and trying to click on the element.
The only solution I found for my case was a bad practice, but functional as a workaround. I try to get the element inside a Loop with Try/Catch as found here in Falgun Cont response:
StackExchange - How to wait for element to be clickable in WebDriver with C#

Popup's in selenium webdrivers

So I'm working with selenium firefox webdrivers in c# winform and I have this code below to get the handle of the popup that shows when you click on the "webtraffic_popup_start_button" and it should get the handle of the popup but the popup handle is same as current one.
string current = driver.CurrentWindowHandle;
driver.FindElement(By.XPath("//*[#id='webtraffic_popup_start_button']")).Click();
Thread.Sleep(Sleep_Seconds);
popup = driver.CurrentWindowHandle;
Thread.Sleep(3000);
driver.SwitchTo().Window(current);
Thread.Sleep(1000);
Any help with this would be much appreciated thank you
This is what pop up looks like.
WebDriver does absolutely no tracking whatsoever to detect which window is actually in the foreground in the OS, and does no automatic switching when new browser windows are opened. That means the proper way to get the handle of a newly-opened popup window is a multi-step process. To do so, you would:
Save the currently-focused window handle into a variable so that you
can switch back to it later.
Get the list of currently opened window handles.
Perform the action that would cause the new window to appear.
Wait for the number of window handles to increase by 1.
Get the new list of window handles.
Find the new handle in the list of handles.
Switch to that new window.
In code using the .NET language bindings, that would look something like this:
string currentHandle = driver.CurrentWindowHandle;
ReadOnlyCollection<string> originalHandles = driver.WindowHandles;
// Cause the popup to appear
driver.FindElement(By.XPath("//*[#id='webtraffic_popup_start_button']")).Click();
// WebDriverWait.Until<T> waits until the delegate returns
// a non-null value for object types. We can leverage this
// behavior to return the popup window handle.
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(5));
string popupWindowHandle = wait.Until<string>((d) =>
{
string foundHandle = null;
// Subtract out the list of known handles. In the case of a single
// popup, the newHandles list will only have one value.
List<string> newHandles = driver.WindowHandles.Except(originalHandles).ToList();
if (newHandles.Count > 0)
{
foundHandle = newHandles[0];
}
return foundHandle;
});
driver.SwitchTo().Window(popupWindowHandle);
// Do whatever you need to on the popup browser, then...
driver.Close();
driver.SwitchTo().Window(currentHandle);
Alternatively, if you're using the .NET bindings, there's a PopupWindowFinder class in the WebDriver.Support assembly that is specifically designed to do these operations for you. Using that class is much simpler.
// Get the current window handle so you can switch back later.
string currentHandle = driver.CurrentWindowHandle;
// Find the element that triggers the popup when clicked on.
IWebElement element = driver.FindElement(By.XPath("//*[#id='webtraffic_popup_start_button']"));
// The Click method of the PopupWindowFinder class will click
// the desired element, wait for the popup to appear, and return
// the window handle to the popped-up browser window. Note that
// you still need to switch to the window to manipulate the page
// displayed by the popup window.
PopupWindowFinder finder = new PopupWindowFinder(driver);
string popupWindowHandle = finder.Click(element);
driver.SwitchTo().Window(popupWindowHandle);
// Do whatever you need to on the popup browser, then...
driver.Close();
// Switch back to parent window
driver.SwitchTo().Window(currentHandle);
If the lastly opened window is your target then simply do the following after the click
driver.SwitchTo().Window(driver.WindowHandles.ToList().Last());
EDIT
//You may need to go back to parent window to perform additional actions;
// to the new window
driver.SwitchTo().Window(driver.WindowHandles.ToList().Last());
// to the new window
driver.SwitchTo().Window(driver.WindowHandles.ToList().First());
//or
driver.SwitchTo().DefaultContent();
I've got some code you might like. The quickest solution is to use Popup Finder, but I've made my own method as well. I would never rely on the order the Window Handles are in to select the appropriate window. Popup Window Finder:
PopupWindowFinder finder = new PopupWindowFinder(driver);
driver.SwitchTo().Window(newWin);
My Custom method. Basically you pass it the element you want to click, your webdriver, and optionally the time to wait before searching after you click the element.
It takes all of your current handles and makes a list. It uses that list to eliminate the previously existing windows from accidentally getting switched to. Then it clicks the element that launches the new window. There should always be some sort of a delay after the click, as nothing happens instantly. And then it makes a new list and compares that against the old one until it finds a new window or the loop expires. If it fails to find a new window it returns null, so if you have an iffy webelement that doesn't always work, you can do a null check to see if the switch worked.
public static string ClickAndSwitchWindow(IWebElement elementToBeClicked,
IWebDriver driver, int timer = 2000)
{
System.Collections.Generic.List<string> previousHandles = new
System.Collections.Generic.List<string>();
System.Collections.Generic.List<string> currentHandles = new
System.Collections.Generic.List<string>();
previousHandles.AddRange(driver.WindowHandles);
elementToBeClicked.Click();
Thread.Sleep(timer);
for (int i = 0; i < 20; i++)
{
currentHandles.Clear();
currentHandles.AddRange(driver.WindowHandles);
foreach (string s in previousHandles)
{
currentHandles.RemoveAll(p => p == s);
}
if (currentHandles.Count == 1)
{
driver.SwitchTo().Window(currentHandles[0]);
Thread.Sleep(100);
return currentHandles[0];
}
else
{
Thread.Sleep(500);
}
}
return null;
}

Categories