From d6bf0c1b71236497ee3ecc78801ced1cd7184d5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Fri, 10 Jan 2020 13:14:00 +0300 Subject: [PATCH] Feature/36 separate window and form (#39) +semver: feature * Renamed namespaces and folders from "Windows" to "Forms" * Separate Form and Window classes * Extract interface from Form, add and update the tests * extract locators from the forms to reduce the code duplication * Update core lib, fix application session getting * Replace Application implementation references with interface, extend the IWindowsApplication interface * fix WindowsElementFinder to ensure that ElementStateProvider works as expected. Fix application tests * Update Aquality.Selenium.Core to the latest version and support changes * Add chrome test to check multiple windows * Update the test to pass on the Azure DevOps environment * add test to FindChildElement from the root-session element. corrected ElementFactory in the Element * Rework session supplier setting logic in elements and forms * update Aquality.Selenium.Core library and removed temporary fix at WindowsElementFinder +semver: feature --- .../Applications/Application.cs | 42 ++-- .../Applications/ApplicationFactory.cs | 4 +- .../Applications/ApplicationStartup.cs | 1 + .../Applications/AqualityServices.cs | 6 +- .../Applications/IApplicationFactory.cs | 2 +- .../Applications/IWindowsApplication.cs | 29 ++- .../Applications/LocalApplicationFactory.cs | 2 +- .../Applications/RemoteApplicationFactory.cs | 2 +- .../WindowHandleApplicationFactory.cs | 2 +- .../Aquality.WinAppDriver.csproj | 2 +- .../Aquality.WinAppDriver.xml | 182 ++++++++++++------ .../Aquality.WinAppDriver/Elements/Button.cs | 10 +- .../Aquality.WinAppDriver/Elements/Element.cs | 27 ++- .../Elements/ElementFactory.cs | 70 +++++-- .../Elements/Interfaces/IElement.cs | 7 + .../Elements/Interfaces/IElementFactory.cs | 13 -- .../Aquality.WinAppDriver/Elements/Label.cs | 10 +- .../Aquality.WinAppDriver/Elements/TextBox.cs | 10 +- .../Elements/WindowsElementFinder.cs | 55 ++++++ .../Extensions/WindowExtensions.cs | 12 ++ .../src/Aquality.WinAppDriver/Forms/Form.cs | 90 +++++++++ .../src/Aquality.WinAppDriver/Forms/IForm.cs | 23 +++ .../src/Aquality.WinAppDriver/Forms/Window.cs | 29 +++ .../Resources/Localization/be.json | 1 + .../Resources/Localization/en.json | 1 + .../Resources/Localization/ru.json | 1 + .../Aquality.WinAppDriver/Windows/Window.cs | 59 ------ .../Actions/KeyboardActionsTests.cs | 4 +- .../Actions/MouseActionsTests.cs | 4 +- .../Applications/AqualityServicesTests.cs | 36 ++-- .../WindowHandleApplicationFactoryTests.cs | 47 +---- .../Aquality.WinAppDriver.Tests.csproj | 5 +- .../Elements/Actions/MouseActionsTests.cs | 4 +- .../Elements/ElementFactoryTests.cs | 16 +- .../Elements/ElementStateProviderTests.cs | 8 +- .../Elements/ElementTests.cs | 6 +- .../Elements/TextBoxTests.cs | 4 +- .../Forms/AbstractFormTests.cs | 90 +++++++++ .../Forms/CalculatorForm.cs | 34 ++++ .../CalculatorFormWithRelativeElements.cs} | 14 +- .../Forms/CalculatorLocators.cs | 30 +++ .../Forms/CalculatorWindow.cs | 32 +++ .../Forms/Chrome/ChromeNavigationPanel.cs | 23 +++ .../Forms/Chrome/ChromeWindow.cs | 28 +++ .../Forms/Chrome/CoreChromeWindow.cs | 15 ++ .../Forms/Chrome/MultipleWindowsTest.cs | 47 +++++ .../Forms/FormTests.cs | 12 ++ .../Forms/ICalculatorForm.cs | 26 +++ .../Forms/ITestForm.cs | 9 + .../Forms/TestForm.cs | 14 ++ .../{Windows => Forms}/TestWindow.cs | 6 +- .../Forms/WindowTests.cs | 42 ++++ .../TestWithApplication.cs | 2 +- .../TestWithCustomApplication.cs | 22 +++ .../Windows/CalculatorWindow.cs | 36 ---- .../Windows/WindowTests.cs | 82 -------- 56 files changed, 1001 insertions(+), 389 deletions(-) create mode 100644 Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/WindowsElementFinder.cs create mode 100644 Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/WindowExtensions.cs create mode 100644 Aquality.WinAppDriver/src/Aquality.WinAppDriver/Forms/Form.cs create mode 100644 Aquality.WinAppDriver/src/Aquality.WinAppDriver/Forms/IForm.cs create mode 100644 Aquality.WinAppDriver/src/Aquality.WinAppDriver/Forms/Window.cs delete mode 100644 Aquality.WinAppDriver/src/Aquality.WinAppDriver/Windows/Window.cs create mode 100644 Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Forms/AbstractFormTests.cs create mode 100644 Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Forms/CalculatorForm.cs rename Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/{Windows/CalculatorWindowWithRelativeElements.cs => Forms/CalculatorFormWithRelativeElements.cs} (51%) create mode 100644 Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Forms/CalculatorLocators.cs create mode 100644 Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Forms/CalculatorWindow.cs create mode 100644 Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Forms/Chrome/ChromeNavigationPanel.cs create mode 100644 Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Forms/Chrome/ChromeWindow.cs create mode 100644 Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Forms/Chrome/CoreChromeWindow.cs create mode 100644 Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Forms/Chrome/MultipleWindowsTest.cs create mode 100644 Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Forms/FormTests.cs create mode 100644 Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Forms/ICalculatorForm.cs create mode 100644 Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Forms/ITestForm.cs create mode 100644 Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Forms/TestForm.cs rename Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/{Windows => Forms}/TestWindow.cs (59%) create mode 100644 Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Forms/WindowTests.cs create mode 100644 Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/TestWithCustomApplication.cs delete mode 100644 Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Windows/CalculatorWindow.cs delete mode 100644 Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Windows/WindowTests.cs diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs index 4330263..0cb7586 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/Application.cs @@ -3,8 +3,8 @@ using Aquality.Selenium.Core.Configurations; using Aquality.Selenium.Core.Localization; using Aquality.WinAppDriver.Actions; -using OpenQA.Selenium.Appium.Windows; using OpenQA.Selenium.Remote; +using WindowsDriver = OpenQA.Selenium.Appium.Windows.WindowsDriver; namespace Aquality.WinAppDriver.Applications { @@ -14,17 +14,17 @@ namespace Aquality.WinAppDriver.Applications public class Application : IWindowsApplication { private TimeSpan implicitWait; - private WindowsDriver applicationSession; - private WindowsDriver rootSession; - private readonly Func> createApplicationSession; - private readonly Func> createDesktopSession; + private WindowsDriver applicationSession; + private WindowsDriver rootSession; + private readonly Func createApplicationSession; + private readonly Func createDesktopSession; /// /// Instantiate application. /// /// Function to create an instance of WinAppDriver for current application /// Function to create an instance of WinAppDriver for desktop session - public Application(Func> createApplicationSession, Func> createRootSession) + public Application(Func createApplicationSession, Func createRootSession) { this.createApplicationSession = createApplicationSession; this.createDesktopSession = createRootSession; @@ -39,11 +39,11 @@ public Application(Func> createApplicationSession, RemoteWebDriver IApplication.Driver => Driver; - public WindowsDriver Driver + public virtual WindowsDriver Driver { get { - if (applicationSession == null) + if (!IsSessionStarted(applicationSession)) { applicationSession = createApplicationSession(); Logger.Info("loc.application.ready"); @@ -53,15 +53,15 @@ public WindowsDriver Driver } } - public IKeyboardActions KeyboardActions { get; } + public virtual IKeyboardActions KeyboardActions { get; } - public IMouseActions MouseActions { get; } + public virtual IMouseActions MouseActions { get; } - public WindowsDriver RootSession + public virtual WindowsDriver RootSession { get { - if (rootSession == null) + if (!IsSessionStarted(rootSession)) { rootSession = createDesktopSession(); rootSession.Manage().Timeouts().ImplicitWait = implicitWait; @@ -70,12 +70,16 @@ public WindowsDriver RootSession } } + public virtual bool IsStarted => IsSessionStarted(applicationSession) || IsSessionStarted(rootSession); + + private bool IsSessionStarted(WindowsDriver session) => session?.SessionId != null; + /// /// Sets WinAppDriver ImplicitWait timeout. /// Default value: . /// /// Desired Implicit wait timeout. - public void SetImplicitWaitTimeout(TimeSpan timeout) + public virtual void SetImplicitWaitTimeout(TimeSpan timeout) { if (timeout != implicitWait) { @@ -94,10 +98,18 @@ public void SetImplicitWaitTimeout(TimeSpan timeout) /// /// Quit application. /// - public void Quit() + public virtual void Quit() { Logger.Info("loc.application.quit"); - Driver?.Quit(); + applicationSession?.Quit(); + rootSession?.Quit(); + } + + public virtual IWindowsApplication Launch() + { + var launchedAppTitle = Driver.Title; + AqualityServices.Logger.Debug(launchedAppTitle); + return this; } } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationFactory.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationFactory.cs index 5ef47ea..f0615e7 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationFactory.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationFactory.cs @@ -21,9 +21,9 @@ protected ApplicationFactory() timeoutConfiguration = AqualityServices.Get(); } - public abstract Application Application { get; } + public abstract IWindowsApplication Application { get; } - protected virtual Application GetApplication(Uri driverServerUri) + protected virtual IWindowsApplication GetApplication(Uri driverServerUri) { return new Application(() => GetApplicationSession(driverServerUri), () => GetRootSession(driverServerUri)); } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationStartup.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationStartup.cs index 2a26426..4c85cbd 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationStartup.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/ApplicationStartup.cs @@ -34,6 +34,7 @@ public override IServiceCollection ConfigureServices(IServiceCollection services services.AddTransient(serviceProvider => AqualityServices.ApplicationFactory); services.AddTransient(); services.AddTransient(); + services.AddScoped(serviceProvider => applicationProvider(serviceProvider) as IWindowsApplication); return services; } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/AqualityServices.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/AqualityServices.cs index d5b43ae..52c3236 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/AqualityServices.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/AqualityServices.cs @@ -16,7 +16,7 @@ namespace Aquality.WinAppDriver.Applications /// /// Controls application and Aquality services /// - public class AqualityServices : AqualityServices + public class AqualityServices : AqualityServices { private static readonly ThreadLocal ApplicationStartupContainer = new ThreadLocal(() => new ApplicationStartup()); private static readonly ThreadLocal ApplicationFactoryContainer = new ThreadLocal(); @@ -82,7 +82,7 @@ public static bool TryToStopAppiumLocalService() /// /// Provides current instance of application /// - public static Application Application + public static IWindowsApplication Application { get => GetApplication(StartApplicationFunction, ConfigureServices); set => SetApplication(value); @@ -161,7 +161,7 @@ public static void SetWindowHandleApplicationFactory(Func GetServiceProvider(services => Application, ConfigureServices); - private static Func StartApplicationFunction + private static Func StartApplicationFunction { get { diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/IApplicationFactory.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/IApplicationFactory.cs index e1af788..d7732ff 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/IApplicationFactory.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/IApplicationFactory.cs @@ -2,6 +2,6 @@ { public interface IApplicationFactory { - Application Application { get; } + IWindowsApplication Application { get; } } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/IWindowsApplication.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/IWindowsApplication.cs index 5beab78..f52f8c1 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/IWindowsApplication.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/IWindowsApplication.cs @@ -1,18 +1,43 @@ using Aquality.Selenium.Core.Applications; +using Aquality.WinAppDriver.Actions; using OpenQA.Selenium.Appium.Windows; namespace Aquality.WinAppDriver.Applications { + /// + /// Provides functionality to work with Windows application via WinAppDriver. + /// public interface IWindowsApplication : IApplication { /// - /// Provides instance of Windows Driver for current application + /// Provides instance of Windows Driver for current application. /// new WindowsDriver Driver { get; } /// - /// Provides instance of Windows Driver for desktop session + /// Provides instance of Windows Driver for desktop session. /// WindowsDriver RootSession { get; } + + /// + /// Provides methods representing basic keyboard actions. + /// + IKeyboardActions KeyboardActions { get; } + + /// + /// Provides methods representing basic mouse actions. + /// + IMouseActions MouseActions { get; } + + /// + /// Launches an instance of the current application. + /// + /// Current application instance. + IWindowsApplication Launch(); + + /// + /// Closes current application and desktop sessions. + /// + void Quit(); } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/LocalApplicationFactory.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/LocalApplicationFactory.cs index 8ead442..6e9695b 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/LocalApplicationFactory.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/LocalApplicationFactory.cs @@ -11,7 +11,7 @@ public LocalApplicationFactory(AppiumLocalService driverService) : base() this.driverService = driverService; } - public override Application Application + public override IWindowsApplication Application { get { diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/RemoteApplicationFactory.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/RemoteApplicationFactory.cs index cdfb64e..56dbd26 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/RemoteApplicationFactory.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/RemoteApplicationFactory.cs @@ -14,7 +14,7 @@ public RemoteApplicationFactory(Uri driverServerUri) : base() this.driverServerUri = driverServerUri; } - public override Application Application + public override IWindowsApplication Application { get { diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/WindowHandleApplicationFactory.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/WindowHandleApplicationFactory.cs index c0164e6..3b778d5 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/WindowHandleApplicationFactory.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Applications/WindowHandleApplicationFactory.cs @@ -22,7 +22,7 @@ public WindowHandleApplicationFactory(Uri driverServerUri, Func().IsRemote; } - public override Application Application + public override IWindowsApplication Application { get { diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.csproj b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.csproj index 54c9888..33cfaf3 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.csproj +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.csproj @@ -46,7 +46,7 @@ - + diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.xml b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.xml index 39bf629..3be2fad 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.xml +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Aquality.WinAppDriver.xml @@ -614,14 +614,40 @@ Function to get window handle via RootSession of Application + + + Provides functionality to work with Windows application via WinAppDriver. + + - Provides instance of Windows Driver for current application + Provides instance of Windows Driver for current application. - Provides instance of Windows Driver for desktop session + Provides instance of Windows Driver for desktop session. + + + + + Provides methods representing basic keyboard actions. + + + + + Provides methods representing basic mouse actions. + + + + + Launches an instance of the current application. + + Current application instance. + + + + Closes current application and desktop sessions. @@ -819,6 +845,15 @@ Factory that creates elements. + + + Resolves element supplier or return itself if it is not null. + + type of target element. + target element supplier. + Custom search context supplier to perform relative search for element. + non-null element supplier + Describes behavior of Button UI element. @@ -829,6 +864,11 @@ Descibes behavior of any application element. + + + Provides access to WinAppDriver session used for the search and interaction with the current element. + + Provides access to against the current element. @@ -871,18 +911,6 @@ Element existance state Instance of element that implements ITextBox interface - - - Finds element relative to parent window. - - Type of the target element. - Parent window for the element. - Locator of the element relative to parent window. - Name of the element. - Delegate that defines constructor of element in case of custom element. - Element existance state - Instance of element. - Describes behavior of Label UI element. @@ -937,6 +965,91 @@ + + + Defines base class for any form on any application's window. + + + + + Constructor with parameters. + + Unique locator of the window. + Name of the window. + Parent form. If set to null, search context of is used. + Custom WinAppDriver session supplier. + Element presence state. + + + + Return window state for form locator + + True - form is opened, + False - form is not opened. + + + + Element factory + + Element factory. + + + + Windows Application . + + + + + Element factory to search from the context of the current form. + + Relative element factory. + + + + Finds element relative to current form. + + Type of the target element. + Locator of the element relative to current form. + Name of the element. + Delegate that defines constructor of element in case of custom element. + Element existance state + Instance of element. + + + + Gets size of the form element defined by its locator. + + + + + Defines an interface for any form on any application's window. + + + + + Return window state for form locator + + True - form is opened, + False - form is not opened. + + + + Gets size of the form element defined by its locator. + + + + + Defines base class for a separate window of any application. + + + + + Constructor with parameters. + + Unique locator of the window. + Name of the window. + Custom WinAppDriver session supplier. + Provides ability to detect running processes and to stop them. @@ -1002,46 +1115,5 @@ Implementation of - - - Defines base class for any application's window. - - - - - Constructor with parameters. - - Unique locator of the window. - Name of the window. - - - - Element factory - - Element factory. - - - - Finds element relative to current window. - - Type of the target element. - Locator of the element relative to current window. - Name of the element. - Delegate that defines constructor of element in case of custom element. - Element existance state - Instance of element. - - - - 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/Elements/Button.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Button.cs index 64a2d2d..5a9fd44 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Button.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Button.cs @@ -1,5 +1,7 @@ using Aquality.WinAppDriver.Elements.Interfaces; using OpenQA.Selenium; +using OpenQA.Selenium.Appium.Windows; +using System; using ElementState = Aquality.Selenium.Core.Elements.ElementState; namespace Aquality.WinAppDriver.Elements @@ -9,7 +11,13 @@ namespace Aquality.WinAppDriver.Elements /// public class Button : Element, IButton { - protected internal Button(By locator, string name, ElementState elementState = ElementState.Displayed) : base(locator, name, elementState) + protected internal Button( + By locator, + string name, + Func searchContextSupplier = null, + Func> customSessionSupplier = null, + ElementState elementState = ElementState.ExistsInAnyState) + : base(locator, name, searchContextSupplier, customSessionSupplier, elementState) { } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Element.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Element.cs index 64c724a..d3bb3d2 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Element.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Element.cs @@ -12,35 +12,46 @@ using CoreElementFactory = Aquality.Selenium.Core.Elements.Interfaces.IElementFactory; using CoreElementFinder = Aquality.Selenium.Core.Elements.Interfaces.IElementFinder; using OpenQA.Selenium.Appium.Windows; +using System; namespace Aquality.WinAppDriver.Elements { public abstract class Element : CoreElement, IElement { - protected Element(By locator, string name, ElementState elementState = ElementState.Displayed) : base(locator, name, elementState) + private readonly Func searchContextSupplier; + + protected Element( + By locator, + string name, + Func searchContextSupplier = null, + Func> customSessionSupplier = null, + ElementState elementState = ElementState.ExistsInAnyState) + : base(locator, name, elementState) { + this.searchContextSupplier = searchContextSupplier; + WindowsDriverSupplier = customSessionSupplier ?? (() => AqualityServices.Application.Driver); } protected override ElementActionRetrier ActionRetrier => AqualityServices.Get(); protected override IApplication Application => AqualityServices.Application; - protected virtual WindowsDriver WindowsDriver => AqualityServices.Application.Driver; - protected override ConditionalWait ConditionalWait => AqualityServices.ConditionalWait; protected override CoreElementFactory Factory => CustomFactory; - protected virtual IElementFactory CustomFactory => AqualityServices.Get(); + protected virtual IElementFactory CustomFactory => new ElementFactory(ConditionalWait, Finder, LocalizationManager, driverSessionSupplier: WindowsDriverSupplier); + + public virtual Func> WindowsDriverSupplier { get; } - public virtual IKeyboardActions KeyboardActions => new KeyboardActions(this, ElementType, () => WindowsDriver, LocalizedLogger, ActionRetrier); + public virtual IKeyboardActions KeyboardActions => new KeyboardActions(this, ElementType, WindowsDriverSupplier, LocalizedLogger, ActionRetrier); - public virtual IMouseActions MouseActions => new MouseActions(this, ElementType, () => WindowsDriver, LocalizedLogger, ActionRetrier); + public virtual IMouseActions MouseActions => new MouseActions(this, ElementType, WindowsDriverSupplier, LocalizedLogger, ActionRetrier); - protected override CoreElementFinder Finder => AqualityServices.Get(); + protected override CoreElementFinder Finder => new WindowsElementFinder(LocalizedLogger, ConditionalWait, searchContextSupplier ?? WindowsDriverSupplier); protected override ILocalizedLogger LocalizedLogger => AqualityServices.LocalizedLogger; - protected ILocalizationManager LocalizationManager => AqualityServices.Get(); + protected virtual ILocalizationManager LocalizationManager => AqualityServices.Get(); } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/ElementFactory.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/ElementFactory.cs index 8f6299d..3a40356 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/ElementFactory.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/ElementFactory.cs @@ -5,13 +5,12 @@ using Aquality.Selenium.Core.Localization; using Aquality.Selenium.Core.Waitings; using Aquality.WinAppDriver.Elements.Interfaces; -using Aquality.WinAppDriver.Extensions; -using Aquality.WinAppDriver.Windows; using OpenQA.Selenium; -using OpenQA.Selenium.Support.PageObjects; using CoreFactory = Aquality.Selenium.Core.Elements.ElementFactory; -using IElement = Aquality.WinAppDriver.Elements.Interfaces.IElement; +using CoreElement = Aquality.Selenium.Core.Elements.Interfaces.IElement; using IElementFactory = Aquality.WinAppDriver.Elements.Interfaces.IElementFactory; +using System.Reflection; +using OpenQA.Selenium.Appium.Windows; namespace Aquality.WinAppDriver.Elements { @@ -20,29 +19,40 @@ namespace Aquality.WinAppDriver.Elements /// public class ElementFactory : CoreFactory, IElementFactory { - public ElementFactory(ConditionalWait conditionalWait, IElementFinder elementFinder, ILocalizationManager localizationManager) : base(conditionalWait, elementFinder, localizationManager) + private readonly Func searchContextSupplier; + private readonly Func> driverSessionSupplier; + + public ElementFactory( + ConditionalWait conditionalWait, + IElementFinder elementFinder, + ILocalizationManager localizationManager, + Func searchContextSupplier = null, + Func> driverSessionSupplier = null) + : base(conditionalWait, elementFinder, localizationManager) { + this.searchContextSupplier = searchContextSupplier; + this.driverSessionSupplier = driverSessionSupplier; } - public IButton GetButton(By locator, string name, ElementState elementState = ElementState.Displayed) + public virtual IButton GetButton(By locator, string name, ElementState elementState = ElementState.Displayed) { return GetCustomElement(ResolveSupplier(null), locator, name, elementState); } - public ILabel GetLabel(By locator, string name, ElementState elementState = ElementState.Displayed) + public virtual ILabel GetLabel(By locator, string name, ElementState elementState = ElementState.Displayed) { return GetCustomElement(ResolveSupplier(null), locator, name, elementState); } - public ITextBox GetTextBox(By locator, string name, ElementState elementState = ElementState.Displayed) + public virtual ITextBox GetTextBox(By locator, string name, ElementState elementState = ElementState.Displayed) { return GetCustomElement(ResolveSupplier(null), locator, name, elementState); } - public T FindChildElement(Window parentWindow, By childLocator, string childName, ElementSupplier supplier = null, ElementState elementState = ElementState.Displayed) where T : IElement + public override T FindChildElement(CoreElement parentElement, By childLocator, string name = null, ElementSupplier supplier = null, ElementState state = ElementState.Displayed) { - var elementSupplier = ResolveSupplier(supplier); - return elementSupplier(new ByChained(parentWindow.Locator, childLocator), $"{childName}' - {parentWindow.GetElementType()} '{parentWindow.Name}", elementState); + var elementSupplier = ResolveSupplier(supplier, () => parentElement.GetElement()); + return elementSupplier(childLocator, name ?? $"Child element of {parentElement.Name}", state); } protected override IDictionary ElementTypesMap @@ -55,7 +65,43 @@ protected override IDictionary ElementTypesMap { typeof(ILabel), typeof(Label) }, { typeof(ITextBox), typeof(TextBox) } }; - } + } + } + + protected override ElementSupplier ResolveSupplier(ElementSupplier supplier) + { + return ResolveSupplier(supplier, searchContextSupplier); + } + + /// + /// Resolves element supplier or return itself if it is not null. + /// + /// type of target element. + /// target element supplier. + /// Custom search context supplier to perform relative search for element. + /// non-null element supplier + protected virtual ElementSupplier ResolveSupplier(ElementSupplier supplier, Func customSearchContextSupplier) + where T : CoreElement + { + if (supplier != null) + { + return supplier; + } + else + { + var type = typeof(T); + var elementType = type.IsInterface ? ElementTypesMap[type] : type; + var elementCntr = elementType.GetConstructor( + BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.CreateInstance | BindingFlags.Instance, + null, + new[] { typeof(By), typeof(string), typeof(Func), typeof(Func>), typeof(ElementState) }, + null); + if (elementCntr == null) + { + return base.ResolveSupplier(supplier); + } + return (locator, name, state) => (T)elementCntr.Invoke(new object[] { locator, name, customSearchContextSupplier, driverSessionSupplier, state }); + } } } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Interfaces/IElement.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Interfaces/IElement.cs index 9416781..723fedf 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Interfaces/IElement.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Interfaces/IElement.cs @@ -1,4 +1,6 @@ using Aquality.WinAppDriver.Elements.Actions; +using OpenQA.Selenium.Appium.Windows; +using System; using CoreElement = Aquality.Selenium.Core.Elements.Interfaces.IElement; using IKeyboardActions = Aquality.WinAppDriver.Actions.IKeyboardActions; @@ -9,6 +11,11 @@ namespace Aquality.WinAppDriver.Elements.Interfaces /// public interface IElement : CoreElement { + /// + /// Provides access to WinAppDriver session used for the search and interaction with the current element. + /// + Func> WindowsDriverSupplier { get; } + /// /// Provides access to against the current element. /// diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Interfaces/IElementFactory.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Interfaces/IElementFactory.cs index 9a4266f..998cd53 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Interfaces/IElementFactory.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Interfaces/IElementFactory.cs @@ -1,5 +1,4 @@ using Aquality.Selenium.Core.Elements; -using Aquality.WinAppDriver.Windows; using OpenQA.Selenium; using CoreElementFactory = Aquality.Selenium.Core.Elements.Interfaces.IElementFactory; @@ -36,17 +35,5 @@ public interface IElementFactory : CoreElementFactory /// Element existance state /// Instance of element that implements ITextBox interface ITextBox GetTextBox(By locator, string name, ElementState elementState = ElementState.Displayed); - - /// - /// Finds element relative to parent window. - /// - /// Type of the target element. - /// Parent window for the element. - /// Locator of the element relative to parent window. - /// Name of the element. - /// Delegate that defines constructor of element in case of custom element. - /// Element existance state - /// Instance of element. - T FindChildElement(Window parentWindow, By childLocator, string childName, ElementSupplier supplier = null, ElementState elementState = ElementState.Displayed) where T : IElement; } } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Label.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Label.cs index dfd0b3f..4038e10 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Label.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/Label.cs @@ -1,5 +1,7 @@ using Aquality.WinAppDriver.Elements.Interfaces; using OpenQA.Selenium; +using OpenQA.Selenium.Appium.Windows; +using System; using ElementState = Aquality.Selenium.Core.Elements.ElementState; namespace Aquality.WinAppDriver.Elements @@ -9,7 +11,13 @@ namespace Aquality.WinAppDriver.Elements /// public class Label : Element, ILabel { - protected internal Label(By locator, string name, ElementState elementState = ElementState.Displayed) : base(locator, name, elementState) + protected internal Label( + By locator, + string name, + Func searchContextSupplier = null, + Func> customSessionSupplier = null, + ElementState elementState = ElementState.ExistsInAnyState) + : base(locator, name, searchContextSupplier, customSessionSupplier, elementState) { } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/TextBox.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/TextBox.cs index 8bd802b..1b6a9f2 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/TextBox.cs +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/TextBox.cs @@ -1,5 +1,7 @@ using Aquality.WinAppDriver.Elements.Interfaces; using OpenQA.Selenium; +using OpenQA.Selenium.Appium.Windows; +using System; using ElementState = Aquality.Selenium.Core.Elements.ElementState; namespace Aquality.WinAppDriver.Elements @@ -11,7 +13,13 @@ public class TextBox : Element, ITextBox { private const string SecretMask = "*********"; - protected internal TextBox(By locator, string name, ElementState elementState = ElementState.Displayed) : base(locator, name, elementState) + protected internal TextBox( + By locator, + string name, + Func searchContextSupplier = null, + Func> customSessionSupplier = null, + ElementState elementState = ElementState.ExistsInAnyState) + : base(locator, name, searchContextSupplier, customSessionSupplier, elementState) { } diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/WindowsElementFinder.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/WindowsElementFinder.cs new file mode 100644 index 0000000..c6c94dc --- /dev/null +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Elements/WindowsElementFinder.cs @@ -0,0 +1,55 @@ +using System; +using Aquality.Selenium.Core.Elements; +using Aquality.Selenium.Core.Localization; +using Aquality.Selenium.Core.Waitings; +using OpenQA.Selenium; + +namespace Aquality.WinAppDriver.Elements +{ + public class WindowsElementFinder : RelativeElementFinder + { + public WindowsElementFinder(ILocalizedLogger logger, ConditionalWait conditionalWait, Func searchContextSupplier) + : base(logger, conditionalWait, searchContextSupplier) + { + Logger = logger; + ConditionalWait = conditionalWait; + SearchContextSupplier = searchContextSupplier; + } + + private ILocalizedLogger Logger { get; } + + private ConditionalWait ConditionalWait { get; } + + private Func SearchContextSupplier { get; } + + public override IWebElement FindElement(By locator, Func elementStateCondition, string stateName, TimeSpan? timeout = null) + { + IWebElement element = null; + if (!ConditionalWait.WaitFor(() => + { + try + { + element = SearchContextSupplier().FindElement(locator); + return elementStateCondition(element); + } + catch (WebDriverException) + { + return false; + } + }, timeout)) + { + if (element != null) + { + Logger.Debug("loc.elements.were.found.but.not.in.state", null, locator.ToString(), stateName); + } + else + { + Logger.Debug("loc.no.elements.found.by.locator", null, locator.ToString()); + } + throw new NoSuchElementException($"No elements with locator '{locator.ToString()}' were found in {stateName} state"); + } + + return element; + } + } +} diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/WindowExtensions.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/WindowExtensions.cs new file mode 100644 index 0000000..d1886ad --- /dev/null +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Extensions/WindowExtensions.cs @@ -0,0 +1,12 @@ +using Aquality.WinAppDriver.Forms; + +namespace Aquality.WinAppDriver.Extensions +{ + public static class WindowExtensions + { + public static string GetNativeWindowHandle(this Window window) + { + return int.Parse(window.GetElement().GetAttribute("NativeWindowHandle")).ToString("x"); + } + } +} diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Forms/Form.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Forms/Form.cs new file mode 100644 index 0000000..8feb892 --- /dev/null +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Forms/Form.cs @@ -0,0 +1,90 @@ +using Aquality.Selenium.Core.Elements; +using Aquality.WinAppDriver.Applications; +using Aquality.WinAppDriver.Elements; +using Aquality.WinAppDriver.Elements.Interfaces; +using OpenQA.Selenium; +using System; +using System.Drawing; +using Element = Aquality.WinAppDriver.Elements.Element; +using IElement = Aquality.Selenium.Core.Elements.Interfaces.IElement; +using ElementFactory = Aquality.WinAppDriver.Elements.ElementFactory; +using OpenQA.Selenium.Appium.Windows; + +namespace Aquality.WinAppDriver.Forms +{ + /// + /// Defines base class for any form on any application's window. + /// + public abstract class Form : Element, IForm + { + /// + /// Constructor with parameters. + /// + /// Unique locator of the window. + /// Name of the window. + /// Parent form. If set to null, search context of is used. + /// Custom WinAppDriver session supplier. + /// Element presence state. + protected Form(By locator, string name, IForm parentForm = null, Func> customSessionSupplier = null, ElementState elementState = ElementState.Displayed) + : base(locator, name, ResolveSearchContextSupplier(parentForm), customSessionSupplier ?? parentForm?.WindowsDriverSupplier, elementState) + { + var relativeFinderFromForm = new WindowsElementFinder(LocalizedLogger, ConditionalWait, () => GetElement()); + RelativeElementFactory = new ElementFactory(ConditionalWait, relativeFinderFromForm, LocalizationManager); + } + + private static Func ResolveSearchContextSupplier(IForm parentForm) + { + return parentForm == null + ? null + : (Func)(() => parentForm.GetElement()); + } + + /// + /// Return window state for form locator + /// + /// True - form is opened, + /// False - form is not opened. + public virtual bool IsDisplayed => State.WaitForDisplayed(); + + /// + /// Element factory + /// + /// Element factory. + protected virtual IElementFactory ElementFactory => AqualityServices.Get(); + + /// + /// Windows Application . + /// + protected virtual new IWindowsApplication Application => AqualityServices.Application; + + /// + /// Element factory to search from the context of the current form. + /// + /// Relative element factory. + protected virtual IElementFactory RelativeElementFactory { get; } + + /// + /// Finds element relative to current form. + /// + /// Type of the target element. + /// Locator of the element relative to current form. + /// Name of the element. + /// Delegate that defines constructor of element in case of custom element. + /// Element existance state + /// Instance of element. + protected virtual new T FindChildElement(By childLocator, string childName, ElementSupplier supplier = null, ElementState elementState = ElementState.Displayed) + where T : IElement + { + return RelativeElementFactory.FindChildElement(this, childLocator, GetChildElementName(childName), supplier, elementState); + } + + protected virtual string GetChildElementName(string pureName) => $"{pureName}' - {ElementType} '{Name}"; + + /// + /// Gets size of the form element defined by its locator. + /// + public virtual Size Size => GetElement().Size; + + protected override string ElementType => LocalizationManager.GetLocalizedMessage("loc.form"); + } +} diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Forms/IForm.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Forms/IForm.cs new file mode 100644 index 0000000..ff825be --- /dev/null +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Forms/IForm.cs @@ -0,0 +1,23 @@ +using System.Drawing; +using Aquality.WinAppDriver.Elements.Interfaces; + +namespace Aquality.WinAppDriver.Forms +{ + /// + /// Defines an interface for any form on any application's window. + /// + public interface IForm : IElement + { + /// + /// Return window state for form locator + /// + /// True - form is opened, + /// False - form is not opened. + bool IsDisplayed { get; } + + /// + /// Gets size of the form element defined by its locator. + /// + Size Size { get; } + } +} \ No newline at end of file diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Forms/Window.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Forms/Window.cs new file mode 100644 index 0000000..eb8f808 --- /dev/null +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Forms/Window.cs @@ -0,0 +1,29 @@ +using Aquality.WinAppDriver.Applications; +using OpenQA.Selenium; +using WindowsDriverSupplier = System.Func>; + +namespace Aquality.WinAppDriver.Forms +{ + /// + /// Defines base class for a separate window of any application. + /// + public abstract class Window : Form + { + /// + /// Constructor with parameters. + /// + /// Unique locator of the window. + /// Name of the window. + /// Custom WinAppDriver session supplier. + protected Window(By locator, string name, WindowsDriverSupplier customSessionSupplier = null) + : base(locator, name, customSessionSupplier: ResolveWindowsSessionSupplier(customSessionSupplier)) + { + } + private static WindowsDriverSupplier ResolveWindowsSessionSupplier(WindowsDriverSupplier customSessionSupplier) + { + return customSessionSupplier ?? (() => AqualityServices.Application.RootSession); + } + + protected override string ElementType => LocalizationManager.GetLocalizedMessage("loc.window"); + } +} diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/be.json b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/be.json index ad0f6c2..24bbcd3 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/be.json +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/be.json @@ -16,6 +16,7 @@ "loc.button": "Кнопка", "loc.label": "Надпіс", "loc.window": "Акно", + "loc.form": "Форма", "loc.text.field": "Тэкставае поле", "loc.text.clearing": "Aчышчаем", "loc.text.typing": "Уводзім значэнне '{0}'", diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/en.json b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/en.json index 147e368..c294de2 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/en.json +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/en.json @@ -16,6 +16,7 @@ "loc.button": "Button", "loc.label": "Label", "loc.window": "Window", + "loc.form": "Form", "loc.text.field": "Text Field", "loc.text.clearing": "Clearing", "loc.text.typing": "Typing '{0}'", diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/ru.json b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/ru.json index b4167bb..03d0827 100644 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/ru.json +++ b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Resources/Localization/ru.json @@ -16,6 +16,7 @@ "loc.button": "Кнопка", "loc.label": "Надпись", "loc.window": "Окно", + "loc.form": "Форма", "loc.text.field": "Текстовое поле", "loc.text.clearing": "Очищаем", "loc.text.typing": "Вводим значение '{0}'", diff --git a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Windows/Window.cs b/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Windows/Window.cs deleted file mode 100644 index 27b2f50..0000000 --- a/Aquality.WinAppDriver/src/Aquality.WinAppDriver/Windows/Window.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Aquality.Selenium.Core.Elements; -using Aquality.WinAppDriver.Applications; -using Aquality.WinAppDriver.Elements.Interfaces; -using OpenQA.Selenium; -using System.Drawing; -using Element = Aquality.WinAppDriver.Elements.Element; -using IElementFactory = Aquality.WinAppDriver.Elements.Interfaces.IElementFactory; - -namespace Aquality.WinAppDriver.Windows -{ - /// - /// Defines base class for any application's window. - /// - public abstract class Window : Element - { - /// - /// Constructor with parameters. - /// - /// Unique locator of the window. - /// Name of the window. - protected Window(By locator, string name) : base(locator, name) - { - } - - /// - /// Element factory - /// - /// Element factory. - protected IElementFactory ElementFactory => AqualityServices.Get(); - - /// - /// Finds element relative to current window. - /// - /// Type of the target element. - /// Locator of the element relative to current window. - /// Name of the element. - /// Delegate that defines constructor of element in case of custom element. - /// Element existance state - /// Instance of element. - public T FindChildElement(By childLocator, string childName, ElementSupplier supplier = null, ElementState elementState = ElementState.Displayed) where T : IElement - { - return ElementFactory.FindChildElement(this, childLocator, childName, supplier, elementState); - } - - /// - /// Return window state for window locator - /// - /// True - window is opened, - /// False - window is not opened. - public bool IsDisplayed => State.WaitForDisplayed(); - - /// - /// Gets size of window element defined by its locator. - /// - public Size Size => GetElement().Size; - - protected override string ElementType => LocalizationManager.GetLocalizedMessage("loc.window"); - } -} diff --git a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs index c78f588..81d17c6 100644 --- a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs +++ b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/KeyboardActionsTests.cs @@ -1,7 +1,7 @@ using Aquality.WinAppDriver.Actions; using Aquality.WinAppDriver.Applications; using Aquality.WinAppDriver.Elements.Interfaces; -using Aquality.WinAppDriver.Tests.Windows; +using Aquality.WinAppDriver.Tests.Forms; using NUnit.Framework; using OpenQA.Selenium; using System; @@ -14,7 +14,7 @@ public class KeyboardActionsTests : TestWithApplication protected virtual IKeyboardActions KeyboardActions => AqualityServices.KeyboardActions; - protected ITextBox RightArgumentTextBox => new CalculatorWindow().RightArgumentTextBox; + protected ITextBox RightArgumentTextBox => new CalculatorForm().RightArgumentTextBox; protected static readonly ModifierKey[] modifierKeys = Enum.GetValues(typeof(ModifierKey)) as ModifierKey[]; diff --git a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/MouseActionsTests.cs b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/MouseActionsTests.cs index 06cda4d..40583e0 100644 --- a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/MouseActionsTests.cs +++ b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Actions/MouseActionsTests.cs @@ -1,7 +1,7 @@ using Aquality.WinAppDriver.Actions; using Aquality.WinAppDriver.Applications; using Aquality.WinAppDriver.Elements.Interfaces; -using Aquality.WinAppDriver.Tests.Windows; +using Aquality.WinAppDriver.Tests.Forms; using NUnit.Framework; namespace Aquality.WinAppDriver.Tests.Actions @@ -10,7 +10,7 @@ public class MouseActionsTests : TestWithApplication { protected virtual IMouseActions MouseActions => AqualityServices.MouseActions; - protected ITextBox RightArgumentTextBox => new CalculatorWindow().RightArgumentTextBox; + protected ITextBox RightArgumentTextBox => new CalculatorForm().RightArgumentTextBox; [Test] public void Should_PerformMouseActions() diff --git a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Applications/AqualityServicesTests.cs b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Applications/AqualityServicesTests.cs index b661478..849b1a6 100644 --- a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Applications/AqualityServicesTests.cs +++ b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Applications/AqualityServicesTests.cs @@ -1,7 +1,7 @@ using Aquality.Selenium.Core.Applications; using Aquality.Selenium.Core.Elements.Interfaces; using Aquality.WinAppDriver.Applications; -using Aquality.WinAppDriver.Tests.Windows; +using Aquality.WinAppDriver.Tests.Forms; using Microsoft.Extensions.DependencyInjection; using NUnit.Framework; using System; @@ -10,27 +10,27 @@ namespace Aquality.WinAppDriver.Tests.Applications { public class AqualityServicesTests : TestWithApplication { - private readonly CalculatorWindow calculatorWindow = new CalculatorWindow(); + private readonly CalculatorForm calculatorForm = new CalculatorForm(); [Test] public void Should_WorkWithCalculator() { - AqualityServices.Application.Driver.FindElement(calculatorWindow.OneButton.Locator).Click(); - AqualityServices.Application.Driver.FindElement(calculatorWindow.PlusButton.Locator).Click(); - AqualityServices.Application.Driver.FindElement(calculatorWindow.TwoButton.Locator).Click(); - AqualityServices.Application.Driver.FindElement(calculatorWindow.EqualsButton.Locator).Click(); - var result = AqualityServices.Application.Driver.FindElement(calculatorWindow.ResultsLabel.Locator).Text; + AqualityServices.Application.Driver.FindElement(calculatorForm.OneButton.Locator).Click(); + AqualityServices.Application.Driver.FindElement(calculatorForm.PlusButton.Locator).Click(); + AqualityServices.Application.Driver.FindElement(calculatorForm.TwoButton.Locator).Click(); + AqualityServices.Application.Driver.FindElement(calculatorForm.EqualsButton.Locator).Click(); + var result = AqualityServices.Application.Driver.FindElement(calculatorForm.ResultsLabel.Locator).Text; StringAssert.Contains("3", result); } [Test] public void Should_WorkWithCalculator_ViaElementFinder() { - AqualityServices.Get().FindElement(calculatorWindow.OneButton.Locator).Click(); - AqualityServices.Get().FindElement(calculatorWindow.PlusButton.Locator).Click(); - AqualityServices.Get().FindElement(calculatorWindow.TwoButton.Locator).Click(); - AqualityServices.Get().FindElement(calculatorWindow.EqualsButton.Locator).Click(); - var result = AqualityServices.Get().FindElement(calculatorWindow.ResultsLabel.Locator).Text; + AqualityServices.Get().FindElement(calculatorForm.OneButton.Locator).Click(); + AqualityServices.Get().FindElement(calculatorForm.PlusButton.Locator).Click(); + AqualityServices.Get().FindElement(calculatorForm.TwoButton.Locator).Click(); + AqualityServices.Get().FindElement(calculatorForm.EqualsButton.Locator).Click(); + var result = AqualityServices.Get().FindElement(calculatorForm.ResultsLabel.Locator).Text; StringAssert.Contains("3", result); } @@ -52,7 +52,7 @@ public void Should_GetCurrentApplication_AfterSetApplication() IApplication firstApplication; using (var scope = AqualityServices.Get().CreateScope()) { - firstApplication = scope.ServiceProvider.GetRequiredService(); + firstApplication = scope.ServiceProvider.GetRequiredService().Launch(); } // Creating a second instance of Application @@ -60,17 +60,17 @@ public void Should_GetCurrentApplication_AfterSetApplication() using (var scope = AqualityServices.Get().CreateScope()) { - var secondApplication = scope.ServiceProvider.GetRequiredService(); + var secondApplication = scope.ServiceProvider.GetRequiredService().Launch(); Assert.AreNotSame(firstApplication, secondApplication); secondApplication.Driver.Quit(); } // Switching back to a first instance of Application - AqualityServices.Application = firstApplication as Application; + AqualityServices.Application = firstApplication as IWindowsApplication; using (var scope = AqualityServices.Get().CreateScope()) { - Assert.AreSame(firstApplication, scope.ServiceProvider.GetRequiredService()); + Assert.AreSame(firstApplication, scope.ServiceProvider.GetRequiredService().Launch()); } } @@ -78,8 +78,8 @@ public void Should_GetCurrentApplication_AfterSetApplication() public void Should_GetCurrentApplication_AfterQuit() { var firstApplication = AqualityServices.Application; - firstApplication.Quit(); - var secondApplication = AqualityServices.Application; + firstApplication.Launch().Quit(); + var secondApplication = AqualityServices.Application.Launch(); Assert.AreNotSame(firstApplication, secondApplication); using (var scope = AqualityServices.Get().CreateScope()) { diff --git a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Applications/WindowHandleApplicationFactoryTests.cs b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Applications/WindowHandleApplicationFactoryTests.cs index 567a7fd..8166d84 100644 --- a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Applications/WindowHandleApplicationFactoryTests.cs +++ b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Applications/WindowHandleApplicationFactoryTests.cs @@ -1,56 +1,21 @@ using Aquality.WinAppDriver.Applications; using Aquality.WinAppDriver.Configurations; -using Aquality.WinAppDriver.Tests.Windows; -using Aquality.WinAppDriver.Utilities; +using Aquality.WinAppDriver.Extensions; +using Aquality.WinAppDriver.Tests.Forms; using NUnit.Framework; -using OpenQA.Selenium.Appium.Windows; namespace Aquality.WinAppDriver.Tests.Applications { - public class WindowHandleApplicationFactoryTests : TestWithApplication + public class WindowHandleApplicationFactoryTests : TestWithCustomApplication { - private IProcessManager ProcessManager => AqualityServices.ProcessManager; - private string ApplicationPath => AqualityServices.Get().ApplicationPath; + protected override string ApplicationPath => AqualityServices.Get().ApplicationPath; [Test] public void Should_BePossibleTo_SetWindowHandleApplicationFactory() { - const string appName = "Day Maxi Calc v.1.5 Freeware"; ProcessManager.Start(ApplicationPath); - - AqualityServices.SetWindowHandleApplicationFactory(rootSession => GetWindowHandle(rootSession, appName)); - Assert.IsTrue(new CalculatorWindow().IsDisplayed); - } - - [TearDown] - public new void CleanUp() - { - base.CleanUp(); - AqualityServices.SetDefaultFactory(); - var executableName = ApplicationPath.Contains('\\') ? ApplicationPath.Substring(ApplicationPath.LastIndexOf('\\') + 1) : ApplicationPath; - ProcessManager.TryToStopExecutables(executableName); - } - - /// - /// returns window handle attribute, converted to HEX format - /// - /// - private string GetWindowHandle(WindowsDriver webDriver, string appName) - { - AqualityServices.ConditionalWait.WaitForTrue(() => - { - try - { - return webDriver.FindElementByName(appName) != null; - } - catch - { - return false; - } - }); - - var nativeWindowHandle = webDriver.FindElementByName(appName).GetAttribute("NativeWindowHandle"); - return int.Parse(nativeWindowHandle).ToString("x"); + AqualityServices.SetWindowHandleApplicationFactory(rootSession => new CalculatorWindow(() => rootSession).GetNativeWindowHandle()); + Assert.IsTrue(new CalculatorForm().IsDisplayed); } } } diff --git a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Aquality.WinAppDriver.Tests.csproj b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Aquality.WinAppDriver.Tests.csproj index 15dfb63..c68d9f1 100644 --- a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Aquality.WinAppDriver.Tests.csproj +++ b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Aquality.WinAppDriver.Tests.csproj @@ -8,7 +8,10 @@ - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Elements/Actions/MouseActionsTests.cs b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Elements/Actions/MouseActionsTests.cs index dfff884..f86970e 100644 --- a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Elements/Actions/MouseActionsTests.cs +++ b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Elements/Actions/MouseActionsTests.cs @@ -1,6 +1,6 @@ using Aquality.WinAppDriver.Actions; using Aquality.WinAppDriver.Elements.Interfaces; -using Aquality.WinAppDriver.Tests.Windows; +using Aquality.WinAppDriver.Tests.Forms; using NUnit.Framework; using OpenQA.Selenium.Interactions; @@ -9,7 +9,7 @@ namespace Aquality.WinAppDriver.Tests.Elements.Actions public class MouseActionsTests : Tests.Actions.MouseActionsTests { protected override IMouseActions MouseActions => RightArgumentTextBox.MouseActions; - private ITextBox LeftArgumentTextBox => new CalculatorWindow().LeftArgumentTextBox; + private ITextBox LeftArgumentTextBox => new CalculatorForm().LeftArgumentTextBox; [Test] public void Should_PerformElementSpecificMouseActions() diff --git a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Elements/ElementFactoryTests.cs b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Elements/ElementFactoryTests.cs index 9951c7c..2599fc8 100644 --- a/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Elements/ElementFactoryTests.cs +++ b/Aquality.WinAppDriver/tests/Aquality.WinAppDriver.Tests/Elements/ElementFactoryTests.cs @@ -1,7 +1,7 @@ using Aquality.WinAppDriver.Applications; using Aquality.WinAppDriver.Elements; using Aquality.WinAppDriver.Elements.Interfaces; -using Aquality.WinAppDriver.Tests.Windows; +using Aquality.WinAppDriver.Tests.Forms; using NUnit.Framework; using OpenQA.Selenium; using System; @@ -10,23 +10,23 @@ namespace Aquality.WinAppDriver.Tests.Elements { public class ElementFactoryTests : TestWithApplication { - private static readonly CalculatorWindow calculatorWindow = new CalculatorWindow(); + private static readonly CalculatorForm calculatorForm = new CalculatorForm(); private IElementFactory Factory => AqualityServices.Get(); [Test] public void Should_WorkWithCalculator_ViaElementFactory() { - calculatorWindow.OneButton.Click(); - calculatorWindow.PlusButton.Click(); - calculatorWindow.TwoButton.Click(); - calculatorWindow.EqualsButton.Click(); - StringAssert.Contains("3", calculatorWindow.ResultsLabel.Text); + calculatorForm.OneButton.Click(); + calculatorForm.PlusButton.Click(); + calculatorForm.TwoButton.Click(); + calculatorForm.EqualsButton.Click(); + StringAssert.Contains("3", calculatorForm.ResultsLabel.Text); } [Test] public void Should_FindChildElements_ViaElementFactory() { - Assert.IsNotNull(Factory.FindChildElement