From 0b9d6e36cdf71a008196d52c356a94d1ec79a142 Mon Sep 17 00:00:00 2001 From: Nick Abalov Date: Thu, 3 Dec 2015 16:42:51 +0600 Subject: [PATCH 1/2] Add support of AutomationProperties to GetElementAttribute --- .../py-functional/tests/test_commands.py | 3 +- .../Commands/ExecuteCommand.cs | 2 +- .../Commands/GetElementAttributeCommand.cs | 19 ++-- .../Helpers/AutomationPropertiesAccessor.cs | 28 ++++++ .../Helpers/AutomationPropertiesHelper.cs | 61 ++++++++++++ .../Element/Helpers/PropertiesAccessor.cs | 95 +++++++++++++++++++ .../Element/WiniumElement.GetSetAttribute.cs | 71 ++------------ .../Winium.StoreApps.InnerServer.csproj | 3 + 8 files changed, 206 insertions(+), 76 deletions(-) create mode 100644 Winium/Winium.StoreApps.InnerServer/Element/Helpers/AutomationPropertiesAccessor.cs create mode 100644 Winium/Winium.StoreApps.InnerServer/Element/Helpers/AutomationPropertiesHelper.cs create mode 100644 Winium/Winium.StoreApps.InnerServer/Element/Helpers/PropertiesAccessor.cs diff --git a/Winium/TestApp.Test/py-functional/tests/test_commands.py b/Winium/TestApp.Test/py-functional/tests/test_commands.py index c012317..066dece 100644 --- a/Winium/TestApp.Test/py-functional/tests/test_commands.py +++ b/Winium/TestApp.Test/py-functional/tests/test_commands.py @@ -108,7 +108,8 @@ def test_get_element_text(self): @pytest.mark.parametrize(("attr_name", "expected_value"), [ ('Width', '300'), ('DesiredSize.Width', '300'), - ], ids=['simple property', 'nested property']) + ('AutomationIdProperty', 'MyTextBox') + ], ids=['simple property', 'nested property', 'automation property']) def test_get_element_attribute(self, attr_name, expected_value): """ GET /session/:sessionId/element/:id/attribute/:name Get the value of an element's attribute. diff --git a/Winium/Winium.StoreApps.InnerServer/Commands/ExecuteCommand.cs b/Winium/Winium.StoreApps.InnerServer/Commands/ExecuteCommand.cs index d227167..b54b708 100644 --- a/Winium/Winium.StoreApps.InnerServer/Commands/ExecuteCommand.cs +++ b/Winium/Winium.StoreApps.InnerServer/Commands/ExecuteCommand.cs @@ -180,7 +180,7 @@ private string ExecuteAttributeScript(string command) var attributeName = args[1].ToString(); var value = args[2]; - element.SetAttribute(attributeName, value); + element.SetProperty(attributeName, value); return null; } diff --git a/Winium/Winium.StoreApps.InnerServer/Commands/GetElementAttributeCommand.cs b/Winium/Winium.StoreApps.InnerServer/Commands/GetElementAttributeCommand.cs index 237485f..1c9dd0f 100644 --- a/Winium/Winium.StoreApps.InnerServer/Commands/GetElementAttributeCommand.cs +++ b/Winium/Winium.StoreApps.InnerServer/Commands/GetElementAttributeCommand.cs @@ -9,7 +9,6 @@ using Newtonsoft.Json.Linq; using Winium.StoreApps.Common; - using Winium.StoreApps.Common.Exceptions; #endregion @@ -21,7 +20,7 @@ internal class GetElementAttributeCommand : CommandBase #endregion - #region Public Methods and Operators + #region Methods protected override string DoImpl() { @@ -43,21 +42,15 @@ protected override string DoImpl() * property value as plain string if property is scalar or string, * JSON encoded property if property is Lists, Dictionary or other nonscalar types */ - try - { - var propertyObject = element.GetAttribute(attributeName); + object propertyObject; - return this.JsonResponse(ResponseStatus.Success, SerializeObjectAsString(propertyObject)); - } - catch (AutomationException) + if (!element.TryGetAutomationProperty(attributeName, out propertyObject)) { - return this.JsonResponse(); + element.TryGetProperty(attributeName, out propertyObject); } - } - #endregion - - #region Methods + return this.JsonResponse(ResponseStatus.Success, SerializeObjectAsString(propertyObject)); + } private static bool IsTypeSerializedUsingToString(Type type) { diff --git a/Winium/Winium.StoreApps.InnerServer/Element/Helpers/AutomationPropertiesAccessor.cs b/Winium/Winium.StoreApps.InnerServer/Element/Helpers/AutomationPropertiesAccessor.cs new file mode 100644 index 0000000..f08fe12 --- /dev/null +++ b/Winium/Winium.StoreApps.InnerServer/Element/Helpers/AutomationPropertiesAccessor.cs @@ -0,0 +1,28 @@ +namespace Winium.StoreApps.InnerServer.Element.Helpers +{ + #region + + using Windows.UI.Xaml; + + #endregion + + internal static class AutomationPropertiesAccessor + { + #region Public Methods and Operators + + public static bool TryGetAutomationProperty(FrameworkElement element, string propertyName, out object value) + { + value = null; + DependencyProperty property; + if (!AutomationPropertiesHelper.Instance.TryGetAutomationProperty(propertyName, out property)) + { + return false; + } + + value = element.GetValue(property); + return true; + } + + #endregion + } +} diff --git a/Winium/Winium.StoreApps.InnerServer/Element/Helpers/AutomationPropertiesHelper.cs b/Winium/Winium.StoreApps.InnerServer/Element/Helpers/AutomationPropertiesHelper.cs new file mode 100644 index 0000000..d3f085f --- /dev/null +++ b/Winium/Winium.StoreApps.InnerServer/Element/Helpers/AutomationPropertiesHelper.cs @@ -0,0 +1,61 @@ +namespace Winium.StoreApps.InnerServer.Element.Helpers +{ + #region + + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + + using Windows.UI.Xaml; + using Windows.UI.Xaml.Automation; + + #endregion + + internal class AutomationPropertiesHelper + { + #region Static Fields + + private static readonly Lazy LazyInstance = + new Lazy(() => new AutomationPropertiesHelper()); + + #endregion + + #region Fields + + private readonly Dictionary properties; + + #endregion + + #region Constructors and Destructors + + private AutomationPropertiesHelper() + { + this.properties = typeof(AutomationProperties).GetRuntimeProperties() + .ToDictionary(f => f.Name, f => (DependencyProperty)f.GetValue(null)); + } + + #endregion + + #region Public Properties + + public static AutomationPropertiesHelper Instance + { + get + { + return LazyInstance.Value; + } + } + + #endregion + + #region Public Methods and Operators + + public bool TryGetAutomationProperty(string name, out DependencyProperty property) + { + return this.properties.TryGetValue(name, out property); + } + + #endregion + } +} diff --git a/Winium/Winium.StoreApps.InnerServer/Element/Helpers/PropertiesAccessor.cs b/Winium/Winium.StoreApps.InnerServer/Element/Helpers/PropertiesAccessor.cs new file mode 100644 index 0000000..c877e8c --- /dev/null +++ b/Winium/Winium.StoreApps.InnerServer/Element/Helpers/PropertiesAccessor.cs @@ -0,0 +1,95 @@ +namespace Winium.StoreApps.InnerServer.Element.Helpers +{ + #region + + using System; + using System.Linq; + using System.Reflection; + + using Newtonsoft.Json.Linq; + + using Windows.UI.Xaml; + + using Winium.StoreApps.Common.Exceptions; + + #endregion + + internal static class PropertiesAccessor + { + #region Public Methods and Operators + + public static void SetProperty(FrameworkElement element, string propertyName, JToken value) + { + object targetObject; + PropertyInfo targetPropertyInfo; + + if (GetPropertyTarget(element, propertyName, out targetObject, out targetPropertyInfo)) + { + targetPropertyInfo.SetValue(targetObject, value.ToObject(targetPropertyInfo.PropertyType)); + } + else + { + throw new AutomationException("Could not access attribute {0}.", propertyName); + } + } + + public static bool TryGetProperty(FrameworkElement element, string propertyName, out object value) + { + value = null; + object targetObject; + PropertyInfo targetPropertyInfo; + + if (!GetPropertyTarget(element, propertyName, out targetObject, out targetPropertyInfo)) + { + return false; + } + + value = targetPropertyInfo.GetValue(targetObject, null); + return true; + } + + #endregion + + #region Methods + + private static bool GetPropertyTarget( + object sourceObject, + string propertyName, + out object targetObject, + out PropertyInfo targetPropertyInfo) + { + targetObject = null; + targetPropertyInfo = null; + + object parent = null; + var curObject = sourceObject; + PropertyInfo propertyInfo = null; + + var properties = propertyName.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); + + if (!properties.Any()) + { + return false; + } + + foreach (var property in properties) + { + parent = curObject; + propertyInfo = curObject.GetType().GetRuntimeProperty(property); + if (propertyInfo == null) + { + return false; + } + + curObject = propertyInfo.GetValue(curObject, null); + } + + targetObject = parent; + targetPropertyInfo = propertyInfo; + + return true; + } + + #endregion + } +} diff --git a/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.GetSetAttribute.cs b/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.GetSetAttribute.cs index 7eb232f..bdecd1a 100644 --- a/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.GetSetAttribute.cs +++ b/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.GetSetAttribute.cs @@ -2,13 +2,9 @@ { #region - using System; - using System.Linq; - using System.Reflection; - using Newtonsoft.Json.Linq; - using Winium.StoreApps.Common.Exceptions; + using Winium.StoreApps.InnerServer.Element.Helpers; #endregion @@ -16,69 +12,22 @@ internal partial class WiniumElement { #region Methods - internal object GetAttribute(string attributeName) + internal void SetProperty(string attributeName, JToken value) { - object targetObject; - PropertyInfo targetPropertyInfo; - - if (this.GetAttributeTarget(attributeName, out targetObject, out targetPropertyInfo)) - { - return targetPropertyInfo.GetValue(targetObject, null); - } - - throw new AutomationException("Could not access attribute {0}.", attributeName); + PropertiesAccessor.SetProperty(this.Element, attributeName, value); } - internal void SetAttribute(string attributeName, JToken value) + internal bool TryGetAutomationProperty(string automationPropertyName, out object value) { - object targetObject; - PropertyInfo targetPropertyInfo; - - if (this.GetAttributeTarget(attributeName, out targetObject, out targetPropertyInfo)) - { - targetPropertyInfo.SetValue(targetObject, value.ToObject(targetPropertyInfo.PropertyType)); - } - else - { - throw new AutomationException("Could not access attribute {0}.", attributeName); - } + return AutomationPropertiesAccessor.TryGetAutomationProperty( + this.Element, + automationPropertyName, + out value); } - private bool GetAttributeTarget( - string attributeName, - out object targetObject, - out PropertyInfo targetPropertyInfo) + internal bool TryGetProperty(string attributeName, out object value) { - targetObject = null; - targetPropertyInfo = null; - - object parent = null; - var curObject = (object)this.Element; - PropertyInfo propertyInfo = null; - - var properties = attributeName.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); - - if (!properties.Any()) - { - return false; - } - - foreach (var property in properties) - { - parent = curObject; - propertyInfo = curObject.GetType().GetRuntimeProperty(property); - if (propertyInfo == null) - { - return false; - } - - curObject = propertyInfo.GetValue(curObject, null); - } - - targetObject = parent; - targetPropertyInfo = propertyInfo; - - return true; + return PropertiesAccessor.TryGetProperty(this.Element, attributeName, out value); } #endregion diff --git a/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj b/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj index f735ab9..d1e30e0 100644 --- a/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj +++ b/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj @@ -69,6 +69,9 @@ + + + From eaa1f8fc283a0d55d5755910c2940797d6529278 Mon Sep 17 00:00:00 2001 From: Nick Abalov Date: Fri, 4 Dec 2015 09:46:43 +0600 Subject: [PATCH 2/2] Move Properties and Automation Properties methods to WiniumElement.cs --- .../Element/WiniumElement.GetSetAttribute.cs | 35 ------------------- .../Element/WiniumElement.cs | 21 +++++++++++ .../Winium.StoreApps.InnerServer.csproj | 1 - 3 files changed, 21 insertions(+), 36 deletions(-) delete mode 100644 Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.GetSetAttribute.cs diff --git a/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.GetSetAttribute.cs b/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.GetSetAttribute.cs deleted file mode 100644 index bdecd1a..0000000 --- a/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.GetSetAttribute.cs +++ /dev/null @@ -1,35 +0,0 @@ -namespace Winium.StoreApps.InnerServer.Element -{ - #region - - using Newtonsoft.Json.Linq; - - using Winium.StoreApps.InnerServer.Element.Helpers; - - #endregion - - internal partial class WiniumElement - { - #region Methods - - internal void SetProperty(string attributeName, JToken value) - { - PropertiesAccessor.SetProperty(this.Element, attributeName, value); - } - - internal bool TryGetAutomationProperty(string automationPropertyName, out object value) - { - return AutomationPropertiesAccessor.TryGetAutomationProperty( - this.Element, - automationPropertyName, - out value); - } - - internal bool TryGetProperty(string attributeName, out object value) - { - return PropertiesAccessor.TryGetProperty(this.Element, attributeName, out value); - } - - #endregion - } -} diff --git a/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.cs b/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.cs index 91ca947..cf5c3e1 100644 --- a/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.cs +++ b/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.cs @@ -4,11 +4,14 @@ using System; + using Newtonsoft.Json.Linq; + using Windows.UI.Xaml; using Winium.StoreApps.Common; using Winium.StoreApps.Common.Exceptions; using Winium.StoreApps.InnerServer.Commands.Helpers; + using Winium.StoreApps.InnerServer.Element.Helpers; #endregion @@ -135,6 +138,24 @@ public override int GetHashCode() return this.weakElement != null ? this.weakElement.GetHashCode() : 0; } + public void SetProperty(string attributeName, JToken value) + { + PropertiesAccessor.SetProperty(this.Element, attributeName, value); + } + + public bool TryGetAutomationProperty(string automationPropertyName, out object value) + { + return AutomationPropertiesAccessor.TryGetAutomationProperty( + this.Element, + automationPropertyName, + out value); + } + + public bool TryGetProperty(string attributeName, out object value) + { + return PropertiesAccessor.TryGetProperty(this.Element, attributeName, out value); + } + #endregion } } diff --git a/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj b/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj index d1e30e0..81a3143 100644 --- a/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj +++ b/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj @@ -76,7 +76,6 @@ -