Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/keyboard and mouse actions #12

Merged
merged 13 commits into from
Sep 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
/// Abstract class for any actions against the whole application.
/// </summary>
public abstract class ApplicationActions
{
private readonly LocalizationLogger localizationLogger;
private readonly Func<WindowsDriver<WindowsElement>> windowsDriverSupplier;


/// <summary>
/// Instantiates Aplication actions.
/// </summary>
/// <param name="localizationLogger">Logger for localized values.</param>
/// <param name="windowsDriverSupplier">Method to get current application session.</param>
protected ApplicationActions(LocalizationLogger localizationLogger, Func<WindowsDriver<WindowsElement>> windowsDriverSupplier)
{
this.localizationLogger = localizationLogger;
this.windowsDriverSupplier = windowsDriverSupplier;
}

/// <summary>
/// Performs submitted action against new <see cref="SeleniumActions"/> object.
/// </summary>
/// <param name="action">Action to be performed.</param>
protected virtual void PerformAction(Func<SeleniumActions, SeleniumActions> action)
{
action(new SeleniumActions(windowsDriverSupplier())).Build().Perform();
}

/// <summary>
/// Logs keyboard action in specific format.
/// </summary>
/// <param name="messageKey">Key of the localized message.</param>
/// <param name="args">Arguments for the localized message.</param>
protected virtual void LogAction(string messageKey, params object[] args)
{
localizationLogger.Info(messageKey, args);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
namespace Aquality.WinAppDriver.Actions
{
/// <summary>
/// Provides methods representing basic keyboard actions.
/// </summary>
public interface IKeyboardActions
{
/// <summary>
/// Presses a key.
/// </summary>
/// <param name="keyToPress">The <see cref="ModifierKey"/> value representing the key to press.</param>
void PressKey(ModifierKey keyToPress);

/// <summary>
/// Releases a key.
/// </summary>
/// <param name="keyToRelease">The <see cref="ModifierKey"/> value representing the key to release.</param>
void ReleaseKey(ModifierKey keyToRelease);

/// <summary>
/// Sends a sequence of keystrokes to the target.
/// </summary>
/// <param name="keySequence">A string representing the keystrokes to send.</param>
void SendKeys(string keySequence);

/// <summary>
/// Sends a sequence of keystrokes to the application, holding a specified key.
/// After the action, holded key is released.
/// </summary>
/// <param name="keySequence">A string representing the keystrokes to send.</param>
/// <param name="keyToHold">The <see cref="ModifierKey"/> value representing the key to hold.</param>
void SendKeysWithKeyHold(string keySequence, ModifierKey keyToHold);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
namespace Aquality.WinAppDriver.Actions
{
/// <summary>
/// Provides methods representing basic mouse actions.
/// </summary>
public interface IMouseActions
{
/// <summary>
/// Clicks the mouse at the last known mouse coordinates.
/// </summary>
void Click();

/// <summary>
/// Clicks and holds the mouse button at the last known mouse coordinates.
/// </summary>
void ClickAndHold();

/// <summary>
/// Releases the mouse button at the last known mouse coordinates.
/// </summary>
void Release();

/// <summary>
/// Right-clicks the mouse at the last known mouse coordinates.
/// </summary>
void ContextClick();

/// <summary>
/// Double-clicks the mouse at the last known mouse coordinates.
/// </summary>
void DoubleClick();

/// <summary>
/// Moves the mouse to the specified offset of the last known mouse coordinates.
/// </summary>
/// <param name="offsetX">The horizontal offset to which to move the mouse.</param>
/// <param name="offsetY">The vertical offset to which to move the mouse.</param>
void MoveByOffset(int offsetX, int offsetY);

/// <summary>
/// Scrolls the current screen by specified offset.
/// </summary>
/// <param name="offsetX">The horizontal offset relative to the view port.</param>
/// <param name="offsetY">The vertical offset relative to the view port.</param>
void Scroll(int offsetX, int offsetY);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using Aquality.Selenium.Core.Localization;
using OpenQA.Selenium.Appium.Windows;
using System;

namespace Aquality.WinAppDriver.Actions
{
/// <summary>
/// Implements Keyboard actions for the whole application.
/// </summary>
public class KeyboardActions : ApplicationActions, IKeyboardActions
{
public KeyboardActions(LocalizationLogger localizationLogger, Func<WindowsDriver<WindowsElement>> windowsDriverSupplier)
: base(localizationLogger, windowsDriverSupplier)
{
}

public void PressKey(ModifierKey keyToPress)
{
LogAction("loc.keyboard.presskey", keyToPress);
PerformAction(actions => actions.KeyDown(keyToPress.GetKeysString()));
}

public void ReleaseKey(ModifierKey keyToRelease)
{
LogAction("loc.keyboard.releasekey", keyToRelease);
PerformAction(actions => actions.KeyUp(keyToRelease.GetKeysString()));
}

public void SendKeys(string keySequence)
{
LogAction("loc.keyboard.sendkeys", keySequence);
PerformAction(actions => actions.SendKeys(keySequence));
}

public void SendKeysWithKeyHold(string keySequence, ModifierKey keyToHold)
{
var keyToHoldString = keyToHold.GetKeysString();
LogAction("loc.keyboard.sendkeys.withkeyhold", keySequence, keyToHold);
PerformAction(actions => actions.KeyDown(keyToHoldString).SendKeys(keySequence).KeyUp(keyToHoldString));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using OpenQA.Selenium;
using System.Linq;
using System.Reflection;

namespace Aquality.WinAppDriver.Actions
{
/// <summary>
/// Represents modifier keys which could be used in <see cref="IKeyboardActions"/>.
/// Directly related to <see cref="Keys"/>
/// </summary>
public enum ModifierKey
{
/// <summary>
/// Represents the Alt key.
/// </summary>
Alt,
/// <summary>
/// Represents the function key COMMAND.
/// </summary>
Command,
/// <summary>
/// Represents the Control key.
/// </summary>
Control,
/// <summary>
/// Represents the Left Alt key.
/// </summary>
LeftAlt,
/// <summary>
/// Represents the Left Control key.
/// </summary>
LeftControl,
/// <summary>
/// Represents the Left Shift key.
/// </summary>
LeftShift,
/// <summary>
/// Represents the function key META.
/// </summary>
Meta,
/// <summary>
/// Represents the Shift key.
/// </summary>
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();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using Aquality.Selenium.Core.Localization;
using OpenQA.Selenium.Appium.Windows;
using OpenQA.Selenium.Remote;
using System;

namespace Aquality.WinAppDriver.Actions
{
/// <summary>
/// Implements Mouse actions for the whole application.
/// </summary>
public class MouseActions : ApplicationActions, IMouseActions
{
private readonly Func<RemoteTouchScreen> remoteTouchScreenSupplier;

public MouseActions(LocalizationLogger localizationLogger, Func<WindowsDriver<WindowsElement>> windowsDriverSupplier)
: base(localizationLogger, windowsDriverSupplier)
{
remoteTouchScreenSupplier = () => new RemoteTouchScreen(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", 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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using Aquality.Selenium.Core.Applications;
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;

Expand All @@ -13,19 +15,21 @@ namespace Aquality.WinAppDriver.Applications
public class Application : IApplication
{
private TimeSpan implicitWait;

/// <summary>
/// Instantiate application.
/// </summary>
/// <param name="windowsDriver">Instance of WinAppDriver</param>
/// <param name="timeoutConfiguration">Instance of <see cref="ITimeoutConfiguration"/></param>
/// <param name="logger">Instance of <see cref="LocalizationLogger"/></param>
public Application(WindowsDriver<WindowsElement> windowsDriver, ITimeoutConfiguration timeoutConfiguration, LocalizationLogger logger)
/// <param name="serviceProvider">Service provider to resolve all dependencies from DI container</param>
public Application(WindowsDriver<WindowsElement> windowsDriver, IServiceProvider serviceProvider)
{
Logger = logger;
WindowsDriver = windowsDriver;
Logger = serviceProvider.GetRequiredService<LocalizationLogger>();
KeyboardActions = serviceProvider.GetRequiredService<IKeyboardActions>();
MouseActions = serviceProvider.GetRequiredService<IMouseActions>();
var timeoutConfiguration = serviceProvider.GetRequiredService<ITimeoutConfiguration>();
WindowsDriver.Manage().Timeouts().ImplicitWait = timeoutConfiguration.Implicit;
logger.Info("loc.application.ready");
Logger.Info("loc.application.ready");
}

private LocalizationLogger Logger { get; }
Expand All @@ -37,6 +41,10 @@ public Application(WindowsDriver<WindowsElement> windowsDriver, ITimeoutConfigur
/// </summary>
public WindowsDriver<WindowsElement> WindowsDriver { get; }

public IKeyboardActions KeyboardActions { get; }

public IMouseActions MouseActions { get; }

/// <summary>
/// Sets WinAppDriver ImplicitWait timeout.
/// Default value: <see cref="ITimeoutConfiguration.Implicit"/>.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,36 @@
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;

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<LocalizationLogger>();
driverSettings = serviceProvider.GetRequiredService<IDriverSettings>();
timeoutConfiguration = serviceProvider.GetRequiredService<ITimeoutConfiguration>();
ServiceProvider = serviceProvider;
}

public abstract Application Application { get; }

protected WindowsDriver<WindowsElement> GetDriver(Uri driverServerUri, AppiumOptions options, TimeSpan commandTimeout)
protected WindowsDriver<WindowsElement> GetDriver(Uri driverServerUri)
{
var options = driverSettings.AppiumOptions;
options.ToDictionary().TryGetValue("app", out var appPath);
localizationLogger.Info("loc.application.start", appPath);
return new WindowsDriver<WindowsElement>(driverServerUri, options, commandTimeout);
LocalizationLogger.Info("loc.application.start", appPath);
return new WindowsDriver<WindowsElement>(driverServerUri, options, timeoutConfiguration.Command);
}
}
}
Loading