In my scenario, I'm verifying whether clicking on a link navigates to another page (verifying for the page title). IE, FF and chrome return 2 as expected but Opera returns 4. I didn't have any other Opera instances opened at the time of running tests. It clicks on the link and required page is opened but WindowHandles returns 4.
Code:
string BaseWindow = Drivers._driverInstance.CurrentWindowHandle;
Drivers._driverInstance.SwitchTo().Frame(Drivers._driverInstance.FindElement(By.ClassName("iframe-fix")));
if (Drivers._driverInstance.GetType().Name.ToString() == "InternetExplorerDriver")
{
IJavaScriptExecutor js = (IJavaScriptExecutor)Drivers._driverInstance;
js.ExecuteScript("arguments[0].click();", Drivers._driverInstance.FindElement(By.LinkText("Professional Services.")));
}
else
{
Drivers._driverInstance.FindElement(By.LinkText("Professional Services.")).Click();
}
System.Collections.ObjectModel.ReadOnlyCollection<string> handles = Drivers._driverInstance.WindowHandles;
if (handles.Count == 2)
{
foreach (string handle in handles)
{
if (handle != BaseWindow)
{
string title = Drivers._driverInstance.SwitchTo().Window(handle).Title;
Assert.AreEqual("title of the page", Drivers._driverInstance.Title);
}
}
}
else
{
Assert.Fail("WindowHandles returns " + handles.Count + " instead of 2");
}
Drivers._driverInstance.SwitchTo().Window(BaseWindow);
Can someone suggest why Opera returns 4 instead of 2.
Thanks.
The Opera driver doesn't return the right number of handles. This issue has already been reported to the project but it seems that the project is no longer maintained:
https://github.com/operasoftware/operachromiumdriver/issues/15
I encountered the same thing as you with Opera driver, plus (if I remember it right), the CurrentWindowHandle property doesn't work either.
Workaround:
public static void SwitchToPopup(TestTarget target, bool toPopup)
{
if (target.IsOpera)
{
if (toPopup)
{
_windowIndex += 3;
new WebDriverWait(target.Driver, TimeSpan.FromSeconds(DefaultTimeoutInSeconds)).Until(d => d.WindowHandles.Count > _windowIndex);
}
else
{
_windowIndex -= 3;
}
target.Driver.SwitchTo().Window(target.Driver.WindowHandles[_windowIndex]);
}
else
{
IEnumerable<string> windowHandles = toPopup ? target.Driver.WindowHandles : target.Driver.WindowHandles.Reverse();
bool bFound = false;
foreach (string windowHandle in windowHandles)
{
if (bFound)
{
target.Driver.SwitchTo().Window(windowHandle);
break;
}
bFound = windowHandle == target.Driver.CurrentWindowHandle;
}
}
}
Related
I am developing a plugin for an application.
The application is calling the plugin when it loads and the plugin start and endless look in this form:
const int sleepTime = 60 * 1000;
while (true)
{
try
{
Thread.Sleep(sleepTime);
//vaProxy.WriteToLog("Invoking checker...", "Green");
Dictionary<string, dynamic> SessionState = vaProxy.SessionState;
Dictionary<string, CallBack> callBacks = vaProxy.SessionState["CallBacks"];
//Checks will only occur in the Pit
if (!Config.IsProcessRunning("Falcon BMS")) continue;
var isJoystickProfileLoaded = vaProxy.GetBoolean("isJoystickProfileLoaded");
bool isProfileLoaded = isJoystickProfileLoaded == true;
if (ConfigFile.IsTrue(vaProxy, "EnableJoystickLoaded") &&
!vaProxy.SessionState["JanJanJoystickIsLoaded"] && !isProfileLoaded)
{
Config.SaySomething("Verify Joystick profile is loaded");
}
if (!SharedMem.GetStatus("isFlying")) continue;
if (ConfigFile.GetEntry(vaProxy, "AutoAVTR") == "True" &&
!SharedMem.GetStatus("isOnGround"))
{
//Check AVTR status
if (!SharedMem.GetStatus("AVTR"))
{
callBacks["SimAVTRSwitchOn"]
.Press(vaProxy, sayWhat: "Start recording", waitAfter: 500);
}
}
if (SessionState.ContainsKey("JanJanIsAutoSave") && !SharedMem.GetStatus("isOnGround"))
{
if (vaProxy.SessionState["JanJanIsAutoSave"])
{
//vaProxy.WriteToLog("Checking save time", "Green");
//save game...
GameIO.SaveGame(vaProxy);
}
}
if (!SessionState.ContainsKey("JanJanIsStatusReport")) continue;
if (vaProxy.SessionState["JanJanIsStatusReport"])
{
Sim.MyStatus(vaProxy);
}
}
catch (Exception ex)
{
vaProxy.WriteToLog("Dynamic Checks\n" + ex.Message, "Red");
Console.Beep();
}
}
vaProxy is a dynamic variable controlled by the sending application.
I suspect that this endless loop is causing a memory leak.
How can I prevent this?
Should I use the using() statement and if yes how?
I can convert the "DO SOME STUFF" to a class, will that help?
I was calling a function not created by be which did not dispose of itself properly.
Placing it in a using(){...} block solved it.
I would like to be able to loop through all the tabs on a chrome page and close any tabs which are youtube pages.
I have done some googling & found the code below. There are two (well probably more) issues. Firstly I have create a WPF application and added the System.Windows.Automation namespace (using visual studio 2015 .net 4.5) but AutomationElement is not recognised.
Also I am unsure of how to loop through the tabs and test if a page is a youtube page.
Process[] procsChrome = Process.GetProcessesByName("chrome");
if (procsChrome.Length <= 0)
return null;
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)
{
AutomationPattern[] patterns = SearchBar.GetSupportedPatterns();
if(patterns.Length > 0)
{
ValuePattern val = (ValuePattern)SearchBar.GetCachedPattern(patterns[0]);
if (val.Current.Value.Contains("youtube.com") || val.Current.Value.Contains("youtube.co.uk"))
proc.Close();
}
}
}
System.Windows.Automation is in UIAutomationClient.dll.Did you add UIAutomationClient.dll as a reference to your project?
Check for value "youtube".
if (SearchBar != null)
{
AutomationPattern[] patterns = SearchBar.GetSupportedPatterns();
if (patterns.Length > 0)
{
ValuePattern val = (ValuePattern)SearchBar.GetCurrentPattern(patterns[0]);
if(val.Current.Value.Contains("youtube.com"))
proc.Close();
}
}
Based on your question, I wrote a small program to achieve this. Let me know if it works.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;
class Program
{
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
static void Main()
{
Process[] procs = Process.GetProcessesByName("chrome");
if (procs.Length == 0)
{
Console.WriteLine("Google Chrome is not currently open");
return;
}
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
Thread.Sleep(100);
int next = 1;
string title;
while (next <= numTabs)
{
try
{
title = Process.GetProcessById(id).MainWindowTitle.Replace(" - Google Chrome", "");
if (title.ToLower().Contains("youtube"))
{
SendKeys.SendWait("^{w}"); // close tab.
Thread.Sleep(100);
}
next++;
SendKeys.SendWait("^{TAB}"); // change focus to next tab
Thread.Sleep(100);
}
catch (Exception ex)
{
// Chrome internal process, doesn't have tab.
}
}
if (isMinimized)
{
ShowWindow(hWnd, 6); // minimize again
Thread.Sleep(100);
}
hWnd = Process.GetCurrentProcess().MainWindowHandle;
SetForegroundWindow(hWnd);
Thread.Sleep(100);
Console.WriteLine("Closed youtube tabs");
Console.ReadKey();
}
}
It can be done easily with AutoHotkey
Here is a script that will open Chrome, loop all tabs and close the YouTube ones, then minimize Chrome again
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
SetTitleMatchMode, 2
IfWinExist, ahk_class Chrome_WidgetWin_1
{
WinActivate, Chrome
WinGetActiveTitle, ActiveWindowOld
Loop {
Send, ^{Tab}
Sleep, 500
WinGetActiveTitle, ActiveWindow
if (ActiveWindow = ActiveWindowOld)
{
break
}
IfInString, ActiveWindow, YouTube - Google Chrome
{
Send, ^{w}
}
}
WinMinimize, Chrome
}
Credit: https://autohotkey.com/board/topic/148742-cycling-through-all-chrome-tabs-and-closing-a-specific-tab/
if (SearchBar != null)
{
bool valuePatternExist = (bool)SearchBar.GetCurrentPropertyValue(AutomationElement.IsValuePatternAvailableProperty);
if (valuePatternExist)
{
ValuePattern val = SearchBar.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
if (val.Current.Value.Contains("youtube.com") || val.Current.Value.Contains("youtube.co.uk"))
proc.Close();
}
}
Killing just Chrome tabs with YouTube doesn't really seem like a solution to the actual problem here. I think it would fair easier and more reliable to force all the workstations to go to sleep.
Something from this post ought to do the trick.
rundll32.exe powrprof.dll,SetSuspendState 0,1,0 perhaps?
I am using this code from a C# application to find a tab in Google Chrome:
Process[] procsChrome = Process.GetProcessesByName("chrome");
foreach (Process chrome in procsChrome)
{
// the chrome process must have a window
if (chrome.MainWindowHandle == IntPtr.Zero)
{
continue;
}
AutomationElement root = AutomationElement.FromHandle(chrome.MainWindowHandle);
/*
Condition condNewTab = new PropertyCondition(AutomationElement.NameProperty, "Nueva pestaƱa");
AutomationElement elmNewTab = root.FindFirst(TreeScope.Descendants, condNewTab);
// get the tabstrip by getting the parent of the 'new tab' button
TreeWalker treewalker = TreeWalker.ControlViewWalker;
AutomationElement elmTabStrip = treewalker.GetParent(elmNewTab);
*/
// loop through all the tabs and get the names which is the page title
Condition condTabItem = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TabItem);
foreach (AutomationElement tabitem in root.FindAll(TreeScope.Descendants, condTabItem))
{
Console.WriteLine(tabitem.Current.Name);
// I NEED TO ACTIVATE THE TAB HERE
break;
}
Condition condUrl = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit);
foreach (AutomationElement edit in root.FindAll(TreeScope.Descendants, condUrl))
{
string value = ((System.Windows.Automation.ValuePattern)edit.GetCurrentPattern(ValuePattern.Pattern)).Current.Value;
Console.WriteLine(value);
}
}
I need to select certain tab item using UI Automation. How can I do it?
For those desperate souls, still searching for an answer. Here is my method, based solely on UI Automation API, without focusing windows and sending click events or hotkeys. To use the code below you need to use interop reference for UIAutomationCore.dll as described by Guy Barker.
Process[] allChromeProcesses = Process.GetProcessesByName("chrome");
Process[] mainChromes = allChromeProcesses.Where(p => !String.IsNullOrEmpty(p.MainWindowTitle)).ToArray();
//...
//Here you need to check if you have found correct chrome instance
//...
var uiaClassObject = new CUIAutomation();
IUIAutomationElement chromeMainUIAElement = uiaClassObject.ElementFromHandle(mainChromes[0].MainWindowHandle);
//UIA_ControlTypePropertyId =30003, UIA_TabItemControlTypeId = 50019
IUIAutomationCondition chromeTabCondition = uiaClassObject.CreatePropertyCondition(30003, 50019);
var chromeTabCollection = chromeMainUIAElement.FindAll(TreeScope.TreeScope_Descendants, chromeTabCondition);
//UIA_LegacyIAccessiblePatternId = 10018, 0 -> Number of Chrome tab you want to activate
var lp = chromeTabCollection.GetElement(0).GetCurrentPattern(10018) as IUIAutomationLegacyIAccessiblePattern;
lp.DoDefaultAction();
The only thing you need to remember is that searching of tabs for minimized Chrome window is impossible.
I needed to solve similar problem. Since Chrome doesn't fully implement Windows Automation features, it has to be implemented differently.
Thanks to this GitHub project I was able to activate the correct Chrome tab. The trick is to press Ctrl+tab index to activate the tab in the case its position is between 1 and 8 (9 switches to the last tab, see Chromebook keyboard shortcuts). For tabs appearing further in the collection Ctrl+Tab is pressed repeatedly until the desired tab is reached.
However, it is not that easy, since sometimes the tabs can appear in the UI automation collection out of order. I have fixed this by calling the TryGetClickablePoint method for each tab and sorting the tabs by the X coordinate of the point returned.
bool ActivateChromeTab(string title)
{
Process[] procsChrome = Process.GetProcessesByName("chrome");
foreach (Process proc in procsChrome)
{
if (proc.MainWindowHandle == IntPtr.Zero)
{
continue;
}
AutomationElement root = AutomationElement.FromHandle(proc.MainWindowHandle);
Condition condNewTab = new PropertyCondition(AutomationElement.NameProperty, "New Tab");
AutomationElement elmNewTab = root.FindFirst(TreeScope.Descendants, condNewTab);
TreeWalker treewalker = TreeWalker.ControlViewWalker;
AutomationElement elmTabStrip = treewalker.GetParent(elmNewTab);
Condition condTabItem = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TabItem);
var index = 0;
var tabItems = elmTabStrip.FindAll(TreeScope.Children, condTabItem);
var coll = new List<AutomationElement>();
foreach (AutomationElement element in tabItems)
{
coll.Add(element);
}
bool NameMatch(string name)
{
return name == title || name.StartsWith(title + " ");
}
// short-circuit the search when no searched string cannot be found
if (!coll.Any(e => NameMatch(e.Current.Name)))
{
continue;
}
var t = new Stopwatch();
t.Start();
var withPoints = coll.AsParallel().Select(e =>
{
var point = new System.Windows.Point(int.MaxValue, int.MaxValue);
if (e.TryGetClickablePoint(out point))
{
}
return new
{
Name = e.Current.Name,
Element = e,
Point = point
};
}).OrderBy(e => e.Point.X);
foreach (var tabItem in withPoints)
{
index++;
var name = tabItem.Name;
if (NameMatch(name))
{
SetForegroundWindow(proc.MainWindowHandle); // activate window
Select(index); // select tab
return true;
}
}
}
return false;
}
And the method to select the tab:
public void Select(int tabIndex)
{
const int maxShortcutNumber = 8;
if (tabIndex <= 0) { return; }
KeyDown(LCtrl);
if (tabIndex <= maxShortcutNumber)
{
KeyPress(GetKeyNumber(tabIndex));
}
else
{
KeyPress(GetKeyNumber(maxShortcutNumber));
for (var i = 0; i < tabIndex - maxShortcutNumber; i++)
{
i.Dump();
const int timeToDigestPreviousKeyPress = 75;
Thread.Sleep(timeToDigestPreviousKeyPress);
KeyPress(Tab);
}
}
KeyUp(LCtrl);
}
And keyboard handling methods (adapted from KeyboardSend class)
[DllImport("user32.dll")]
private static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
public static byte GetKeyNumber(int number)
{
if (number < 0 || number > 9)
throw new ApplicationException("Invalid number for key press.");
return (byte)(0x30 + number);
}
public static void KeyDown(byte vKey)
{
keybd_event(vKey, 0, KEYEVENTF_EXTENDEDKEY, 0);
}
public static void KeyUp(byte vKey)
{
keybd_event(vKey, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
public static void KeyPress(byte vKey)
{
KeyDown(vKey);
KeyUp(vKey);
}
public static byte LCtrl = 0xA2; //VK_LCONTROL
public static byte LWin = 0x5B; //VK_LWIN
public static byte LAlt = 0xA4; //VK_LMENU
public static byte Tab = 0x09; //VK_TAB
private const int KEYEVENTF_EXTENDEDKEY = 1;
private const int KEYEVENTF_KEYUP = 2;
I use the code
windowHandles = SeleniumHelper.WindowHandles();
// click...
if (SeleniumHelper.WindowHandles().Count > windowHandles.Count)
{
windowHandles = SeleniumHelper.WindowHandles();
while (pageTitle == SeleniumHelper.Driver.Title)
{
SeleniumHelper.Driver.SwitchTo().Window(windowHandles[windowHandles.Count - 1]);
Thread.Sleep(2000);
}
// do something...
SeleniumHelper.Driver.Close();
SeleniumHelper.BackToMainWindow();
}
The problem is that the driver finds the window, but does not switch to it.
Maybe there is a different way to switch to another window, like switch by javascript?
The problem is in
SeleniumHelper.Driver.SwitchTo().Window(windowHandles[windowHandles.Count - 1]);
You always switch to the last window regardless the while loop condition. Try this
string currentWindoe = SeleniumHelper.Driver.CurrentWindowHandle();
while (pageTitle != SeleniumHelper.Driver.Title)
{
SeleniumHelper.Driver.SwitchTo().Window(SeleniumHelper.Driver.CurrentWindowHandle());
Thread.Sleep(2000);
}
Or
string currentWindow = SeleniumHelper.Driver.CurrentWindowHandle();
foreach (string window in SeleniumHelper.Driver.WindowHandles())
{
if (!window.equals(currentWindow))
{
SeleniumHelper.Driver.SwitchTo().Window(window));
}
}
I am breaking a list into chunks and processing it as below:
foreach (var partialist in breaklistinchunks(chunksize))
{
try
{
do something
}
catch
{
print error
}
}
public static class IEnumerableExtensions
{
public static IEnumerable<List<T>> BreakListinChunks<T>(this IEnumerable<T> sourceList, int chunkSize)
{
List<T> chunkReturn = new List<T>(chunkSize);
foreach (var item in sourceList)
{
chunkReturn.Add(item);
if (chunkReturn.Count == chunkSize)
{
yield return chunkReturn;
chunkReturn = new List<T>(chunkSize);
}
}
if (chunkReturn.Any())
{
yield return chunkReturn;
}
}
}
If there is an error, I wish to run the chunk again. Is it possible to find the particular chunk number where we received the error and run that again ?
The batches have to be executed in sequential order .So if batch#2 generates an error, then I need to be able to run 2 again, if it fails again. I just need to get out of the loop for good .
List<Chunk> failedChunks = new List<Chunk>();
foreach (var partialist in breaklistinchunks(chunksize))
{
try
{
//do something
}
catch
{
//print error
failedChunks.Add(partiallist);
}
}
// attempt to re-process failed chunks here
I propose this answer based on your comment to Aaron's answer.
The batches have to be executed in sequential order .So if 2 is a problem , then I need to be able to run 2 again, if it fails again. I just need to get out of the loop for good.
foreach (var partialist in breaklistinchunks(chunksize))
{
int fails = 0;
bool success = false;
do
{
try
{
// do your action
success = true; // should be on the last line before the 'catch'
}
catch
{
fails += 1;
// do something about error before running again
}
}while (!success && fails < 2);
// exit the iteration if not successful and fails is 2
if (!success && fails >= 2)
break;
}
I made a possible solution for you if you don't mind switching from Enumerable to Queue, which kind of fits given the requirements...
void Main()
{
var list = new Queue<int>();
list.Enqueue(1);
list.Enqueue(2);
list.Enqueue(3);
list.Enqueue(4);
list.Enqueue(5);
var random = new Random();
int chunksize = 2;
foreach (var chunk in list.BreakListinChunks(chunksize))
{
foreach (var item in chunk)
{
try
{
if(random.Next(0, 3) == 0) // 1 in 3 chance of error
throw new Exception(item + " is a problem");
else
Console.WriteLine (item + " is OK");
}
catch (Exception ex)
{
Console.WriteLine (ex.Message);
list.Enqueue(item);
}
}
}
}
public static class IEnumerableExtensions
{
public static IEnumerable<List<T>> BreakListinChunks<T>(this Queue<T> sourceList, int chunkSize)
{
List<T> chunkReturn = new List<T>(chunkSize);
while(sourceList.Count > 0)
{
chunkReturn.Add(sourceList.Dequeue());
if (chunkReturn.Count == chunkSize || sourceList.Count == 0)
{
yield return chunkReturn;
chunkReturn = new List<T>(chunkSize);
}
}
}
}
Outputs
1 is a problem
2 is OK
3 is a problem
4 is a problem
5 is a problem
1 is a problem
3 is OK
4 is OK
5 is OK
1 is a problem
1 is OK
One possibility would be to use a for loop instead of a foreach loop and use the counter as a means to determine where an error occurred. Then you could continue from where you left off.
You can use break to exit out of the loop as soon as a chunk fails twice:
foreach (var partialList in breaklistinchunks(chunksize))
{
if(!TryOperation(partialList) && !TryOperation(partialList))
{
break;
}
}
private bool TryOperation<T>(List<T> list)
{
try
{
// do something
}
catch
{
// print error
return false;
}
return true;
}
You could even make the loop into a one-liner with LINQ, but it is generally bad practice to combine LINQ with side-effects, and it's not very readable:
breaklistinchunks(chunksize).TakeWhile(x => TryOperation(x) || TryOperation(x));