From 330f2d62ee626f643fff7a1159514e072915c69b Mon Sep 17 00:00:00 2001 From: Ole Vegard Mythe Moland Date: Thu, 3 Sep 2015 10:31:49 +0200 Subject: [PATCH 01/21] Improved exception handling --- Winium/Winium.StoreApps.InnerServer/Commands/CommandBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Winium/Winium.StoreApps.InnerServer/Commands/CommandBase.cs b/Winium/Winium.StoreApps.InnerServer/Commands/CommandBase.cs index 95f3dac..505fb50 100644 --- a/Winium/Winium.StoreApps.InnerServer/Commands/CommandBase.cs +++ b/Winium/Winium.StoreApps.InnerServer/Commands/CommandBase.cs @@ -93,7 +93,7 @@ private static void InvokeSync(CoreDispatcher dispatcher, Action action) if (exception != null) { - throw exception; + throw new Exception("An exception occured while execuiting a command. ", exception); } } From 712c0a20a301697a88487f62f8aaae3e270d33f7 Mon Sep 17 00:00:00 2001 From: Ole Vegard Mythe Moland Date: Thu, 3 Sep 2015 10:32:22 +0200 Subject: [PATCH 02/21] Updated README --- README.md | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) diff --git a/README.md b/README.md index 4ac10ac..e6cf04f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,156 @@ + +# Capture Winium tests + +The Capture Winium / Selenium tests consists of several parts + +## system_test.py +--- +This is where the induvidual tests functions are implemented. It contains all functions for setting up, executing the various steps of each test and tearing down the test. + +It mostly serves as a wrapper around the appium/winium specific parts of the test to provide a platform-independant interface. It enables writing one test for all three platforms. The implementations of these functions is located in `wp_driver.py` + +It supports : + +##### setUp() +Does everything needed to start a test, including starting the emulator, connecting to it, installing the app on the emulator and starting it. + +##### tearDown() + +Does everything needed to stop the test + +##### click( id ) +Clicks on the elment with the id `id`. If no element was found or the element wasn't clickable, the test will fail + +##### verify_text( text, id ) +Verifies that the text of the element with the id `id` is the same as `text`. Fails if the texts are different + +##### verify_text_using_libres_impl( element ) +Takes an element ( note `element` is the actual element, not an id ). And verifies that it has the correct value in `strings.csv`. +Test fail if string is not identical + +See `string_dictonary` for more info + +##### verify_text_using_libres ( id ) +Helper function for `verify_text_using_libres_impl`. This function takes an `id` + +##### verify_all_using_libres() +Helper function for `verify_text_using_libres_impl`. This function gets all visible elements on the current page and checks them usinga `verify_text_using_libres_impl` + +##### verify_unescaped( id ) +This function is used to verify escaping. It checks whether the element with the id `id` has any XML escape characters in it text + +##### is_displayed( id ) +Returns true of the element with the id `id` is visible + +##### verify_visible( id ) +Does the above check, but fails the test if the item is not visible + +##### verify_not_visible( id ) +Does the `is_displayed` check, but fails the test if the item is visible + +##### enter_text( text, id ) +Writes the text `text` into the element with the id `id` + +### app_fields.py +--- +Contains the element ids as constant strings so that the can be refered to by the id wihtout writing the id itself + +### app_screens.py +--- +Contains functionality for confirming that the various screens are correct using system_test + +Note : not an actual test in itself, it's just used by the test to confirm that the page is correct + +### test_login.py +--- +Currently the only test. It tests the login page in various ways by using system_test and app_screens.py + +### context.py +--- +Contains a few helper functions for creating correct parts and similar + +### lookup_ids.csv +--- +A mapping between the element ids and the string ids. Used by string dictionary to check strings + +### string_dictionary.py +--- +A dictonary that can be used to get the correct string for a given element id. It uses the `lookup_ids.csv` and `strings.csv` to look up strings based on the element id. + +It can be configured to look up strings in any supported language, it defaults to English + +##### look_up( id ) +Looks up a the element with the id `id` and returns the corresponding string + +##### find_string_key( id ) +Finds the strings.csv key for the element with the id `id` + +##### get_from_key( key ) +Returs the string for a the key `key` + +Note : `key` is the strings.csv id, not the element id. It is meant to be used with the find_string_key + +### wp_driver.py +--- +The winium specific implementation of system_test.py. It deals with everything that concerns the phone / emulator we are testing on + +##### start() +Starts the driver, which is the windows equivelent of Appium. It also tells the driver about the dependency ( VisualC++ ) + +##### connect() +Connects to the driver and tells it to start the emulator and install + start the app. + +##### disconnect() +Disconnects from the driver which tells the emulator to stop + +##### stop() +Disconnects from the server and kills the driver.exe + +##### find_item( id ) +Returns an item with the id, `id` + +##### find_all_items() +Returns all visible elements of the types TextBlock, Button, HyperlinkButton and PasswordBox. + +Can be extended to support more control types + +##### has_item( id ) +Verifies that an item with the id `id` is present and reachable + +##### hide_keyboard() +What the signature said + +##### click( id ) +Hides keyboard and tries to click the item with the id `id` + +It needs to hide the keyboard first because if we don't, we could end up pressing the keyboard instead of the actual button + +##### find_last_appx_file() +Used to find the appx file with the highest version number so that we can have multiple appx files without having to delete the old ones or specify an explicit path + +## Step by step +--- + +### 1. Building appx package +In visual studio, right click on the project `Capture.UniWin.WindowsPhone` and selecet `Store -> Create App Package` and press `Next` + +From the bottom left menu, selct `x86` and `Debug(x86)` + +Click `Create` + +The package will now be created and placed in `[CAPTURE ROOT]\Capture.UniWin\Capture.UniWin.WindowsPhone\bin` + +### 2. Starting the tests +Open a terminal and navigate to `[CAPTURE ROOT]\SystemTest`. + +Run `py -3 -m unitttest discover` ( you might have to swap `py -3` with `python` or similar. The `-3` parameter is not mandatory. ) + +### 3. Sit back and watch the magic +The test will now start the winium server. Which in turns will start the emulator, install the app and so on. The test will also look for the latest appx package ( the one with the highest version number ) and install that along with the dependencies. + +Finally when all is set up, the tests defined in `test_login.py` ( and any other unit tests ) will run. The test will not stop until all test steps are done, even if there have been failures. You have to wait in order to get feedback ( though an option should be added here so that we don't always have to wait ) + +

English description | Описание на русском

