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 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;
}
}
I have a WPF window and I'm calling it from a C++/cli code and it works fine. What I need is what's the best way to intercept user action I mean whether he click OK or Cancel. Wath I think to do is to define a Boolean property in my window and set it depends on user action. Here is my code :
MyWindowView^ window = gcnew MyWindowView();
System::Windows::Interop::WindowInteropHelper^ windowInteropHelper = gcnew System::Windows::Interop::WindowInteropHelper(window);
windowInteropHelper->Owner = (IntPtr)AfxGetMainWnd()->m_hWnd;
window->WindowStartupLocation = System::Windows::WindowStartupLocation::CenterScreen;
window->ShowDialog();
if ()
{
//some action
}
else
{
//
}
Also I want to know do I need to delete the window object ?
Window.ShowDialog returns dialog result. I can't see any reason to get this result in some way, that differs from C# or VB .NET:
System::Nullable<System::Boolean> result = window->ShowDialog();
if (result.HasValue)
{
// OK or Cancel
if (result.Value)
{
// OK clicked
}
else
{
// Cancel clicked
}
}
else
{
// dialog closed via system menu or Alt+F4
}
do I need to delete the window object ?
No, you don't. See this answer.
I am in a fairly odd situation here. I have created a custom MessageBox form (instead of the built-in MessageBox.Show). The below code is what I use to call up the form, when I need it:
internal DialogResult ShowCustomMessageBox(string message, string caption, Icon icon = null)
{
var result = DialogResult.None;
MainForm.Get.UISynchContext.Send(s =>
{
var messageBox = new DialogBox
{
Icon = icon,
Text = caption,
rtbInDialogBox = { Text = message }
};
result = messageBox.ShowDialog();
messageBox.Dispose();
}, null);
return result;
}
When I run this, I get an error message on messageBox.ShowDialog(); that the messageBox instance has already been disposed.
When I post the code to the synchronization context I was pretty sure MainForm would run the code itself (as opposed to other threads), and I am not sure why it tells me that the messageBox has already been disposed.
Any ideas?
I found the problem. Apparently you need to specify the owner of the dialog box: result = messageBox.ShowDialog(MainForm.Get);
This is web single sign on code that runs on a .net 3.5 winform. The code runs fine for ie6 or ie8 as long as ie8 only has one tab open. The problem is that if the user opens a new tab (tab 2,3,etc.) and navigates to a web site (web form internal in the organization) the below code will be executed but the ie COM automation object will return the HTMLDocument for the first tab (Tab 1) even though tab 2 is the active tab. I can't find any IE tab references in the InternetExplorer or HTMLDocument classes anywhere. Actually, there's very little IE tab related documentation anywherer in the IE COM automation docs.
AutoResetEvent ie2_NavigateCompleteAutoReset;
/// <summary>
/// Given the handle of an Internet Explorer instance, this method performs single sign on to
/// several known web login forms.
/// </summary>
/// <param name="iEFramHandle"></param>
private void WebFormSignOn(int iEFramHandle)
{
foreach (SHDocVw.InternetExplorer ie2 in new SHDocVw.ShellWindows())
{
if (ie2.HWND == iEFramHandle)
{
while (true)
{
Thread.Sleep(100);
if (ie2.ReadyState == SHDocVw.tagREADYSTATE.READYSTATE_COMPLETE)
{
try
{
mshtml.HTMLDocument doc = (mshtml.HTMLDocument)ie2.Document;
ie2.NavigateComplete2 += new SHDocVw.DWebBrowserEvents2_NavigateComplete2EventHandler(ie2_NavigateComplete2);
ie2_NavigateCompleteAutoReset = new AutoResetEvent(false);
/*Find the username element and enter the user's username*/
mshtml.HTMLInputElement userID = (mshtml.HTMLInputElement)doc.all.item("username", 0);
userID.value = Globals.Username;
/*Find the password element and enter the user's password*/
mshtml.HTMLInputElement pwd = (mshtml.HTMLInputElement)doc.all.item("password", 0);
pwd.value = Globals.GetAppName();
/*Find the submit element/button and click it*/
mshtml.HTMLInputElement btnsubmit = (mshtml.HTMLInputElement)doc.all.item("submit", 0);
btnsubmit.click();
/*Wait up to 5 seconds for the form submit to complete.
This is to prevent this method from being called multiple times
while waiting for the form submit and subsequent navigation from completing.*/
ie2_NavigateCompleteAutoReset.WaitOne(5000);
return;
}
catch (Exception err)
{
Logger.Log(err.ToString(), Logger.StatusFlag.Error, this.ToString(), "WebFormSignOn");
return;
}
finally
{
/*Remove the event handler*/
ie2.NavigateComplete2 -= ie2_NavigateComplete2;
}
}
}
}
}
}
void ie2_NavigateComplete2(object pDisp, ref object URL)
{
ie2_NavigateCompleteAutoReset.Set();
}
It turns out that each tab in IE 8 has it's own process and handle. In the original code i was always getting the handle from the first IEFrame. I modified the code (below) and now it works. The change is that instead of looking for just the first IEFrame handle, the code also looks for a LocationURL that matches the url that triggerd the method that calls WebFormsSignOut.
private void WebFormSignOn(int iEFramHandle,string addressBarText)
{
var shellWindows = new SHDocVw.ShellWindows();
foreach (SHDocVw.InternetExplorer ie2 in shellWindows)
{
if (ie2.LocationURL==addressBarText)
{ //rest of the code (see orignal post)
Internet Explorer does not have any public tab APIs (beyond allowing you to target a navigation to a new foreground or background tab). Each ActiveX control or BHO is loaded individually into an individual tab instance. Trying to walk down from the ShellWindows collection isn't likely to work in general, instead you should have your plugin reach out to its hosting site (e.g. IObjectWithSite::SetSite will convey this info) which will allow you to determine your hosting tab.
So I'm trying to make a folderbrowser for my custom application in C# and the folderbrowser thing is okay, but I want to set it up like how the default one acts.
According to #Kevin I am trying to make a modal dialog.
// I create the folderbrowser control and await the directory
string CreateFileDialog(bool allowFixedDrives)
{
FolderBrowser fb = new FolderBrowser(this, allowFixedDrives);
fb.Show();
//return THE_SELECTED_FOLDER_DIR;
return "";
}
So in the folderbrowser there is a boolean to allow fixed drives and also a reference to the parent form:
// Create the control and receive whether or not it should read fixed drives and also get a reference to the parent control.
public FolderBrowser(Form1 frm1, bool allowFixed)
{
InitializeComponent();
this.allowFixed = allowFixed;
frm1.Enabled = false;
}
I freeze the main form when this dialog is created. If the user closes the form, it will return null or "" and if the user presses okay, it should return the selected directory (where THE_SELECTED_FOLDER_DIR is).
Does anyone know how I can cleanly implement a dialog that sends feedback to the parent form?
Feel free to ask if you are as confused as I am :)
So after a rather interesting discussion with #Kevin, I've decided that the best way to go about this would be to call a public function in the form and then show it. Kinda hard to explain, so I'll show you:
NB: I think this should be kept open just in case someone has the same issues I did...
So I want to simply get a selected folder name and I'll display that selected folder on a text control for example:
bool invalid = false;
string value = CreateFileDialog(true, out invalid);
if (!invalid)
{
txt_File.Text = value;
}
else
{
MessageBox.Show("A folder was not selected.");
}
Okay, so I'm creating a dialog. I check if the dialog was closed without selecting a file and display a messagebox if it's invalid....
string CreateFileDialog(bool allowFixedDrives, out bool invalid)
{
FolderBrowser fb = new FolderBrowser(this, allowFixedDrives);
return fb.ShowForm(out invalid);
}
Now here is where it gets interesting. I create the dialog here and call a function on the form to actually show it, but I pass a boolean as an out variable to detect if it was closed without selecting a file.
And finally:
public string ShowForm(out bool a)
{
ShowDialog();
frm1.Enabled = true;
if (!Directory.Exists(selectedFolder))
{
a = true;
return selectedFolder;
}
else
{
a = false;
return selectedFolder;
}
}
I return the selected folder name if the user pressed OK, otherwise don't return it and also set the out parameter to false.
There you have it.
I'd like to thank everyone who pitched in here, namely #Kevin.