I am stuck when trying to switch windows using the latest version of webdriver in C#.
I have a base window, when i click a button, it opens a new window.
The target code for this button is as below.
window.open(uri, "DisplayPage", " width=1200, scrollbars=yes , resizable = yes , toolbar = no , menubar = no");
I am using the below mentioned code to target the new window
string BaseWindow = _driver.CurrentWindowHandle;
ReadOnlyCollection<string> handles = _driver.WindowHandles;
foreach (string handle in handles)
{
if (handle != BaseWindow)
{
_driver.SwitchTo().Window(handle).Title.Equals("DisplayPage");
}
}
}
As you can see from above, I am switching to the window using the Target Title from the base window. This does not seem to work.
I then noticed that the Title of the opened window was different, it was "Display - Transaction Page"
I then modified the code to this
string BaseWindow = _driver.CurrentWindowHandle;
ReadOnlyCollection<string> handles = _driver.WindowHandles;
foreach (string handle in handles)
{
if (handle != BaseWindow)
{
_driver.SwitchTo().Window(handle).Title.Equals("Display - Transaction Page");
}
}
}
Still no luck.
Interestingly, I do not get any errors saying "Window not found".
The problem is that When i try to click on elements on the newly opened page, i get a NoSuchElementException which means that the newly opened window has not been targeted.
Any ideas?
Regards,
Hasan
You should break the loop once window changed to your window, otherwise it will always switch to last opened window:
foreach (string handle in handles) {
if (handle != BaseWindow) {
if(_driver.SwitchTo().Window(handle).Title.Equals("Display - Transaction Page"))
break;
}
}
You can try with Contains instead of equal, it will simplify the window search:
_driver.SwitchTo().Window(handle).Title.Contains("Display");
Although you cracked the answer yourself, there is another way to handle switching between the windows in C#.
// initiate webdriver
IWebDriver driver = new FirefoxDriver();
//perform some action to open a new window. Like clicking a link.
driver.FindElement(By.Id("btnId")).Click();
//switch to new window.
driver.SwitchTo().Window(driver.WindowHandles.Last());
//if you want to switch back to your first window
driver.SwitchTo().Window(driver.WindowHandles.First());
Related
I am trying to figure a way to get focus of tab in Internet Explorer. I've done some research and found that there is no simple way of doing it.
In the code that is written below, I check for already open tabs that meet a certain criteria and if any of them is found I use it to navigate to a webpage. If there is no webpage that meets the criteria, I open a new tab. Afterwards, I want to get that tab to foreground.
Using SetForegroundWindow is a basic and incomplete approach as it sets any of the Internet Explorer windows to foreground. For example, if I have multiple windows open, with multiple tabs each, it is possible to get another instance of Internet Explorer Window to foreground, not the one containing the tab I need.
Also, I've tried using mshtml to get focus of the tab, but it doesn't work.
So far, I have been using SHDocVw to Navigate in Internet Explorer. As a limitation, I cannot use any of the available automation alternatives, such as Selenium Webdriver.
What approach should I take? In the worst case scenario, I am thinking about using SendKeys to navigate through open tabs, but I would like a better approach.
public static void openwebpage()
{
start:
InternetExplorer ie = null;
ShellWindows allBrowser = new ShellWindows();//get all windows
int browserCount = -1;
List<int> tabs = new List<int>(); // list containing shellwindows that meet certain criteria - InternetExplorer and webapp ip
tabs.Clear();
foreach (InternetExplorer browser in allBrowser)
{
browserCount++;
ie = allBrowser.Item(browserCount) as InternetExplorer;
if (ie != null && ie.FullName.ToLower().Contains("iexplore.exe") && ie.LocationURL.Contains(Properties.Settings.Default["adresa"].ToString())) // requirements for identifying open local webapp pages
{
tabs.Add(browserCount);
}
}
bool gasit = false;
foreach (var tab in tabs)
{
ie = allBrowser.Item(tab) as InternetExplorer;
if (ie.LocationURL.Contains("main.aspx")) //if the tab is in the main interface - use that tab to navigate
{
gasit = true;
ie.Navigate2(Properties.Settings.Default["adresa"] + + "?id_dosar=" + IDdosar);
ie = allBrowser.Item(tab) as InternetExplorer;
Thread.Sleep(500);
SetForegroundWindow((IntPtr)ie.HWND); //get ie to foreground
((HTMLDocument)ie.Document).focus();
break;
}
}
if (!gasit) // if neither of the tabs is in the main interface (main.aspx), open a new tab
{
ie.Navigate2(Properties.Settings.Default["adresa"] + "?id_dosar=" + IDdosar, 65536/* 0x0800*/);// 0800 e cu focus, 0x1000 fara focus
Thread.Sleep(500);
ie = allBrowser.Item(tabs.LastOrDefault() + 1) as InternetExplorer;
SetForegroundWindow((IntPtr)ie.HWND);
((HTMLDocument)ie.Document).focus();
}
}
No easy way i guess.This is not a clear way, but hopefully you can work with it
Process[] procs = Process.GetProcessesByName("Internet");
if (procs.Length == 0)
{
Console.WriteLine("internet is not currently open");
}
List<string> titles = new List<string>();
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;
}
}
bool isMinimized = IsIconic(hWnd);
if (isMinimized)
{
ShowWindow(hWnd, 9); // restore
Thread.Sleep(100);
}
SetForegroundWindow(hWnd);
SendKeys.SendWait("^+1"); // change focus to first tab
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;
}
I have a WPF C# using FirstFloor MUI Framework app, that on start, checks for settings and will show the specific startup uri as per below;
if(somethings_true) {
Application curApp = Application.Current;
//ModernWindow
curApp.StartupUri = new Uri("MainWindow.xaml", UriKind.RelativeOrAbsolute);
}else{
Application curApp = Application.Current;
//ModernWindow
curApp.StartupUri = new Uri("OtherWindow.xaml", UriKind.RelativeOrAbsolute);
}
which works fine, however when the "OtherWindow.xaml" is active first it has a onclick event that does other checks, and on finishing opens the MainWindow.xaml. But in the Button_Click() which does the opening of MainWindow.xaml, I cant get the OtherWindow.xaml to close and ive tried inside OtherWindow.xaml..
this.Close();
&
var OtherWin = new OtherWindow();
OtherWin.Close();
&
var w = Application.Current.Windows[0];
w.Hide();
//Only hides the OtherWindows.xaml (Still runs hidden in background even after MainWindow.xaml is closed)
I use the below code to check if OtherWindow.xaml is still open inside MainWindow.xaml in which it states that it does;
foreach (var wndOtherWindow in Application.Current.Windows)
{
if (wndOtherWindow is OtherWindow)
{
//Its Open Still...
//How to close() "OtherWindow.xaml" from here?
}
}
Is there another way to close() the OtherWindow.xaml?
You should cast to Window or specific type(in your case OtherWindow), that way you can call Close() method. Try this:
foreach (var wndOtherWindow in Application.Current.Windows)
{
if (wndOtherWindow is OtherWindow)
{
(wndOtherWindow as Window).Close();
}
}
Hope helps.
I work at a place that blocks social media sites and pops up a proxy log-in for those (few) folks who have legitimate business reasons for going to them. Since most sites have a Facebook, Twitter or similar link, the proxy prompt comes up quite a bit. When browsing in a normal, human-driven fashion, I just hit the ESC key to get rid of the proxy log-in dialogue. How can I do this via Selenium? I've seen alot of posts and solutions for either closing ALERT messages or modal dialogues but I haven't seen anything for closing the proxy log-in; just bypassing it by supplying credentials.
Any help/tips would be appreciated. Thanks!
Specs:
I'm using Selenium 2.44 with the Firefox driver in C#
(Edit #2: A little more info on this dialogue)
This log-in prompt is coming from our own internal proxy server. Our proxy server is basically asking the user if they even have permission to go to the site requested before any communication is made to the remote site. It pops up any time an element is on the remote site. So for instance, if a site has a button for Facebook and Twitter which pulls the button from Facebook or Twitter itself, the user will see two proxy log-in prompts. While the other elements of the page will load as it waits, the page-load process ultimately waits for an answer for any elements that are otherwise automatically blocked.
One way I have gotten around this is to use the Firefox driver in combination with NoScript and remove all social networking links from the white-list. It's a crude workaround and forces the use of one browser. What I'm seeking is a way for Selenium to simply close the proxy log-in prompt via code (if that even be done).
(Edit: Added screenshot example)
(Edit: Added screenshot from Inspect)
Not sure about selenium but you could use the System.Windows.Automation namespace instead.
Subscribe to top level window opens
Use the AutomationElement received to check if it matches your Firefox window information (you can use a took like Inspect to find out what they are)
Use the AutomationElement above to subscribe to child window opened events
On event, check if it is the proxy popup
Use the close method on it or SendKeys to send an ESC
Here's a sample code, you will have to gather the classnames, automation ids and names of the windows (feel free to commend and I'll edit the answer):
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Automation;
namespace FirefoxAutomation
{
class FirefoxAutomation
{
private const string FF_CLASSNAME = "MozillaWindowClass"; //"Firefox ClassName taken from Inspect";
private const string FF_AUTOMATIONID = null;//"Firefox AutomationId taken from Inspect";
private static readonly Regex FF_NAME = new Regex("( - Mozilla Firefox)$"); //new Regex("Firefox Name regex based on name taken from Inspect");
private const string PROXY_CLASSNAME = "MozillaDialogClass";//"Proxy window ClassName taken from Inspect";
private const string PROXY_AUTOMATIONID = null;//"Proxy window AutomationId taken from Inspect";
private static readonly Regex PROXY_NAME = new Regex("^(Authentication Required)$");//new Regex("Proxy window Name regex based on name taken from Inspect");
public FirefoxAutomation()
{
SubscribeTopLevelWindowOpened();
}
private void SubscribeTopLevelWindowOpened()
{
Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent,
AutomationElement.RootElement, TreeScope.Children, TopLevelWindowOpened);
}
private void TopLevelWindowOpened(object sender, AutomationEventArgs e)
{
var element = sender as AutomationElement;
if (element == null) return;
// Filter for FireFox window element
if (!MatchWindow(element, FF_CLASSNAME, FF_AUTOMATIONID, FF_NAME)) return;
// Subscribe for child window opened even
Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent,
element, TreeScope.Children, FireFoxChildWindowOpened);
}
private void FireFoxChildWindowOpened(object sender, AutomationEventArgs e)
{
var element = sender as AutomationElement;
if (element == null) return;
// Filter for a proxy message
if (!MatchWindow(element, PROXY_CLASSNAME, PROXY_AUTOMATIONID, PROXY_NAME)) return;
// Find the cancel button
var controls = element.FindAll(TreeScope.Children, Condition.TrueCondition).Cast<AutomationElement>().ToList();
var cancelButton = controls.FirstOrDefault(c => c.Current.ControlType == ControlType.Button && c.Current.Name == "Cancel");
if (cancelButton == null) return;
// Get the click pattern
object clickPatternObj;
if (!cancelButton.TryGetCurrentPattern(InvokePattern.Pattern, out clickPatternObj)) return;
((InvokePattern)clickPatternObj).Invoke(); // click the cancel button
}
private bool MatchWindow(AutomationElement element, string className, string automationId, Regex name)
{
var current = element.Current;
if (current.ControlType != ControlType.Window) return false;
if (className != null && current.ClassName != className) return false;
if (automationId != null && current.AutomationId != automationId) return false;
if (name != null && name.IsMatch(current.Name)) return false;
return true;
}
}
}
Navigate to the website like this:
WebDriver.Navigate().GoToUrl("http://username:password#website.com");
The website.com would be the usual website.
If you do not want to log in you can just use an Action to send an Escape key to the driver:
var action = new Actions(WebDriver);
action.SendKeys(Keys.ESCAPE).Build().Perform();
I have the handle of a window and what I want to do is click it's button named "Load Settings". I have 2 problems.
My first problem is when I call Invoke on a certain InvokePattern, it brings the window to focus and this is undesirable for my application.
My second problem is visible and documented in the comments towards the end of my following code:
AutomationElement aeBot = AutomationElement.FromHandle(mbotSettingList.ElementAt(i).getWindowHandle());
AutomationElement aeButtonLoadSettings = aeBot.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "Load Settings"));
InvokePattern ipClickLoadSettings = (InvokePattern)aeButtonLoadSettings.GetCurrentPattern(InvokePattern.Pattern);
Thread invokeLoadSettingsThread = new Thread(ipClickLoadSettings.Invoke);
InvokePattern ipClickOpen = null;
AutomationElement aeOpenDialogEdit = null;
AutomationElement aeButtonOpen = null;
AutomationElementCollection aeDialogs = null;
AutomationElement aeOpenDialog = null;
ValuePattern vpOpenDialogEdit = null;
//Using a thread to invoke the Load Settings button click because as a result of clicking Load Settings a dialog is opened and invoke doesnt return for nealy 10 seconds
invokeLoadSettingsThread.Start();
//We probably wont join() this thread because it goes on for far longer than we expect to be in this function
//Get a collection of the Dialog windows that are direct children of the main window we have a handle to
aeDialogs = aeBot.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ClassNameProperty, "#32770"));
while (aeDialogs.Count == 0)
{
//This while loop is to continue to check for the Open file dialog as it may take a little time to open
aeDialogs = aeBot.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ClassNameProperty, "#32770"));
Thread.Sleep(250);
}
for (int j = 0; j < aeDialogs.Count; j++)
{
//There is usually only 1 child dialog window, but just make sure we have the correct one
if (aeDialogs[j].Current.Name == "Open")
{
Debug.WriteLine("Found open dialog!");
aeOpenDialog = aeDialogs[j];
break;
}
}
//Inside the Open window, the first Edit window is the one where the file name/path should be entered
aeOpenDialogEdit = aeOpenDialog.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.ClassNameProperty, "Edit"));
//Set the value of the file name/path to the string variable "loadSettingsString"
vpOpenDialogEdit = (ValuePattern)aeOpenDialogEdit.GetCurrentPattern(ValuePattern.Pattern);
vpOpenDialogEdit.SetValue(loadSettingsString);
//******************************************PROBLEM BEGINING BELOW******************************************
//Using multiple methods, we can successfully get a successful AutomationElement for the "Open" button in the Open file dialog
aeButtonOpen = aeOpenDialog.FindFirst(TreeScope.Subtree, new PropertyCondition(AutomationElement.NameProperty, "Open"));
//aeButtonOpen = aeOpenDialog.FindFirst(TreeScope.Subtree, new PropertyCondition(AutomationElement.NameProperty, "Cancel"));
//Something to consider: If we assigned aeButtonOpen to the AutomationElement we find be looking for "Cancel" rather than "Open"
Debug.WriteLine(aeButtonOpen.Current.Name + " button found!");
//Prints "Open button found!"
//If aeButtonOpen were assigned to "Cancel", this would print "Cancel button found!"
ipClickOpen = (InvokePattern)aeButtonOpen.GetCurrentPattern(InvokePattern.Pattern);
//GetCurrentPattern has returned null
//If aeButtonOpen were assigned to "Cancel", this would NOT be null
ipClickOpen.Invoke();
//Invoke() on a null results in "Unsupported Pattern" exception
//If aeButtonOpen were assigned to "Cancel", this would work and the Open file dialog would then be exited just as if cancel were clicked
Use UIAVerify to look at the UIA tree of your application. Looking at your code, I suspect you're not retrieving the element you think you are. If the 'Open' element is a button, it should support the Invoke pattern.
Alternatively, you are opening a dialog and then immediately searching for a sub element of that dialog. It is possible that you are running into a reliability issue here where the UIA tree is still being created for that dialog. To check for this, add a sleep for one second and see if that resolves your issue. If this is the case, look into UIA structure changed events. Those events will let you synchronize your UIA test code against changes in the UIA tree.