From 98bff1aa6a8d21f0d0c0da65ff1815b8a427fb97 Mon Sep 17 00:00:00 2001 From: Ole Vegard Date: Wed, 9 Sep 2015 08:59:13 +0200 Subject: [PATCH 03/21] Updated readme.md to point to gist Readme now has a link to the gist, this makes editing the Capture-specific options a while lot easier --- README.md | 150 +----------------------------------------------------- 1 file changed, 1 insertion(+), 149 deletions(-) diff --git a/README.md b/README.md index e6cf04f..a571617 100644 --- a/README.md +++ b/README.md @@ -1,155 +1,7 @@ # Capture Winium tests -The Capture Winium / Selenium tests consists of several parts - -## system_test.py ---- -This is where the induvidual tests functions are implemented. It contains all functions for setting up, executing the various steps of each test and tearing down the test. - -It mostly serves as a wrapper around the appium/winium specific parts of the test to provide a platform-independant interface. It enables writing one test for all three platforms. The implementations of these functions is located in `wp_driver.py` - -It supports : - -##### setUp() -Does everything needed to start a test, including starting the emulator, connecting to it, installing the app on the emulator and starting it. - -##### tearDown() - -Does everything needed to stop the test - -##### click( id ) -Clicks on the elment with the id `id`. If no element was found or the element wasn't clickable, the test will fail - -##### verify_text( text, id ) -Verifies that the text of the element with the id `id` is the same as `text`. Fails if the texts are different - -##### verify_text_using_libres_impl( element ) -Takes an element ( note `element` is the actual element, not an id ). And verifies that it has the correct value in `strings.csv`. -Test fail if string is not identical - -See `string_dictonary` for more info - -##### verify_text_using_libres ( id ) -Helper function for `verify_text_using_libres_impl`. This function takes an `id` - -##### verify_all_using_libres() -Helper function for `verify_text_using_libres_impl`. This function gets all visible elements on the current page and checks them usinga `verify_text_using_libres_impl` - -##### verify_unescaped( id ) -This function is used to verify escaping. It checks whether the element with the id `id` has any XML escape characters in it text - -##### is_displayed( id ) -Returns true of the element with the id `id` is visible - -##### verify_visible( id ) -Does the above check, but fails the test if the item is not visible - -##### verify_not_visible( id ) -Does the `is_displayed` check, but fails the test if the item is visible - -##### enter_text( text, id ) -Writes the text `text` into the element with the id `id` - -### app_fields.py ---- -Contains the element ids as constant strings so that the can be refered to by the id wihtout writing the id itself - -### app_screens.py ---- -Contains functionality for confirming that the various screens are correct using system_test - -Note : not an actual test in itself, it's just used by the test to confirm that the page is correct - -### test_login.py ---- -Currently the only test. It tests the login page in various ways by using system_test and app_screens.py - -### context.py ---- -Contains a few helper functions for creating correct parts and similar - -### lookup_ids.csv ---- -A mapping between the element ids and the string ids. Used by string dictionary to check strings - -### string_dictionary.py ---- -A dictonary that can be used to get the correct string for a given element id. It uses the `lookup_ids.csv` and `strings.csv` to look up strings based on the element id. - -It can be configured to look up strings in any supported language, it defaults to English - -##### look_up( id ) -Looks up a the element with the id `id` and returns the corresponding string - -##### find_string_key( id ) -Finds the strings.csv key for the element with the id `id` - -##### get_from_key( key ) -Returs the string for a the key `key` - -Note : `key` is the strings.csv id, not the element id. It is meant to be used with the find_string_key - -### wp_driver.py ---- -The winium specific implementation of system_test.py. It deals with everything that concerns the phone / emulator we are testing on - -##### start() -Starts the driver, which is the windows equivelent of Appium. It also tells the driver about the dependency ( VisualC++ ) - -##### connect() -Connects to the driver and tells it to start the emulator and install + start the app. - -##### disconnect() -Disconnects from the driver which tells the emulator to stop - -##### stop() -Disconnects from the server and kills the driver.exe - -##### find_item( id ) -Returns an item with the id, `id` - -##### find_all_items() -Returns all visible elements of the types TextBlock, Button, HyperlinkButton and PasswordBox. - -Can be extended to support more control types - -##### has_item( id ) -Verifies that an item with the id `id` is present and reachable - -##### hide_keyboard() -What the signature said - -##### click( id ) -Hides keyboard and tries to click the item with the id `id` - -It needs to hide the keyboard first because if we don't, we could end up pressing the keyboard instead of the actual button - -##### find_last_appx_file() -Used to find the appx file with the highest version number so that we can have multiple appx files without having to delete the old ones or specify an explicit path - -## Step by step ---- - -### 1. Building appx package -In visual studio, right click on the project `Capture.UniWin.WindowsPhone` and selecet `Store -> Create App Package` and press `Next` - -From the bottom left menu, selct `x86` and `Debug(x86)` - -Click `Create` - -The package will now be created and placed in `[CAPTURE ROOT]\Capture.UniWin\Capture.UniWin.WindowsPhone\bin` - -### 2. Starting the tests -Open a terminal and navigate to `[CAPTURE ROOT]\SystemTest`. - -Run `py -3 -m unitttest discover` ( you might have to swap `py -3` with `python` or similar. The `-3` parameter is not mandatory. ) - -### 3. Sit back and watch the magic -The test will now start the winium server. Which in turns will start the emulator, install the app and so on. The test will also look for the latest appx package ( the one with the highest version number ) and install that along with the dependencies. - -Finally when all is set up, the tests defined in `test_login.py` ( and any other unit tests ) will run. The test will not stop until all test steps are done, even if there have been failures. You have to wait in order to get feedback ( though an option should be added here so that we don't always have to wait ) - +The Capture specific SystemTest documentation can be found [here.](https://gist.github.com/ole-vegard/05ae46c2d7accd170f9f)

