From be4339b4c14c56043c83ba9e40de4ab68ce27ddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Tue, 17 Sep 2019 15:08:57 +0300 Subject: [PATCH 01/13] add KeyboardActions for Application for #9 --- .../Actions/IKeyboardActions.cs | 67 +++++++++++++++++ .../Actions/KeyboardActions.cs | 42 +++++++++++ .../Applications/Application.cs | 6 +- .../Applications/ApplicationManager.cs | 1 + .../Actions/KeyboardActionsTests.cs | 73 +++++++++++++++++++ 5 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/IKeyboardActions.cs create mode 100644 Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs create mode 100644 Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/IKeyboardActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/IKeyboardActions.cs new file mode 100644 index 0000000..284648d --- /dev/null +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/IKeyboardActions.cs @@ -0,0 +1,67 @@ +namespace Aquality.WinAppDriver.Actions +{ + /// + /// Provides methods representing basic keyboard actions. + /// + public interface IKeyboardActions + { + /// + /// Presses a key. + /// + /// The key value representing the key to press. + /// The key value must be one of the values from the class. + /// If the key sent is not is not one of: + /// , + /// , + /// , + /// , + /// , + /// , + /// , + /// + /// + void PressKey(string keyToPress); + + /// + /// Releases a key. + /// + /// The key value representing the key to release. + /// The key value must be one of the values from the class. + /// If the key sent is not is not one of: + /// , + /// , + /// , + /// , + /// , + /// , + /// , + /// + /// + void ReleaseKey(string keyToRelease); + + /// + /// Sends a sequence of keystrokes to the target. + /// + /// A string representing the keystrokes to send. + void SendKeys(string keySequence); + + /// + /// Sends a sequence of keystrokes to the target, holding a specified key. + /// After the action, holded key is released. + /// + /// A string representing the keystrokes to send. + /// The key value representing the key to hold. + /// The key value must be one of the values from the class. + /// If the key sent is not is not one of: + /// , + /// , + /// , + /// , + /// , + /// , + /// , + /// + /// + void SendKeysWithKeyHold(string keySequence, string keyToHold); + } +} diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs new file mode 100644 index 0000000..30e2e46 --- /dev/null +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs @@ -0,0 +1,42 @@ +using Aquality.Selenium.Core.Localization; +using OpenQA.Selenium.Appium.Windows; +using SeleniumActions = OpenQA.Selenium.Interactions.Actions; + +namespace Aquality.WinAppDriver.Actions +{ + public class KeyboardActions : IKeyboardActions + { + private readonly LocalizationLogger localizationLogger; + private readonly WindowsDriver windowsDriver; + + public KeyboardActions(LocalizationLogger localizationLogger, WindowsDriver windowsDriver) + { + this.localizationLogger = localizationLogger; + this.windowsDriver = windowsDriver; + } + + public void PressKey(string keyToPress) + { + localizationLogger.Info("loc.keyboard.presskey", keyToPress); + new SeleniumActions(windowsDriver).KeyDown(keyToPress).Build().Perform(); + } + + public void ReleaseKey(string keyToRelease) + { + localizationLogger.Info("loc.keyboard.releasekey", keyToRelease); + new SeleniumActions(windowsDriver).KeyUp(keyToRelease).Build().Perform(); + } + + public void SendKeys(string keySequence) + { + localizationLogger.Info("loc.keyboard.sendkeys", keySequence); + new SeleniumActions(windowsDriver).SendKeys(keySequence).Build().Perform(); + } + + public void SendKeysWithKeyHold(string keySequence, string keyToHold) + { + localizationLogger.Info("loc.keyboard.sendkeys.withkeyhold", keySequence); + new SeleniumActions(windowsDriver).KeyDown(keyToHold).SendKeys(keySequence).KeyUp(keyToHold).Build().Perform(); + } + } +} diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs index 89d8adb..1e07665 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs @@ -2,6 +2,7 @@ using Aquality.Selenium.Core.Applications; using Aquality.Selenium.Core.Configurations; using Aquality.Selenium.Core.Localization; +using Aquality.WinAppDriver.Actions; using OpenQA.Selenium.Appium.Windows; using OpenQA.Selenium.Remote; @@ -20,11 +21,12 @@ public class Application : IApplication /// Instance of WinAppDriver /// Instance of /// Instance of - public Application(WindowsDriver windowsDriver, ITimeoutConfiguration timeoutConfiguration, LocalizationLogger logger) + public Application(WindowsDriver windowsDriver, ITimeoutConfiguration timeoutConfiguration, LocalizationLogger logger, IKeyboardActions keyboardActions = null) { Logger = logger; WindowsDriver = windowsDriver; WindowsDriver.Manage().Timeouts().ImplicitWait = timeoutConfiguration.Implicit; + KeyboardActions = keyboardActions ?? new KeyboardActions(logger, windowsDriver); logger.Info("loc.application.ready"); } @@ -37,6 +39,8 @@ public Application(WindowsDriver windowsDriver, ITimeoutConfigur /// public WindowsDriver WindowsDriver { get; } + public IKeyboardActions KeyboardActions { get; } + /// /// Sets WinAppDriver ImplicitWait timeout. /// Default value: . diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs index 7d8846d..89b01ce 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs @@ -11,6 +11,7 @@ using OpenQA.Selenium.Appium.Service; using Aquality.Selenium.Core.Logging; using System.Reflection; +using Aquality.WinAppDriver.Actions; namespace Aquality.WinAppDriver.Applications { diff --git a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs new file mode 100644 index 0000000..91cac3a --- /dev/null +++ b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs @@ -0,0 +1,73 @@ +using Aquality.WinAppDriver.Actions; +using Aquality.WinAppDriver.Applications; +using Aquality.WinAppDriver.Elements.Interfaces; +using NUnit.Framework; +using OpenQA.Selenium; +using OpenQA.Selenium.Appium; +using System; + +namespace Aquality.WinAppDriver.Tests.Elements +{ + public class KeyboardActionsTests : TestWithApplication + { + private const string ValueToSend = "abc"; + private IKeyboardActions KeyboardActions => ApplicationManager.Application.KeyboardActions; + + private ITextBox RightArgumentTextBox => ApplicationManager.GetRequiredService().GetTextBox(MobileBy.AccessibilityId("49"), "Right Argument"); + + [Test] + public void Should_SendKeys_ViaKeyboardActions() + { + RightArgumentTextBox.Click(); + KeyboardActions.SendKeys(ValueToSend); + Assert.AreEqual(ValueToSend, RightArgumentTextBox.Value); + } + + [Test] + public void Should_PressKey_ViaKeyboardActions() + { + RightArgumentTextBox.Click(); + KeyboardActions.PressKey(Keys.Shift); + KeyboardActions.SendKeys(ValueToSend); + KeyboardActions.ReleaseKey(Keys.Shift); + Assert.AreEqual(ValueToSend.ToUpper(), RightArgumentTextBox.Value); + } + + [Test] + public void Should_SendKeysWithKeyHold_ViaKeyboardActions() + { + RightArgumentTextBox.Click(); + KeyboardActions.SendKeysWithKeyHold(ValueToSend, Keys.Shift); + Assert.AreEqual(ValueToSend.ToUpper(), RightArgumentTextBox.Value); + } + + [Test] + public void Should_ReleaseKey_ViaKeyboardActions() + { + RightArgumentTextBox.Click(); + KeyboardActions.PressKey(Keys.Shift); + KeyboardActions.SendKeys(ValueToSend); + KeyboardActions.ReleaseKey(Keys.Shift); + KeyboardActions.SendKeys(ValueToSend); + Assert.AreEqual($"{ValueToSend.ToUpper()}{ValueToSend}", RightArgumentTextBox.Value); + } + + [Test] + public void Should_ThrowArgumentException_ForInvalidPressedKey_ViaKeyboardActions() + { + Assert.Throws(() => KeyboardActions.PressKey("invalid")); + } + + [Test] + public void Should_ThrowArgumentException_ForInvalidReleasedKey_ViaKeyboardActions() + { + Assert.Throws(() => KeyboardActions.ReleaseKey("invalid")); + } + + [Test] + public void Should_ThrowArgumentException_ForInvalidHoldedKey_ViaKeyboardActions() + { + Assert.Throws(() => KeyboardActions.SendKeysWithKeyHold(ValueToSend, "invalid")); + } + } +} From 1748e8dac9e97b8c05f05ebe89a5831c493de8df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Tue, 17 Sep 2019 16:43:10 +0300 Subject: [PATCH 02/13] Implement element actions to resolve #9 --- .../Actions/KeyboardActions.cs | 36 ++++++-- .../Elements/Actions/KeyboardActions.cs | 86 +++++++++++++++++++ .../Aquality.WinAppDriver/Elements/Element.cs | 8 +- .../Elements/Interfaces/IElement.cs | 4 +- .../Actions/KeyboardActionsTests.cs | 9 +- .../Elements/Actions/KeyboardActionsTests.cs | 9 ++ 6 files changed, 137 insertions(+), 15 deletions(-) create mode 100644 Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs create mode 100644 Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Elements/Actions/KeyboardActionsTests.cs diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs index 30e2e46..1dc5f66 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs @@ -1,5 +1,6 @@ using Aquality.Selenium.Core.Localization; using OpenQA.Selenium.Appium.Windows; +using System; using SeleniumActions = OpenQA.Selenium.Interactions.Actions; namespace Aquality.WinAppDriver.Actions @@ -17,26 +18,45 @@ public KeyboardActions(LocalizationLogger localizationLogger, WindowsDriver actions.KeyDown(keyToPress)); } public void ReleaseKey(string keyToRelease) { - localizationLogger.Info("loc.keyboard.releasekey", keyToRelease); - new SeleniumActions(windowsDriver).KeyUp(keyToRelease).Build().Perform(); + LogAction("loc.keyboard.releasekey", keyToRelease); + PerformAction(actions => actions.KeyUp(keyToRelease)); } public void SendKeys(string keySequence) { - localizationLogger.Info("loc.keyboard.sendkeys", keySequence); - new SeleniumActions(windowsDriver).SendKeys(keySequence).Build().Perform(); + LogAction("loc.keyboard.sendkeys", keySequence); + PerformAction(actions => actions.SendKeys(keySequence)); } public void SendKeysWithKeyHold(string keySequence, string keyToHold) { - localizationLogger.Info("loc.keyboard.sendkeys.withkeyhold", keySequence); - new SeleniumActions(windowsDriver).KeyDown(keyToHold).SendKeys(keySequence).KeyUp(keyToHold).Build().Perform(); + LogAction("loc.keyboard.sendkeys.withkeyhold", keySequence); + PerformAction(actions => actions.KeyDown(keyToHold).SendKeys(keySequence).KeyUp(keyToHold)); + } + + /// + /// Performs submited action against new object. + /// + /// Action to be performed. + protected virtual void PerformAction(Func action) + { + action(new SeleniumActions(windowsDriver)).Build().Perform(); + } + + /// + /// Logs keyboard action in specific format. + /// + /// Key of the localized message. + /// arguments for the localized message + protected virtual void LogAction(string messageKey, params object[] args) + { + localizationLogger.Info(messageKey, args); } } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs new file mode 100644 index 0000000..4047633 --- /dev/null +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs @@ -0,0 +1,86 @@ +using Aquality.Selenium.Core.Applications; +using Aquality.Selenium.Core.Localization; +using Aquality.Selenium.Core.Utilities; +using Aquality.WinAppDriver.Actions; +using Aquality.WinAppDriver.Elements.Interfaces; +using OpenQA.Selenium; +using System; +using SeleniumActions = OpenQA.Selenium.Interactions.Actions; + +namespace Aquality.WinAppDriver.Elements.Actions +{ + /// + /// Implements Keyboard actions for a specific element. + /// + public class KeyboardActions : IKeyboardActions + { + private readonly IElement element; + private readonly string elementType; + private readonly IApplication application; + private readonly LocalizationLogger localizationLogger; + private readonly ElementActionRetrier elementActionsRetrier; + + /// + /// Instantiates Keyboard actions for a specific element. + /// + /// Target element. + /// Target element's type. + /// Current application session. + /// Logger for localized values. + /// Retrier for element actions. + public KeyboardActions(IElement element, string elementType, IApplication application, LocalizationLogger localizationLogger, ElementActionRetrier elementActionsRetrier) + { + this.element = element; + this.elementType = elementType; + this.application = application; + this.localizationLogger = localizationLogger; + this.elementActionsRetrier = elementActionsRetrier; + } + + public void PressKey(string keyToPress) + { + LogElementAction("loc.keyboard.presskey", keyToPress); + PerformAction((actions, element) => actions.KeyDown(element, keyToPress)); + } + + public void ReleaseKey(string keyToRelease) + { + LogElementAction("loc.keyboard.releasekey", keyToRelease); + PerformAction((actions, element) => actions.KeyUp(element, keyToRelease)); + } + + public void SendKeys(string keySequence) + { + LogElementAction("loc.keyboard.sendkeys", keySequence); + PerformAction((actions, element) => actions.SendKeys(element, keySequence)); + } + + public void SendKeysWithKeyHold(string keySequence, string keyToHold) + { + LogElementAction("loc.keyboard.sendkeys.withkeyhold", keySequence); + PerformAction((actions, element) => actions.KeyDown(element, keyToHold).SendKeys(element, keySequence).KeyUp(element, keyToHold)); + } + + /// + /// Performs submited action against new object. + /// + /// Action to be performed. + protected virtual void PerformAction(Func action) + { + elementActionsRetrier.DoWithRetry(() => + { + action(new SeleniumActions(application.Driver), element.GetElement()).Build().Perform(); + }); + } + + /// + /// Logs element action in specific format. + /// + /// Key of the localized message. + /// arguments for the localized message + protected virtual void LogElementAction(string messageKey, params object[] args) + { + localizationLogger.InfoElementAction(elementType, element.Name, messageKey, args); + } + } +} diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Element.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Element.cs index 801ce0f..aa94284 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Element.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Element.cs @@ -3,16 +3,18 @@ using Aquality.Selenium.Core.Localization; using Aquality.Selenium.Core.Utilities; using Aquality.Selenium.Core.Waitings; +using Aquality.WinAppDriver.Actions; using Aquality.WinAppDriver.Applications; using Aquality.WinAppDriver.Elements.Interfaces; using OpenQA.Selenium; +using KeyboardActions = Aquality.WinAppDriver.Elements.Actions.KeyboardActions; using CoreElement = Aquality.Selenium.Core.Elements.Element; using CoreElementFactory = Aquality.Selenium.Core.Elements.Interfaces.IElementFactory; using CoreElementFinder = Aquality.Selenium.Core.Elements.Interfaces.IElementFinder; namespace Aquality.WinAppDriver.Elements { - public abstract class Element : CoreElement + public abstract class Element : CoreElement, IElement { protected Element(By locator, string name) : base(locator, name, ElementState.Displayed) { @@ -26,7 +28,9 @@ protected Element(By locator, string name) : base(locator, name, ElementState.Di protected override CoreElementFactory Factory => CustomFactory; - protected IElementFactory CustomFactory => ApplicationManager.GetRequiredService(); + protected virtual IElementFactory CustomFactory => ApplicationManager.GetRequiredService(); + + public virtual IKeyboardActions KeyboardActions => new KeyboardActions(this, ElementType, Application, LocalizationLogger, ActionRetrier); public T FindChildElement(By childLocator, ElementSupplier supplier = null) where T : IElement { diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Interfaces/IElement.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Interfaces/IElement.cs index f059d7b..a0f671f 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Interfaces/IElement.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Interfaces/IElement.cs @@ -1,8 +1,10 @@ -using CoreElement = Aquality.Selenium.Core.Elements.Interfaces.IElement; +using Aquality.WinAppDriver.Actions; +using CoreElement = Aquality.Selenium.Core.Elements.Interfaces.IElement; namespace Aquality.WinAppDriver.Elements.Interfaces { public interface IElement : CoreElement { + IKeyboardActions KeyboardActions { get; } } } diff --git a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs index 91cac3a..d11626f 100644 --- a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs +++ b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs @@ -1,19 +1,20 @@ using Aquality.WinAppDriver.Actions; using Aquality.WinAppDriver.Applications; using Aquality.WinAppDriver.Elements.Interfaces; +using Aquality.WinAppDriver.Tests.Applications.Locators; using NUnit.Framework; using OpenQA.Selenium; -using OpenQA.Selenium.Appium; using System; -namespace Aquality.WinAppDriver.Tests.Elements +namespace Aquality.WinAppDriver.Tests.Actions { public class KeyboardActionsTests : TestWithApplication { private const string ValueToSend = "abc"; - private IKeyboardActions KeyboardActions => ApplicationManager.Application.KeyboardActions; - private ITextBox RightArgumentTextBox => ApplicationManager.GetRequiredService().GetTextBox(MobileBy.AccessibilityId("49"), "Right Argument"); + protected virtual IKeyboardActions KeyboardActions => ApplicationManager.Application.KeyboardActions; + + protected ITextBox RightArgumentTextBox => new CalculatorWindow().RightArgumentTextBox; [Test] public void Should_SendKeys_ViaKeyboardActions() diff --git a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Elements/Actions/KeyboardActionsTests.cs b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Elements/Actions/KeyboardActionsTests.cs new file mode 100644 index 0000000..8f0e79e --- /dev/null +++ b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Elements/Actions/KeyboardActionsTests.cs @@ -0,0 +1,9 @@ +using Aquality.WinAppDriver.Actions; + +namespace Aquality.WinAppDriver.Tests.Elements.Actions +{ + public class KeyboardActionsTests : Tests.Actions.KeyboardActionsTests + { + protected override IKeyboardActions KeyboardActions => RightArgumentTextBox.KeyboardActions; + } +} From be6ab9a7c5b2a5d23a19bbb0583e613b21fcace7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Tue, 17 Sep 2019 17:14:37 +0300 Subject: [PATCH 03/13] add localization for new actions, fixed logging of Keys to fix #9. --- .../Actions/KeyboardActions.cs | 7 +++--- .../Elements/Actions/KeyboardActions.cs | 7 +++--- .../Extensions/StringExtensions.cs | 22 +++++++++++++++++++ .../Resources/Localization/be.json | 6 ++++- .../Resources/Localization/en.json | 6 ++++- .../Resources/Localization/ru.json | 6 ++++- 6 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/StringExtensions.cs diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs index 1dc5f66..cde880f 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs @@ -1,4 +1,5 @@ using Aquality.Selenium.Core.Localization; +using Aquality.WinAppDriver.Extensions; using OpenQA.Selenium.Appium.Windows; using System; using SeleniumActions = OpenQA.Selenium.Interactions.Actions; @@ -18,13 +19,13 @@ public KeyboardActions(LocalizationLogger localizationLogger, WindowsDriver actions.KeyDown(keyToPress)); } public void ReleaseKey(string keyToRelease) { - LogAction("loc.keyboard.releasekey", keyToRelease); + LogAction("loc.keyboard.releasekey", keyToRelease.GetLoggableValueForKeyboardKey()); PerformAction(actions => actions.KeyUp(keyToRelease)); } @@ -36,7 +37,7 @@ public void SendKeys(string keySequence) public void SendKeysWithKeyHold(string keySequence, string keyToHold) { - LogAction("loc.keyboard.sendkeys.withkeyhold", keySequence); + LogAction("loc.keyboard.sendkeys.withkeyhold", keySequence, keyToHold.GetLoggableValueForKeyboardKey()); PerformAction(actions => actions.KeyDown(keyToHold).SendKeys(keySequence).KeyUp(keyToHold)); } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs index 4047633..1210724 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs @@ -3,6 +3,7 @@ using Aquality.Selenium.Core.Utilities; using Aquality.WinAppDriver.Actions; using Aquality.WinAppDriver.Elements.Interfaces; +using Aquality.WinAppDriver.Extensions; using OpenQA.Selenium; using System; using SeleniumActions = OpenQA.Selenium.Interactions.Actions; @@ -39,13 +40,13 @@ public KeyboardActions(IElement element, string elementType, IApplication applic public void PressKey(string keyToPress) { - LogElementAction("loc.keyboard.presskey", keyToPress); + LogElementAction("loc.keyboard.presskey", keyToPress.GetLoggableValueForKeyboardKey()); PerformAction((actions, element) => actions.KeyDown(element, keyToPress)); } public void ReleaseKey(string keyToRelease) { - LogElementAction("loc.keyboard.releasekey", keyToRelease); + LogElementAction("loc.keyboard.releasekey", keyToRelease.GetLoggableValueForKeyboardKey()); PerformAction((actions, element) => actions.KeyUp(element, keyToRelease)); } @@ -57,7 +58,7 @@ public void SendKeys(string keySequence) public void SendKeysWithKeyHold(string keySequence, string keyToHold) { - LogElementAction("loc.keyboard.sendkeys.withkeyhold", keySequence); + LogElementAction("loc.keyboard.sendkeys.withkeyhold", keySequence, keyToHold.GetLoggableValueForKeyboardKey()); PerformAction((actions, element) => actions.KeyDown(element, keyToHold).SendKeys(element, keySequence).KeyUp(element, keyToHold)); } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/StringExtensions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/StringExtensions.cs new file mode 100644 index 0000000..5e0eb0a --- /dev/null +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/StringExtensions.cs @@ -0,0 +1,22 @@ +using OpenQA.Selenium; +using System.Linq; +using System.Reflection; + +namespace Aquality.WinAppDriver.Extensions +{ + public static class StringExtensions + { + /// + /// Returns name of the value from , readable in the log. + /// + /// Keyboard key to define. + /// Readable value. + public static string GetLoggableValueForKeyboardKey(this string key) + { + return typeof(Keys) + .GetFields(BindingFlags.Public | BindingFlags.Static) + .ToList() + .FirstOrDefault(field => key.Equals(field.GetValue(null)))?.Name ?? key; + } + } +} diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/be.json b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/be.json index 1cfb140..84793c5 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/be.json +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/be.json @@ -17,5 +17,9 @@ "loc.label": "Надпіс", "loc.text.field": "Тэкставае поле", "loc.text.clearing": "Aчышчаем", - "loc.text.typing": "Уводзім значэнне '{0}'" + "loc.text.typing": "Уводзім значэнне '{0}'", + "loc.keyboard.presskey": "Заціскаем клавішу '{0}'", + "loc.keyboard.releasekey": "Адпускаем клавішу '{0}'", + "loc.keyboard.sendkeys": "Націскаем клавішы '{0}'", + "loc.keyboard.sendkeys.withkeyhold": "Націскаем клавішы '{0}' з заціснутай клавішай '{1}'" } \ No newline at end of file diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/en.json b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/en.json index 67e7054..03aabf2 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/en.json +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/en.json @@ -17,5 +17,9 @@ "loc.label": "Label", "loc.text.field": "Text Field", "loc.text.clearing": "Clearing", - "loc.text.typing": "Typing '{0}'" + "loc.text.typing": "Typing '{0}'", + "loc.keyboard.presskey": "Pressing key '{0}'", + "loc.keyboard.releasekey": "Releasing key '{0}'", + "loc.keyboard.sendkeys": "Sending keys '{0}'", + "loc.keyboard.sendkeys.withkeyhold": "Sending keys '{0}' with holded key '{1}'" } \ No newline at end of file diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/ru.json b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/ru.json index 835bca8..08c2779 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/ru.json +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/ru.json @@ -17,5 +17,9 @@ "loc.label": "Надпись", "loc.text.field": "Текстовое поле", "loc.text.clearing": "Очищаем", - "loc.text.typing": "Вводим значение '{0}'" + "loc.text.typing": "Вводим значение '{0}'", + "loc.keyboard.presskey": "Зажимаем клавишу '{0}'", + "loc.keyboard.releasekey": "Отпускаем клавишу '{0}'", + "loc.keyboard.sendkeys": "Нажимаем клавиши '{0}'", + "loc.keyboard.sendkeys.withkeyhold": "Нажимаем клавиши '{0}' с зажатой клавишей '{1}'" } \ No newline at end of file From 5023348851f4ba46b64e9286a2cb93d194cb823c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Tue, 17 Sep 2019 17:26:55 +0300 Subject: [PATCH 04/13] removed redundant .ToList() call --- .../src/Aquality.WinAppDriver/Extensions/StringExtensions.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/StringExtensions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/StringExtensions.cs index 5e0eb0a..8ce15c4 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/StringExtensions.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/StringExtensions.cs @@ -15,7 +15,6 @@ public static string GetLoggableValueForKeyboardKey(this string key) { return typeof(Keys) .GetFields(BindingFlags.Public | BindingFlags.Static) - .ToList() .FirstOrDefault(field => key.Equals(field.GetValue(null)))?.Name ?? key; } } From cc70fc9cdca0b605857720f69c4bddf94de3db4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Wed, 18 Sep 2019 11:42:09 +0300 Subject: [PATCH 05/13] rework container registration, fix review comments --- .../Actions/KeyboardActions.cs | 15 +++++++++------ .../Applications/Application.cs | 4 ++-- .../Applications/ApplicationManager.cs | 13 +++++++------ .../Applications/LocalApplicationFactory.cs | 8 ++++++-- .../Applications/RemoteApplicationFactory.cs | 8 ++++++-- .../Elements/Actions/KeyboardActions.cs | 14 +++++++------- .../src/Aquality.WinAppDriver/Elements/Element.cs | 2 +- .../Actions/KeyboardActionsTests.cs | 2 +- .../Applications/KeyboardActionsTests.cs | 10 ++++++++++ 9 files changed, 49 insertions(+), 27 deletions(-) create mode 100644 Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Applications/KeyboardActionsTests.cs diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs index cde880f..23c1db5 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs @@ -6,15 +6,18 @@ namespace Aquality.WinAppDriver.Actions { + /// + /// Implements Keyboard actions for the whole application. + /// public class KeyboardActions : IKeyboardActions { private readonly LocalizationLogger localizationLogger; - private readonly WindowsDriver windowsDriver; + private readonly Func> windowsDriverSupplier; - public KeyboardActions(LocalizationLogger localizationLogger, WindowsDriver windowsDriver) + public KeyboardActions(LocalizationLogger localizationLogger, Func> windowsDriverSupplier) { this.localizationLogger = localizationLogger; - this.windowsDriver = windowsDriver; + this.windowsDriverSupplier = windowsDriverSupplier; } public void PressKey(string keyToPress) @@ -42,19 +45,19 @@ public void SendKeysWithKeyHold(string keySequence, string keyToHold) } /// - /// Performs submited action against new object. + /// Performs submitted action against new object. /// /// Action to be performed. protected virtual void PerformAction(Func action) { - action(new SeleniumActions(windowsDriver)).Build().Perform(); + action(new SeleniumActions(windowsDriverSupplier())).Build().Perform(); } /// /// Logs keyboard action in specific format. /// /// Key of the localized message. - /// arguments for the localized message + /// Arguments for the localized message. protected virtual void LogAction(string messageKey, params object[] args) { localizationLogger.Info(messageKey, args); diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs index 1e07665..d71df2a 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs @@ -21,12 +21,12 @@ public class Application : IApplication /// Instance of WinAppDriver /// Instance of /// Instance of - public Application(WindowsDriver windowsDriver, ITimeoutConfiguration timeoutConfiguration, LocalizationLogger logger, IKeyboardActions keyboardActions = null) + public Application(WindowsDriver windowsDriver, ITimeoutConfiguration timeoutConfiguration, LocalizationLogger logger, IKeyboardActions keyboardActions) { Logger = logger; WindowsDriver = windowsDriver; WindowsDriver.Manage().Timeouts().ImplicitWait = timeoutConfiguration.Implicit; - KeyboardActions = keyboardActions ?? new KeyboardActions(logger, windowsDriver); + KeyboardActions = keyboardActions; logger.Info("loc.application.ready"); } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs index 89b01ce..442b35e 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs @@ -70,15 +70,16 @@ public static void SetDefaultFactory() var driverSettings = GetRequiredService(); var localizationLogger = GetRequiredService(); var timeoutConfiguration = GetRequiredService(); + var keyboardActions = GetRequiredService(); IApplicationFactory applicationFactory; if (appProfile.IsRemote) { - applicationFactory = new RemoteApplicationFactory(appProfile.RemoteConnectionUrl, driverSettings, timeoutConfiguration, localizationLogger); + applicationFactory = new RemoteApplicationFactory(appProfile.RemoteConnectionUrl, driverSettings, timeoutConfiguration, localizationLogger, keyboardActions); } else { - applicationFactory = new LocalApplicationFactory(AppiumLocalServiceContainer.Value, driverSettings, timeoutConfiguration, localizationLogger); + applicationFactory = new LocalApplicationFactory(AppiumLocalServiceContainer.Value, driverSettings, timeoutConfiguration, localizationLogger, keyboardActions); } SetFactory(applicationFactory); @@ -101,10 +102,10 @@ private static IServiceCollection RegisterServices(Func(); services.AddTransient(); - var driverSettings = new DriverSettings(settingsFile); - services.AddSingleton(driverSettings); - services.AddSingleton(new ApplicationProfile(settingsFile, driverSettings)); - services.AddSingleton(new LocalizationManager(new LoggerConfiguration(settingsFile), Logger.Instance, Assembly.GetExecutingAssembly())); + services.AddSingleton(serviceProvider => new DriverSettings(settingsFile)); + services.AddSingleton(serviceProvider => new ApplicationProfile(settingsFile, serviceProvider.GetRequiredService())); + services.AddSingleton(serviceProvider => new LocalizationManager(serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService(), Assembly.GetExecutingAssembly())); + services.AddSingleton(serviceProvider => new KeyboardActions(serviceProvider.GetRequiredService(), () => Application.WindowsDriver)); return services; } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/LocalApplicationFactory.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/LocalApplicationFactory.cs index cc4cff7..643b04e 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/LocalApplicationFactory.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/LocalApplicationFactory.cs @@ -1,5 +1,6 @@ using Aquality.Selenium.Core.Configurations; using Aquality.Selenium.Core.Localization; +using Aquality.WinAppDriver.Actions; using Aquality.WinAppDriver.Configurations; using OpenQA.Selenium.Appium.Service; @@ -11,13 +12,16 @@ public class LocalApplicationFactory : ApplicationFactory private readonly IDriverSettings driverSettings; private readonly ITimeoutConfiguration timeoutConfiguration; private readonly LocalizationLogger localizationLogger; + private readonly IKeyboardActions keyboardActions; - public LocalApplicationFactory(AppiumLocalService driverService, IDriverSettings driverSettings, ITimeoutConfiguration timeoutConfiguration, LocalizationLogger localizationLogger) : base(localizationLogger) + public LocalApplicationFactory(AppiumLocalService driverService, IDriverSettings driverSettings, ITimeoutConfiguration timeoutConfiguration, LocalizationLogger localizationLogger, IKeyboardActions keyboardActions) + : base(localizationLogger) { this.driverService = driverService; this.driverSettings = driverSettings; this.timeoutConfiguration = timeoutConfiguration; this.localizationLogger = localizationLogger; + this.keyboardActions = keyboardActions; } public override Application Application @@ -28,7 +32,7 @@ public override Application Application var serviceUrl = driverService.ServiceUrl; localizationLogger.Info("loc.application.driver.service.local.start", serviceUrl); var driver = GetDriver(serviceUrl, driverSettings.AppiumOptions, timeoutConfiguration.Command); - return new Application(driver, timeoutConfiguration, localizationLogger); + return new Application(driver, timeoutConfiguration, localizationLogger, keyboardActions); } } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/RemoteApplicationFactory.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/RemoteApplicationFactory.cs index 6bed05e..01c4135 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/RemoteApplicationFactory.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/RemoteApplicationFactory.cs @@ -1,5 +1,6 @@ using Aquality.Selenium.Core.Configurations; using Aquality.Selenium.Core.Localization; +using Aquality.WinAppDriver.Actions; using Aquality.WinAppDriver.Configurations; using OpenQA.Selenium.Remote; using System; @@ -12,13 +13,16 @@ public class RemoteApplicationFactory : ApplicationFactory private readonly IDriverSettings driverSettings; private readonly ITimeoutConfiguration timeoutConfiguration; private readonly LocalizationLogger localizationLogger; + private readonly IKeyboardActions keyboardActions; - public RemoteApplicationFactory(Uri driverServerUri, IDriverSettings driverSettings, ITimeoutConfiguration timeoutConfiguration, LocalizationLogger localizationLogger) : base(localizationLogger) + public RemoteApplicationFactory(Uri driverServerUri, IDriverSettings driverSettings, ITimeoutConfiguration timeoutConfiguration, LocalizationLogger localizationLogger, IKeyboardActions keyboardActions) + : base(localizationLogger) { this.driverServerUri = driverServerUri; this.driverSettings = driverSettings; this.timeoutConfiguration = timeoutConfiguration; this.localizationLogger = localizationLogger; + this.keyboardActions = keyboardActions; } public override Application Application @@ -28,7 +32,7 @@ public override Application Application localizationLogger.Info("loc.application.driver.service.remote", driverServerUri); var driver = GetDriver(driverServerUri, driverSettings.AppiumOptions, timeoutConfiguration.Command); driver.FileDetector = new LocalFileDetector(); - return new Application(driver, timeoutConfiguration, localizationLogger); + return new Application(driver, timeoutConfiguration, localizationLogger, keyboardActions); } } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs index 1210724..e5ebbc8 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs @@ -17,7 +17,7 @@ public class KeyboardActions : IKeyboardActions { private readonly IElement element; private readonly string elementType; - private readonly IApplication application; + private readonly Func applicationSupplier; private readonly LocalizationLogger localizationLogger; private readonly ElementActionRetrier elementActionsRetrier; @@ -26,14 +26,14 @@ public class KeyboardActions : IKeyboardActions /// /// Target element. /// Target element's type. - /// Current application session. + /// Method to get current application session. /// Logger for localized values. /// Retrier for element actions. - public KeyboardActions(IElement element, string elementType, IApplication application, LocalizationLogger localizationLogger, ElementActionRetrier elementActionsRetrier) + public KeyboardActions(IElement element, string elementType, Func applicationSupplier, LocalizationLogger localizationLogger, ElementActionRetrier elementActionsRetrier) { this.element = element; this.elementType = elementType; - this.application = application; + this.applicationSupplier = applicationSupplier; this.localizationLogger = localizationLogger; this.elementActionsRetrier = elementActionsRetrier; } @@ -63,14 +63,14 @@ public void SendKeysWithKeyHold(string keySequence, string keyToHold) } /// - /// Performs submited action against new object. + /// Performs submtted action against new object. /// /// Action to be performed. protected virtual void PerformAction(Func action) { elementActionsRetrier.DoWithRetry(() => { - action(new SeleniumActions(application.Driver), element.GetElement()).Build().Perform(); + action(new SeleniumActions(applicationSupplier().Driver), element.GetElement()).Build().Perform(); }); } @@ -78,7 +78,7 @@ protected virtual void PerformAction(Func /// Key of the localized message. - /// arguments for the localized message + /// Arguments for the localized message. protected virtual void LogElementAction(string messageKey, params object[] args) { localizationLogger.InfoElementAction(elementType, element.Name, messageKey, args); diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Element.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Element.cs index aa94284..531e489 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Element.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Element.cs @@ -30,7 +30,7 @@ protected Element(By locator, string name) : base(locator, name, ElementState.Di protected virtual IElementFactory CustomFactory => ApplicationManager.GetRequiredService(); - public virtual IKeyboardActions KeyboardActions => new KeyboardActions(this, ElementType, Application, LocalizationLogger, ActionRetrier); + public virtual IKeyboardActions KeyboardActions => new KeyboardActions(this, ElementType, () => Application, LocalizationLogger, ActionRetrier); public T FindChildElement(By childLocator, ElementSupplier supplier = null) where T : IElement { diff --git a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs index d11626f..43ad3c0 100644 --- a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs +++ b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs @@ -12,7 +12,7 @@ public class KeyboardActionsTests : TestWithApplication { private const string ValueToSend = "abc"; - protected virtual IKeyboardActions KeyboardActions => ApplicationManager.Application.KeyboardActions; + protected virtual IKeyboardActions KeyboardActions => ApplicationManager.GetRequiredService(); protected ITextBox RightArgumentTextBox => new CalculatorWindow().RightArgumentTextBox; diff --git a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Applications/KeyboardActionsTests.cs b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Applications/KeyboardActionsTests.cs new file mode 100644 index 0000000..faaa143 --- /dev/null +++ b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Applications/KeyboardActionsTests.cs @@ -0,0 +1,10 @@ +using Aquality.WinAppDriver.Actions; +using Aquality.WinAppDriver.Applications; + +namespace Aquality.WinAppDriver.Tests.Applications +{ + public class KeyboardActionsTests : Actions.KeyboardActionsTests + { + protected override IKeyboardActions KeyboardActions => ApplicationManager.Application.KeyboardActions; + } +} From b713e4858e7c4d6647fd7d2c1fc73befef34214a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Wed, 18 Sep 2019 18:13:35 +0300 Subject: [PATCH 06/13] fix typo in the documentation --- .../Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs index e5ebbc8..b65c065 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs @@ -63,7 +63,7 @@ public void SendKeysWithKeyHold(string keySequence, string keyToHold) } /// - /// Performs submtted action against new object. + /// Performs submitted action against new object. /// /// Action to be performed. protected virtual void PerformAction(Func action) From 5134446e439ff60912d95c72d894deb2ae4ca3f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Wed, 18 Sep 2019 14:27:11 +0300 Subject: [PATCH 07/13] Add setters to Application and ServiceProvider properties --- .../Applications/ApplicationManager.cs | 24 +++++++++++++++++-- .../Aquality.WinAppDriver.csproj | 2 +- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs index 442b35e..c737bd3 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs @@ -42,12 +42,32 @@ public static bool TryToStopAppiumLocalService() /// /// Provides current instance of application /// - public static Application Application => GetApplication(StartApplicationFunction, () => RegisterServices(services => Application)); + public static Application Application + { + get + { + return GetApplication(StartApplicationFunction, () => RegisterServices(services => Application)); + } + set + { + SetApplication(value); + } + } /// /// Provides access to Aquality services, registered in DI container. /// - public static IServiceProvider ServiceProvider => GetServiceProvider(services => Application, () => RegisterServices(services => Application)); + public static IServiceProvider ServiceProvider + { + get + { + return GetServiceProvider(services => Application, () => RegisterServices(services => Application)); + } + set + { + SetServiceProvider(value); + } + } /// /// Resolves required service from diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.csproj b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.csproj index 0c59001..a7c2ef0 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.csproj +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.csproj @@ -41,7 +41,7 @@ - + From 968b9ff0540929a0bc8d5a4b5813c7a698653e65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Wed, 18 Sep 2019 18:10:58 +0300 Subject: [PATCH 08/13] implemented MouseActions for custom element and for the whole application to resolve #8 --- .../Actions/ApplicationActions.cs | 47 ++++++++ .../Actions/IKeyboardActions.cs | 2 +- .../Actions/IMouseActions.cs | 40 +++++++ .../Actions/KeyboardActions.cs | 28 +---- .../Actions/MouseActions.cs | 53 +++++++++ .../Applications/Application.cs | 5 +- .../Applications/ApplicationManager.cs | 8 +- .../Applications/LocalApplicationFactory.cs | 6 +- .../Applications/RemoteApplicationFactory.cs | 6 +- .../Elements/Actions/ElementActions.cs | 61 ++++++++++ .../Elements/Actions/IMouseActions.cs | 57 ++++++++++ .../Elements/Actions/KeyboardActions.cs | 46 +------- .../Elements/Actions/MouseActions.cs | 105 ++++++++++++++++++ 13 files changed, 389 insertions(+), 75 deletions(-) create mode 100644 Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/ApplicationActions.cs create mode 100644 Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/IMouseActions.cs create mode 100644 Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/MouseActions.cs create mode 100644 Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/ElementActions.cs create mode 100644 Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/IMouseActions.cs create mode 100644 Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/MouseActions.cs diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/ApplicationActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/ApplicationActions.cs new file mode 100644 index 0000000..feca2e5 --- /dev/null +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/ApplicationActions.cs @@ -0,0 +1,47 @@ +using Aquality.Selenium.Core.Localization; +using OpenQA.Selenium.Appium.Windows; +using System; +using SeleniumActions = OpenQA.Selenium.Interactions.Actions; + +namespace Aquality.WinAppDriver.Actions +{ + /// + /// Abstract class for any actions against the whole application. + /// + public abstract class ApplicationActions + { + private readonly LocalizationLogger localizationLogger; + private readonly Func> windowsDriverSupplier; + + + /// + /// Instantiates Aplication actions. + /// + /// Logger for localized values. + /// Method to get current application session. + protected ApplicationActions(LocalizationLogger localizationLogger, Func> windowsDriverSupplier) + { + this.localizationLogger = localizationLogger; + this.windowsDriverSupplier = windowsDriverSupplier; + } + + /// + /// Performs submitted action against new object. + /// + /// Action to be performed. + protected virtual void PerformAction(Func action) + { + action(new SeleniumActions(windowsDriverSupplier())).Build().Perform(); + } + + /// + /// Logs keyboard action in specific format. + /// + /// Key of the localized message. + /// Arguments for the localized message. + protected virtual void LogAction(string messageKey, params object[] args) + { + localizationLogger.Info(messageKey, args); + } + } +} diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/IKeyboardActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/IKeyboardActions.cs index 284648d..05e6250 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/IKeyboardActions.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/IKeyboardActions.cs @@ -46,7 +46,7 @@ public interface IKeyboardActions void SendKeys(string keySequence); /// - /// Sends a sequence of keystrokes to the target, holding a specified key. + /// Sends a sequence of keystrokes to the application, holding a specified key. /// After the action, holded key is released. /// /// A string representing the keystrokes to send. diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/IMouseActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/IMouseActions.cs new file mode 100644 index 0000000..6d85631 --- /dev/null +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/IMouseActions.cs @@ -0,0 +1,40 @@ +namespace Aquality.WinAppDriver.Actions +{ + /// + /// Provides methods representing basic mouse actions. + /// + public interface IMouseActions + { + /// + /// Clicks the mouse at the last known mouse coordinates. + /// + void Click(); + + /// + /// Clicks and holds the mouse button at the last known mouse coordinates. + /// + void ClickAndHold(); + + /// + /// Releases the mouse button at the last known mouse coordinates. + /// + void Release(); + + /// + /// Right-clicks the mouse at the last known mouse coordinates. + /// + void ContextClick(); + + /// + /// Double-clicks the mouse at the last known mouse coordinates. + /// + void DoubleClick(); + + /// + /// Moves the mouse to the specified offset of the last known mouse coordinates. + /// + /// The horizontal offset to which to move the mouse. + /// The vertical offset to which to move the mouse. + void MoveByOffset(int offsetX, int offsetY); + } +} diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs index 23c1db5..f40e553 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs @@ -2,22 +2,17 @@ using Aquality.WinAppDriver.Extensions; using OpenQA.Selenium.Appium.Windows; using System; -using SeleniumActions = OpenQA.Selenium.Interactions.Actions; namespace Aquality.WinAppDriver.Actions { /// /// Implements Keyboard actions for the whole application. /// - public class KeyboardActions : IKeyboardActions + public class KeyboardActions : ApplicationActions, IKeyboardActions { - private readonly LocalizationLogger localizationLogger; - private readonly Func> windowsDriverSupplier; - public KeyboardActions(LocalizationLogger localizationLogger, Func> windowsDriverSupplier) + : base(localizationLogger, windowsDriverSupplier) { - this.localizationLogger = localizationLogger; - this.windowsDriverSupplier = windowsDriverSupplier; } public void PressKey(string keyToPress) @@ -43,24 +38,5 @@ public void SendKeysWithKeyHold(string keySequence, string keyToHold) LogAction("loc.keyboard.sendkeys.withkeyhold", keySequence, keyToHold.GetLoggableValueForKeyboardKey()); PerformAction(actions => actions.KeyDown(keyToHold).SendKeys(keySequence).KeyUp(keyToHold)); } - - /// - /// Performs submitted action against new object. - /// - /// Action to be performed. - protected virtual void PerformAction(Func action) - { - action(new SeleniumActions(windowsDriverSupplier())).Build().Perform(); - } - - /// - /// Logs keyboard action in specific format. - /// - /// Key of the localized message. - /// Arguments for the localized message. - protected virtual void LogAction(string messageKey, params object[] args) - { - localizationLogger.Info(messageKey, args); - } } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/MouseActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/MouseActions.cs new file mode 100644 index 0000000..050adf4 --- /dev/null +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/MouseActions.cs @@ -0,0 +1,53 @@ +using Aquality.Selenium.Core.Localization; +using OpenQA.Selenium.Appium.Windows; +using System; + +namespace Aquality.WinAppDriver.Actions +{ + /// + /// Implements Mouse actions for the whole application. + /// + public class MouseActions : ApplicationActions, IMouseActions + { + public MouseActions(LocalizationLogger localizationLogger, Func> windowsDriverSupplier) + : base(localizationLogger, windowsDriverSupplier) + { + } + + public void Click() + { + LogAction("loc.mouse.click"); + PerformAction(actions => actions.Click()); + } + + public void ClickAndHold() + { + LogAction("loc.mouse.clickandhold"); + PerformAction(actions => actions.ClickAndHold()); + } + + public void Release() + { + LogAction("loc.mouse.release"); + PerformAction(actions => actions.Release()); + } + + public void ContextClick() + { + LogAction("loc.mouse.contextclick"); + PerformAction(actions => actions.ContextClick()); + } + + public void DoubleClick() + { + LogAction("loc.mouse.doubleclick"); + PerformAction(actions => actions.DoubleClick()); + } + + public void MoveByOffset(int offsetX, int offsetY) + { + LogAction("loc.mouse.movebyoffset"); + PerformAction(actions => actions.MoveByOffset(offsetX, offsetY)); + } + } +} diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs index d71df2a..6a6eebd 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs @@ -21,12 +21,13 @@ public class Application : IApplication /// Instance of WinAppDriver /// Instance of /// Instance of - public Application(WindowsDriver windowsDriver, ITimeoutConfiguration timeoutConfiguration, LocalizationLogger logger, IKeyboardActions keyboardActions) + public Application(WindowsDriver windowsDriver, ITimeoutConfiguration timeoutConfiguration, LocalizationLogger logger, IKeyboardActions keyboardActions, IMouseActions mouseActions) { Logger = logger; WindowsDriver = windowsDriver; WindowsDriver.Manage().Timeouts().ImplicitWait = timeoutConfiguration.Implicit; KeyboardActions = keyboardActions; + MouseActions = mouseActions; logger.Info("loc.application.ready"); } @@ -41,6 +42,8 @@ public Application(WindowsDriver windowsDriver, ITimeoutConfigur public IKeyboardActions KeyboardActions { get; } + public IMouseActions MouseActions { get; } + /// /// Sets WinAppDriver ImplicitWait timeout. /// Default value: . diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs index c737bd3..91fcb7f 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs @@ -91,15 +91,16 @@ public static void SetDefaultFactory() var localizationLogger = GetRequiredService(); var timeoutConfiguration = GetRequiredService(); var keyboardActions = GetRequiredService(); - + var mouseActions = GetRequiredService(); + IApplicationFactory applicationFactory; if (appProfile.IsRemote) { - applicationFactory = new RemoteApplicationFactory(appProfile.RemoteConnectionUrl, driverSettings, timeoutConfiguration, localizationLogger, keyboardActions); + applicationFactory = new RemoteApplicationFactory(appProfile.RemoteConnectionUrl, driverSettings, timeoutConfiguration, localizationLogger, keyboardActions, mouseActions); } else { - applicationFactory = new LocalApplicationFactory(AppiumLocalServiceContainer.Value, driverSettings, timeoutConfiguration, localizationLogger, keyboardActions); + applicationFactory = new LocalApplicationFactory(AppiumLocalServiceContainer.Value, driverSettings, timeoutConfiguration, localizationLogger, keyboardActions, mouseActions); } SetFactory(applicationFactory); @@ -126,6 +127,7 @@ private static IServiceCollection RegisterServices(Func(serviceProvider => new ApplicationProfile(settingsFile, serviceProvider.GetRequiredService())); services.AddSingleton(serviceProvider => new LocalizationManager(serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService(), Assembly.GetExecutingAssembly())); services.AddSingleton(serviceProvider => new KeyboardActions(serviceProvider.GetRequiredService(), () => Application.WindowsDriver)); + services.AddSingleton(serviceProvider => new MouseActions(serviceProvider.GetRequiredService(), () => Application.WindowsDriver)); return services; } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/LocalApplicationFactory.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/LocalApplicationFactory.cs index 643b04e..1eb63fd 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/LocalApplicationFactory.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/LocalApplicationFactory.cs @@ -13,8 +13,9 @@ public class LocalApplicationFactory : ApplicationFactory private readonly ITimeoutConfiguration timeoutConfiguration; private readonly LocalizationLogger localizationLogger; private readonly IKeyboardActions keyboardActions; + private readonly IMouseActions mouseActions; - public LocalApplicationFactory(AppiumLocalService driverService, IDriverSettings driverSettings, ITimeoutConfiguration timeoutConfiguration, LocalizationLogger localizationLogger, IKeyboardActions keyboardActions) + public LocalApplicationFactory(AppiumLocalService driverService, IDriverSettings driverSettings, ITimeoutConfiguration timeoutConfiguration, LocalizationLogger localizationLogger, IKeyboardActions keyboardActions, IMouseActions mouseActions) : base(localizationLogger) { this.driverService = driverService; @@ -22,6 +23,7 @@ public LocalApplicationFactory(AppiumLocalService driverService, IDriverSettings this.timeoutConfiguration = timeoutConfiguration; this.localizationLogger = localizationLogger; this.keyboardActions = keyboardActions; + this.mouseActions = mouseActions; } public override Application Application @@ -32,7 +34,7 @@ public override Application Application var serviceUrl = driverService.ServiceUrl; localizationLogger.Info("loc.application.driver.service.local.start", serviceUrl); var driver = GetDriver(serviceUrl, driverSettings.AppiumOptions, timeoutConfiguration.Command); - return new Application(driver, timeoutConfiguration, localizationLogger, keyboardActions); + return new Application(driver, timeoutConfiguration, localizationLogger, keyboardActions, mouseActions); } } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/RemoteApplicationFactory.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/RemoteApplicationFactory.cs index 01c4135..9428777 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/RemoteApplicationFactory.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/RemoteApplicationFactory.cs @@ -14,8 +14,9 @@ public class RemoteApplicationFactory : ApplicationFactory private readonly ITimeoutConfiguration timeoutConfiguration; private readonly LocalizationLogger localizationLogger; private readonly IKeyboardActions keyboardActions; + private readonly IMouseActions mouseActions; - public RemoteApplicationFactory(Uri driverServerUri, IDriverSettings driverSettings, ITimeoutConfiguration timeoutConfiguration, LocalizationLogger localizationLogger, IKeyboardActions keyboardActions) + public RemoteApplicationFactory(Uri driverServerUri, IDriverSettings driverSettings, ITimeoutConfiguration timeoutConfiguration, LocalizationLogger localizationLogger, IKeyboardActions keyboardActions, IMouseActions mouseActions) : base(localizationLogger) { this.driverServerUri = driverServerUri; @@ -23,6 +24,7 @@ public RemoteApplicationFactory(Uri driverServerUri, IDriverSettings driverSetti this.timeoutConfiguration = timeoutConfiguration; this.localizationLogger = localizationLogger; this.keyboardActions = keyboardActions; + this.mouseActions = mouseActions; } public override Application Application @@ -32,7 +34,7 @@ public override Application Application localizationLogger.Info("loc.application.driver.service.remote", driverServerUri); var driver = GetDriver(driverServerUri, driverSettings.AppiumOptions, timeoutConfiguration.Command); driver.FileDetector = new LocalFileDetector(); - return new Application(driver, timeoutConfiguration, localizationLogger, keyboardActions); + return new Application(driver, timeoutConfiguration, localizationLogger, keyboardActions, mouseActions); } } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/ElementActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/ElementActions.cs new file mode 100644 index 0000000..7f4cfb8 --- /dev/null +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/ElementActions.cs @@ -0,0 +1,61 @@ +using Aquality.Selenium.Core.Applications; +using Aquality.Selenium.Core.Localization; +using Aquality.Selenium.Core.Utilities; +using Aquality.WinAppDriver.Elements.Interfaces; +using OpenQA.Selenium; +using System; +using SeleniumActions = OpenQA.Selenium.Interactions.Actions; + +namespace Aquality.WinAppDriver.Elements.Actions +{ + /// + /// Abstract class for any actions agains element. + /// + public abstract class ElementActions + { + private readonly IElement element; + private readonly string elementType; + private readonly Func applicationSupplier; + private readonly LocalizationLogger localizationLogger; + private readonly ElementActionRetrier elementActionsRetrier; + + /// + /// Instantiates Element actions for a specific element. + /// + /// Target element. + /// Target element's type. + /// Method to get current application session. + /// Logger for localized values. + /// Retrier for element actions. + protected ElementActions(IElement element, string elementType, Func applicationSupplier, LocalizationLogger localizationLogger, ElementActionRetrier elementActionsRetrier) + { + this.element = element; + this.elementType = elementType; + this.applicationSupplier = applicationSupplier; + this.localizationLogger = localizationLogger; + this.elementActionsRetrier = elementActionsRetrier; + } + + /// + /// Performs submtted action against new object. + /// + /// Action to be performed. + protected virtual void PerformAction(Func action) + { + elementActionsRetrier.DoWithRetry(() => + { + action(new SeleniumActions(applicationSupplier().Driver), element.GetElement()).Build().Perform(); + }); + } + + /// + /// Logs element action in specific format. + /// + /// Key of the localized message. + /// Arguments for the localized message. + protected virtual void LogAction(string messageKey, params object[] args) + { + localizationLogger.InfoElementAction(elementType, element.Name, messageKey, args); + } + } +} diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/IMouseActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/IMouseActions.cs new file mode 100644 index 0000000..2b897ac --- /dev/null +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/IMouseActions.cs @@ -0,0 +1,57 @@ +using Aquality.WinAppDriver.Elements.Interfaces; +using OpenQA.Selenium.Interactions; + +namespace Aquality.WinAppDriver.Elements.Actions +{ + /// + /// Provides methods representing basic mouse actions against the current element. + /// Current element's coordinates are user as last known mouse coordinates. + /// + public interface IMouseActions : WinAppDriver.Actions.IMouseActions + { + /// + /// Performs a drag-and-drop operation on the current element; drops it on target element. + /// + /// The element on which the drop is performed. + void DragAndDrop(IElement target); + + /// + /// Performs a drag-and-drop operation on the current element to a specified offset. + /// + /// The horizontal offset to which to move the mouse. + /// The vertical offset to which to move the mouse. + void DragAndDropToOffset(int offsetX, int offsetY); + + /// + /// Moves the current element to a specified offset. Works the same as to + /// + /// The horizontal offset to which to move the mouse. + /// The vertical offset to which to move the mouse. + new void MoveByOffset(int offsetX, int offsetY); + + /// + /// Moves the mouse to the current element. + /// + void MoveToElement(); + + /// + /// Moves the mouse from the current element. + /// + void MoveFromElement(); + + /// + /// Moves the mouse to the specified offset of the top-left corner of the current element. + /// + /// The horizontal offset to which to move the mouse. + /// The vertical offset to which to move the mouse. + void MoveToElement(int offsetX, int offsetY); + + /// + /// Moves the mouse to the specified offset of specified offset origin of the current element. + /// + /// The horizontal offset to which to move the mouse. + /// The vertical offset to which to move the mouse. + /// The value from which to calculate the offset. + void MoveToElement(int offsetX, int offsetY, MoveToElementOffsetOrigin offsetOrigin); + } +} diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs index b65c065..c76cd76 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs @@ -4,23 +4,15 @@ using Aquality.WinAppDriver.Actions; using Aquality.WinAppDriver.Elements.Interfaces; using Aquality.WinAppDriver.Extensions; -using OpenQA.Selenium; using System; -using SeleniumActions = OpenQA.Selenium.Interactions.Actions; namespace Aquality.WinAppDriver.Elements.Actions { /// /// Implements Keyboard actions for a specific element. /// - public class KeyboardActions : IKeyboardActions + public class KeyboardActions : ElementActions, IKeyboardActions { - private readonly IElement element; - private readonly string elementType; - private readonly Func applicationSupplier; - private readonly LocalizationLogger localizationLogger; - private readonly ElementActionRetrier elementActionsRetrier; - /// /// Instantiates Keyboard actions for a specific element. /// @@ -30,58 +22,32 @@ public class KeyboardActions : IKeyboardActions /// Logger for localized values. /// Retrier for element actions. public KeyboardActions(IElement element, string elementType, Func applicationSupplier, LocalizationLogger localizationLogger, ElementActionRetrier elementActionsRetrier) + : base(element, elementType, applicationSupplier, localizationLogger, elementActionsRetrier) { - this.element = element; - this.elementType = elementType; - this.applicationSupplier = applicationSupplier; - this.localizationLogger = localizationLogger; - this.elementActionsRetrier = elementActionsRetrier; } public void PressKey(string keyToPress) { - LogElementAction("loc.keyboard.presskey", keyToPress.GetLoggableValueForKeyboardKey()); + LogAction("loc.keyboard.presskey", keyToPress.GetLoggableValueForKeyboardKey()); PerformAction((actions, element) => actions.KeyDown(element, keyToPress)); } public void ReleaseKey(string keyToRelease) { - LogElementAction("loc.keyboard.releasekey", keyToRelease.GetLoggableValueForKeyboardKey()); + LogAction("loc.keyboard.releasekey", keyToRelease.GetLoggableValueForKeyboardKey()); PerformAction((actions, element) => actions.KeyUp(element, keyToRelease)); } public void SendKeys(string keySequence) { - LogElementAction("loc.keyboard.sendkeys", keySequence); + LogAction("loc.keyboard.sendkeys", keySequence); PerformAction((actions, element) => actions.SendKeys(element, keySequence)); } public void SendKeysWithKeyHold(string keySequence, string keyToHold) { - LogElementAction("loc.keyboard.sendkeys.withkeyhold", keySequence, keyToHold.GetLoggableValueForKeyboardKey()); + LogAction("loc.keyboard.sendkeys.withkeyhold", keySequence, keyToHold.GetLoggableValueForKeyboardKey()); PerformAction((actions, element) => actions.KeyDown(element, keyToHold).SendKeys(element, keySequence).KeyUp(element, keyToHold)); } - - /// - /// Performs submitted action against new object. - /// - /// Action to be performed. - protected virtual void PerformAction(Func action) - { - elementActionsRetrier.DoWithRetry(() => - { - action(new SeleniumActions(applicationSupplier().Driver), element.GetElement()).Build().Perform(); - }); - } - - /// - /// Logs element action in specific format. - /// - /// Key of the localized message. - /// Arguments for the localized message. - protected virtual void LogElementAction(string messageKey, params object[] args) - { - localizationLogger.InfoElementAction(elementType, element.Name, messageKey, args); - } } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/MouseActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/MouseActions.cs new file mode 100644 index 0000000..0930058 --- /dev/null +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/MouseActions.cs @@ -0,0 +1,105 @@ +using Aquality.Selenium.Core.Applications; +using Aquality.Selenium.Core.Localization; +using Aquality.Selenium.Core.Utilities; +using Aquality.WinAppDriver.Elements.Interfaces; +using OpenQA.Selenium.Interactions; +using System; + +namespace Aquality.WinAppDriver.Elements.Actions +{ + /// + /// Implements Mouse actions for a specific element. + /// + public class MouseActions : ElementActions, IMouseActions + { + private readonly IElement element; + + /// + /// Instantiates Mouse actions for a specific element. + /// + /// Target element. + /// Target element's type. + /// Method to get current application session. + /// Logger for localized values. + /// Retrier for element actions. + public MouseActions(IElement element, string elementType, Func applicationSupplier, LocalizationLogger localizationLogger, ElementActionRetrier elementActionsRetrier) + : base(element, elementType, applicationSupplier, localizationLogger, elementActionsRetrier) + { + this.element = element; + } + + public void Click() + { + LogAction("loc.mouse.click"); + PerformAction((actions, element) => actions.Click(element)); + } + + public void ClickAndHold() + { + LogAction("loc.mouse.clickandhold"); + PerformAction((actions, element) => actions.ClickAndHold(element)); + } + + public void Release() + { + LogAction("loc.mouse.release"); + PerformAction((actions, element) => actions.Release(element)); + } + + public void ContextClick() + { + LogAction("loc.mouse.contextclick"); + PerformAction((actions, element) => actions.ContextClick(element)); + } + + public void DoubleClick() + { + LogAction("loc.mouse.doubleclick"); + PerformAction((actions, element) => actions.DoubleClick(element)); + } + + public void MoveByOffset(int offsetX, int offsetY) + { + DragAndDropToOffset(offsetX, offsetY); + } + + public void DragAndDrop(IElement target) + { + //todo: try add localized as {elementType} '{elementName}' + LogAction("loc.mouse.draganddrop", target.GetType(), target.Name); + PerformAction((actions, element) => actions.DragAndDrop(element, target.GetElement())); + } + + public void DragAndDropToOffset(int offsetX, int offsetY) + { + LogAction("loc.mouse.draganddrop.tooffset", offsetX, offsetY); + PerformAction((actions, element) => actions.DragAndDropToOffset(element, offsetX, offsetY)); + } + + public void MoveToElement() + { + LogAction("loc.mouse.movetoelement"); + PerformAction((actions, element) => actions.MoveToElement(element)); + } + + public void MoveFromElement() + { + var offsetX = - element.GetElement().Size.Width / 2; + var offsetY = - element.GetElement().Size.Height / 2; + LogAction("loc.mouse.movefromelement", offsetX, offsetY); + PerformAction((actions, element) => actions.MoveToElement(element, offsetX, offsetY)); + } + + public void MoveToElement(int offsetX, int offsetY) + { + LogAction("loc.mouse.movetoelement.byoffset", offsetX, offsetY); + PerformAction((actions, element) => actions.MoveToElement(element, offsetX, offsetY)); + } + + public void MoveToElement(int offsetX, int offsetY, MoveToElementOffsetOrigin offsetOrigin) + { + LogAction("loc.mouse.movetoelement.byoffset.withorigin", offsetX, offsetY, offsetOrigin); + PerformAction((actions, element) => actions.MoveToElement(element, offsetX, offsetY, offsetOrigin)); + } + } +} From dcac790781503985988397313dcf6b13d99a250d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Thu, 19 Sep 2019 14:25:07 +0300 Subject: [PATCH 09/13] Add localization for new actions. Add xml documentation to library. Fix documentation for some classes. Add Scroll as mouse action to resolve #14 --- .../Actions/IMouseActions.cs | 7 + .../Actions/MouseActions.cs | 12 +- .../Applications/Application.cs | 4 +- .../Applications/ApplicationManager.cs | 4 +- .../Aquality.WinAppDriver.csproj | 5 + .../Aquality.WinAppDriver.xml | 569 ++++++++++++++++++ .../Configurations/ApplicationProfile.cs | 1 + .../Elements/Actions/ElementActions.cs | 2 +- .../Elements/Actions/IMouseActions.cs | 15 +- .../Elements/Actions/MouseActions.cs | 25 +- .../Aquality.WinAppDriver/Elements/Element.cs | 6 +- .../Elements/Interfaces/IElement.cs | 14 +- .../Elements/Interfaces/IElementFactory.cs | 1 - .../Extensions/ElementExtensions.cs | 30 + .../Resources/Localization/be.json | 15 +- .../Resources/Localization/en.json | 15 +- .../Resources/Localization/ru.json | 15 +- .../Aquality.WinAppDriver/Windows/Window.cs | 4 +- .../Actions/MouseActionsTests.cs | 31 + .../Applications/Locators/CalculatorWindow.cs | 2 + .../Applications/MouseActionsTests.cs | 10 + .../Elements/Actions/MouseActionsTests.cs | 32 + .../Localization/LocalizationFilesTest.cs | 36 +- 23 files changed, 822 insertions(+), 33 deletions(-) create mode 100644 Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.xml create mode 100644 Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/ElementExtensions.cs create mode 100644 Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/MouseActionsTests.cs create mode 100644 Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Applications/MouseActionsTests.cs create mode 100644 Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Elements/Actions/MouseActionsTests.cs diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/IMouseActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/IMouseActions.cs index 6d85631..b222bbd 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/IMouseActions.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/IMouseActions.cs @@ -36,5 +36,12 @@ public interface IMouseActions /// The horizontal offset to which to move the mouse. /// The vertical offset to which to move the mouse. void MoveByOffset(int offsetX, int offsetY); + + /// + /// Scrolls the current screen by specified offset. + /// + /// The horizontal offset relative to the view port. + /// The vertical offset relative to the view port. + void Scroll(int offsetX, int offsetY); } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/MouseActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/MouseActions.cs index 050adf4..9aaef02 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/MouseActions.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/MouseActions.cs @@ -1,5 +1,6 @@ using Aquality.Selenium.Core.Localization; using OpenQA.Selenium.Appium.Windows; +using OpenQA.Selenium.Remote; using System; namespace Aquality.WinAppDriver.Actions @@ -9,9 +10,12 @@ namespace Aquality.WinAppDriver.Actions /// public class MouseActions : ApplicationActions, IMouseActions { + private readonly Func remoteTouchScreenSupplier; + public MouseActions(LocalizationLogger localizationLogger, Func> windowsDriverSupplier) : base(localizationLogger, windowsDriverSupplier) { + remoteTouchScreenSupplier = () => new RemoteTouchScreen(windowsDriverSupplier()); } public void Click() @@ -46,8 +50,14 @@ public void DoubleClick() public void MoveByOffset(int offsetX, int offsetY) { - LogAction("loc.mouse.movebyoffset"); + LogAction("loc.mouse.movebyoffset", offsetX, offsetY); PerformAction(actions => actions.MoveByOffset(offsetX, offsetY)); } + + public void Scroll(int offsetX, int offsetY) + { + LogAction("loc.mouse.scrollbyoffset", offsetX, offsetY); + remoteTouchScreenSupplier().Scroll(offsetX, offsetY); + } } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs index 6a6eebd..d8ece76 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs @@ -14,13 +14,15 @@ namespace Aquality.WinAppDriver.Applications public class Application : IApplication { private TimeSpan implicitWait; - + /// /// Instantiate application. /// /// Instance of WinAppDriver /// Instance of /// Instance of + /// Instance of + /// Instance of public Application(WindowsDriver windowsDriver, ITimeoutConfiguration timeoutConfiguration, LocalizationLogger logger, IKeyboardActions keyboardActions, IMouseActions mouseActions) { Logger = logger; diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs index 91fcb7f..e77ec0c 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs @@ -73,7 +73,7 @@ public static IServiceProvider ServiceProvider /// Resolves required service from /// /// type of required service - /// . + /// Thrown if there is no service of the required type. /// public static T GetRequiredService() { @@ -109,7 +109,7 @@ public static void SetDefaultFactory() /// /// Sets custom application factory. /// - /// Custom implementation of + /// Custom implementation of public static void SetFactory(IApplicationFactory applicationFactory) { ApplicationFactoryContainer.Value = applicationFactory; diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.csproj b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.csproj index a7c2ef0..4508ec3 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.csproj +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.csproj @@ -18,6 +18,11 @@ true + + Aquality.WinAppDriver.xml + 1701;1702;1591 + + diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.xml b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.xml new file mode 100644 index 0000000..86b6b0e --- /dev/null +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.xml @@ -0,0 +1,569 @@ + + + + Aquality.WinAppDriver + + + + + Abstract class for any actions against the whole application. + + + + + Instantiates Aplication actions. + + Logger for localized values. + Method to get current application session. + + + + Performs submitted action against new object. + + Action to be performed. + + + + Logs keyboard action in specific format. + + Key of the localized message. + Arguments for the localized message. + + + + Provides methods representing basic keyboard actions. + + + + + Presses a key. + + The key value representing the key to press. + The key value must be one of the values from the class. + If the key sent is not is not one of: + , + , + , + , + , + , + , + + + + + + Releases a key. + + The key value representing the key to release. + The key value must be one of the values from the class. + If the key sent is not is not one of: + , + , + , + , + , + , + , + + + + + + Sends a sequence of keystrokes to the target. + + A string representing the keystrokes to send. + + + + Sends a sequence of keystrokes to the application, holding a specified key. + After the action, holded key is released. + + A string representing the keystrokes to send. + The key value representing the key to hold. + The key value must be one of the values from the class. + If the key sent is not is not one of: + , + , + , + , + , + , + , + + + + + + Provides methods representing basic mouse actions. + + + + + Clicks the mouse at the last known mouse coordinates. + + + + + Clicks and holds the mouse button at the last known mouse coordinates. + + + + + Releases the mouse button at the last known mouse coordinates. + + + + + Right-clicks the mouse at the last known mouse coordinates. + + + + + Double-clicks the mouse at the last known mouse coordinates. + + + + + Moves the mouse to the specified offset of the last known mouse coordinates. + + The horizontal offset to which to move the mouse. + The vertical offset to which to move the mouse. + + + + Scrolls the current screen by specified offset. + + The horizontal offset relative to the view port. + The vertical offset relative to the view port. + + + + Implements Keyboard actions for the whole application. + + + + + Implements Mouse actions for the whole application. + + + + + Provides functionality to work with Windows application via WinAppDriver. + + + + + Instantiate application. + + Instance of WinAppDriver + Instance of + Instance of + Instance of + Instance of + + + + Provides instance of Windows Driver + + + + + Sets WinAppDriver ImplicitWait timeout. + Default value: . + + Desired Implicit wait timeout. + + + + Quit application. + + + + + Controls application and Aquality services + + + + + Stops appium local service. + + True if service was running, false otherwise + + + + Provides current instance of application + + + + + Provides access to Aquality services, registered in DI container. + + + + + Resolves required service from + + type of required service + Thrown if there is no service of the required type. + + + + + Sets default factory responsible for application creation. + RemoteApplicationFactory if value set in configuration and LocalApplicationFactory otherwise. + + + + + Sets custom application factory. + + Custom implementation of + + + + Provides application profile. + + + + + Instantiates class using JSON file with general settings. + + JSON settings file. + Instance of + + + + Provides target application profile. + + + + + Instantiates class using JSON file with general settings. + + JSON settings file. + + + + Defines does the current settings have the application path defined + + + + + Describes application settings. + + + + + Is remote WinAppDriver service or not: true to use and false to create default . + + + + + Gets remote connection URI is case of remote browser. + + + + + Gets WinAppDriver settings for application. + + + + + Describes WinAppDriver settings. + + + + + Gets desired WinAppDriver options + + + + + Provides a path to the application + + + + + Abstract class for any actions agains element. + + + + + Instantiates Element actions for a specific element. + + Target element. + Target element's type. + Method to get current application session. + Logger for localized values. + Retrier for element actions. + + + + Performs submitted action against new object. + + Action to be performed. + + + + Logs element action in specific format. + + Key of the localized message. + Arguments for the localized message. + + + + Provides methods representing basic mouse actions against the current element. + Current element's coordinates are user as last known mouse coordinates. + + + + + Performs a drag-and-drop operation on the current element; drops it on target element. + + The element on which the drop is performed. + + + + Performs a drag-and-drop operation on the current element to a specified offset. + + The horizontal offset to which to move the mouse. + The vertical offset to which to move the mouse. + + + + Moves the current element to a specified offset. Works the same as to + + The horizontal offset to which to move the mouse. + The vertical offset to which to move the mouse. + + + + Moves the mouse from the current element. + + + + + Moves the mouse to the current element. + + + + + Moves the mouse to the specified offset of the top-left corner of the current element. + + The horizontal offset to which to move the mouse. + The vertical offset to which to move the mouse. + + + + Moves the mouse to the specified offset of specified offset origin of the current element. + + The horizontal offset to which to move the mouse. + The vertical offset to which to move the mouse. + The value from which to calculate the offset. + + + + Scrolls the current screen by specified offset, starting from the current element. + + + + + + + Implements Keyboard actions for a specific element. + + + + + Instantiates Keyboard actions for a specific element. + + Target element. + Target element's type. + Method to get current application session. + Logger for localized values. + Retrier for element actions. + + + + Implements Mouse actions for a specific element. + + + + + Instantiates Mouse actions for a specific element. + + Target element. + Target element's type. + Method to get current application session. + Logger for localized values. + Retrier for element actions. + + + + Defines Button UI element. + + + + + Factory that creates elements. + + + + + Describes behavior of Button UI element. + + + + + Descibes behavior of any application element. + + + + + Provides access to against the current element. + + + + + Provides access to against the current element. + + + + + Defines the interface used to create the windows application's elements. + + + + + Creates element that implements IButton interface. + + Element locator + Element name + Instance of element that implements IButton interface + + + + Creates element that implements ILabel interface. + + Element locator + Element name + Instance of element that implements ILabel interface + + + + Creates element that implements ITextBox interface. + + Element locator + Element name + Instance of element that implements ITextBox interface + + + + Describes behavior of Label UI element. + + + + + Describes behavior of TextBox UI element. + + + + + Gets text value of an element. + + String representation of element's value + + + + Type text in an element. + + Text to type. + Should the typing text be hidden in logs or not. False by default. + + + + Clear element text and type value. + + Text to type. + Should the typing text be hidden in logs or not. False by default. + + + + Defines Label UI element. + + + + + Defines TextBox UI element. + + + + + Provides extension methods for classes. + + + + + element.GetType().Name provides a non-localized name; + ElementType property is localized, but has the protected access and is not defined in the IElement interface. + So current method allows to get ElementType if the current element is assignable from + + + + + + + Returns name of the value from , readable in the log. + + Keyboard key to define. + Readable value. + + + + Defines base class for any application's window. + + + + + Constructor with parameters. + + Unique locator of the window. + Name of the window. + + + + Locator of specified window. + + + + + Name of specified window. + + + + + Instance of logger + + Logger instance. + + + + Element factory + + Element factory. + + + + Return window state for window locator + + True - window is opened, + False - window is not opened. + + + + Gets size of window element defined by its locator. + + + + diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Configurations/ApplicationProfile.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Configurations/ApplicationProfile.cs index 19098ca..9bd75cc 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Configurations/ApplicationProfile.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Configurations/ApplicationProfile.cs @@ -12,6 +12,7 @@ public class ApplicationProfile : IApplicationProfile /// Instantiates class using JSON file with general settings. /// /// JSON settings file. + /// Instance of public ApplicationProfile(JsonFile settingsFile, IDriverSettings driverSettings) { SettingsFile = settingsFile; diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/ElementActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/ElementActions.cs index 7f4cfb8..d72d988 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/ElementActions.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/ElementActions.cs @@ -37,7 +37,7 @@ protected ElementActions(IElement element, string elementType, Func - /// Performs submtted action against new object. + /// Performs submitted action against new object. /// /// Action to be performed. protected virtual void PerformAction(Func action) diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/IMouseActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/IMouseActions.cs index 2b897ac..5f9db93 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/IMouseActions.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/IMouseActions.cs @@ -30,14 +30,14 @@ public interface IMouseActions : WinAppDriver.Actions.IMouseActions new void MoveByOffset(int offsetX, int offsetY); /// - /// Moves the mouse to the current element. + /// Moves the mouse from the current element. /// - void MoveToElement(); + void MoveFromElement(); /// - /// Moves the mouse from the current element. + /// Moves the mouse to the current element. /// - void MoveFromElement(); + void MoveToElement(); /// /// Moves the mouse to the specified offset of the top-left corner of the current element. @@ -53,5 +53,12 @@ public interface IMouseActions : WinAppDriver.Actions.IMouseActions /// The vertical offset to which to move the mouse. /// The value from which to calculate the offset. void MoveToElement(int offsetX, int offsetY, MoveToElementOffsetOrigin offsetOrigin); + + /// + /// Scrolls the current screen by specified offset, starting from the current element. + /// + /// + /// + new void Scroll(int offsetX, int offsetY); } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/MouseActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/MouseActions.cs index 0930058..5c4cf57 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/MouseActions.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/MouseActions.cs @@ -2,7 +2,9 @@ using Aquality.Selenium.Core.Localization; using Aquality.Selenium.Core.Utilities; using Aquality.WinAppDriver.Elements.Interfaces; +using Aquality.WinAppDriver.Extensions; using OpenQA.Selenium.Interactions; +using OpenQA.Selenium.Remote; using System; namespace Aquality.WinAppDriver.Elements.Actions @@ -13,6 +15,7 @@ namespace Aquality.WinAppDriver.Elements.Actions public class MouseActions : ElementActions, IMouseActions { private readonly IElement element; + private readonly Func remoteTouchScreenSupplier; /// /// Instantiates Mouse actions for a specific element. @@ -26,6 +29,7 @@ public MouseActions(IElement element, string elementType, Func app : base(element, elementType, applicationSupplier, localizationLogger, elementActionsRetrier) { this.element = element; + remoteTouchScreenSupplier = () => new RemoteTouchScreen(applicationSupplier().Driver); } public void Click() @@ -65,8 +69,7 @@ public void MoveByOffset(int offsetX, int offsetY) public void DragAndDrop(IElement target) { - //todo: try add localized as {elementType} '{elementName}' - LogAction("loc.mouse.draganddrop", target.GetType(), target.Name); + LogAction("loc.mouse.draganddrop", target.GetElementType(), target.Name); PerformAction((actions, element) => actions.DragAndDrop(element, target.GetElement())); } @@ -76,12 +79,6 @@ public void DragAndDropToOffset(int offsetX, int offsetY) PerformAction((actions, element) => actions.DragAndDropToOffset(element, offsetX, offsetY)); } - public void MoveToElement() - { - LogAction("loc.mouse.movetoelement"); - PerformAction((actions, element) => actions.MoveToElement(element)); - } - public void MoveFromElement() { var offsetX = - element.GetElement().Size.Width / 2; @@ -90,6 +87,12 @@ public void MoveFromElement() PerformAction((actions, element) => actions.MoveToElement(element, offsetX, offsetY)); } + public void MoveToElement() + { + LogAction("loc.mouse.movetoelement"); + PerformAction((actions, element) => actions.MoveToElement(element)); + } + public void MoveToElement(int offsetX, int offsetY) { LogAction("loc.mouse.movetoelement.byoffset", offsetX, offsetY); @@ -101,5 +104,11 @@ public void MoveToElement(int offsetX, int offsetY, MoveToElementOffsetOrigin of LogAction("loc.mouse.movetoelement.byoffset.withorigin", offsetX, offsetY, offsetOrigin); PerformAction((actions, element) => actions.MoveToElement(element, offsetX, offsetY, offsetOrigin)); } + + public void Scroll(int offsetX, int offsetY) + { + LogAction("loc.mouse.scrollbyoffset", offsetX, offsetY); + remoteTouchScreenSupplier().Scroll(element.GetElement().Coordinates, offsetX, offsetY); + } } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Element.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Element.cs index 531e489..dcb7241 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Element.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Element.cs @@ -3,11 +3,11 @@ using Aquality.Selenium.Core.Localization; using Aquality.Selenium.Core.Utilities; using Aquality.Selenium.Core.Waitings; -using Aquality.WinAppDriver.Actions; using Aquality.WinAppDriver.Applications; +using Aquality.WinAppDriver.Elements.Actions; using Aquality.WinAppDriver.Elements.Interfaces; using OpenQA.Selenium; -using KeyboardActions = Aquality.WinAppDriver.Elements.Actions.KeyboardActions; +using IKeyboardActions = Aquality.WinAppDriver.Actions.IKeyboardActions; using CoreElement = Aquality.Selenium.Core.Elements.Element; using CoreElementFactory = Aquality.Selenium.Core.Elements.Interfaces.IElementFactory; using CoreElementFinder = Aquality.Selenium.Core.Elements.Interfaces.IElementFinder; @@ -32,6 +32,8 @@ protected Element(By locator, string name) : base(locator, name, ElementState.Di public virtual IKeyboardActions KeyboardActions => new KeyboardActions(this, ElementType, () => Application, LocalizationLogger, ActionRetrier); + public virtual IMouseActions MouseActions => new MouseActions(this, ElementType, () => Application, LocalizationLogger, ActionRetrier); + public T FindChildElement(By childLocator, ElementSupplier supplier = null) where T : IElement { return FindChildElement(childLocator, supplier, ElementState.Displayed); diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Interfaces/IElement.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Interfaces/IElement.cs index a0f671f..9416781 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Interfaces/IElement.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Interfaces/IElement.cs @@ -1,10 +1,22 @@ -using Aquality.WinAppDriver.Actions; +using Aquality.WinAppDriver.Elements.Actions; using CoreElement = Aquality.Selenium.Core.Elements.Interfaces.IElement; +using IKeyboardActions = Aquality.WinAppDriver.Actions.IKeyboardActions; namespace Aquality.WinAppDriver.Elements.Interfaces { + /// + /// Descibes behavior of any application element. + /// public interface IElement : CoreElement { + /// + /// Provides access to against the current element. + /// IKeyboardActions KeyboardActions { get; } + + /// + /// Provides access to against the current element. + /// + IMouseActions MouseActions { get; } } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Interfaces/IElementFactory.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Interfaces/IElementFactory.cs index dc651fd..57407dd 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Interfaces/IElementFactory.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Interfaces/IElementFactory.cs @@ -21,7 +21,6 @@ public interface IElementFactory : CoreElementFactory /// /// Element locator /// Element name - /// Element state /// Instance of element that implements ILabel interface ILabel GetLabel(By locator, string name); diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/ElementExtensions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/ElementExtensions.cs new file mode 100644 index 0000000..bf6e95b --- /dev/null +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/ElementExtensions.cs @@ -0,0 +1,30 @@ +using Aquality.Selenium.Core.Elements; +using Aquality.WinAppDriver.Elements.Interfaces; +using System.Reflection; + +namespace Aquality.WinAppDriver.Extensions +{ + /// + /// Provides extension methods for classes. + /// + public static class ElementExtensions + { + /// + /// element.GetType().Name provides a non-localized name; + /// ElementType property is localized, but has the protected access and is not defined in the IElement interface. + /// So current method allows to get ElementType if the current element is assignable from + /// + /// + /// + public static string GetElementType(this IElement element) + { + string elementType = null; + if (typeof(Element).IsAssignableFrom(element.GetType())) + { + elementType = element.GetType().GetProperty("ElementType", BindingFlags.NonPublic | BindingFlags.Instance)?.GetValue(element).ToString(); + } + + return elementType ?? element.GetType().Name; + } + } +} diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/be.json b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/be.json index 84793c5..a7b06d4 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/be.json +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/be.json @@ -21,5 +21,18 @@ "loc.keyboard.presskey": "Заціскаем клавішу '{0}'", "loc.keyboard.releasekey": "Адпускаем клавішу '{0}'", "loc.keyboard.sendkeys": "Націскаем клавішы '{0}'", - "loc.keyboard.sendkeys.withkeyhold": "Націскаем клавішы '{0}' з заціснутай клавішай '{1}'" + "loc.keyboard.sendkeys.withkeyhold": "Націскаем клавішы '{0}' з заціснутай клавішай '{1}'", + "loc.mouse.click": "Націскаем кнопку мышы", + "loc.mouse.clickandhold": "Заціскаем кнопку мышы", + "loc.mouse.release": "Адпускаем кнопку мышы", + "loc.mouse.contextclick": "Націскаем правую кнопку мышы", + "loc.mouse.doubleclick": "Падвойна націскаем кнопку мышы", + "loc.mouse.movebyoffset": "Перамяшчаем курсор мышы на '{0}' пунктаў па вертыкалі і '{1}' пунктаў па гарызанталі", + "loc.mouse.draganddrop": "Перамяшчаем курсор мышы да элемента '{0} '{1}''", + "loc.mouse.draganddrop.tooffset": "Перамяшчаем курсор мышы на '{0}' пунктаў па вертыкалі і '{1}' пунктаў па гарызанталі", + "loc.mouse.movefromelement": "Адводзім курсор мышы ад элемента", + "loc.mouse.movetoelement": "Наводзім курсор мышы на элемент", + "loc.mouse.movetoelement.byoffset": "Наводзім курсор мышы на элемент са змяшчэннем на '{0}' пунктаў па вертыкалі і '{1}' пунктаў па гарызанталі", + "loc.mouse.movetoelement.byoffset.withorigin": "Наводзім курсор мышы на элемент са змяшчэннем на '{0}' пунктаў па вертыкалі і '{1}' пунктаў па гарызанталі, пачынаючы ад '{2}'", + "loc.mouse.scrollbyoffset": "Пракручваем кольца мышы на '{0}' пунктаў па вертыкалі і '{1}' пунктаў па гарызанталі" } \ No newline at end of file diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/en.json b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/en.json index 03aabf2..84bac09 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/en.json +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/en.json @@ -21,5 +21,18 @@ "loc.keyboard.presskey": "Pressing key '{0}'", "loc.keyboard.releasekey": "Releasing key '{0}'", "loc.keyboard.sendkeys": "Sending keys '{0}'", - "loc.keyboard.sendkeys.withkeyhold": "Sending keys '{0}' with holded key '{1}'" + "loc.keyboard.sendkeys.withkeyhold": "Sending keys '{0}' with holded key '{1}'", + "loc.mouse.click": "Clicking mouse button", + "loc.mouse.clickandhold": "Holding mouse button", + "loc.mouse.release": "Releasing mouse button", + "loc.mouse.contextclick": "Clicking right mouse button", + "loc.mouse.doubleclick": "Double-clicking mouse button", + "loc.mouse.movebyoffset": "Moving mouse by '{0}' vertical and '{1}' horizontal offset", + "loc.mouse.draganddrop": "Drag-and-drop to element '{0} '{1}''", + "loc.mouse.draganddrop.tooffset": "Drag-and-drop to '{0}' vertical and '{1}' horizontal offset", + "loc.mouse.movefromelement": "Moving mouse from element", + "loc.mouse.movetoelement": "Moving mouse to element", + "loc.mouse.movetoelement.byoffset": "Moving mouse to element by '{0}' vertical and '{1}' horizontal offset", + "loc.mouse.movetoelement.byoffset.withorigin": "Moving mouse to element by '{0}' vertical and '{1}' horizontal offset with origin at '{2}'", + "loc.mouse.scrollbyoffset": "Scroll mouse wheel by '{0}' vertical and '{1}' horizontal offset" } \ No newline at end of file diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/ru.json b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/ru.json index 08c2779..ec379db 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/ru.json +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/ru.json @@ -21,5 +21,18 @@ "loc.keyboard.presskey": "Зажимаем клавишу '{0}'", "loc.keyboard.releasekey": "Отпускаем клавишу '{0}'", "loc.keyboard.sendkeys": "Нажимаем клавиши '{0}'", - "loc.keyboard.sendkeys.withkeyhold": "Нажимаем клавиши '{0}' с зажатой клавишей '{1}'" + "loc.keyboard.sendkeys.withkeyhold": "Нажимаем клавиши '{0}' с зажатой клавишей '{1}'", + "loc.mouse.click": "Щёлкаем кнопку мыши", + "loc.mouse.clickandhold": "Зажимаем кнопку мыши", + "loc.mouse.release": "Отпускаем кнопку мыши", + "loc.mouse.contextclick": "Щёлкаем правую кнопку мыши", + "loc.mouse.doubleclick": "Дважды щёлкаем кнопку мыши", + "loc.mouse.movebyoffset": "Перемещаем курсор мыши на '{0}' пунктов по вертикали и '{1}' пунктов по горизонтали", + "loc.mouse.draganddrop": "Перемещаем к элементу '{0} '{1}''", + "loc.mouse.draganddrop.tooffset": "Перемещаем на '{0}' пунктов по вертикали и '{1}' пунктов по горизонтали", + "loc.mouse.movefromelement": "Отводим курсор мыши от элемента", + "loc.mouse.movetoelement": "Наводим курсор мыши на элемент", + "loc.mouse.movetoelement.byoffset": "Наводим курсор мыши на элемент со смещением на '{0}' пунктов по вертикали и '{1}' пунктов по горизонтали", + "loc.mouse.movetoelement.byoffset.withorigin": "Наводим курсор мыши на элемент со смещением на '{0}' пунктов по вертикали и '{1}' пунктов по горизонтали, отсчитывая от '{2}'", + "loc.mouse.scrollbyoffset": "Прокручиваем колёсико мыши на '{0}' пунктов по вертикали и '{1}' пунктов по горизонтали" } \ No newline at end of file diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Windows/Window.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Windows/Window.cs index d72703e..4dc3748 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Windows/Window.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Windows/Window.cs @@ -34,13 +34,13 @@ protected Window(By locator, string name) public string Name { get; } /// - /// Instance of logger + /// Instance of logger /// /// Logger instance. protected Logger Logger => ApplicationManager.GetRequiredService(); /// - /// Element factory + /// Element factory /// /// Element factory. protected IElementFactory ElementFactory => ApplicationManager.GetRequiredService(); diff --git a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/MouseActionsTests.cs b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/MouseActionsTests.cs new file mode 100644 index 0000000..a948783 --- /dev/null +++ b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/MouseActionsTests.cs @@ -0,0 +1,31 @@ +using Aquality.WinAppDriver.Actions; +using Aquality.WinAppDriver.Applications; +using Aquality.WinAppDriver.Elements.Interfaces; +using Aquality.WinAppDriver.Tests.Applications.Locators; +using NUnit.Framework; + +namespace Aquality.WinAppDriver.Tests.Actions +{ + public class MouseActionsTests : TestWithApplication + { + protected virtual IMouseActions MouseActions => ApplicationManager.GetRequiredService(); + + protected ITextBox RightArgumentTextBox => new CalculatorWindow().RightArgumentTextBox; + + [Test] + public void Should_PerformMouseActions() + { + RightArgumentTextBox.Click(); + Assert.DoesNotThrow(() => + { + MouseActions.Click(); + MouseActions.ClickAndHold(); + MouseActions.Release(); + MouseActions.ContextClick(); + MouseActions.DoubleClick(); + MouseActions.MoveByOffset(10, 10); + MouseActions.Scroll(10, 10); + }); + } + } +} diff --git a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Applications/Locators/CalculatorWindow.cs b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Applications/Locators/CalculatorWindow.cs index 4d5bbbc..dbefe7e 100644 --- a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Applications/Locators/CalculatorWindow.cs +++ b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Applications/Locators/CalculatorWindow.cs @@ -9,6 +9,8 @@ public class CalculatorWindow : Window { private static By WindowLocator => By.TagName("Window"); + public ITextBox LeftArgumentTextBox => ElementFactory.GetTextBox(MobileBy.AccessibilityId("50"), "Left Argument"); + public ITextBox RightArgumentTextBox => ElementFactory.GetTextBox(By.XPath("//*[@AutomationId='49']"), "Right Argument"); public IButton OneButton => ElementFactory.GetButton(By.Name("1"), "1"); diff --git a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Applications/MouseActionsTests.cs b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Applications/MouseActionsTests.cs new file mode 100644 index 0000000..f92483a --- /dev/null +++ b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Applications/MouseActionsTests.cs @@ -0,0 +1,10 @@ +using Aquality.WinAppDriver.Actions; +using Aquality.WinAppDriver.Applications; + +namespace Aquality.WinAppDriver.Tests.Applications +{ + public class MouseActionsTests : Actions.MouseActionsTests + { + protected override IMouseActions MouseActions => ApplicationManager.Application.MouseActions; + } +} diff --git a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Elements/Actions/MouseActionsTests.cs b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Elements/Actions/MouseActionsTests.cs new file mode 100644 index 0000000..701d241 --- /dev/null +++ b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Elements/Actions/MouseActionsTests.cs @@ -0,0 +1,32 @@ +using Aquality.WinAppDriver.Actions; +using Aquality.WinAppDriver.Elements.Interfaces; +using Aquality.WinAppDriver.Tests.Applications.Locators; +using NUnit.Framework; +using OpenQA.Selenium.Interactions; + +namespace Aquality.WinAppDriver.Tests.Elements.Actions +{ + public class MouseActionsTests : Tests.Actions.MouseActionsTests + { + protected override IMouseActions MouseActions => RightArgumentTextBox.MouseActions; + private ITextBox LeftArgumentTextBox => new CalculatorWindow().LeftArgumentTextBox; + + [Test] + public void Should_PerformElementSpecificMouseActions() + { + RightArgumentTextBox.Click(); + Assert.DoesNotThrow(() => + { + RightArgumentTextBox.MouseActions.DragAndDrop(LeftArgumentTextBox); + RightArgumentTextBox.MouseActions.DragAndDropToOffset(10, 10); + RightArgumentTextBox.MouseActions.MoveByOffset(10, 10); + RightArgumentTextBox.MouseActions.MoveFromElement(); + RightArgumentTextBox.MouseActions.MoveToElement(); + RightArgumentTextBox.MouseActions.MoveToElement(10, 10); + RightArgumentTextBox.MouseActions.MoveToElement(10, 10, MoveToElementOffsetOrigin.Center); + RightArgumentTextBox.MouseActions.MoveToElement(10, 10, MoveToElementOffsetOrigin.TopLeft); + RightArgumentTextBox.MouseActions.Scroll(10, 10); + }); + } + } +} diff --git a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Localization/LocalizationFilesTest.cs b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Localization/LocalizationFilesTest.cs index c057c34..74db3af 100644 --- a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Localization/LocalizationFilesTest.cs +++ b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Localization/LocalizationFilesTest.cs @@ -13,14 +13,14 @@ namespace Aquality.WinAppDriver.Tests.Localization { public class LocalizationFilesTest { - private static readonly string[] SupportedLanguages = { "be", "en", "ru" }; + private const string EnglishLanguageCode = "en"; + private static readonly string[] SupportedLanguages = { "be", EnglishLanguageCode, "ru" }; private static readonly Assembly LibraryAssembly = Assembly.GetAssembly(typeof(ApplicationManager)); - private static readonly IList> LocalizationFileDictionary - = new JsonFile("Resources.Localization.en.json", LibraryAssembly).GetValue>("$").ToList(); - private static readonly IEnumerable KeysWithoutParams = LocalizationFileDictionary.Where(pair => !pair.Value.Contains("{0}")).Select(pair => pair.Key); - private static readonly IEnumerable KeysWithOneParameter = LocalizationFileDictionary.Where(pair => pair.Value.Contains("{0}") && !pair.Value.Contains("{1}")).Select(pair => pair.Key); - private static readonly IEnumerable KeysWithTwoAndMoreParameters = LocalizationFileDictionary.Where(pair => pair.Value.Contains("{1}")).Select(pair => pair.Key); - private static readonly IEnumerable KeysWithParameters = LocalizationFileDictionary.Where(pair => pair.Value.Contains("{0}")).Select(pair => pair.Key); + private static readonly IList> LocalizationFileEnglishDictionary = GetLocalizationDictionaryAsList(EnglishLanguageCode); + private static readonly IEnumerable KeysWithoutParams = LocalizationFileEnglishDictionary.Where(pair => !pair.Value.Contains("{0}")).Select(pair => pair.Key); + private static readonly IEnumerable KeysWithOneParameter = LocalizationFileEnglishDictionary.Where(pair => pair.Value.Contains("{0}") && !pair.Value.Contains("{1}")).Select(pair => pair.Key); + private static readonly IEnumerable KeysWithTwoAndMoreParameters = LocalizationFileEnglishDictionary.Where(pair => pair.Value.Contains("{1}")).Select(pair => pair.Key); + private static readonly IEnumerable KeysWithParameters = LocalizationFileEnglishDictionary.Where(pair => pair.Value.Contains("{0}")).Select(pair => pair.Key); private LocalizationManager LocalizationManager => ApplicationManager.GetRequiredService(); @@ -72,6 +72,28 @@ public void Should_ThrowsFormatException_WhenKeysRequireParams([ValueSource(name Assert.Throws(() => GetLocalizationManager(language).GetLocalizedMessage(key)); } + [Test] + public void Should_HaveSameAmountOfValues([ValueSource(nameof(SupportedLanguages))] string language) + { + Assert.AreEqual(LocalizationFileEnglishDictionary.Count, GetLocalizationDictionaryAsList(language).Count); + } + + [Test] + public void Should_HaveNotAllValuesTheSame_InDifferentLanguages([ValueSource(nameof(SupportedLanguages))] string language) + { + var currentLanguageDictionary = GetLocalizationDictionaryAsList(language); + + foreach (var dictionary in SupportedLanguages.Except(new[] { language }).Select(lang => GetLocalizationDictionaryAsList(lang))) + { + CollectionAssert.AreNotEquivalent(currentLanguageDictionary, dictionary); + } + } + + private static IList> GetLocalizationDictionaryAsList(string language) + { + return new JsonFile($"Resources.Localization.{language}.json", LibraryAssembly).GetValue>("$").ToList(); + } + private LocalizationManager GetLocalizationManager(string customLanguage) { var configuration = new DynamicConfiguration From c94773cb1cc7e64db8cf45df1e7c08ec99020baa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Thu, 19 Sep 2019 15:22:21 +0300 Subject: [PATCH 10/13] Refactor ApplicationManager and Factories. Fixed Localization test --- .../Applications/Application.cs | 17 ++++--- .../Applications/ApplicationFactory.cs | 26 ++++++---- .../Applications/ApplicationManager.cs | 47 ++++++++++--------- .../Applications/LocalApplicationFactory.cs | 26 +++------- .../Applications/RemoteApplicationFactory.cs | 25 +++------- .../Aquality.WinAppDriver.xml | 18 +++---- .../Localization/LocalizationFilesTest.cs | 2 +- 7 files changed, 71 insertions(+), 90 deletions(-) diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs index d8ece76..4102c0c 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs @@ -3,6 +3,7 @@ using Aquality.Selenium.Core.Configurations; using Aquality.Selenium.Core.Localization; using Aquality.WinAppDriver.Actions; +using Microsoft.Extensions.DependencyInjection; using OpenQA.Selenium.Appium.Windows; using OpenQA.Selenium.Remote; @@ -19,18 +20,16 @@ public class Application : IApplication /// Instantiate application. /// /// Instance of WinAppDriver - /// Instance of - /// Instance of - /// Instance of - /// Instance of - public Application(WindowsDriver windowsDriver, ITimeoutConfiguration timeoutConfiguration, LocalizationLogger logger, IKeyboardActions keyboardActions, IMouseActions mouseActions) + /// Service provider to resolve all dependencies from DI container + public Application(WindowsDriver windowsDriver, IServiceProvider serviceProvider) { - Logger = logger; WindowsDriver = windowsDriver; + Logger = serviceProvider.GetRequiredService(); + KeyboardActions = serviceProvider.GetRequiredService(); + MouseActions = serviceProvider.GetRequiredService(); + var timeoutConfiguration = serviceProvider.GetRequiredService(); WindowsDriver.Manage().Timeouts().ImplicitWait = timeoutConfiguration.Implicit; - KeyboardActions = keyboardActions; - MouseActions = mouseActions; - logger.Info("loc.application.ready"); + Logger.Info("loc.application.ready"); } private LocalizationLogger Logger { get; } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationFactory.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationFactory.cs index b0e634a..7a647be 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationFactory.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationFactory.cs @@ -1,5 +1,7 @@ -using Aquality.Selenium.Core.Localization; -using OpenQA.Selenium.Appium; +using Aquality.Selenium.Core.Configurations; +using Aquality.Selenium.Core.Localization; +using Aquality.WinAppDriver.Configurations; +using Microsoft.Extensions.DependencyInjection; using OpenQA.Selenium.Appium.Windows; using System; @@ -7,20 +9,28 @@ namespace Aquality.WinAppDriver.Applications { public abstract class ApplicationFactory : IApplicationFactory { - private readonly LocalizationLogger localizationLogger; + private readonly IDriverSettings driverSettings; + private readonly ITimeoutConfiguration timeoutConfiguration; - protected ApplicationFactory(LocalizationLogger localizationLogger) + protected LocalizationLogger LocalizationLogger { get; } + protected IServiceProvider ServiceProvider { get; } + + protected ApplicationFactory(IServiceProvider serviceProvider) { - this.localizationLogger = localizationLogger; + LocalizationLogger = serviceProvider.GetRequiredService(); + driverSettings = serviceProvider.GetRequiredService(); + timeoutConfiguration = serviceProvider.GetRequiredService(); + ServiceProvider = serviceProvider; } public abstract Application Application { get; } - protected WindowsDriver GetDriver(Uri driverServerUri, AppiumOptions options, TimeSpan commandTimeout) + protected WindowsDriver GetDriver(Uri driverServerUri) { + var options = driverSettings.AppiumOptions; options.ToDictionary().TryGetValue("app", out var appPath); - localizationLogger.Info("loc.application.start", appPath); - return new WindowsDriver(driverServerUri, options, commandTimeout); + LocalizationLogger.Info("loc.application.start", appPath); + return new WindowsDriver(driverServerUri, options, timeoutConfiguration.Command); } } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs index e77ec0c..3e818a6 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationManager.cs @@ -69,6 +69,25 @@ public static IServiceProvider ServiceProvider } } + /// + /// Factory for application creation. + /// + public static IApplicationFactory ApplicationFactory + { + get + { + if (!ApplicationFactoryContainer.IsValueCreated) + { + SetDefaultFactory(); + } + return ApplicationFactoryContainer.Value; + } + set + { + ApplicationFactoryContainer.Value = value; + } + } + /// /// Resolves required service from /// @@ -87,32 +106,17 @@ public static T GetRequiredService() public static void SetDefaultFactory() { var appProfile = GetRequiredService(); - var driverSettings = GetRequiredService(); - var localizationLogger = GetRequiredService(); - var timeoutConfiguration = GetRequiredService(); - var keyboardActions = GetRequiredService(); - var mouseActions = GetRequiredService(); - IApplicationFactory applicationFactory; if (appProfile.IsRemote) { - applicationFactory = new RemoteApplicationFactory(appProfile.RemoteConnectionUrl, driverSettings, timeoutConfiguration, localizationLogger, keyboardActions, mouseActions); + applicationFactory = new RemoteApplicationFactory(appProfile.RemoteConnectionUrl, ServiceProvider); } else { - applicationFactory = new LocalApplicationFactory(AppiumLocalServiceContainer.Value, driverSettings, timeoutConfiguration, localizationLogger, keyboardActions, mouseActions); + applicationFactory = new LocalApplicationFactory(AppiumLocalServiceContainer.Value, ServiceProvider); } - SetFactory(applicationFactory); - } - - /// - /// Sets custom application factory. - /// - /// Custom implementation of - public static void SetFactory(IApplicationFactory applicationFactory) - { - ApplicationFactoryContainer.Value = applicationFactory; + ApplicationFactory = applicationFactory; } private static IServiceCollection RegisterServices(Func applicationSupplier) @@ -128,6 +132,7 @@ private static IServiceCollection RegisterServices(Func new LocalizationManager(serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService(), Assembly.GetExecutingAssembly())); services.AddSingleton(serviceProvider => new KeyboardActions(serviceProvider.GetRequiredService(), () => Application.WindowsDriver)); services.AddSingleton(serviceProvider => new MouseActions(serviceProvider.GetRequiredService(), () => Application.WindowsDriver)); + services.AddSingleton(serviceProvider => ApplicationFactory); return services; } @@ -135,11 +140,7 @@ private static Func StartApplicationFunction { get { - if (!ApplicationFactoryContainer.IsValueCreated) - { - SetDefaultFactory(); - } - return (services) => ApplicationFactoryContainer.Value.Application; + return (services) => ApplicationFactory.Application; } } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/LocalApplicationFactory.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/LocalApplicationFactory.cs index 1eb63fd..0f528f7 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/LocalApplicationFactory.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/LocalApplicationFactory.cs @@ -1,29 +1,17 @@ -using Aquality.Selenium.Core.Configurations; -using Aquality.Selenium.Core.Localization; -using Aquality.WinAppDriver.Actions; -using Aquality.WinAppDriver.Configurations; +using Aquality.Selenium.Core.Localization; using OpenQA.Selenium.Appium.Service; +using System; namespace Aquality.WinAppDriver.Applications { public class LocalApplicationFactory : ApplicationFactory { private readonly AppiumLocalService driverService; - private readonly IDriverSettings driverSettings; - private readonly ITimeoutConfiguration timeoutConfiguration; - private readonly LocalizationLogger localizationLogger; - private readonly IKeyboardActions keyboardActions; - private readonly IMouseActions mouseActions; - public LocalApplicationFactory(AppiumLocalService driverService, IDriverSettings driverSettings, ITimeoutConfiguration timeoutConfiguration, LocalizationLogger localizationLogger, IKeyboardActions keyboardActions, IMouseActions mouseActions) - : base(localizationLogger) + public LocalApplicationFactory(AppiumLocalService driverService, IServiceProvider serviceProvider) + : base(serviceProvider) { this.driverService = driverService; - this.driverSettings = driverSettings; - this.timeoutConfiguration = timeoutConfiguration; - this.localizationLogger = localizationLogger; - this.keyboardActions = keyboardActions; - this.mouseActions = mouseActions; } public override Application Application @@ -32,9 +20,9 @@ public override Application Application { driverService.Start(); var serviceUrl = driverService.ServiceUrl; - localizationLogger.Info("loc.application.driver.service.local.start", serviceUrl); - var driver = GetDriver(serviceUrl, driverSettings.AppiumOptions, timeoutConfiguration.Command); - return new Application(driver, timeoutConfiguration, localizationLogger, keyboardActions, mouseActions); + LocalizationLogger.Info("loc.application.driver.service.local.start", serviceUrl); + var driver = GetDriver(serviceUrl); + return new Application(driver, ServiceProvider); } } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/RemoteApplicationFactory.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/RemoteApplicationFactory.cs index 9428777..2622205 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/RemoteApplicationFactory.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/RemoteApplicationFactory.cs @@ -1,7 +1,4 @@ -using Aquality.Selenium.Core.Configurations; -using Aquality.Selenium.Core.Localization; -using Aquality.WinAppDriver.Actions; -using Aquality.WinAppDriver.Configurations; +using Aquality.Selenium.Core.Localization; using OpenQA.Selenium.Remote; using System; @@ -10,31 +7,21 @@ namespace Aquality.WinAppDriver.Applications public class RemoteApplicationFactory : ApplicationFactory { private readonly Uri driverServerUri; - private readonly IDriverSettings driverSettings; - private readonly ITimeoutConfiguration timeoutConfiguration; - private readonly LocalizationLogger localizationLogger; - private readonly IKeyboardActions keyboardActions; - private readonly IMouseActions mouseActions; - public RemoteApplicationFactory(Uri driverServerUri, IDriverSettings driverSettings, ITimeoutConfiguration timeoutConfiguration, LocalizationLogger localizationLogger, IKeyboardActions keyboardActions, IMouseActions mouseActions) - : base(localizationLogger) + public RemoteApplicationFactory(Uri driverServerUri, IServiceProvider serviceProvider) + : base(serviceProvider) { this.driverServerUri = driverServerUri; - this.driverSettings = driverSettings; - this.timeoutConfiguration = timeoutConfiguration; - this.localizationLogger = localizationLogger; - this.keyboardActions = keyboardActions; - this.mouseActions = mouseActions; } public override Application Application { get { - localizationLogger.Info("loc.application.driver.service.remote", driverServerUri); - var driver = GetDriver(driverServerUri, driverSettings.AppiumOptions, timeoutConfiguration.Command); + LocalizationLogger.Info("loc.application.driver.service.remote", driverServerUri); + var driver = GetDriver(driverServerUri); driver.FileDetector = new LocalFileDetector(); - return new Application(driver, timeoutConfiguration, localizationLogger, keyboardActions, mouseActions); + return new Application(driver, ServiceProvider); } } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.xml b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.xml index 86b6b0e..a00b537 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.xml +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.xml @@ -152,15 +152,12 @@ Provides functionality to work with Windows application via WinAppDriver. - + Instantiate application. Instance of WinAppDriver - Instance of - Instance of - Instance of - Instance of + Service provider to resolve all dependencies from DI container @@ -200,6 +197,11 @@ Provides access to Aquality services, registered in DI container. + + + Factory for application creation. + + Resolves required service from @@ -214,12 +216,6 @@ RemoteApplicationFactory if value set in configuration and LocalApplicationFactory otherwise. - - - Sets custom application factory. - - Custom implementation of - Provides application profile. diff --git a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Localization/LocalizationFilesTest.cs b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Localization/LocalizationFilesTest.cs index 74db3af..2b9f40a 100644 --- a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Localization/LocalizationFilesTest.cs +++ b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Localization/LocalizationFilesTest.cs @@ -58,7 +58,7 @@ public void Should_ReturnNonKeyValues_AndNotEmptyValues_ForKeysWithOneParameter( [Test] public void Should_ReturnNonKeyValues_AndNotEmptyValues_ForKeysWithTwoAndMoreParameters([ValueSource(nameof(SupportedLanguages))] string language, [ValueSource(nameof(KeysWithTwoAndMoreParameters))] string key) { - var paramsArray = new[] { "a", "b" }; + var paramsArray = new[] { "a", "b" , "c", "d" }; var localizedValue = GetLocalizationManager(language).GetLocalizedMessage(key, paramsArray); Assert.AreNotEqual(key, localizedValue, "Value should be defined in resource files"); Assert.IsNotEmpty(localizedValue, "Value should not be empty"); From 79625bfb5eab2ecaaec6f8ec0ac1c353f5d862cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Thu, 19 Sep 2019 15:52:19 +0300 Subject: [PATCH 11/13] Rework KeyboardActions with holding/releasing a key --- .../Actions/IKeyboardActions.cs | 45 ++------ .../Actions/KeyboardActions.cs | 20 ++-- .../Actions/ModifierKey.cs | 56 ++++++++++ .../Aquality.WinAppDriver.xml | 100 ++++++++++-------- .../Elements/Actions/KeyboardActions.cs | 20 ++-- .../Extensions/ElementExtensions.cs | 4 +- .../Extensions/StringExtensions.cs | 21 ---- .../Actions/KeyboardActionsTests.cs | 30 ++---- 8 files changed, 147 insertions(+), 149 deletions(-) create mode 100644 Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/ModifierKey.cs delete mode 100644 Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/StringExtensions.cs diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/IKeyboardActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/IKeyboardActions.cs index 05e6250..83c8b40 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/IKeyboardActions.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/IKeyboardActions.cs @@ -8,36 +8,14 @@ public interface IKeyboardActions /// /// Presses a key. /// - /// The key value representing the key to press. - /// The key value must be one of the values from the class. - /// If the key sent is not is not one of: - /// , - /// , - /// , - /// , - /// , - /// , - /// , - /// - /// - void PressKey(string keyToPress); + /// The value representing the key to press. + void PressKey(ModifierKey keyToPress); /// /// Releases a key. /// - /// The key value representing the key to release. - /// The key value must be one of the values from the class. - /// If the key sent is not is not one of: - /// , - /// , - /// , - /// , - /// , - /// , - /// , - /// - /// - void ReleaseKey(string keyToRelease); + /// The value representing the key to release. + void ReleaseKey(ModifierKey keyToRelease); /// /// Sends a sequence of keystrokes to the target. @@ -50,18 +28,7 @@ public interface IKeyboardActions /// After the action, holded key is released. /// /// A string representing the keystrokes to send. - /// The key value representing the key to hold. - /// The key value must be one of the values from the class. - /// If the key sent is not is not one of: - /// , - /// , - /// , - /// , - /// , - /// , - /// , - /// - /// - void SendKeysWithKeyHold(string keySequence, string keyToHold); + /// The value representing the key to hold. + void SendKeysWithKeyHold(string keySequence, ModifierKey keyToHold); } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs index f40e553..c2ba474 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/KeyboardActions.cs @@ -1,5 +1,4 @@ using Aquality.Selenium.Core.Localization; -using Aquality.WinAppDriver.Extensions; using OpenQA.Selenium.Appium.Windows; using System; @@ -15,16 +14,16 @@ public KeyboardActions(LocalizationLogger localizationLogger, Func actions.KeyDown(keyToPress)); + LogAction("loc.keyboard.presskey", keyToPress); + PerformAction(actions => actions.KeyDown(keyToPress.GetKeysString())); } - public void ReleaseKey(string keyToRelease) + public void ReleaseKey(ModifierKey keyToRelease) { - LogAction("loc.keyboard.releasekey", keyToRelease.GetLoggableValueForKeyboardKey()); - PerformAction(actions => actions.KeyUp(keyToRelease)); + LogAction("loc.keyboard.releasekey", keyToRelease); + PerformAction(actions => actions.KeyUp(keyToRelease.GetKeysString())); } public void SendKeys(string keySequence) @@ -33,10 +32,11 @@ public void SendKeys(string keySequence) PerformAction(actions => actions.SendKeys(keySequence)); } - public void SendKeysWithKeyHold(string keySequence, string keyToHold) + public void SendKeysWithKeyHold(string keySequence, ModifierKey keyToHold) { - LogAction("loc.keyboard.sendkeys.withkeyhold", keySequence, keyToHold.GetLoggableValueForKeyboardKey()); - PerformAction(actions => actions.KeyDown(keyToHold).SendKeys(keySequence).KeyUp(keyToHold)); + var keyToHoldString = keyToHold.GetKeysString(); + LogAction("loc.keyboard.sendkeys.withkeyhold", keySequence, keyToHold); + PerformAction(actions => actions.KeyDown(keyToHoldString).SendKeys(keySequence).KeyUp(keyToHoldString)); } } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/ModifierKey.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/ModifierKey.cs new file mode 100644 index 0000000..e613f51 --- /dev/null +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Actions/ModifierKey.cs @@ -0,0 +1,56 @@ +using OpenQA.Selenium; +using System.Linq; +using System.Reflection; + +namespace Aquality.WinAppDriver.Actions +{ + /// + /// Represents modifier keys which could be used in . + /// Directly related to + /// + public enum ModifierKey + { + /// + /// Represents the Alt key. + /// + Alt, + /// + /// Represents the function key COMMAND. + /// + Command, + /// + /// Represents the Control key. + /// + Control, + /// + /// Represents the Left Alt key. + /// + LeftAlt, + /// + /// Represents the Left Control key. + /// + LeftControl, + /// + /// Represents the Left Shift key. + /// + LeftShift, + /// + /// Represents the function key META. + /// + Meta, + /// + /// Represents the Shift key. + /// + Shift + } + + internal static class ModifierKeyExtensions + { + public static string GetKeysString(this ModifierKey modifierKey) + { + return typeof(Keys) + .GetFields(BindingFlags.Public | BindingFlags.Static) + .FirstOrDefault(field => field.Name == modifierKey.ToString())?.GetValue(null).ToString(); + } + } +} diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.xml b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.xml index a00b537..b09b64a 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.xml +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.xml @@ -34,39 +34,17 @@ Provides methods representing basic keyboard actions. - + Presses a key. - The key value representing the key to press. - The key value must be one of the values from the class. - If the key sent is not is not one of: - , - , - , - , - , - , - , - - - - + The value representing the key to press. + + Releases a key. - The key value representing the key to release. - The key value must be one of the values from the class. - If the key sent is not is not one of: - , - , - , - , - , - , - , - - + The value representing the key to release. @@ -74,24 +52,13 @@ A string representing the keystrokes to send. - + Sends a sequence of keystrokes to the application, holding a specified key. After the action, holded key is released. A string representing the keystrokes to send. - The key value representing the key to hold. - The key value must be one of the values from the class. - If the key sent is not is not one of: - , - , - , - , - , - , - , - - + The value representing the key to hold. @@ -142,6 +109,52 @@ Implements Keyboard actions for the whole application. + + + Represents modifier keys which could be used in . + Directly related to + + + + + Represents the Alt key. + + + + + Represents the function key COMMAND. + + + + + Represents the Control key. + + + + + Represents the Left Alt key. + + + + + Represents the Left Control key. + + + + + Represents the Left Shift key. + + + + + Represents the function key META. + + + + + Represents the Shift key. + + Implements Mouse actions for the whole application. @@ -508,13 +521,6 @@ - - - Returns name of the value from , readable in the log. - - Keyboard key to define. - Readable value. - Defines base class for any application's window. diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs index c76cd76..922bd0f 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Actions/KeyboardActions.cs @@ -3,7 +3,6 @@ using Aquality.Selenium.Core.Utilities; using Aquality.WinAppDriver.Actions; using Aquality.WinAppDriver.Elements.Interfaces; -using Aquality.WinAppDriver.Extensions; using System; namespace Aquality.WinAppDriver.Elements.Actions @@ -26,16 +25,16 @@ public KeyboardActions(IElement element, string elementType, Func { } - public void PressKey(string keyToPress) + public void PressKey(ModifierKey keyToPress) { - LogAction("loc.keyboard.presskey", keyToPress.GetLoggableValueForKeyboardKey()); - PerformAction((actions, element) => actions.KeyDown(element, keyToPress)); + LogAction("loc.keyboard.presskey", keyToPress); + PerformAction((actions, element) => actions.KeyDown(element, keyToPress.GetKeysString())); } - public void ReleaseKey(string keyToRelease) + public void ReleaseKey(ModifierKey keyToRelease) { - LogAction("loc.keyboard.releasekey", keyToRelease.GetLoggableValueForKeyboardKey()); - PerformAction((actions, element) => actions.KeyUp(element, keyToRelease)); + LogAction("loc.keyboard.releasekey", keyToRelease); + PerformAction((actions, element) => actions.KeyUp(element, keyToRelease.GetKeysString())); } public void SendKeys(string keySequence) @@ -44,10 +43,11 @@ public void SendKeys(string keySequence) PerformAction((actions, element) => actions.SendKeys(element, keySequence)); } - public void SendKeysWithKeyHold(string keySequence, string keyToHold) + public void SendKeysWithKeyHold(string keySequence, ModifierKey keyToHold) { - LogAction("loc.keyboard.sendkeys.withkeyhold", keySequence, keyToHold.GetLoggableValueForKeyboardKey()); - PerformAction((actions, element) => actions.KeyDown(element, keyToHold).SendKeys(element, keySequence).KeyUp(element, keyToHold)); + var keyToHoldString = keyToHold.GetKeysString(); + LogAction("loc.keyboard.sendkeys.withkeyhold", keySequence, keyToHold); + PerformAction((actions, element) => actions.KeyDown(element, keyToHoldString).SendKeys(element, keySequence).KeyUp(element, keyToHoldString)); } } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/ElementExtensions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/ElementExtensions.cs index bf6e95b..abe7a89 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/ElementExtensions.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/ElementExtensions.cs @@ -7,7 +7,7 @@ namespace Aquality.WinAppDriver.Extensions /// /// Provides extension methods for classes. /// - public static class ElementExtensions + internal static class ElementExtensions { /// /// element.GetType().Name provides a non-localized name; @@ -16,7 +16,7 @@ public static class ElementExtensions /// /// /// - public static string GetElementType(this IElement element) + internal static string GetElementType(this IElement element) { string elementType = null; if (typeof(Element).IsAssignableFrom(element.GetType())) diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/StringExtensions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/StringExtensions.cs deleted file mode 100644 index 8ce15c4..0000000 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/StringExtensions.cs +++ /dev/null @@ -1,21 +0,0 @@ -using OpenQA.Selenium; -using System.Linq; -using System.Reflection; - -namespace Aquality.WinAppDriver.Extensions -{ - public static class StringExtensions - { - /// - /// Returns name of the value from , readable in the log. - /// - /// Keyboard key to define. - /// Readable value. - public static string GetLoggableValueForKeyboardKey(this string key) - { - return typeof(Keys) - .GetFields(BindingFlags.Public | BindingFlags.Static) - .FirstOrDefault(field => key.Equals(field.GetValue(null)))?.Name ?? key; - } - } -} diff --git a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs index 43ad3c0..13b69c3 100644 --- a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs +++ b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs @@ -3,7 +3,6 @@ using Aquality.WinAppDriver.Elements.Interfaces; using Aquality.WinAppDriver.Tests.Applications.Locators; using NUnit.Framework; -using OpenQA.Selenium; using System; namespace Aquality.WinAppDriver.Tests.Actions @@ -16,6 +15,8 @@ public class KeyboardActionsTests : TestWithApplication protected ITextBox RightArgumentTextBox => new CalculatorWindow().RightArgumentTextBox; + private static readonly ModifierKey[] modifierKeys = Enum.GetValues(typeof(ModifierKey)) as ModifierKey[]; + [Test] public void Should_SendKeys_ViaKeyboardActions() { @@ -28,9 +29,9 @@ public void Should_SendKeys_ViaKeyboardActions() public void Should_PressKey_ViaKeyboardActions() { RightArgumentTextBox.Click(); - KeyboardActions.PressKey(Keys.Shift); + KeyboardActions.PressKey(ModifierKey.Shift); KeyboardActions.SendKeys(ValueToSend); - KeyboardActions.ReleaseKey(Keys.Shift); + KeyboardActions.ReleaseKey(ModifierKey.Shift); Assert.AreEqual(ValueToSend.ToUpper(), RightArgumentTextBox.Value); } @@ -38,7 +39,7 @@ public void Should_PressKey_ViaKeyboardActions() public void Should_SendKeysWithKeyHold_ViaKeyboardActions() { RightArgumentTextBox.Click(); - KeyboardActions.SendKeysWithKeyHold(ValueToSend, Keys.Shift); + KeyboardActions.SendKeysWithKeyHold(ValueToSend, ModifierKey.Shift); Assert.AreEqual(ValueToSend.ToUpper(), RightArgumentTextBox.Value); } @@ -46,29 +47,18 @@ public void Should_SendKeysWithKeyHold_ViaKeyboardActions() public void Should_ReleaseKey_ViaKeyboardActions() { RightArgumentTextBox.Click(); - KeyboardActions.PressKey(Keys.Shift); + KeyboardActions.PressKey(ModifierKey.Shift); KeyboardActions.SendKeys(ValueToSend); - KeyboardActions.ReleaseKey(Keys.Shift); + KeyboardActions.ReleaseKey(ModifierKey.Shift); KeyboardActions.SendKeys(ValueToSend); Assert.AreEqual($"{ValueToSend.ToUpper()}{ValueToSend}", RightArgumentTextBox.Value); } [Test] - public void Should_ThrowArgumentException_ForInvalidPressedKey_ViaKeyboardActions() - { - Assert.Throws(() => KeyboardActions.PressKey("invalid")); - } - - [Test] - public void Should_ThrowArgumentException_ForInvalidReleasedKey_ViaKeyboardActions() + public void Should_NotThrow_WhenHoldModifierKeys_ViaKeyboardActions([ValueSource(nameof(modifierKeys))]ModifierKey modifierKey) { - Assert.Throws(() => KeyboardActions.ReleaseKey("invalid")); - } - - [Test] - public void Should_ThrowArgumentException_ForInvalidHoldedKey_ViaKeyboardActions() - { - Assert.Throws(() => KeyboardActions.SendKeysWithKeyHold(ValueToSend, "invalid")); + RightArgumentTextBox.Click(); + Assert.DoesNotThrow(() => KeyboardActions.SendKeysWithKeyHold(ValueToSend, modifierKey)); } } } From 2403470437bf58efedb0a6cf7a5d8101ccf8ec9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Thu, 19 Sep 2019 16:12:53 +0300 Subject: [PATCH 12/13] try to fix Should_NotThrow_WhenHoldModifierKeys_ViaKeyboardActions test --- .../Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs index 13b69c3..d4ccc7e 100644 --- a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs +++ b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs @@ -55,7 +55,7 @@ public void Should_ReleaseKey_ViaKeyboardActions() } [Test] - public void Should_NotThrow_WhenHoldModifierKeys_ViaKeyboardActions([ValueSource(nameof(modifierKeys))]ModifierKey modifierKey) + public void Should_NotThrow_WhenHoldModifierKeys_ViaKeyboardActions([ValueSource(nameof(modifierKeys))] ModifierKey modifierKey) { RightArgumentTextBox.Click(); Assert.DoesNotThrow(() => KeyboardActions.SendKeysWithKeyHold(ValueToSend, modifierKey)); From 7cd3231151171e49c91906f681dbc79c886689ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Thu, 19 Sep 2019 16:15:06 +0300 Subject: [PATCH 13/13] make ValueSource field protected for inherited tests --- .../Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs index d4ccc7e..e9184ad 100644 --- a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs +++ b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs @@ -15,7 +15,7 @@ public class KeyboardActionsTests : TestWithApplication protected ITextBox RightArgumentTextBox => new CalculatorWindow().RightArgumentTextBox; - private static readonly ModifierKey[] modifierKeys = Enum.GetValues(typeof(ModifierKey)) as ModifierKey[]; + protected static readonly ModifierKey[] modifierKeys = Enum.GetValues(typeof(ModifierKey)) as ModifierKey[]; [Test] public void Should_SendKeys_ViaKeyboardActions()