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;
}
Related
I programatically created a new window and frame, in order to navigate to a separate page (Authentication). Upon closing the window, I want to do some stuff, but the if statement is never returning false.
Window newWindow = new Window();
Page authentication = new Authentication();
Frame newFrame = new Frame();
newWindow.Title = "Authentication";
newWindow.Content = newFrame;
newFrame.NavigationService.Navigate(authentication);
newWindow.Show();
if (IsWindowOpen<Window>("Authentication") == false)
{
//DO THINGS HERE
}
This is my IsWindowOpen method:
public static bool IsWindowOpen<T>(string name = null) where T : Window
{
return string.IsNullOrEmpty(name)
? Application.Current.Windows.OfType<T>().Any()
: Application.Current.Windows.OfType<T>().Any(w => w.Title.Equals(name));
}
I manage to open the new window and run the separate page, but upon closing nothing happens. I've added a print line in the if statement to check, and it doesn't print.
Calling Show() won't block the main thread.
If you want to do something when the window closes you should handle Closing event and do things there.
If you want to block the current thread until the window is closed, you should use ShowDialog() instead.
PROBLEM
I am using a secondary view to run my media files, but When I close my secondary view with close button on it ( while media is still playing ) the secondary view/window closes but the media somehow keeps playing because I can hear the sound and source of sound seems to be the primary view ( main app window ). how can I completely terminate the secondary window when I close it?
TRIED
I followed windows samples multiple views and was able to complete all steps, I copied the ViewLifetimeControl.cs file from the sample and used it in my project. the code runs fine until it reaches Windows.Current.Close() in released event of the secondary view.
Then it gives an exception when it tries "Window.Current.Close()" with in the released event. according to documentation exception occurs due to any on going changes ( which might be because of media file playing ), but I need to force close the window even when media file is playing how can I do that? btw here is the exception :
Message = "COM object that has been separated from its underlying RCW cannot be used."
Code to Create and Show secondary view
internal static async Task CompactOpen(string Title, string caption)
{
ViewLifetimeControl viewControl = null;
await CoreApplication.CreateNewView().Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
viewControl = ViewLifetimeControl.CreateForCurrentView();
viewControl.Title = Title;
viewControl.StartViewInUse();
var frame = new Frame();
frame.MinHeight = 200;
frame.MinWidth = 200;
frame.Navigate(typeof(CompactNowPlayingPage), new object[] { viewControl,caption});
Window.Current.Content = frame;
Window.Current.Activate();
ApplicationView.GetForCurrentView().Title = viewControl.Title;
});
((App)App.Current).SecondaryViews.Add(viewControl);
var selectedView = viewControl;
var sizePreference = new SizePreferenceString() { Title = "SizePreference", Preference = ViewSizePreference.Default };
var anchorSizePreference = new SizePreferenceString() { Title = "AnchorSizePreference", Preference = ViewSizePreference.Default };
if (selectedView != null && sizePreference != null && anchorSizePreference != null)
{
try
{
selectedView.StartViewInUse();
var viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync(
selectedView.Id,
sizePreference.Preference,
ApplicationView.GetForCurrentView().Id,
anchorSizePreference.Preference);
if (!viewShown)
{
// The window wasn't actually shown, so release the reference to it
// This may trigger the window to be destroyed
}
// Signal that switching has completed and let the view close
selectedView.StopViewInUse();
}
catch (InvalidOperationException)
{
// The view could be in the process of closing, and
// this thread just hasn't updated. As part of being closed,
// this thread will be informed to clean up its list of
// views (see SecondaryViewPage.xaml.cs)
}
}
}
Released Event
private async void ViewLifetimeControl_Released(Object sender, EventArgs e)
{
((ViewLifetimeControl)sender).Released -= ViewLifetimeControl_Released;
// The ViewLifetimeControl object is bound to UI elements on the main thread
// So, the object must be removed from that thread
await mainDispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
((App)App.Current).SecondaryViews.Remove(thisViewControl);
});
// The released event is fired on the thread of the window
// it pertains to.
//
// It's important to make sure no work is scheduled on this thread
// after it starts to close (no data binding changes, no changes to
// XAML, creating new objects in destructors, etc.) since
// that will throw exceptions
Window.Current.Close(); //this is where that exception occurs
}
Note : both of above methods and even all the related variables, all of them I have followed the guidelines within the uwp sample for multiple views.
Thanks in advance, any help would be really appreciated, I only want to force close the secondary view ( If that's possible )
Is this in the editor or the app? If it's in your debug or build of the app, the secondary view is most likely still open but hidden. You may be using a custom close button which doesn't perform its job well enough. Instead of putting down SecondaryViews.Remove you should do what you had originally written and try StopViewInUse. It may not work, I'm not used to this kind of thing.
I have write the ActiveX using C# to communicate with the other browser-based system b, it need pops up an dialog in an other thread because of the existing architecture. the current behavior is that the dialog can be hidden behind if i click the browser title. Is it possible to keep the pops-up dialog always on the top of browser(IE8)? Thanks in advance.
public int operation()
{
....
MyMsgBox myMsgBox = new MyMsgBox(message,title);
evt = System.Threading.AutoResetEvent(false);
Thread showDialogThread = new Thread(ShowMsgDialog);
ShowDislogThread.SetApartmentState(System.Threading.ApartmentState.STA);
showDialogThread.Start(myMsgBox);
System.Threading.WaitHanle.WaitAll(new System.Threading.WaitHandle[] {evt});
....
}
public void ShowMsgDialog(object requestObj)
{
MyMsgBox msgBox = (MyMsgbox)requestObj;
msgBox.showDialog();
evt.Set();
}
Class MyMsgBox:Form
{
public MyMsgBox(string message, string title)
{
//do initialization....
}
}
I have tried to set the TopMost of Form to 'true', then it will be always on the top of all applications. it's not meet the requirement as the pops-up dialog need be only always on the top of browser. Thanks.
I don't think that what you want will be possible.
However, you can make a div stretched across all page and set and event on mouse move to call BringToFront on your ActiveX object. That should do the trick.
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.
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());