English description | Описание на русском From 7be57cf7fd7ea76b4ea61543919cedd85e3fe0ee Mon Sep 17 00:00:00 2001 From: Magnar Nedland Date: Fri, 11 Sep 2015 14:26:48 +0200 Subject: [PATCH 04/21] Use ToString on exceptions to get stack trace of inner exceptions too. --- Winium/Winium.StoreApps.InnerServer/Commands/CommandBase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Winium/Winium.StoreApps.InnerServer/Commands/CommandBase.cs b/Winium/Winium.StoreApps.InnerServer/Commands/CommandBase.cs index 505fb50..b2c40e3 100644 --- a/Winium/Winium.StoreApps.InnerServer/Commands/CommandBase.cs +++ b/Winium/Winium.StoreApps.InnerServer/Commands/CommandBase.cs @@ -43,11 +43,11 @@ public string Do() } catch (AutomationException exception) { - response = this.JsonResponse(exception.Status, exception); + response = this.JsonResponse(exception.Status, exception.ToString()); } catch (Exception exception) { - response = this.JsonResponse(ResponseStatus.UnknownError, exception); + response = this.JsonResponse(ResponseStatus.UnknownError, exception.ToString()); } return response; From c9d80e6a110b3ad940a22b32e9c42ad0a0cf3d49 Mon Sep 17 00:00:00 2001 From: Ole Vegard Mythe Moland Date: Wed, 16 Sep 2015 14:15:36 +0200 Subject: [PATCH 05/21] Removed IsHitTestVisible from IsUserVisible -IsHitTestVisible is intended to prevent the FrameworkElement from consuming the click/tap so that it goes straight to the componenet under. -It's true by default, it has to be set to false epxlicitly. -Thus it doesn't say anything about whether the FrameworkElement is visible or not, just whehter it is clickable --- .../Element/WiniumElement.IsUserVisible.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.IsUserVisible.cs b/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.IsUserVisible.cs index 145e0e8..e251c25 100644 --- a/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.IsUserVisible.cs +++ b/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.IsUserVisible.cs @@ -46,8 +46,7 @@ internal bool IsUserVisible() while (true) { - if (currentElement.Visibility != Visibility.Visible || !currentElement.IsHitTestVisible - || !(currentElement.Opacity > 0)) + if (currentElement.Visibility != Visibility.Visible || !(currentElement.Opacity > 0)) { return false; } From 4fd1cf74ae8212bd72b0d73d78903c1047b5a1f9 Mon Sep 17 00:00:00 2001 From: Ole Vegard Mythe Moland Date: Fri, 25 Sep 2015 14:32:46 +0200 Subject: [PATCH 06/21] Added support for dependencies -Dependencies are installed before the app itself -This is required by some app, for instance thoose who uses C++ runtimes -Used by setting a list in Capabilities, this can be done just like setting other options in Capabilities -Added an InstallDependency() function which is a slightly modified version of Install() -Loads the manifestinfo from the path ( using function in Utils) -Installs the package normally --- .../Automator/Automator.cs | 1 + .../Automator/Capabilities.cs | 4 ++++ .../CommandLineOptions.cs | 3 +++ .../EmulatorHelpers/Deployer.cs | 19 +++++++++++++++++++ 4 files changed, 27 insertions(+) diff --git a/Winium/Winium.StoreApps.Driver/Automator/Automator.cs b/Winium/Winium.StoreApps.Driver/Automator/Automator.cs index 64e66f9..f76c57e 100644 --- a/Winium/Winium.StoreApps.Driver/Automator/Automator.cs +++ b/Winium/Winium.StoreApps.Driver/Automator/Automator.cs @@ -162,6 +162,7 @@ public void InitializeApp() this.Deployer = new Deployer(this.ActualCapabilities.DeviceName, strictMatchDeviceName, appPath); if (!debugDoNotDeploy) { + this.Deployer.InstallDependencies(this.ActualCapabilities.Dependencies); this.Deployer.Install(); this.Deployer.SendFiles(this.ActualCapabilities.Files); } diff --git a/Winium/Winium.StoreApps.Driver/Automator/Capabilities.cs b/Winium/Winium.StoreApps.Driver/Automator/Capabilities.cs index 30a9078..a3f951e 100644 --- a/Winium/Winium.StoreApps.Driver/Automator/Capabilities.cs +++ b/Winium/Winium.StoreApps.Driver/Automator/Capabilities.cs @@ -32,6 +32,7 @@ internal Capabilities() this.LaunchTimeout = 10000; this.DebugConnectToRunningApp = false; this.TakesScreenshot = true; + this.Dependencies = new List(); } #endregion @@ -99,6 +100,9 @@ public static string PlatformName [JsonProperty("takesScreenshot")] public bool TakesScreenshot { get; set; } + [JsonProperty("dependencies")] + public List Dependencies { get; set; } + #endregion #region Public Methods and Operators diff --git a/Winium/Winium.StoreApps.Driver/CommandLineOptions.cs b/Winium/Winium.StoreApps.Driver/CommandLineOptions.cs index 1b6cc56..15574b4 100644 --- a/Winium/Winium.StoreApps.Driver/CommandLineOptions.cs +++ b/Winium/Winium.StoreApps.Driver/CommandLineOptions.cs @@ -30,6 +30,9 @@ internal class CommandLineOptions [Option("bound-device-name", Required = false, HelpText = "strict name of emulator to bind with driver. Driver will be able to start sessions only on this device, if session will specify deviceName that is not a substring of bound device name, then an error will occur. Use this option to run tests in parallel on differen driver-emulator pairs connected to Selenium Grid on same host.")] public string BoundDeviceName { get; set; } + [Option("dependency", Required = false, HelpText = "dependencies to be installed before main app")] + public string Dependency { get; set; } + #endregion #region Public Methods and Operators diff --git a/Winium/Winium.StoreApps.Driver/EmulatorHelpers/Deployer.cs b/Winium/Winium.StoreApps.Driver/EmulatorHelpers/Deployer.cs index 8ecabd9..9fd7bb6 100644 --- a/Winium/Winium.StoreApps.Driver/EmulatorHelpers/Deployer.cs +++ b/Winium/Winium.StoreApps.Driver/EmulatorHelpers/Deployer.cs @@ -155,6 +155,25 @@ public void SendFiles(Dictionary files) } } + public void InstallDependencies(List dependencies ) + { + if (dependencies == null || !dependencies.Any()) + { + return; + } + + foreach (var dependency in dependencies) + { + InstallDependency(dependency); + } + } + + public void InstallDependency(string path) + { + var appManifest = Utils.ReadAppManifestInfoFromPackage(path); + Utils.InstallApplication(this.deviceInfo, appManifest, DeploymentOptions.None, path); + } + public void Terminate() { throw new NotImplementedException("Deployer.Terminate"); From 7ed489dc614ea61acdec1159d31040c0a352f280 Mon Sep 17 00:00:00 2001 From: Ole Vegard Mythe Moland Date: Tue, 6 Oct 2015 14:54:55 +0200 Subject: [PATCH 07/21] Added 'Label' to InnerDrivers TextCommand -AppBarButtons have' Label' as their text, not 'Text or 'Content' --- .../Element/WiniumElement.GetText.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.GetText.cs b/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.GetText.cs index d595f1f..5aa50e5 100644 --- a/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.GetText.cs +++ b/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.GetText.cs @@ -16,7 +16,7 @@ internal string GetText() { var element = this.Element; - var propertyNames = new List { "Text", "Content" }; + var propertyNames = new List { "Text", "Content", "Label" }; foreach (var textProperty in from propertyName in propertyNames select element.GetType().GetRuntimeProperty(propertyName) From 3117c346fe2de04cb103b8887de82676b7ca4224 Mon Sep 17 00:00:00 2001 From: Ole Vegard Mythe Moland Date: Tue, 6 Oct 2015 14:56:46 +0200 Subject: [PATCH 08/21] Added support for AppBarButtons in IsUserVisible -AppBarButtons often lay in a Grid with opacity 0, even when visible. -This grid is outside of the Page in the view hierarchy so 0 must be a default / valid value for the AppBar -Added a function that returns true if : -The FrameworkElement is an AppBarButton -The AppBarButton is visible -The AppBarButtons parents is also available and visible --- .../Element/WiniumElement.IsUserVisible.cs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.IsUserVisible.cs b/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.IsUserVisible.cs index e251c25..a121a19 100644 --- a/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.IsUserVisible.cs +++ b/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.IsUserVisible.cs @@ -5,6 +5,7 @@ using Windows.Foundation; using Windows.UI.Xaml; using Windows.UI.Xaml.Media; + using Windows.UI.Xaml.Controls; #endregion @@ -25,6 +26,9 @@ internal bool IsUserVisible() var currentElementSize = new Size(currentElement.ActualWidth, currentElement.ActualHeight); + if (CommandBarCheck(currentElement)) + return true; + // Check if currentElement is of zero size if (currentElementSize.Width <= 0 || currentElementSize.Height <= 0) { @@ -82,6 +86,39 @@ internal bool IsUserVisible() } } + private CommandBar FindCommandBar(FrameworkElement element) + { + DependencyObject parent = element; + + while ( parent != null ) + { + parent = VisualTreeHelper.GetParent(parent); + + if (parent.GetType() == typeof(AppBar) || parent.GetType() == typeof(CommandBar)) + return parent as CommandBar; + } + + return null; + } + + private bool CommandBarCheck(FrameworkElement element) + { + AppBarButton appBarButton = element as AppBarButton; + + if ( appBarButton == null) + return false; + + if (appBarButton.IsCompact || !appBarButton.IsEnabled || appBarButton.Visibility != Visibility.Visible ) + return false; + + CommandBar bar = FindCommandBar(element); + + if ( bar == null|| !bar.IsEnabled || bar.Visibility != Visibility.Visible ) + return false; + + return true; + } + #endregion } } From f3d251871df103e0a7067ad2b61ab856bfb0b587 Mon Sep 17 00:00:00 2001 From: Ole Vegard Mythe Moland Date: Wed, 7 Oct 2015 07:44:18 +0200 Subject: [PATCH 09/21] Changed IsUserVisible -If the element is AppBarButton, the function will return the value of CommandBarCheck(...) directely -CommandBarCheck now checks the visibility of all parents -Added check for CommandBar ( in addition to the already existing AppBarButton ) --- .../Element/WiniumElement.IsUserVisible.cs | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.IsUserVisible.cs b/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.IsUserVisible.cs index a121a19..d50eb71 100644 --- a/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.IsUserVisible.cs +++ b/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.IsUserVisible.cs @@ -26,8 +26,11 @@ internal bool IsUserVisible() var currentElementSize = new Size(currentElement.ActualWidth, currentElement.ActualHeight); - if (CommandBarCheck(currentElement)) - return true; + if (currentElement is AppBarButton) + return CheckAppBarButton(currentElement as AppBarButton); + + if (currentElement is CommandBar) + return CheckCommandBar(currentElement as CommandBar); // Check if currentElement is of zero size if (currentElementSize.Width <= 0 || currentElementSize.Height <= 0) @@ -86,7 +89,7 @@ internal bool IsUserVisible() } } - private CommandBar FindCommandBar(FrameworkElement element) + private CommandBar FindCommandBar(AppBarButton element) { DependencyObject parent = element; @@ -94,6 +97,11 @@ private CommandBar FindCommandBar(FrameworkElement element) { parent = VisualTreeHelper.GetParent(parent); + FrameworkElement parentElement = parent as FrameworkElement; + + if (parentElement != null && parentElement.Visibility == Visibility.Collapsed ) + return null; + if (parent.GetType() == typeof(AppBar) || parent.GetType() == typeof(CommandBar)) return parent as CommandBar; } @@ -101,22 +109,20 @@ private CommandBar FindCommandBar(FrameworkElement element) return null; } - private bool CommandBarCheck(FrameworkElement element) + private bool CheckAppBarButton(AppBarButton appBarButton ) { - AppBarButton appBarButton = element as AppBarButton; - if ( appBarButton == null) return false; if (appBarButton.IsCompact || !appBarButton.IsEnabled || appBarButton.Visibility != Visibility.Visible ) return false; - CommandBar bar = FindCommandBar(element); - - if ( bar == null|| !bar.IsEnabled || bar.Visibility != Visibility.Visible ) - return false; + return CheckCommandBar(FindCommandBar(appBarButton)); + } - return true; + private bool CheckCommandBar(CommandBar bar) + { + return ( bar != null && bar.IsEnabled && bar.Visibility == Visibility.Visible ); } #endregion From bcb44e9908a8cf51e1c77adabfc9f63026dac1a0 Mon Sep 17 00:00:00 2001 From: Ole Vegard Mythe Moland Date: Thu, 8 Oct 2015 08:22:14 +0200 Subject: [PATCH 10/21] Minor changes after code review -Changed loop -Renamed functions --- .../Element/WiniumElement.IsUserVisible.cs | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.IsUserVisible.cs b/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.IsUserVisible.cs index d50eb71..7a1605a 100644 --- a/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.IsUserVisible.cs +++ b/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.IsUserVisible.cs @@ -27,10 +27,10 @@ internal bool IsUserVisible() var currentElementSize = new Size(currentElement.ActualWidth, currentElement.ActualHeight); if (currentElement is AppBarButton) - return CheckAppBarButton(currentElement as AppBarButton); + return CheckAppBarButtonVisible(currentElement as AppBarButton); if (currentElement is CommandBar) - return CheckCommandBar(currentElement as CommandBar); + return CheckCommandBarVisible(currentElement as CommandBar); // Check if currentElement is of zero size if (currentElementSize.Width <= 0 || currentElementSize.Height <= 0) @@ -89,27 +89,25 @@ internal bool IsUserVisible() } } - private CommandBar FindCommandBar(AppBarButton element) + private CommandBar FindCommandBarIfVisible(AppBarButton element) { - DependencyObject parent = element; + FrameworkElement parent = element; while ( parent != null ) { - parent = VisualTreeHelper.GetParent(parent); - - FrameworkElement parentElement = parent as FrameworkElement; - - if (parentElement != null && parentElement.Visibility == Visibility.Collapsed ) + if (parent.Visibility == Visibility.Collapsed ) return null; if (parent.GetType() == typeof(AppBar) || parent.GetType() == typeof(CommandBar)) return parent as CommandBar; + + parent = VisualTreeHelper.GetParent(parent) as FrameworkElement; } return null; } - private bool CheckAppBarButton(AppBarButton appBarButton ) + private bool CheckAppBarButtonVisible(AppBarButton appBarButton ) { if ( appBarButton == null) return false; @@ -117,10 +115,10 @@ private bool CheckAppBarButton(AppBarButton appBarButton ) if (appBarButton.IsCompact || !appBarButton.IsEnabled || appBarButton.Visibility != Visibility.Visible ) return false; - return CheckCommandBar(FindCommandBar(appBarButton)); + return CheckCommandBarVisible(FindCommandBarIfVisible(appBarButton)); } - private bool CheckCommandBar(CommandBar bar) + private bool CheckCommandBarVisible(CommandBar bar) { return ( bar != null && bar.IsEnabled && bar.Visibility == Visibility.Visible ); } From 6dffd3228622fed330f2c959624ff54cd3486735 Mon Sep 17 00:00:00 2001 From: Ole Vegard Mythe Moland Date: Thu, 22 Oct 2015 14:11:12 +0200 Subject: [PATCH 11/21] Changed click in Winium.StoreApps -ClickCommand is forwarded to InnerDriver -InnerDriver performs click by automation peer --- .../CommandExecutors/ClickElementExecutor.cs | 10 +++-- .../Winium.StoreApps.InnerServer/Automator.cs | 4 ++ .../Commands/ClickCommand.cs | 44 +++++++++++++++++++ .../Winium.StoreApps.InnerServer.csproj | 1 + 4 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 Winium/Winium.StoreApps.InnerServer/Commands/ClickCommand.cs diff --git a/Winium/Winium.StoreApps.Driver/CommandExecutors/ClickElementExecutor.cs b/Winium/Winium.StoreApps.Driver/CommandExecutors/ClickElementExecutor.cs index c1885d4..ff42644 100644 --- a/Winium/Winium.StoreApps.Driver/CommandExecutors/ClickElementExecutor.cs +++ b/Winium/Winium.StoreApps.Driver/CommandExecutors/ClickElementExecutor.cs @@ -3,6 +3,7 @@ #region using Winium.StoreApps.Driver.Automator; + using System; #endregion @@ -27,9 +28,12 @@ internal static bool ClickElement(Automator automator, string elementId) protected override string DoImpl() { - ClickElement(this.Automator, this.ExecutedCommand.Parameters["ID"].ToString()); - - return this.JsonResponse(); + try { + return this.Automator.CommandForwarder.ForwardCommand(this.ExecutedCommand); + } catch (Exception e) { + ClickElement(this.Automator, this.ExecutedCommand.Parameters["ID"].ToString()); + return this.JsonResponse(); + } } #endregion diff --git a/Winium/Winium.StoreApps.InnerServer/Automator.cs b/Winium/Winium.StoreApps.InnerServer/Automator.cs index bd14b74..baaab36 100644 --- a/Winium/Winium.StoreApps.InnerServer/Automator.cs +++ b/Winium/Winium.StoreApps.InnerServer/Automator.cs @@ -153,6 +153,10 @@ public string ProcessCommand(string content) { commandToExecute = new CloseAppCommand(); } + else if (command.Equals(DriverCommand.ClickElement)) + { + commandToExecute = new ClickCommand {ElementId = elementId}; + } else { throw new NotImplementedException("Not implemented: " + command); diff --git a/Winium/Winium.StoreApps.InnerServer/Commands/ClickCommand.cs b/Winium/Winium.StoreApps.InnerServer/Commands/ClickCommand.cs new file mode 100644 index 0000000..6d3e087 --- /dev/null +++ b/Winium/Winium.StoreApps.InnerServer/Commands/ClickCommand.cs @@ -0,0 +1,44 @@ +namespace Winium.StoreApps.InnerServer.Commands +{ + #region + + using Windows.UI.Xaml.Automation.Peers; + using Windows.UI.Xaml.Automation.Provider; + using Windows.UI.Xaml.Controls; + using Common; + + #endregion + + internal class ClickCommand : CommandBase + { + #region Public Properties + + public string ElementId { private get; set; } + + #endregion + + #region Public Methods and Operators + + protected override string DoImpl() + { + var element = this.Automator.ElementsRegistry.GetRegisteredElement(this.ElementId); + Button button = element.Element as Button; + if (button != null) + { + ButtonAutomationPeer peer = new ButtonAutomationPeer(button); + IInvokeProvider invokeProv = peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider; + if (invokeProv != null) + { + invokeProv.Invoke(); + return this.JsonResponse(ResponseStatus.Success, ""); + } + + return this.JsonResponse(ResponseStatus.UnknownError, "Failed to create invocation provider"); + } + + return this.JsonResponse(ResponseStatus.UnknownError, "Element is not a button"); + } + + #endregion + } +} \ No newline at end of file diff --git a/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj b/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj index 18be416..1987459 100644 --- a/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj +++ b/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj @@ -47,6 +47,7 @@ + From b4046121e2000fc3a77eeb300a27ac311086805b Mon Sep 17 00:00:00 2001 From: Ole Vegard Mythe Moland Date: Fri, 23 Oct 2015 13:49:07 +0200 Subject: [PATCH 12/21] Added id to error message -Added id to error when not being able to click button --- Winium/Winium.StoreApps.InnerServer/Commands/ClickCommand.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Winium/Winium.StoreApps.InnerServer/Commands/ClickCommand.cs b/Winium/Winium.StoreApps.InnerServer/Commands/ClickCommand.cs index 6d3e087..e6dfe68 100644 --- a/Winium/Winium.StoreApps.InnerServer/Commands/ClickCommand.cs +++ b/Winium/Winium.StoreApps.InnerServer/Commands/ClickCommand.cs @@ -33,10 +33,10 @@ protected override string DoImpl() return this.JsonResponse(ResponseStatus.Success, ""); } - return this.JsonResponse(ResponseStatus.UnknownError, "Failed to create invocation provider"); + return this.JsonResponse(ResponseStatus.UnknownError, "Failed to create invocation provider : " + this.ElementId); } - return this.JsonResponse(ResponseStatus.UnknownError, "Element is not a button"); + return this.JsonResponse(ResponseStatus.UnknownError, "Element is not a button" + this.ElementId); } #endregion From c12a6828e95a58519aec35b5bdb3cc81ee5c8040 Mon Sep 17 00:00:00 2001 From: Audun Steinholm Date: Thu, 5 Nov 2015 20:05:16 +0100 Subject: [PATCH 13/21] Added script for reading text file from local isolated storage --- .../CommandExecutors/ExecuteScriptExecutor.cs | 18 ++++++- .../ReadLocalTextFileExecutor.cs | 47 +++++++++++++++++++ .../Winium.StoreApps.Driver.csproj | 1 + 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 Winium/Winium.StoreApps.Driver/CommandExecutors/ReadLocalTextFileExecutor.cs diff --git a/Winium/Winium.StoreApps.Driver/CommandExecutors/ExecuteScriptExecutor.cs b/Winium/Winium.StoreApps.Driver/CommandExecutors/ExecuteScriptExecutor.cs index aa3fce7..6816b4b 100644 --- a/Winium/Winium.StoreApps.Driver/CommandExecutors/ExecuteScriptExecutor.cs +++ b/Winium/Winium.StoreApps.Driver/CommandExecutors/ExecuteScriptExecutor.cs @@ -1,4 +1,6 @@ -namespace Winium.StoreApps.Driver.CommandExecutors +using System.Collections.Generic; + +namespace Winium.StoreApps.Driver.CommandExecutors { #region @@ -50,6 +52,17 @@ internal object ExecuteMobileScript(string command) return null; } + internal object ExecuteStorageScript(string command) + { + switch (command) + { + case "ReadLocalTextFile": + return ReadLocalTextFileExecutor.ReadFile(this.Automator, ExecutedCommand); + default: + throw new AutomationException("Unknown storage command: " + command, ResponseStatus.UnknownCommand); + } + } + internal object ForwardCommand() { var responseBody = this.Automator.CommandForwarder.ForwardCommand(this.ExecutedCommand); @@ -87,6 +100,9 @@ protected override string DoImpl() case "mobile:": response = this.ExecuteMobileScript(command); break; + case "storage:": + response = this.ExecuteStorageScript(command); + break; default: response = this.ForwardCommand(); break; diff --git a/Winium/Winium.StoreApps.Driver/CommandExecutors/ReadLocalTextFileExecutor.cs b/Winium/Winium.StoreApps.Driver/CommandExecutors/ReadLocalTextFileExecutor.cs new file mode 100644 index 0000000..25a6c7a --- /dev/null +++ b/Winium/Winium.StoreApps.Driver/CommandExecutors/ReadLocalTextFileExecutor.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Winium.StoreApps.Common.Exceptions; + +namespace Winium.StoreApps.Driver.CommandExecutors +{ + using System; + using System.Threading; + + using Winium.StoreApps.Common; + using Winium.StoreApps.Driver.Automator; + + internal class ReadLocalTextFileExecutor : CommandExecutorBase + { + #region Public Methods and Operators + + public static string ReadFile(Automator automator, Command command) + { + var args = command.Parameters["args"] as JArray; + if (args == null || args.Count == 0) { + throw new AutomationException("Missing file name", ResponseStatus.UnknownCommand); + } + + var filename = args[0].ToString(); + var filePath = Path.GetTempFileName(); + automator.Deployer.ReceiveFile("Local", filename, filePath); + using (var file = File.OpenText(filePath)) { + return file.ReadToEnd(); + } + } + + #endregion + + #region Methods + + protected override string DoImpl() + { + var fileContent = ReadFile(this.Automator, this.ExecutedCommand); + return this.JsonResponse(ResponseStatus.Success, fileContent); + } + + #endregion + } +} diff --git a/Winium/Winium.StoreApps.Driver/Winium.StoreApps.Driver.csproj b/Winium/Winium.StoreApps.Driver/Winium.StoreApps.Driver.csproj index 2439df5..ca780cf 100644 --- a/Winium/Winium.StoreApps.Driver/Winium.StoreApps.Driver.csproj +++ b/Winium/Winium.StoreApps.Driver/Winium.StoreApps.Driver.csproj @@ -95,6 +95,7 @@ + From 3e1134f6d9b1cbba796e48e5c317a05af2deac98 Mon Sep 17 00:00:00 2001 From: Audun Steinholm Date: Fri, 6 Nov 2015 17:40:37 +0100 Subject: [PATCH 14/21] MouseMoveToExecutor works with move_to_element_with_offset --- .../Automator/Automator.cs | 35 +++++++++++++++++++ .../CommandExecutors/MouseMoveToExecutor.cs | 24 +++++++++---- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/Winium/Winium.StoreApps.Driver/Automator/Automator.cs b/Winium/Winium.StoreApps.Driver/Automator/Automator.cs index f76c57e..cd84e77 100644 --- a/Winium/Winium.StoreApps.Driver/Automator/Automator.cs +++ b/Winium/Winium.StoreApps.Driver/Automator/Automator.cs @@ -214,6 +214,41 @@ public void InitializeApp() return new Point(x, y); } + public Rectangle? RequestElementRect(JToken element) + { + var command = new Command( + DriverCommand.GetElementRect, + new Dictionary { { "ID", element } }); + + var responseBody = this.CommandForwarder.ForwardCommand(command); + + var deserializeObject = JsonConvert.DeserializeObject(responseBody); + + if (deserializeObject.Status != ResponseStatus.Success) + { + return null; + } + + var locationObject = deserializeObject.Value as JObject; + if (locationObject == null) + { + return null; + } + + var location = locationObject.ToObject>(); + + if (location == null) + { + return null; + } + + var x = location["x"]; + var y = location["y"]; + var width = location["width"]; + var height = location["height"]; + return new Rectangle(x, y, width, height); + } + #endregion #region Methods diff --git a/Winium/Winium.StoreApps.Driver/CommandExecutors/MouseMoveToExecutor.cs b/Winium/Winium.StoreApps.Driver/CommandExecutors/MouseMoveToExecutor.cs index a21aa13..e93d680 100644 --- a/Winium/Winium.StoreApps.Driver/CommandExecutors/MouseMoveToExecutor.cs +++ b/Winium/Winium.StoreApps.Driver/CommandExecutors/MouseMoveToExecutor.cs @@ -17,16 +17,26 @@ internal class MouseMoveToExecutor : CommandExecutorBase protected override string DoImpl() { var elementId = Automator.GetValue(this.ExecutedCommand.Parameters, "element"); - Point coordinates; - if (elementId != null) + var xOffsetParam = this.ExecutedCommand.Parameters["xoffset"]; + var yOffsetParam = this.ExecutedCommand.Parameters["yoffset"]; + + Point coordinates = new Point(); + if (xOffsetParam != null && yOffsetParam != null) { - coordinates = this.Automator.RequestElementLocation(elementId).GetValueOrDefault(); + var xOffset = Convert.ToInt32(xOffsetParam, CultureInfo.InvariantCulture); + var yOffset = Convert.ToInt32(yOffsetParam, CultureInfo.InvariantCulture); + coordinates = new Point(xOffset, yOffset); + + if (elementId != null) + { + var elementRect = Automator.RequestElementRect(elementId).GetValueOrDefault(); + coordinates.X += elementRect.X; + coordinates.Y += elementRect.Y; + } } - else + else if (elementId != null) { - var xOffset = Convert.ToInt32(this.ExecutedCommand.Parameters["xoffset"], CultureInfo.InvariantCulture); - var yOffset = Convert.ToInt32(this.ExecutedCommand.Parameters["yoffset"], CultureInfo.InvariantCulture); - coordinates = new Point(xOffset, yOffset); + coordinates = this.Automator.RequestElementLocation(elementId).GetValueOrDefault(); } this.Automator.EmulatorController.MoveCursorTo(coordinates); From 8ccc359ddd94c63f59aae125907dd0be30155aa3 Mon Sep 17 00:00:00 2001 From: Magnar Nedland Date: Tue, 17 Nov 2015 13:50:30 +0100 Subject: [PATCH 15/21] Allow attributes from FrameworkElementExtensions. Currently retrieves result from no-argument extension functions. Should be changed to use DependencyProperties directly, like the implementation in FrameworkElementExtensions does. --- .../Element/WiniumElement.GetSetAttribute.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.GetSetAttribute.cs b/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.GetSetAttribute.cs index 7eb232f..0138f86 100644 --- a/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.GetSetAttribute.cs +++ b/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.GetSetAttribute.cs @@ -9,6 +9,7 @@ using Newtonsoft.Json.Linq; using Winium.StoreApps.Common.Exceptions; + using Winium.StoreApps.InnerServer.Commands.Helpers; #endregion @@ -25,10 +26,21 @@ internal object GetAttribute(string attributeName) { return targetPropertyInfo.GetValue(targetObject, null); } - + // TODO: Use DependencyProperty lookup instead of FrameworkElementExtensions. + object attribute = this.GetExtensionAttribute(attributeName); + if (attribute != null) { + return attribute; + } throw new AutomationException("Could not access attribute {0}.", attributeName); } + private object GetExtensionAttribute(string attributeName) + { + MethodInfo method = typeof(FrameworkElementExtensions).GetRuntimeMethods().First(m => m.Name.Equals(attributeName)); + object[] parameters = { this.Element }; + return method?.Invoke(null, parameters); + } + internal void SetAttribute(string attributeName, JToken value) { object targetObject; From 00b92e5eb98aac5f0265c74cfca00830f95c302b Mon Sep 17 00:00:00 2001 From: Audun Steinholm Date: Thu, 19 Nov 2015 11:25:12 +0100 Subject: [PATCH 16/21] Remove stale registrations of WiniumElement --- Winium/Winium.StoreApps.InnerServer/ElementsRegistry.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Winium/Winium.StoreApps.InnerServer/ElementsRegistry.cs b/Winium/Winium.StoreApps.InnerServer/ElementsRegistry.cs index a2f8669..8db9a7e 100644 --- a/Winium/Winium.StoreApps.InnerServer/ElementsRegistry.cs +++ b/Winium/Winium.StoreApps.InnerServer/ElementsRegistry.cs @@ -64,6 +64,11 @@ public string RegisterElement(WiniumElement element) this.registredElements.Add(registeredKey, element); } + var staleElements = registredElements.Where(x => x.Value.IsStale).ToList(); + foreach (var staleElement in staleElements) { + this.registredElements.Remove(staleElement.Key); + } + return registeredKey; } From 19925c43a3803c45265c2bd69ef8d9313576816c Mon Sep 17 00:00:00 2001 From: Audun Steinholm Date: Sat, 28 Nov 2015 09:36:28 +0100 Subject: [PATCH 17/21] Fixed bug in AlertCommand --- .../Commands/AlertCommand.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Winium/Winium.StoreApps.InnerServer/Commands/AlertCommand.cs b/Winium/Winium.StoreApps.InnerServer/Commands/AlertCommand.cs index 8000607..1556cbd 100644 --- a/Winium/Winium.StoreApps.InnerServer/Commands/AlertCommand.cs +++ b/Winium/Winium.StoreApps.InnerServer/Commands/AlertCommand.cs @@ -40,8 +40,14 @@ protected override string DoImpl() { var buttonName = this.Action == With.Accept ? "Button1Host" : "Button2Host"; - var popup = WiniumVirtualRoot.Current.OpenPopups.FirstOrDefault(); - if (popup == null || !popup.ClassName.EndsWith(".ContentDialog")) + WiniumElement popup = null; + foreach (var winiumElement in WiniumVirtualRoot.Current.OpenPopups) { + if (winiumElement.ClassName.EndsWith(".ContentDialog")) { + popup = winiumElement; + break; + } + } + if (popup == null) { throw new AutomationException("No alert is displayed", ResponseStatus.NoAlertOpenError); } From ca0391c1563da0626b6ee9a36087402ec4764456 Mon Sep 17 00:00:00 2001 From: Rune Karlsen Date: Thu, 17 Mar 2016 13:57:58 +0100 Subject: [PATCH 18/21] Fix project files for Release ARM build to store * changed Windows Phone dependent .csproj files to not use pdbonly debug for any Release config Fixes: CAPSOL-106 --- .../Winium.StoreApps.Common.csproj | 14 +++++++++++--- .../Winium.StoreApps.InnerServer.csproj | 14 +++++++++++--- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Winium/Winium.StoreApps.Common/Winium.StoreApps.Common.csproj b/Winium/Winium.StoreApps.Common/Winium.StoreApps.Common.csproj index c65339e..a0a89ad 100644 --- a/Winium/Winium.StoreApps.Common/Winium.StoreApps.Common.csproj +++ b/Winium/Winium.StoreApps.Common/Winium.StoreApps.Common.csproj @@ -3,8 +3,8 @@ 12.0 - Debug - AnyCPU + Release + ARM {3C8D0B9C-576B-4778-97B1-6839AA944AEE} Library Properties @@ -28,7 +28,15 @@ 4 - pdbonly + none + true + bin\Release\ + TRACE + prompt + 4 + + + none true bin\Release\ TRACE diff --git a/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj b/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj index 1987459..5700d57 100644 --- a/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj +++ b/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj @@ -3,8 +3,8 @@ 12.0 - Debug - AnyCPU + Release + ARM {E8683025-E703-4293-AA7E-3A9A3555BC40} Library Properties @@ -28,7 +28,15 @@ 4 - pdbonly + none + true + bin\Release\ + TRACE + prompt + 4 + + + none true bin\Release\ TRACE From 4161eadd640bd00e305a1c92a07c524730a8dde2 Mon Sep 17 00:00:00 2001 From: Rune Karlsen Date: Thu, 17 Mar 2016 18:09:10 +0100 Subject: [PATCH 19/21] Use "pdbonly" for all Release configurations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * deciding on using “pdbonly” as DebugType for .csproj files * See updated information on `pdbonly` for [CaptureXamarin/pull/337](https://github.com/NetlifeBackupSolutions/Capt ureXamarin/pull/337) Relates to: CAPSOL-106 --- Winium/Winium.StoreApps.Common/Winium.StoreApps.Common.csproj | 4 ++-- .../Winium.StoreApps.InnerServer.csproj | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Winium/Winium.StoreApps.Common/Winium.StoreApps.Common.csproj b/Winium/Winium.StoreApps.Common/Winium.StoreApps.Common.csproj index a0a89ad..659719e 100644 --- a/Winium/Winium.StoreApps.Common/Winium.StoreApps.Common.csproj +++ b/Winium/Winium.StoreApps.Common/Winium.StoreApps.Common.csproj @@ -28,7 +28,7 @@ 4 - none + pdbonly true bin\Release\ TRACE @@ -36,7 +36,7 @@ 4 - none + pdbonly true bin\Release\ TRACE diff --git a/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj b/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj index 5700d57..b44c502 100644 --- a/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj +++ b/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj @@ -28,7 +28,7 @@ 4 - none + pdbonly true bin\Release\ TRACE @@ -36,7 +36,7 @@ 4 - none + pdbonly true bin\Release\ TRACE From 58c2a9fdd5c11081a1907f61fec36656617f105a Mon Sep 17 00:00:00 2001 From: Rune Karlsen Date: Fri, 18 Mar 2016 13:03:49 +0100 Subject: [PATCH 20/21] Revert "Fix project files for Release ARM build to store" --- .../Winium.StoreApps.Common.csproj | 12 ++---------- .../Winium.StoreApps.InnerServer.csproj | 12 ++---------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/Winium/Winium.StoreApps.Common/Winium.StoreApps.Common.csproj b/Winium/Winium.StoreApps.Common/Winium.StoreApps.Common.csproj index 659719e..c65339e 100644 --- a/Winium/Winium.StoreApps.Common/Winium.StoreApps.Common.csproj +++ b/Winium/Winium.StoreApps.Common/Winium.StoreApps.Common.csproj @@ -3,8 +3,8 @@ 12.0 - Release - ARM + Debug + AnyCPU {3C8D0B9C-576B-4778-97B1-6839AA944AEE} Library Properties @@ -35,14 +35,6 @@ prompt 4 - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - diff --git a/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj b/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj index b44c502..1987459 100644 --- a/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj +++ b/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj @@ -3,8 +3,8 @@ 12.0 - Release - ARM + Debug + AnyCPU {E8683025-E703-4293-AA7E-3A9A3555BC40} Library Properties @@ -35,14 +35,6 @@ prompt 4 - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - From a9443776fbd663d8ad3d95dcf5ddbe35219a68ff Mon Sep 17 00:00:00 2001 From: Ole Vegard Mythe Moland Date: Mon, 11 Apr 2016 14:12:50 +0200 Subject: [PATCH 21/21] Refactor get attribute to use own accessor -Moved functionality to new class, ExtensionPropertyAccessor -Use this new class like the other similar functions --- .../Commands/GetElementAttributeCommand.cs | 5 +++ .../Helpers/ExtensionPropertyAccessor.cs | 43 +++++++++++++++++++ .../Element/WiniumElement.cs | 5 +++ .../Winium.StoreApps.InnerServer.csproj | 1 + 4 files changed, 54 insertions(+) create mode 100644 Winium/Winium.StoreApps.InnerServer/Element/Helpers/ExtensionPropertyAccessor.cs diff --git a/Winium/Winium.StoreApps.InnerServer/Commands/GetElementAttributeCommand.cs b/Winium/Winium.StoreApps.InnerServer/Commands/GetElementAttributeCommand.cs index 825cd26..7ffaa66 100644 --- a/Winium/Winium.StoreApps.InnerServer/Commands/GetElementAttributeCommand.cs +++ b/Winium/Winium.StoreApps.InnerServer/Commands/GetElementAttributeCommand.cs @@ -56,6 +56,11 @@ internal static object GetPropertyCascade( return propertyObject; } + if (element.TryGetExtensionProperty(key, out propertyObject)) + { + return propertyObject; + } + return null; } diff --git a/Winium/Winium.StoreApps.InnerServer/Element/Helpers/ExtensionPropertyAccessor.cs b/Winium/Winium.StoreApps.InnerServer/Element/Helpers/ExtensionPropertyAccessor.cs new file mode 100644 index 0000000..e269fd7 --- /dev/null +++ b/Winium/Winium.StoreApps.InnerServer/Element/Helpers/ExtensionPropertyAccessor.cs @@ -0,0 +1,43 @@ +using Winium.StoreApps.InnerServer.Commands.Helpers; + +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 ExtensionPropertyAccessor + { + #region Public Methods and Operators + + public static bool TryGetProperty(FrameworkElement element, string propertyName, out object value) + { + value = GetExtensionProperty(propertyName, element); + + return value != null; + } + + #endregion + + #region Methods + + private static object GetExtensionProperty(string propertyName, FrameworkElement element) + { + MethodInfo method = typeof(FrameworkElementExtensions).GetRuntimeMethods().First(m => m.Name.Equals(propertyName)); + object[] parameters = {element }; + return method?.Invoke(null, parameters); + } + + #endregion + } +} \ No newline at end of file diff --git a/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.cs b/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.cs index f40292c..b49a77d 100644 --- a/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.cs +++ b/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.cs @@ -170,6 +170,11 @@ public bool TryGetProperty(string attributeName, out object value) return PropertiesAccessor.TryGetProperty(this.Element, attributeName, out value); } + public bool TryGetExtensionProperty(string attributeName, out object value) + { + return ExtensionPropertyAccessor.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 f03b136..44bed67 100644 --- a/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj +++ b/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj @@ -74,6 +74,7 @@ +