diff --git a/.gitignore b/.gitignore index 098d4d74..1c390528 100644 --- a/.gitignore +++ b/.gitignore @@ -106,4 +106,7 @@ packages # our output folder for build artifacts build -Thumbs.db \ No newline at end of file +Thumbs.db + +# sample project +src/WhiteProject/* \ No newline at end of file diff --git a/src/.nuget/packages.config b/src/.nuget/packages.config new file mode 100644 index 00000000..a8e522d2 --- /dev/null +++ b/src/.nuget/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/TestStack.White.sln b/src/TestStack.White.sln index d79fdf24..dbc26aa3 100644 --- a/src/TestStack.White.sln +++ b/src/TestStack.White.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.40629.0 +# Visual Studio Express 2013 for Windows Desktop +VisualStudioVersion = 12.0.21005.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1BCBA4C4-8C47-496C-B0D4-FDE9D066ED27}" ProjectSection(SolutionItems) = preProject @@ -57,6 +57,13 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinformsTodo", "Samples\Win EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Todo.Core", "Samples\Todo.Core\Todo.Core.csproj", "{F5604A48-3BD0-4418-83F1-3ECC03DD2FF0}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{81F4B351-6572-4CEA-9E39-B1978CB6DFA2}" + ProjectSection(SolutionItems) = preProject + .nuget\packages.config = .nuget\packages.config + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WhiteProject", "WhiteProject\WhiteProject.csproj", "{39964358-1A5B-4F78-9520-1B106F70CE72}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -131,6 +138,10 @@ Global {F5604A48-3BD0-4418-83F1-3ECC03DD2FF0}.Debug|Any CPU.Build.0 = Debug|Any CPU {F5604A48-3BD0-4418-83F1-3ECC03DD2FF0}.Release|Any CPU.ActiveCfg = Release|Any CPU {F5604A48-3BD0-4418-83F1-3ECC03DD2FF0}.Release|Any CPU.Build.0 = Release|Any CPU + {39964358-1A5B-4F78-9520-1B106F70CE72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39964358-1A5B-4F78-9520-1B106F70CE72}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39964358-1A5B-4F78-9520-1B106F70CE72}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39964358-1A5B-4F78-9520-1B106F70CE72}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -138,13 +149,13 @@ Global GlobalSection(NestedProjects) = preSolution {24929CE3-4000-4600-8830-503BE6A2BA42} = {1AF6AEE7-C9D5-4B05-BEFE-AB61D83667D4} {492E6340-32CC-4D03-A9C4-36FB4C40CF5C} = {1AF6AEE7-C9D5-4B05-BEFE-AB61D83667D4} - {DFCF10D7-82C1-4916-A829-B520E8C65321} = {37EE7583-778A-481E-ADD4-52A357BE95F0} - {5620401C-0857-4F7C-869A-F3F56DF1697F} = {37EE7583-778A-481E-ADD4-52A357BE95F0} {EC32732F-6CB9-4078-B3A8-E3F038D5C2E1} = {1AF6AEE7-C9D5-4B05-BEFE-AB61D83667D4} {C186FEFC-D0B7-4FED-822D-688302B3B8A0} = {1AF6AEE7-C9D5-4B05-BEFE-AB61D83667D4} + {DFCF10D7-82C1-4916-A829-B520E8C65321} = {37EE7583-778A-481E-ADD4-52A357BE95F0} + {5620401C-0857-4F7C-869A-F3F56DF1697F} = {37EE7583-778A-481E-ADD4-52A357BE95F0} + {F5604A48-3BD0-4418-83F1-3ECC03DD2FF0} = {37EE7583-778A-481E-ADD4-52A357BE95F0} + {D0ED95E7-584A-45B9-B8E2-1A7ADD78C366} = {DFCF10D7-82C1-4916-A829-B520E8C65321} {3CC2654B-2108-4A38-AFFF-82718703EBE3} = {5620401C-0857-4F7C-869A-F3F56DF1697F} {51509F9D-12C4-4043-A68F-16A300F38FDB} = {5620401C-0857-4F7C-869A-F3F56DF1697F} - {D0ED95E7-584A-45B9-B8E2-1A7ADD78C366} = {DFCF10D7-82C1-4916-A829-B520E8C65321} - {F5604A48-3BD0-4418-83F1-3ECC03DD2FF0} = {37EE7583-778A-481E-ADD4-52A357BE95F0} EndGlobalSection EndGlobal diff --git a/src/TestStack.White/AutomationElementSearch/DescendantFinder.cs b/src/TestStack.White/AutomationElementSearch/DescendantFinder.cs index 23b9dbc6..160bda25 100644 --- a/src/TestStack.White/AutomationElementSearch/DescendantFinder.cs +++ b/src/TestStack.White/AutomationElementSearch/DescendantFinder.cs @@ -1,13 +1,17 @@ +using Castle.Core.Logging; using System; using System.Collections.Generic; using System.Linq; using System.Windows.Automation; +using TestStack.White.Configuration; +using TestStack.White.UIItems.Finders; namespace TestStack.White.AutomationElementSearch { public class DescendantFinder : IDescendantFinder { private readonly AutomationElement automationElement; + private readonly ILogger logger = CoreAppXmlConfiguration.Instance.LoggerFactory.Create(typeof(DescendantFinder)); public DescendantFinder(AutomationElement automationElement) { @@ -28,6 +32,17 @@ public virtual AutomationElement Descendant(Condition condition) public virtual List Descendants(AutomationSearchCondition automationSearchCondition) { var collection = automationElement.FindAll(TreeScope.Descendants, automationSearchCondition.Condition); + + //Automation elements identified in current window... + //AutomationElement[] elementsArray = new AutomationElement[collection.Count]; + + //collection.CopyTo(elementsArray, 0); + + //foreach (AutomationElement e in elementsArray) + //{ + // logger.InfoFormat("Element Automation Id: ({0})..", e.Current.AutomationId); + //} + var enumerable = collection.Cast(); return new List(enumerable); } diff --git a/src/TestStack.White/Interceptors/CoreInterceptor.cs b/src/TestStack.White/Interceptors/CoreInterceptor.cs index 91163edb..f56a8d24 100644 --- a/src/TestStack.White/Interceptors/CoreInterceptor.cs +++ b/src/TestStack.White/Interceptors/CoreInterceptor.cs @@ -25,8 +25,9 @@ public virtual void Intercept(IInvocation invocation) { CoreAppXmlConfiguration.Instance.Interceptors.Process(invocation, coreInterceptContext); } - catch (Exception) + catch (Exception e) { + logger.Error(e.Message); logger.Error(DynamicProxyInterceptors.ToString(invocation)); throw; } diff --git a/src/TestStack.White/Mappings/ControlDictionary.cs b/src/TestStack.White/Mappings/ControlDictionary.cs index 88e1d7a4..befd6dc7 100644 --- a/src/TestStack.White/Mappings/ControlDictionary.cs +++ b/src/TestStack.White/Mappings/ControlDictionary.cs @@ -154,6 +154,10 @@ public virtual Type GetTestControlType(string className, string name, ControlTyp if (isPrimary.Length == 1) return isPrimary.Single().TestControlType; + //Get the first TestControldType when 'dictionaryItems' contains multiple elements... + var isFirstItem = dictionaryItems.First(); + return isFirstItem.TestControlType; + throw new ControlDictionaryException(string.Format( "Multiple TestControls found for ControlType={0} and FrameworkId:{1} - {2}", controlType.LocalizedControlType, frameWorkId, diff --git a/src/TestStack.White/TestStack.White.csproj b/src/TestStack.White/TestStack.White.csproj index 65b07908..73dd3b70 100644 --- a/src/TestStack.White/TestStack.White.csproj +++ b/src/TestStack.White/TestStack.White.csproj @@ -62,8 +62,13 @@ 1591, 1570 - + ..\packages\Castle.Core.3.3.0\lib\net40-client\Castle.Core.dll + True + + + ..\packages\Castle.Windsor.3.3.0\lib\net40\Castle.Windsor.dll + True diff --git a/src/TestStack.White/UIItems/Finders/SearchConditionFactory.cs b/src/TestStack.White/UIItems/Finders/SearchConditionFactory.cs index 5d55b6f8..98ba3624 100644 --- a/src/TestStack.White/UIItems/Finders/SearchConditionFactory.cs +++ b/src/TestStack.White/UIItems/Finders/SearchConditionFactory.cs @@ -1,8 +1,11 @@ using System; using System.Linq; using System.Windows.Automation; +using System.Xml; +using System.Xml.XPath; using TestStack.White.Mappings; using TestStack.White.UIItems.Custom; +using TestStack.White.UIItems.WindowItems; namespace TestStack.White.UIItems.Finders { @@ -41,6 +44,72 @@ public static SearchCondition CreateForAutomationId(string id) new AutomationElementProperty(id, "AutomationId", AutomationElement.AutomationIdProperty)); } + /// + /// Getting the objects (AutomationElement) hierarchy of the given window + /// Create SimpleSearchCondition with AutomationId for given xpath + /// + /// + /// + /// + public static SearchCondition CreateForXPath(string xpath, Window window) + { + XmlDocument xmlDoc = new XmlDocument(); + string hierarchy = window.GetHierarchy(window.AutomationElement); + + xmlDoc.LoadXml(hierarchy); + XmlNodeList nodeList = xmlDoc.SelectNodes(xpath); + if (nodeList.Count == 0) + { + throw new Exception("No element found for given XPath: " + xpath); + } + else if (nodeList.Count > 1) + { + throw new Exception("Multiple elements found for given XPath: " + xpath); + } + else + { + foreach (XmlNode node in nodeList) + { + var automationId = node.Attributes["AutomationId"].Value; + var className = node.Attributes["ClassName"].Value; + //var controlType = node.Attributes["ControlType"].Value; + var frameworkId = node.Attributes["FrameworkId"].Value; + var name = node.Attributes["Name"].Value; + var helpText = node.Attributes["HelpText"].Value; + + if (!String.IsNullOrEmpty(name)) + { + return new SimpleSearchCondition(automationElement => automationElement.Current.Name, + new AutomationElementProperty(name, "Name", AutomationElement.NameProperty)); + } + else if (!String.IsNullOrEmpty(automationId)) + { + return new SimpleSearchCondition(automationElement => automationElement.Current.AutomationId, + new AutomationElementProperty(automationId, "AutomationId", AutomationElement.AutomationIdProperty)); + } + else if (!String.IsNullOrEmpty(helpText)) + { + return new SimpleSearchCondition(automationElement => automationElement.Current.HelpText, + new AutomationElementProperty(helpText, "HelpText", AutomationElement.HelpTextProperty)); + } + else if (!String.IsNullOrEmpty(className)) + { + return new SimpleSearchCondition(automationElement => automationElement.Current.ClassName, + new AutomationElementProperty(className, "ClassName", AutomationElement.ClassNameProperty)); + } + else if (!String.IsNullOrEmpty(frameworkId)) + { + return new SimpleSearchCondition(automationElement => automationElement.Current.FrameworkId, + new AutomationElementProperty(frameworkId, "FrameworkId", AutomationElement.FrameworkIdProperty)); + } + + + } + } + + throw new Exception("Invalid Xpath"); + } + public static SearchCondition CreateForName(string name) { return new SimpleSearchCondition(automationElement => automationElement.Current.Name, new AutomationElementProperty(name, "Name", AutomationElement.NameProperty)); diff --git a/src/TestStack.White/UIItems/Finders/SearchCriteria.cs b/src/TestStack.White/UIItems/Finders/SearchCriteria.cs index 6b01c92d..d722c071 100644 --- a/src/TestStack.White/UIItems/Finders/SearchCriteria.cs +++ b/src/TestStack.White/UIItems/Finders/SearchCriteria.cs @@ -6,6 +6,7 @@ using System.Windows.Automation; using TestStack.White.AutomationElementSearch; using TestStack.White.UIItems.Custom; +using TestStack.White.UIItems.WindowItems; using TestStack.White.UIItems.WindowStripControls; namespace TestStack.White.UIItems.Finders @@ -72,6 +73,17 @@ public static SearchCriteria ByAutomationId(string identification) return new SearchCriteria(SearchConditionFactory.CreateForAutomationId(identification)); } + /// + /// Create criteria for specified window with specified xpath + /// + /// + /// + /// + public static SearchCriteria ByXPath(string xpath, Window window) + { + return new SearchCriteria(SearchConditionFactory.CreateForXPath(xpath, window)); + } + public static SearchCriteria ByFramework(string framework) { return new SearchCriteria(SearchConditionFactory.CreateForFrameworkId(framework)); diff --git a/src/TestStack.White/UIItems/ListBoxItems/ComboBox.cs b/src/TestStack.White/UIItems/ListBoxItems/ComboBox.cs index a7d07f60..c26e36c2 100644 --- a/src/TestStack.White/UIItems/ListBoxItems/ComboBox.cs +++ b/src/TestStack.White/UIItems/ListBoxItems/ComboBox.cs @@ -1,3 +1,4 @@ +using System; using System.Windows.Automation; using TestStack.White.AutomationElementSearch; using TestStack.White.Recording; @@ -67,26 +68,72 @@ private AutomationElement EditableElement() public override void Select(string itemText) { - if (!Enabled) + //if (!Enabled) + //{ + // Logger.WarnFormat("Could not select {0}in {1} since it is disabled", itemText, Name); + // return; + //} + //if (Equals(itemText, SelectedItemText)) return; + //base.Select(itemText); + + AutomationElement comboboxList = this.AutomationElement.FindFirst(TreeScope.Children, + new PropertyCondition(AutomationElement.ControlTypeProperty, + ControlType.List)); + + AutomationElementCollection comboboxItem = comboboxList.FindAll(TreeScope.Children, + new PropertyCondition(AutomationElement.ControlTypeProperty, + ControlType.ListItem)); + + AutomationElement[] itemArray = new AutomationElement[comboboxItem.Count]; + comboboxItem.CopyTo(itemArray, 0); + + AutomationElement itemToSelect = null; + + for (int i = 0; i < itemArray.Length; i++) + { + if (itemArray[i].Current.Name.Equals(itemText)) + { + itemToSelect = itemArray[i]; + } + } + + if (itemToSelect != null) { - Logger.WarnFormat("Could not select {0}in {1} since it is disabled", itemText, Name); - return; + Object selectPattern = null; + if (itemToSelect.TryGetCurrentPattern(SelectionItemPattern.Pattern, out selectPattern)) + { + ((SelectionItemPattern)selectPattern).Select(); + } } - if (Equals(itemText, SelectedItemText)) return; - base.Select(itemText); } public override void Select(int index) { - if (!Enabled) + //if (!Enabled) + //{ + // Logger.Warn("Could not select " + index + "in " + Name + " since it is disabled"); + // return; + //} + //base.Select(index); + //var p = (ExpandCollapsePattern) this.AutomationElement.GetCurrentPattern(ExpandCollapsePattern.Pattern); + //if (p.Current.ExpandCollapseState.Equals(ExpandCollapseState.Expanded)) + // p.Collapse(); + + AutomationElement comboboxList = this.AutomationElement.FindFirst(TreeScope.Children, + new PropertyCondition(AutomationElement.ControlTypeProperty, + ControlType.List)); + + AutomationElementCollection comboboxItem = comboboxList.FindAll(TreeScope.Children, + new PropertyCondition(AutomationElement.ControlTypeProperty, + ControlType.ListItem)); + + AutomationElement itemToSelect = comboboxItem[index]; + + Object selectPattern = null; + if (itemToSelect.TryGetCurrentPattern(SelectionItemPattern.Pattern, out selectPattern)) { - Logger.Warn("Could not select " + index + "in " + Name + " since it is disabled"); - return; + ((SelectionItemPattern)selectPattern).Select(); } - base.Select(index); - var p = (ExpandCollapsePattern) this.AutomationElement.GetCurrentPattern(ExpandCollapsePattern.Pattern); - if (p.Current.ExpandCollapseState.Equals(ExpandCollapseState.Expanded)) - p.Collapse(); } public override void HookEvents(IUIItemEventListener eventListener) diff --git a/src/TestStack.White/UIItems/UIItem.cs b/src/TestStack.White/UIItems/UIItem.cs index e4a286d2..4ed554f1 100644 --- a/src/TestStack.White/UIItems/UIItem.cs +++ b/src/TestStack.White/UIItems/UIItem.cs @@ -370,8 +370,10 @@ public virtual void SetValue(object value) /// public virtual void Enter(string value) { - var pattern = Pattern(ValuePattern.Pattern) as ValuePattern; - if (pattern != null) pattern.SetValue(string.Empty); + // + //var pattern = Pattern(ValuePattern.Pattern) as ValuePattern; + //if (pattern != null) pattern.SetValue(string.Empty); + if (string.IsNullOrEmpty(value)) return; actionListener.ActionPerformed(Action.WindowMessage); diff --git a/src/TestStack.White/UIItems/UIItemCollection.cs b/src/TestStack.White/UIItems/UIItemCollection.cs index 13ad463a..0133afe1 100644 --- a/src/TestStack.White/UIItems/UIItemCollection.cs +++ b/src/TestStack.White/UIItems/UIItemCollection.cs @@ -49,8 +49,10 @@ public UIItemCollection(IEnumerable automationElements, IActionListener actionLi var uiItem = DictionaryMappedItemFactory.Create(automationElement, actionListener, customItemType); if (uiItem != null) Add(uiItem); } - catch (ControlDictionaryException) + catch (ControlDictionaryException e) { + //Printing the Bease exception message... + logger.Warn(e.GetBaseException().Message); logger.WarnFormat("Couldn't create UIItem for AutomationElement, {0}", automationElement.Display()); } } diff --git a/src/TestStack.White/UIItems/WindowItems/Window.cs b/src/TestStack.White/UIItems/WindowItems/Window.cs index 229104f3..a78c05e4 100644 --- a/src/TestStack.White/UIItems/WindowItems/Window.cs +++ b/src/TestStack.White/UIItems/WindowItems/Window.cs @@ -1,12 +1,15 @@ +using Castle.Core.Logging; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Reflection; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Automation; +using System.Xml; using TestStack.White.AutomationElementSearch; using TestStack.White.Configuration; using TestStack.White.Factory; @@ -43,6 +46,10 @@ public abstract class Window : UIItemContainer, IDisposable public delegate bool WaitTillDelegate(); + public string Hierarchy { get; set; } + + private readonly ILogger logger = CoreAppXmlConfiguration.Instance.LoggerFactory.Create(typeof(Window)); + static Window() { WindowStates.Add(DisplayState.Maximized, WindowVisualState.Maximized); @@ -78,6 +85,112 @@ private void InitializeWindow() WindowSession.Register(this); } + /// + /// Getting AutomationElement proerties and child AutomationElements.. + /// Create XMLDocument of the AutomationElement hierarchy.. + /// + /// + /// + internal string GetHierarchy(AutomationElement element) + { + XmlDocument xmlDoc = new XmlDocument(); + XmlNode rootNode = xmlDoc.CreateElement(element.Current.LocalizedControlType.Replace(" ", "-")); + xmlDoc.AppendChild(rootNode); + addAttributes(element, xmlDoc, rootNode); + findChildElement(element, xmlDoc, rootNode); + + return xmlDoc.OuterXml; + } + + /// + /// Find the child element of given element recursively + /// + /// + /// + /// + private void findChildElement(AutomationElement element, XmlDocument xmlDoc, XmlNode node) + { + try + { + AutomationElementCollection childElementCollection = element.FindAll(TreeScope.Children, Condition.TrueCondition); + foreach (AutomationElement childElement in childElementCollection) + { + XmlNode childNode; + if (String.IsNullOrWhiteSpace(childElement.Current.LocalizedControlType)) + { + childNode = xmlDoc.CreateElement("Unknown"); + } + else + { + childNode = xmlDoc.CreateElement(childElement.Current.LocalizedControlType.Replace(" ", "-")); + } + node.AppendChild(childNode); + addAttributes(childElement, xmlDoc, childNode); + findChildElement(childElement, xmlDoc, childNode); + } + } + catch (InvalidOperationException e) + { + logger.Warn(e.Message); + } + catch (ArgumentException e) + { + logger.Warn(e.Message); + } + } + + /// + /// Getting the important attributes of AutomationElement.. + /// + /// + /// + /// + private void addAttributes(AutomationElement element, XmlDocument xmlDoc, XmlNode node) + { + try + { + XmlAttribute automationIdAttr = xmlDoc.CreateAttribute("AutomationId"); + automationIdAttr.Value = element.Current.AutomationId; + node.Attributes.Append(automationIdAttr); + + XmlAttribute classAttr = xmlDoc.CreateAttribute("ClassName"); + classAttr.Value = element.Current.ClassName; + node.Attributes.Append(classAttr); + + //XmlAttribute controlTypeAttr = xmlDoc.CreateAttribute("ControlType"); + //controlTypeAttr.Value = element.Current.ControlType; + //node.Attributes.Append(controlTypeAttr); + + XmlAttribute frameworkAttr = xmlDoc.CreateAttribute("FrameworkId"); + frameworkAttr.Value = element.Current.FrameworkId; + node.Attributes.Append(frameworkAttr); + + XmlAttribute nameAttr = xmlDoc.CreateAttribute("Name"); + nameAttr.Value = element.Current.Name; + node.Attributes.Append(nameAttr); + + XmlAttribute helpTextAttr = xmlDoc.CreateAttribute("HelpText"); + helpTextAttr.Value = element.Current.HelpText; + node.Attributes.Append(helpTextAttr); + + object patternObj; + if (element.TryGetCurrentPattern(TextPattern.Pattern, out patternObj)) + { + XmlAttribute textAttr = xmlDoc.CreateAttribute("Text"); + var textPattern = (TextPattern) patternObj; + textAttr.Value = textPattern.DocumentRange.GetText(-1).TrimEnd('\r'); + Console.WriteLine("Text attribute added.."); + node.Attributes.Append(textAttr); + } + + + } + catch (Exception e) + { + logger.Warn(e.Message); + } + } + protected override IActionListener ChildrenActionListener { get { return this; } diff --git a/src/TestStack.White/packages.config b/src/TestStack.White/packages.config index 72098ad9..fceddc39 100644 --- a/src/TestStack.White/packages.config +++ b/src/TestStack.White/packages.config @@ -1,4 +1,5 @@  + \ No newline at end of file diff --git a/src/UpgradeLog.htm b/src/UpgradeLog.htm new file mode 100644 index 00000000..78b1e5f1 Binary files /dev/null and b/src/UpgradeLog.htm differ diff --git a/src/UpgradeLog2.htm b/src/UpgradeLog2.htm new file mode 100644 index 00000000..78b1e5f1 Binary files /dev/null and b/src/UpgradeLog2.htm differ diff --git a/src/UpgradeLog3.htm b/src/UpgradeLog3.htm new file mode 100644 index 00000000..5b10e095 Binary files /dev/null and b/src/UpgradeLog3.htm differ diff --git a/src/UpgradeLog4.htm b/src/UpgradeLog4.htm new file mode 100644 index 00000000..5b10e095 Binary files /dev/null and b/src/UpgradeLog4.htm differ diff --git a/src/UpgradeLog5.htm b/src/UpgradeLog5.htm new file mode 100644 index 00000000..5b10e095 Binary files /dev/null and b/src/UpgradeLog5.htm differ diff --git a/src/WhiteProject/App.config b/src/WhiteProject/App.config new file mode 100644 index 00000000..8e156463 --- /dev/null +++ b/src/WhiteProject/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/WhiteProject/Program.cs b/src/WhiteProject/Program.cs new file mode 100644 index 00000000..594bcc33 --- /dev/null +++ b/src/WhiteProject/Program.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Automation; +using TestStack.White; +using TestStack.White.AutomationElementSearch; +using TestStack.White.Factory; +using TestStack.White.InputDevices; +using TestStack.White.UIItems; +using TestStack.White.UIItems.Finders; +using TestStack.White.UIItems.ListBoxItems; +using TestStack.White.UIItems.WindowItems; + +namespace WhiteProject +{ + class Program + { + [DllImport("kernel32.dll", ExactSpelling = true)] + + private static extern IntPtr GetConsoleWindow(); + private static IntPtr ThisConsole = GetConsoleWindow(); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + + private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); + private const int HIDE = 0; + private const int MAXIMIZE = 3; + private const int MINIMIZE = 6; + private const int RESTORE = 9; + + const string WINDOW_PROPERTY = "Name"; + const string WINDOW_VALUE = "Untitled - Notepad"; + + static void Main(string[] args) + { + //------------------------------ Maximizing Console Window ------------------------------ + Console.SetWindowSize(Console.LargestWindowWidth, Console.LargestWindowHeight); + ShowWindow(ThisConsole, MAXIMIZE); + + //------------------------------ Type in Notepad the save.. ------------------------------ + //TypeAndSaveNotepad(); + + Console.ReadLine(); + } + + public static Window SelectWindow(String property, String value) + { + List windows = WindowFactory.Desktop.DesktopWindows(); + Window selectedWindow = null; + foreach (Window window in windows) + { + System.Reflection.PropertyInfo propertyInfo = window.GetType().GetProperty(property); + String propertyValue = (String)(propertyInfo.GetValue(window, null)); + + if (propertyValue.Equals(value)) + { + selectedWindow = window; + } + } + return selectedWindow; + } + + private static void TypeAndSaveNotepad() + { + //------------------------------ Selecting Window ------------------------------ + Console.WriteLine("------------------------------ Select Window for given Property and Value /------------------------------"); + Window selectedWindow = SelectWindow(WINDOW_PROPERTY, WINDOW_VALUE); + selectedWindow.Focus(); + + //------------------------------ Type in Notepad ------------------------------ + String edit_Notepad = "//document[@ClassName='Edit']"; + String btn_File = "//menu-item[@Name='File']"; + String btn_New = "//menu-item[@Name='Save']"; + String combo_FileName = "//combo-box[@Name='File name:']"; + + IUIItem edit_NotepadObj = selectedWindow.Get(SearchCriteria.ByXPath(edit_Notepad, selectedWindow)); + edit_NotepadObj.Enter("Testing Purpose............"); + + IUIItem btn_FileObj = selectedWindow.Get(SearchCriteria.ByXPath(btn_File, selectedWindow)); + btn_FileObj.Click(); + + IUIItem btn_NewObj = selectedWindow.Get(SearchCriteria.ByXPath(btn_New, selectedWindow)); + btn_NewObj.Click(); + } + + public static void ComboBoxClick(Window w, AutomationElement ele) + { + if (w.AutomationElement != null) + { + AutomationElement comboboxInstance = ele; + if (comboboxInstance == null) + { + Console.WriteLine("ComboBox instance not found."); + } + else + { + AutomationElement comboboxList = comboboxInstance.FindFirst(TreeScope.Children, + new PropertyCondition + (AutomationElement.ControlTypeProperty, ControlType.List)); + + AutomationElementCollection comboboxItem = + comboboxList.FindAll(TreeScope.Children, + new PropertyCondition(AutomationElement.ControlTypeProperty, + ControlType.ListItem)); + + AutomationElement[] itemArray = new AutomationElement[comboboxItem.Count]; + + comboboxItem.CopyTo(itemArray, 0); + + for (int i = 0; i < itemArray.Length; i++) + { + Console.WriteLine(itemArray[1]); + } + + AutomationElement itemToSelect = comboboxItem[1]; + + Object selectPattern = null; + if (itemToSelect.TryGetCurrentPattern(SelectionItemPattern.Pattern, out selectPattern)) + { + ((SelectionItemPattern)selectPattern).Select(); + } + } + } + } + + public static void SetCombobValueByUIA(AutomationElement ctrl, string newValue) + { + ExpandCollapsePattern exPat = ctrl.GetCurrentPattern(ExpandCollapsePattern.Pattern) + as ExpandCollapsePattern; + + if (exPat == null) + { + throw new ApplicationException("Bad Control type..."); + } + + exPat.Expand(); + + AutomationElement itemToSelect = ctrl.FindFirst(TreeScope.Children, new + PropertyCondition(AutomationElement.NameProperty, newValue)); + + SelectionItemPattern sPat = itemToSelect.GetCurrentPattern( + SelectionItemPattern.Pattern) as SelectionItemPattern; + sPat.Select(); + } + + public static void SelectListItem(AutomationElement selectionContainer, String itemText) + { + if ((selectionContainer == null) || (itemText == "")) + { + throw new ArgumentException( + "Argument cannot be null or empty."); + } + + Condition propertyCondition = new PropertyCondition( + AutomationElement.AutomationIdProperty, + itemText, + PropertyConditionFlags.IgnoreCase); + + AutomationElement firstMatch = + selectionContainer.FindFirst(TreeScope.Children, propertyCondition); + + if (firstMatch != null) + { + try + { + SelectionItemPattern selectionItemPattern; + selectionItemPattern = + firstMatch.GetCurrentPattern( + SelectionItemPattern.Pattern) as SelectionItemPattern; + selectionItemPattern.Select(); + } + catch (InvalidOperationException) + { + // Unable to select + return; + } + } + } + } +} diff --git a/src/WhiteProject/Properties/AssemblyInfo.cs b/src/WhiteProject/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..b0a8475f --- /dev/null +++ b/src/WhiteProject/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("WhiteProject")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("WhiteProject")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("d913d1d2-26cd-4679-93c4-d131abbd8eaf")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/WhiteProject/WhiteProject.csproj b/src/WhiteProject/WhiteProject.csproj new file mode 100644 index 00000000..22ec1848 --- /dev/null +++ b/src/WhiteProject/WhiteProject.csproj @@ -0,0 +1,66 @@ + + + + + Debug + AnyCPU + {39964358-1A5B-4F78-9520-1B106F70CE72} + Exe + Properties + WhiteProject + WhiteProject + v4.5 + 512 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + {12c59ce2-9cf7-44f4-b27c-90754609f979} + TestStack.White + + + + + \ No newline at end of file diff --git a/tools/UISpy.zip b/tools/UISpy.zip new file mode 100644 index 00000000..1a388d4d Binary files /dev/null and b/tools/UISpy.zip differ