Here comes 2 windows pop out during the testing.
my code:
string BaseWindow = driver.CurrentWindowHandle;
ReadOnlyCollection<string> handles = driver.WindowHandles;
foreach(string handle in handles)
{
Boolean a = driver.SwitchTo().Window(handle).Url.Contains("Main");
if (a == true)
{
InitialSetting.driver.SwitchTo().Window(handle);
break;
}
}
I want to switch to the window which url contains "Main". But when the test is running, it switches between two windows continuously and it doesn't stop.
I debug and found the foreach didn't break even when the boolean a is true.
How can I resolve this?
//switch to new window
driver.FindElement(By.Id("link")).Click();
//wait for new window to open
Thread.Sleep(2000);
//get the current window handles
string popupHandle = string.Empty;
ReadOnlyCollection<string> windowHandles = driver.WindowHandles;
foreach (string handle in windowHandles)
{
if (handle != existingWindowHandle)
{
popupHandle = handle; break;
}
}
//switch to new window
driver.SwitchTo().Window(popupHandle);
//check for element on new page
webElement = driver.FindElement(By.Id("four04msg"));
if(webElement.Text == "THE CONTENT YOU REQUESTED COULDN’T BE FOUND...")
{
return false;
}
else
{
return true;
}
//close the new window to navigate to the previous one
driver.close();
//switch back to original window
driver.SwitchTo().Window(existingWindowHandle);
Using the original post code.
string existingWindowHandle = driver.CurrentWindowHandle;
Its the first window.
One important thing is:
ReadOnlyCollection<string> windowHandles = driver.WindowHandles
Contains the string name object, not the Windows Title Name, for
example Collection windowHandles could contains:
Not Windows Title Name as {Menu},{PopUp}
It contains: {45e615b3-266f-4ae0-a508-e901f42a36d3},{c6010037-0be6-4842-8d38-7f37c2621e81}
IWebDriver popup = null;
string mainWindow = driver.CurrentWindowHandle;
bool foundPopupTitle = false;
foreach (string handle in driver.WindowHandles)
{
popup = driver.SwitchTo().Window(handle);
if (popup.Title.Contains(title))
{
foundPopupTitle = true;
break;
}
}
if (foundPopupTitle)
{
popup.Close();
}
//switch back to original window
driver.SwitchTo().Window(mainWindow);
IJavaScriptExecutor js = driver as IJavaScriptExecutor;
js.ExecuteScript("window.open()");
String ventanaPrincipal = driver.CurrentWindowHandle;
List<string> listWindow = new List<string>(driver.WindowHandles);
driver.SwitchTo().Window(listWindow[1]);
driver.Navigate().GoToUrl("http:www.google.com");
IWebElement search = driver.FindElement(By.Name("q"));
search.SendKeys("RPA");
string NewWindowHandle = string.Empty;
ReadOnlyCollection<string> windowHandles = driver.WindowHandles;
NewWindowHandle = windowHandles[windowHandles.Count - 1];
driver.SwitchTo().Window(NewWindowHandle);
Related
We are using UIAutomation to monitor the urls for browser, but what we observerd is when ever we start capturing the url the browser are using high cpu and its getting not responding. how come my application effects to browser to use high cpu. This issue is observed in all latest browser only earlier we never faced this kind of issue.
Here is code which i am using to get the url
///--------------------------------------------------------------------------------
/// <summary>
/// Get URL by using AutomatioElement.
/// </summary>
/// <param name="process"></param>
/// <param name="logPrefix"></param>
/// <returns>Url</returns>
private string GetProcessURL(Process process, string logPrefix)
{
AutomationElement UrlBarElement = null;
AutomationElement mainWindowElement = null;
AutomationElement rootElement = null;
try
{
mainWindowElement = AutomationElement.FromHandle(process.MainWindowHandle);
if (mainWindowElement == null)
{
log.Warn(logPrefix + " - Unable to capture the URL as MainWindowElement is Null.");
return null;
}
switch (process.ProcessName)
{
case ApplicationConstants.MicrosoftEdge:
rootElement = AutomationElement.FromHandle(GetDesktopWindow());
foreach (AutomationElement child in rootElement.FindAll(TreeScope.Children, PropertyCondition.TrueCondition))
{
AutomationElement window = GetEdgeCommandsWindow(child);
if (window == null) // not edge
continue;
return GetEdgeUrl(window);
}
break;
case ApplicationConstants.Opera:
UrlBarElement = mainWindowElement.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, ApplicationConstants.OperaNameProperty));
break;
case ApplicationConstants.Chrome:
Condition chromeConditions = new OrCondition(
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit),
new PropertyCondition(AutomationElement.NameProperty, ApplicationConstants.ChromeNameProperty));
UrlBarElement = mainWindowElement.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, ApplicationConstants.ChromeNameProperty));
break;
case ApplicationConstants.FireFox:
Condition fireFoxConditions = new AndCondition(
new PropertyCondition(AutomationElement.NameProperty, ApplicationConstants.FireFoxNameProperty),
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit));
UrlBarElement = mainWindowElement.FindFirst(TreeScope.Descendants, fireFoxConditions);
if (UrlBarElement == null)
{
fireFoxConditions = new OrCondition(
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit),
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Text));
UrlBarElement = mainWindowElement.FindFirst(TreeScope.Descendants, fireFoxConditions);
}
break;
default:
UrlBarElement = mainWindowElement.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit));
break;
}
//Comment Before Deployment.
//Thread.Sleep(5000);
if (UrlBarElement != null)
{
return ((ValuePattern)UrlBarElement.GetCurrentPattern(ValuePattern.Pattern)).Current.Value as string;
}
else
{
log.Info(logPrefix + " - Unable to capture the URL because unable to detect the URLBarelement");
return null;
}
}
catch (Exception exx)
{
}
finally
{
mainWindowElement = null;
process = null;
UrlBarElement = null;
rootElement = null;
//GC.Collect();
}
return null;
}
I'm doing an automation using Selenium with Chrome WebDriver. The application has to do a series of downloads that need to be saved with different names (Data + Report type) and folders that match the type of report I'm downloading.
The problem is that I can only set the default directory when I instantiate a new driver
var chromeOptions = new ChromeOptions();
chromeOptions.AddUserProfilePreference("download.default_directory", downloadDirectory);
chromeOptions.AddUserProfilePreference("intl.accept_languages", "nl");
chromeOptions.AddUserProfilePreference("disable-popup-blocking", "true");
IWebDriver driver = new ChromeDriver(#"location chromeDriver", chromeOptions);
driver.Navigate().GoToUrl(url);
Therefore, I can not rename the file name or select the corresponding directory.
Does anyone have any idea how I can do this?
You can use MS UI Automation with TestStack.White. It's quite difficult but it works for sure.
using System.Text.RegularExpressions;
using System.Windows.Automation;
using TestStack.White.InputDevices;
using TestStack.White.UIItems;
using TestStack.White.UIItems.Finders;
using TestStack.White.UIItems.WindowItems;
...
public class SaveAsWindow
{
AutomationElement _dialog;
Window _win;
public SaveAsWindow(string title)
{
List<Window> winList = TestStack.White.Desktop.Instance.Windows();
foreach (Window win in winList)
{
Regex r = new Regex(title, RegexOptions.IgnoreCase);
Match m = r.Match(win.Title);
if (m.Success)
{
_win = win;
}
}
_dialog = _win.GetElement(SearchCriteria.ByControlType(ControlType.Window));
}
public void Close()
{
Condition condition = new PropertyCondition(AutomationElement.NameProperty, "Cancel");
AutomationElement noButton = _dialog.FindFirst(TreeScope.Children, condition);
System.Windows.Point p = noButton.GetClickablePoint();
Mouse.Instance.Click(p);
}
public string FileName
{
set
{
TextBox fileName =_win.Get<TextBox>(SearchCriteria.ByAutomationId("1001"));
fileName.Text = value;
}
}
public void Save()
{
Condition condition = new PropertyCondition(AutomationElement.AutomationIdProperty, "1");
AutomationElement saveButton = _dialog.FindFirst(TreeScope.Children, condition);
System.Windows.Point p = saveButton.GetClickablePoint();
Mouse.Instance.Click(p);
System.Threading.Thread.Sleep(1000);
}
}
//// Usage
IWebDriver driver = new ChromeDriver(#"location chromeDriver", chromeOptions);
driver.Navigate().GoToUrl(url);
// it did something and save as window appears.
var saveWindow = new SaveAsWindow("title of Chrome browser");
saveWindow.FileName = "c:\what-ever.xlsx";
saveWindow.Save();
I need to get the URL from the active tab from chrome (v47.0.2526.106 m (64-bit)).
I have a method that does work greatly for Firefox / IE, but my method for Chrome is VERY slow and 60% of the time will crash chrome :
public static string GetURL(Process process, string programName, out string url)
{
string temp = null;
if (programName.Equals("chrome"))
{
AutomationElement element = AutomationElement.FromHandle(process.MainWindowHandle);
if (element != null)
{
AutomationElement edit = element.FindFirst(TreeScope.Subtree,
new AndCondition(
new PropertyCondition(AutomationElement.NameProperty, "address and search bar", PropertyConditionFlags.IgnoreCase),
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit)));
temp = ((ValuePattern)edit.GetCurrentPattern(ValuePattern.Pattern)).Current.Value as string;
}
}
url = temp;
return url;
}
So, to my question:
Is there another way to do this efficiently?
I'm trying to read out the TITLE & URL from the Microsoft EDGE Browser.
Doing this with System.Windows.Automation most preferably since the code base already uses this for other problems.
Is it possible with System.Windows.Automation?
How to access the URL?
I'm currently this far:
AutomationId "TitleBar"
ClassName "ApplicationFrameWindow"
Name = [string]
=> Reading out this element gives me the TITLE
=> Walking it's children, I find the item "addressEditBox":
AutomationId "addressEditBox"
ClassName "RichEditBox"
Name "Search or enter web address"
=> I always get back the string "Search or enter web address"
=> This is the control where the url is in, though it isn't updated as the user goes to a website, it always returns a fixed string.
In code:
var digger1 = AutomationElement.FromHandle(process.MainWindowHandle).RootElement.FindAll(TreeScope.Children, Condition.TrueCondition);
foreach(AutomationElement d1 in digger1 {
if(d1.Current.ClassName.Equals("ApplicationFrameWindow")) {
var digger2 = d1.FindAll(TreeScope.Children, Condition.TrueCondition);
foreach(AutomationElement d2 in digger2) {
if(d2.Current.ClassName.Equals("Windows.Ui.Core.CoreWindow")) {
var digger3 = d2.FindAll(TreeScope.Children, Condition.TrueCondition);
foreach(AutomationElement d3 in digger3) {
if(d3.Current.AutomationId.Equals("addressEditBox")) {
var url = d3.Current.Name;
return url;
}
}
}
}
}
}
You're almost there. You just need to get the TextPattern from the addressEditBox element. Here is a full sample Console app that dumps out all currently running Edge's windows on the desktop:
class Program
{
static void Main(string[] args)
{
AutomationElement main = AutomationElement.FromHandle(GetDesktopWindow());
foreach(AutomationElement child in main.FindAll(TreeScope.Children, PropertyCondition.TrueCondition))
{
AutomationElement window = GetEdgeCommandsWindow(child);
if (window == null) // not edge
continue;
Console.WriteLine("title:" + GetEdgeTitle(child));
Console.WriteLine("url:" + GetEdgeUrl(window));
Console.WriteLine();
}
}
public static AutomationElement GetEdgeCommandsWindow(AutomationElement edgeWindow)
{
return edgeWindow.FindFirst(TreeScope.Children, new AndCondition(
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window),
new PropertyCondition(AutomationElement.NameProperty, "Microsoft Edge")));
}
public static string GetEdgeUrl(AutomationElement edgeCommandsWindow)
{
var adressEditBox = edgeCommandsWindow.FindFirst(TreeScope.Children,
new PropertyCondition(AutomationElement.AutomationIdProperty, "addressEditBox"));
return ((TextPattern)adressEditBox.GetCurrentPattern(TextPattern.Pattern)).DocumentRange.GetText(int.MaxValue);
}
public static string GetEdgeTitle(AutomationElement edgeWindow)
{
var adressEditBox = edgeWindow.FindFirst(TreeScope.Children,
new PropertyCondition(AutomationElement.AutomationIdProperty, "TitleBar"));
return adressEditBox.Current.Name;
}
[DllImport("user32")]
public static extern IntPtr GetDesktopWindow();
}
I'm writing a system tray app that needs to check if an internal web based app is open.
I can check IE using the following:
SHDocVw.ShellWindows shellWindows = new SHDocVw.ShellWindows();
string filename;
bool sdOpen = false;
foreach (SHDocVw.InternetExplorer ie in shellWindows)
{
filename = Path.GetFileNameWithoutExtension(ie.FullName).ToLower();
if (filename.Equals("iexplore"))
{
string[] urlParts = (ie.LocationURL.ToString()).Split('/');
string website = urlParts[2];
if (website == "myApp:8080") { sdOpen = true; };
}
}
if (sdOpen) { Console.WriteLine("App is open"); } else { Console.WriteLine("App is not open"); };
Console.ReadKey(true);
However, some of the users using the system prefer Chrome or Firefox.
How can I do the same as above (i.e. get the urls of any open tabs in the browser) for Chrome and Firefox? (I'm not going to bother with other browsers as these are the only ones in use in our organisation.)
It's specific for every browser. That's for the major ones:
Internet Explorer - You can use SHDocVw (like you did)
Firefox - You can get the URL using DDE (source below)
Chrome - You can get the URL while enumerating all the child windows untill you get to the control with class "Chrome_OmniboxView" and then get the text using GetWindowText
Opera - You can use the same thing as Firefox, but with "opera"
Safari - There is no known method since it uses custom drawn controls
EDIT: Since 2014, Chrome has changed and you need to get the URL with Acessibility.
Code to get the URL from Firefox/Opera using DDE (which used NDDE - the only good DDE wrapper for .NET):
//
// usage: GetBrowserURL("opera") or GetBrowserURL("firefox")
//
private string GetBrowserURL(string browser) {
try {
DdeClient dde = new DdeClient(browser, "WWW_GetWindowInfo");
dde.Connect();
string url = dde.Request("URL", int.MaxValue);
string[] text = url.Split(new string[] { "\",\"" }, StringSplitOptions.RemoveEmptyEntries);
dde.Disconnect();
return text[0].Substring(1);
} catch {
return null;
}
}
Using UIAutomation - get urls for FireFox and Chrome:
else if (browser == BrowserType.Chrome)
{
//"Chrome_WidgetWin_1"
Process[] procsChrome = Process.GetProcessesByName("chrome");
foreach (Process chrome in procsChrome)
{
// the chrome process must have a window
if (chrome.MainWindowHandle == IntPtr.Zero)
{
continue;
}
//AutomationElement elm = AutomationElement.RootElement.FindFirst(TreeScope.Children,
// new PropertyCondition(AutomationElement.ClassNameProperty, "Chrome_WidgetWin_1"));
// find the automation element
AutomationElement elm = AutomationElement.FromHandle(chrome.MainWindowHandle);
// manually walk through the tree, searching using TreeScope.Descendants is too slow (even if it's more reliable)
AutomationElement elmUrlBar = null;
try
{
// walking path found using inspect.exe (Windows SDK) for Chrome 29.0.1547.76 m (currently the latest stable)
var elm1 = elm.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "Google Chrome"));
var elm2 = TreeWalker.ControlViewWalker.GetLastChild(elm1); // I don't know a Condition for this for finding :(
var elm3 = elm2.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, ""));
var elm4 = elm3.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ToolBar));
elmUrlBar = elm4.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "Address and search bar"));
}
catch
{
// Chrome has probably changed something, and above walking needs to be modified. :(
// put an assertion here or something to make sure you don't miss it
continue;
}
// make sure it's valid
if (elmUrlBar == null)
{
// it's not..
continue;
}
// elmUrlBar is now the URL bar element. we have to make sure that it's out of keyboard focus if we want to get a valid URL
if ((bool)elmUrlBar.GetCurrentPropertyValue(AutomationElement.HasKeyboardFocusProperty))
{
continue;
}
// there might not be a valid pattern to use, so we have to make sure we have one
AutomationPattern[] patterns = elmUrlBar.GetSupportedPatterns();
if (patterns.Length == 1)
{
string ret = "";
try
{
ret = ((ValuePattern)elmUrlBar.GetCurrentPattern(patterns[0])).Current.Value;
}
catch { }
if (ret != "")
{
// must match a domain name (and possibly "https://" in front)
if (Regex.IsMatch(ret, #"^(https:\/\/)?[a-zA-Z0-9\-\.]+(\.[a-zA-Z]{2,4}).*$"))
{
// prepend http:// to the url, because Chrome hides it if it's not SSL
if (!ret.StartsWith("http"))
{
ret = "http://" + ret;
}
return ret;
}
}
continue;
}
}
}
else if (browser == BrowserType.Firefox)
{
AutomationElement root = AutomationElement.RootElement.FindFirst(TreeScope.Children,
new PropertyCondition(AutomationElement.ClassNameProperty, "MozillaWindowClass"));
Condition toolBar = new AndCondition(
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ToolBar),
new PropertyCondition(AutomationElement.NameProperty, "Browser tabs"));
var tool = root.FindFirst(TreeScope.Children, toolBar);
var tool2 = TreeWalker.ControlViewWalker.GetNextSibling(tool);
var children = tool2.FindAll(TreeScope.Children, Condition.TrueCondition);
foreach (AutomationElement item in children)
{
foreach (AutomationElement i in item.FindAll(TreeScope.Children, Condition.TrueCondition))
{
foreach (AutomationElement ii in i.FindAll(TreeScope.Element, Condition.TrueCondition))
{
if (ii.Current.LocalizedControlType == "edit")
{
if (!ii.Current.BoundingRectangle.X.ToString().Contains("empty"))
{
ValuePattern activeTab = ii.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
var activeUrl = activeTab.Current.Value;
return activeUrl;
}
}
}
}
}
}
Maybe this code can help something;
Thanks to BLEZ for share this code. I use this code to capture unique addresses from firefox and add them to a listbox. But I think this is not for Chrome right?
(you Should add NDde.dll to your project, to do this go to solution explorer right click to References-> add Reference->Browse-> find that DLL (http://ndde.codeplex.com/ from binary folder.))
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using NDde.Client;
namespace WindowsFormsApplication9
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
timer1.Enabled = true;
}
private string GetBrowserURL(string browser)
{
try
{
DdeClient dde = new DdeClient(browser, "WWW_GetWindowInfo");
dde.Connect();
string url = dde.Request("URL", int.MaxValue);
string[] text = url.Split(new string[] { "\",\"" }, StringSplitOptions.RemoveEmptyEntries);
dde.Disconnect();
return text[0].Substring(1);
}
catch
{
return null;
}
}
private void timer1_Tick(object sender, EventArgs e)
{
int j=0;
for (int i = 0; i < listBox1.Items.Count; i++)
{
if (listBox1.Items[i].ToString() == GetBrowserURL("Firefox"))
{
break;
}
else
{
j++;
}
}
if (j == listBox1.Items.Count)
{
listBox1.Items.Add(GetBrowserURL("Firefox"));
}
}
}
}
Below code work pretty well with Chrome Version 58.0.3029.110:
Please add reference of UIAutomationClient and UIAutomationProvider from Assembly provided by .NET.
foreach (Process proc in procsChrome)
{
// the chrome process must have a window
if (proc.MainWindowHandle == IntPtr.Zero)
continue;
// to find the tabs we first need to locate something reliable - the 'New Tab' button
AutomationElement root = AutomationElement.FromHandle(proc.MainWindowHandle);
var SearchBar = root.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "Address and search bar"));
if (SearchBar != null)
return (string)SearchBar.GetCurrentPropertyValue(ValuePatternIdentifiers.ValueProperty);
}