diff --git a/README.md b/README.md
index 0d055ee..6e598c6 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,8 @@
+
+# Capture Winium tests
+
+The Capture specific SystemTest documentation can be found [here.](https://gist.github.com/ole-vegard/05ae46c2d7accd170f9f)
+
English description | Описание на русском
diff --git a/Winium/Winium.Mobile.Connectivity/Deployer.cs b/Winium/Winium.Mobile.Connectivity/Deployer.cs
index 906a91f..d16eb2b 100644
--- a/Winium/Winium.Mobile.Connectivity/Deployer.cs
+++ b/Winium/Winium.Mobile.Connectivity/Deployer.cs
@@ -128,6 +128,25 @@ public void SendFiles(List> 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");
@@ -167,19 +186,6 @@ private IAppManifestInfo InstallApplicationPackage(string path)
return appManifest;
}
- private void InstallDependencies(List dependencies)
- {
- if (dependencies == null || !dependencies.Any())
- {
- return;
- }
-
- foreach (var dependency in dependencies)
- {
- this.InstallApplicationPackage(dependency);
- }
- }
-
#endregion
}
}
diff --git a/Winium/Winium.StoreApps.Driver/Automator/Automator.cs b/Winium/Winium.StoreApps.Driver/Automator/Automator.cs
index 63e8d73..c292a4d 100644
--- a/Winium/Winium.StoreApps.Driver/Automator/Automator.cs
+++ b/Winium/Winium.StoreApps.Driver/Automator/Automator.cs
@@ -244,6 +244,41 @@ private void InitializeDeployer()
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/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.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/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);
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 d847afa..f2b981a 100644
--- a/Winium/Winium.StoreApps.Driver/Winium.StoreApps.Driver.csproj
+++ b/Winium/Winium.StoreApps.Driver/Winium.StoreApps.Driver.csproj
@@ -56,6 +56,7 @@
+
diff --git a/Winium/Winium.StoreApps.InnerServer/Automator.cs b/Winium/Winium.StoreApps.InnerServer/Automator.cs
index c784a16..c5a8159 100644
--- a/Winium/Winium.StoreApps.InnerServer/Automator.cs
+++ b/Winium/Winium.StoreApps.InnerServer/Automator.cs
@@ -157,6 +157,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/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);
}
diff --git a/Winium/Winium.StoreApps.InnerServer/Commands/ClickCommand.cs b/Winium/Winium.StoreApps.InnerServer/Commands/ClickCommand.cs
new file mode 100644
index 0000000..e6dfe68
--- /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 : " + this.ElementId);
+ }
+
+ return this.JsonResponse(ResponseStatus.UnknownError, "Element is not a button" + this.ElementId);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Winium/Winium.StoreApps.InnerServer/Commands/CommandBase.cs b/Winium/Winium.StoreApps.InnerServer/Commands/CommandBase.cs
index 95f3dac..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;
@@ -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);
}
}
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.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)
diff --git a/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.IsUserVisible.cs b/Winium/Winium.StoreApps.InnerServer/Element/WiniumElement.IsUserVisible.cs
index 145e0e8..7a1605a 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,12 @@ internal bool IsUserVisible()
var currentElementSize = new Size(currentElement.ActualWidth, currentElement.ActualHeight);
+ if (currentElement is AppBarButton)
+ return CheckAppBarButtonVisible(currentElement as AppBarButton);
+
+ if (currentElement is CommandBar)
+ return CheckCommandBarVisible(currentElement as CommandBar);
+
// Check if currentElement is of zero size
if (currentElementSize.Width <= 0 || currentElementSize.Height <= 0)
{
@@ -46,8 +53,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;
}
@@ -83,6 +89,40 @@ internal bool IsUserVisible()
}
}
+ private CommandBar FindCommandBarIfVisible(AppBarButton element)
+ {
+ FrameworkElement parent = element;
+
+ while ( parent != null )
+ {
+ 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 CheckAppBarButtonVisible(AppBarButton appBarButton )
+ {
+ if ( appBarButton == null)
+ return false;
+
+ if (appBarButton.IsCompact || !appBarButton.IsEnabled || appBarButton.Visibility != Visibility.Visible )
+ return false;
+
+ return CheckCommandBarVisible(FindCommandBarIfVisible(appBarButton));
+ }
+
+ private bool CheckCommandBarVisible(CommandBar bar)
+ {
+ return ( bar != null && bar.IsEnabled && bar.Visibility == Visibility.Visible );
+ }
+
#endregion
}
}
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/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;
}
diff --git a/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj b/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj
index 117f724..44bed67 100644
--- a/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj
+++ b/Winium/Winium.StoreApps.InnerServer/Winium.StoreApps.InnerServer.csproj
@@ -47,6 +47,7 @@
+
@@ -73,6 +74,7 @@
+