From e24e3a953113ce881e5c815a7137cc313586dfd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Thu, 10 Jun 2021 15:13:08 +0300 Subject: [PATCH] [Visual Testing] Add ability of visualization checks for the Form (#204) +semver: breaking * update Aquality.Selenium.Core nuget package * inherit Form from Core.Forms.Form * [breaking] removed [Obsolete] properties and methods from the Form abstraction * add "visualization" section to settings.json * add visual tests * Stabilization of automation practice site interactions closes #200, fixes #201 * Fix sonar code smells --- .gitignore | 1 + .../Aquality.Selenium.csproj | 2 +- .../Aquality.Selenium/Aquality.Selenium.xml | 45 ++++------- .../Browsers/BrowserTabNavigation.cs | 2 +- .../src/Aquality.Selenium/Elements/Element.cs | 22 +++--- .../Elements/ElementStateProvider.cs | 4 +- .../src/Aquality.Selenium/Forms/Form.cs | 75 +++++++------------ .../Aquality.Selenium/Resources/settings.json | 6 ++ .../Aquality.Selenium.Tests.csproj | 4 +- .../Integration/Actions/JsActionsTests.cs | 5 +- .../Integration/Actions/MouseActionsTests.cs | 3 +- .../Integration/BrowserTabsTests.cs | 2 +- .../Integration/BrowserTests.cs | 6 +- .../Integration/HiddenElementsTests.cs | 6 +- .../Forms/ProductListForm.cs | 4 +- .../AutomationPractice/Forms/SliderForm.cs | 21 ++++++ .../AutomationPractice/Helpers/SiteLoader.cs | 29 +++++++ .../Integration/UITest.cs | 6 ++ .../ElementExistsButNotDisplayedTests.cs | 3 +- .../Integration/Usecases/ShoppingCartTests.cs | 24 ++++-- .../Integration/Usecases/VisualTests.cs | 62 +++++++++++++++ .../Resources/settings.azure.json | 8 +- .../Resources/settings.json | 6 ++ .../Resources/settings.local.json | 6 ++ 24 files changed, 230 insertions(+), 122 deletions(-) create mode 100644 Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/TestApp/AutomationPractice/Helpers/SiteLoader.cs create mode 100644 Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Usecases/VisualTests.cs diff --git a/.gitignore b/.gitignore index 2ee22632..453830dd 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,4 @@ msbuild.wrn .vs/ Log/ +VisualDumps/ diff --git a/Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.csproj b/Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.csproj index 90178d9e..9fc3d55c 100644 --- a/Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.csproj +++ b/Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.csproj @@ -69,7 +69,7 @@ - + diff --git a/Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.xml b/Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.xml index f11c8b41..e7792917 100644 --- a/Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.xml +++ b/Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.xml @@ -1485,6 +1485,21 @@ Instance of logger + + + Visualization configuration used by . + + + + + Localized logger used by . + + + + + Conditional wait + + Element factory @@ -1500,13 +1515,6 @@ Name of the form. - - - Return form state for form locator - - True - form is opened, - False - form is not opened. - Provides ability to get form's state (whether it is displayed, exists or not) and respective waiting functions. @@ -1524,28 +1532,5 @@ horizontal coordinate vertical coordinate - - - Finds child element of current form by its locator. - - Type of child element that has to implement IElement. - Locator of child element relative to form. - Child element name. - Delegate that defines constructor of child element in case of custom element. - Child element state. - Instance of child element. - - - - Finds child elements of current form by their locator. - - Type of child elements that has to implement IElement. - Locator of child elements relative to form. - Child elements name. - Delegate that defines constructor of child element in case of custom element type. - Expected number of elements that have to be found (zero, more then zero, any). - Child elements state. - List of child elements. - diff --git a/Aquality.Selenium/src/Aquality.Selenium/Browsers/BrowserTabNavigation.cs b/Aquality.Selenium/src/Aquality.Selenium/Browsers/BrowserTabNavigation.cs index d88ef17f..ab1a4c61 100644 --- a/Aquality.Selenium/src/Aquality.Selenium/Browsers/BrowserTabNavigation.cs +++ b/Aquality.Selenium/src/Aquality.Selenium/Browsers/BrowserTabNavigation.cs @@ -74,7 +74,7 @@ public void SwitchToTab(int index, bool closeCurrent = false) var names = TabHandles; if (index < 0 || names.Count <= index) { - throw new IndexOutOfRangeException( + throw new ArgumentOutOfRangeException( $"Index of browser tab '{index}' you provided is out of range {0}..{names.Count}"); } diff --git a/Aquality.Selenium/src/Aquality.Selenium/Elements/Element.cs b/Aquality.Selenium/src/Aquality.Selenium/Elements/Element.cs index a2499691..9982576d 100644 --- a/Aquality.Selenium/src/Aquality.Selenium/Elements/Element.cs +++ b/Aquality.Selenium/src/Aquality.Selenium/Elements/Element.cs @@ -1,20 +1,22 @@ -using OpenQA.Selenium; -using Aquality.Selenium.Browsers; -using Aquality.Selenium.Elements.Actions; -using Aquality.Selenium.Elements.Interfaces; -using Aquality.Selenium.Core.Elements; +using Aquality.Selenium.Browsers; using Aquality.Selenium.Configurations; -using Aquality.Selenium.Core.Utilities; using Aquality.Selenium.Core.Applications; +using Aquality.Selenium.Core.Configurations; +using Aquality.Selenium.Core.Elements; using Aquality.Selenium.Core.Localization; +using Aquality.Selenium.Core.Logging; +using Aquality.Selenium.Core.Utilities; +using Aquality.Selenium.Core.Visualization; using Aquality.Selenium.Core.Waitings; +using Aquality.Selenium.Elements.Actions; +using Aquality.Selenium.Elements.Interfaces; +using OpenQA.Selenium; +using System.Reflection; +using System.Linq; using CoreElement = Aquality.Selenium.Core.Elements.Element; using ICoreElementFactory = Aquality.Selenium.Core.Elements.Interfaces.IElementFactory; using ICoreElementFinder = Aquality.Selenium.Core.Elements.Interfaces.IElementFinder; using ICoreElementStateProvider = Aquality.Selenium.Core.Elements.Interfaces.IElementStateProvider; -using Aquality.Selenium.Core.Configurations; -using System.Reflection; -using System.Linq; namespace Aquality.Selenium.Elements { @@ -55,6 +57,8 @@ protected Element(By locator, string name, ElementState state) : base(locator, n protected override IConditionalWait ConditionalWait => AqualityServices.ConditionalWait; + protected override IImageComparator ImageComparator => AqualityServices.Get(); + public void ClickAndWait() { Click(); diff --git a/Aquality.Selenium/src/Aquality.Selenium/Elements/ElementStateProvider.cs b/Aquality.Selenium/src/Aquality.Selenium/Elements/ElementStateProvider.cs index 0d4ad7c1..9a75c767 100644 --- a/Aquality.Selenium/src/Aquality.Selenium/Elements/ElementStateProvider.cs +++ b/Aquality.Selenium/src/Aquality.Selenium/Elements/ElementStateProvider.cs @@ -1,5 +1,5 @@ -using Aquality.Selenium.Core.Elements; -using Aquality.Selenium.Core.Elements.Interfaces; +using Aquality.Selenium.Core.Elements.Interfaces; +using Aquality.Selenium.Core.Logging; using Aquality.Selenium.Core.Waitings; using OpenQA.Selenium; using CoreElementStateProvider = Aquality.Selenium.Core.Elements.ElementStateProvider; diff --git a/Aquality.Selenium/src/Aquality.Selenium/Forms/Form.cs b/Aquality.Selenium/src/Aquality.Selenium/Forms/Form.cs index 0b0862ff..0120ce80 100644 --- a/Aquality.Selenium/src/Aquality.Selenium/Forms/Form.cs +++ b/Aquality.Selenium/src/Aquality.Selenium/Forms/Form.cs @@ -1,19 +1,20 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using OpenQA.Selenium; -using Aquality.Selenium.Core.Elements; -using Aquality.Selenium.Core.Logging; +using System.Drawing; using Aquality.Selenium.Browsers; +using Aquality.Selenium.Core.Logging; +using Aquality.Selenium.Core.Forms; using Aquality.Selenium.Elements.Interfaces; +using OpenQA.Selenium; using IElementStateProvider = Aquality.Selenium.Core.Elements.Interfaces.IElementStateProvider; +using Aquality.Selenium.Core.Configurations; +using Aquality.Selenium.Core.Localization; +using Aquality.Selenium.Core.Waitings; namespace Aquality.Selenium.Forms { /// /// Defines base class for any UI form. /// - public abstract class Form + public abstract class Form : Form { private readonly ILabel formLabel; /// @@ -39,6 +40,21 @@ protected Form(By locator, string name) /// protected static Logger Logger => AqualityServices.Logger; + /// + /// Visualization configuration used by . + /// + protected override IVisualizationConfiguration VisualizationConfiguration => AqualityServices.Get(); + + /// + /// Localized logger used by . + /// + protected override ILocalizedLogger LocalizedLogger => AqualityServices.LocalizedLogger; + + /// + /// Conditional wait + /// + protected static IConditionalWait ConditionalWait => AqualityServices.ConditionalWait; + /// /// Element factory /// @@ -52,15 +68,7 @@ protected Form(By locator, string name) /// /// Name of the form. /// - public string Name { get; } - - /// - /// Return form state for form locator - /// - /// True - form is opened, - /// False - form is not opened. - [Obsolete("This property will be removed in the future release. Use State.WaitForDisplayed() if needed")] - public bool IsDisplayed => FormElement.State.WaitForDisplayed(); + public override string Name { get; } /// /// Provides ability to get form's state (whether it is displayed, exists or not) and respective waiting functions. @@ -70,7 +78,7 @@ protected Form(By locator, string name) /// /// Gets size of form element defined by its locator. /// - public Size Size => FormElement.GetElement().Size; + public Size Size => FormElement.Visual.Size; /// /// Scroll form without scrolling entire page @@ -81,38 +89,5 @@ public void ScrollBy(int x, int y) { FormElement.JsActions.ScrollBy(x, y); } - - /// - /// Finds child element of current form by its locator. - /// - /// Type of child element that has to implement IElement. - /// Locator of child element relative to form. - /// Child element name. - /// Delegate that defines constructor of child element in case of custom element. - /// Child element state. - /// Instance of child element. - [Obsolete("This method will be removed in the future release. Use FormElement property methods to find child element")] - protected T FindChildElement(By childLocator, string name = null, ElementSupplier supplier = null, ElementState state = ElementState.Displayed) - where T : IElement - { - return FormElement.FindChildElement(childLocator, name, supplier, state); - } - - /// - /// Finds child elements of current form by their locator. - /// - /// Type of child elements that has to implement IElement. - /// Locator of child elements relative to form. - /// Child elements name. - /// Delegate that defines constructor of child element in case of custom element type. - /// Expected number of elements that have to be found (zero, more then zero, any). - /// Child elements state. - /// List of child elements. - [Obsolete("This method will be removed in the future release. Use FormElement property methods to find child elements")] - protected IList FindChildElements(By childLocator, string name = null, ElementSupplier supplier = null, ElementsCount expectedCount = ElementsCount.Any, ElementState state = ElementState.Displayed) - where T : IElement - { - return FormElement.FindChildElements(childLocator, name, supplier, expectedCount, state); - } } } diff --git a/Aquality.Selenium/src/Aquality.Selenium/Resources/settings.json b/Aquality.Selenium/src/Aquality.Selenium/Resources/settings.json index ecfba590..3ba92191 100644 --- a/Aquality.Selenium/src/Aquality.Selenium/Resources/settings.json +++ b/Aquality.Selenium/src/Aquality.Selenium/Resources/settings.json @@ -110,5 +110,11 @@ }, "elementCache": { "isEnabled": false + }, + "visualization": { + "defaultThreshold": 0.012, + "comparisonWidth": 16, + "comparisonHeight": 16, + "pathToDumps": "../../../Resources/VisualDumps/" } } \ No newline at end of file diff --git a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Aquality.Selenium.Tests.csproj b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Aquality.Selenium.Tests.csproj index 54fc9f1f..d417d863 100644 --- a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Aquality.Selenium.Tests.csproj +++ b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Aquality.Selenium.Tests.csproj @@ -25,12 +25,12 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Actions/JsActionsTests.cs b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Actions/JsActionsTests.cs index e1f9d586..32d330fd 100644 --- a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Actions/JsActionsTests.cs +++ b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Actions/JsActionsTests.cs @@ -5,7 +5,6 @@ using Aquality.Selenium.Browsers; using Aquality.Selenium.Core.Elements; using Aquality.Selenium.Elements; -using Aquality.Selenium.Tests.Integration.TestApp; using Aquality.Selenium.Tests.Integration.TestApp.AutomationPractice.Forms; using Aquality.Selenium.Tests.Integration.TestApp.TheInternet.Forms; using NUnit.Framework; @@ -47,7 +46,7 @@ public void Should_BePossibleTo_HighlightElement() [Test] public void Should_BePossibleTo_HoverMouse() { - AqualityServices.Browser.GoTo(Constants.UrlAutomationPractice); + OpenAutomationPracticeSite(); var productList = new ProductListForm(); productList.NavigateToLastProduct(); @@ -60,7 +59,7 @@ public void Should_BePossibleTo_HoverMouse() [Test] public void Should_BePossibleTo_SetFocus() { - AqualityServices.Browser.GoTo(Constants.UrlAutomationPractice); + OpenAutomationPracticeSite(); var productList = new ProductListForm(); productList.NavigateToLastProduct(); diff --git a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Actions/MouseActionsTests.cs b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Actions/MouseActionsTests.cs index c80936ff..e86f2544 100644 --- a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Actions/MouseActionsTests.cs +++ b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Actions/MouseActionsTests.cs @@ -1,5 +1,4 @@ using Aquality.Selenium.Browsers; -using Aquality.Selenium.Tests.Integration.TestApp; using Aquality.Selenium.Tests.Integration.TestApp.AutomationPractice.Forms; using Aquality.Selenium.Tests.Integration.TestApp.TheInternet.Forms; using NUnit.Framework; @@ -39,7 +38,7 @@ public void Should_BePossibleTo_RightClick() [Test] public void Should_BePossibleTo_MoveToElement() { - AqualityServices.Browser.GoTo(Constants.UrlAutomationPractice); + OpenAutomationPracticeSite(); var productList = new ProductListForm(); productList.NavigateToLastProduct(); diff --git a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/BrowserTabsTests.cs b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/BrowserTabsTests.cs index 53dc3393..aec43636 100644 --- a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/BrowserTabsTests.cs +++ b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/BrowserTabsTests.cs @@ -135,7 +135,7 @@ public void Should_BePossibleTo_SwitchToNewTabByIndex_AndClose() [Test] public void Should_BeThrow_IfSwitchToNewTab_ByIncorrectIndex() { - Assert.Throws(typeof(IndexOutOfRangeException), () => { AqualityServices.Browser.Tabs().SwitchToTab(10, true); }); + Assert.Throws(() => { AqualityServices.Browser.Tabs().SwitchToTab(10, true); }); } private void CheckSwitchingBy(int expectedTabCount, Action switchMethod) diff --git a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/BrowserTests.cs b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/BrowserTests.cs index 5350935a..e89293c6 100644 --- a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/BrowserTests.cs +++ b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/BrowserTests.cs @@ -1,5 +1,4 @@ using Aquality.Selenium.Browsers; -using Aquality.Selenium.Tests.Integration.TestApp; using Aquality.Selenium.Tests.Integration.TestApp.AutomationPractice.Forms; using Aquality.Selenium.Tests.Integration.TestApp.TheInternet.Forms; using TheInternetAuthenticationForm = Aquality.Selenium.Tests.Integration.TestApp.TheInternet.Forms.AuthenticationForm; @@ -189,12 +188,11 @@ public void Should_BePossibleTo_SetWindowSize() [Test] public void Should_BePossibleTo_ScrollWindowBy() { - var browser = AqualityServices.Browser; - browser.GoTo(Constants.UrlAutomationPractice); + OpenAutomationPracticeSite(); var sliderForm = new SliderForm(); var initialY = sliderForm.FormPointInViewPort.Y; var formHeight = sliderForm.Size.Height; - browser.ScrollWindowBy(0, formHeight); + AqualityServices.Browser.ScrollWindowBy(0, formHeight); Assert.LessOrEqual(Math.Abs(formHeight - (initialY - sliderForm.FormPointInViewPort.Y)), 1, "Window should be scrolled."); } diff --git a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/HiddenElementsTests.cs b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/HiddenElementsTests.cs index 0484566a..f69824db 100644 --- a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/HiddenElementsTests.cs +++ b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/HiddenElementsTests.cs @@ -1,7 +1,5 @@ -using Aquality.Selenium.Browsers; -using Aquality.Selenium.Core.Elements; +using Aquality.Selenium.Core.Elements; using Aquality.Selenium.Elements; -using Aquality.Selenium.Tests.Integration.TestApp; using Aquality.Selenium.Tests.Integration.TestApp.AutomationPractice.Forms; using NUnit.Framework; using System; @@ -30,7 +28,7 @@ private static readonly Func>[] Elemen [SetUp] public void BeforeTest() { - AqualityServices.Browser.GoTo(Constants.UrlAutomationPractice); + OpenAutomationPracticeSite(); } [Test] diff --git a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/TestApp/AutomationPractice/Forms/ProductListForm.cs b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/TestApp/AutomationPractice/Forms/ProductListForm.cs index 1e5636d5..552283f2 100644 --- a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/TestApp/AutomationPractice/Forms/ProductListForm.cs +++ b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/TestApp/AutomationPractice/Forms/ProductListForm.cs @@ -5,6 +5,7 @@ using Aquality.Selenium.Core.Elements; using Aquality.Selenium.Elements.Interfaces; using Aquality.Selenium.Forms; +using Aquality.Selenium.Tests.Integration.TestApp.AutomationPractice.Helpers; using OpenQA.Selenium; namespace Aquality.Selenium.Tests.Integration.TestApp.AutomationPractice.Forms @@ -26,8 +27,7 @@ public ProductListForm() : base(By.XPath(FormLocator), "Product list") public void NavigateToLastProduct() { - AqualityServices.Browser.GoTo(GetLastProduct().Href); - AqualityServices.Browser.WaitForPageToLoad(); + SiteLoader.OpenAutomationPracticeSite(GetLastProduct().Href); } public ILink GetLastProduct() diff --git a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/TestApp/AutomationPractice/Forms/SliderForm.cs b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/TestApp/AutomationPractice/Forms/SliderForm.cs index c5e34a2d..cf77ee11 100644 --- a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/TestApp/AutomationPractice/Forms/SliderForm.cs +++ b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/TestApp/AutomationPractice/Forms/SliderForm.cs @@ -2,20 +2,41 @@ using Aquality.Selenium.Elements.Interfaces; using Aquality.Selenium.Forms; using OpenQA.Selenium; +using System.Collections.Generic; using System.Drawing; namespace Aquality.Selenium.Tests.Integration.TestApp.AutomationPractice.Forms { internal class SliderForm : Form { + private readonly ILabel styleContainer = ElementFactory.GetLabel(By.Id("homeslider"), "Slider style container", ElementState.ExistsInAnyState); + public SliderForm() : base(By.Id("slider_row"), "Slider") { } + protected override IDictionary ElementsForVisualization => ElementsInitializedAsDisplayed; + public IButton NextButton => ElementFactory.GetButton(By.XPath("//a[contains(.,'Next')]"), "Next"); public Point FormPointInViewPort => ElementFactory.GetLabel(Locator, Name).JsActions.GetViewPortCoordinates(); + public string Style => styleContainer.GetAttribute("style"); + + public void WaitForSliding() + { + var style = string.Empty; + ConditionalWait.WaitForTrue(() => + { + if (style == Style) + { + return true; + } + style = Style; + return false; + }, message: "Sliding should stop after a while"); + } + public IButton GetAddToCartBtn(ElementState elementState) { return ElementFactory.GetButton(By.XPath("//ul[@id='blockbestsellers']//li[last()]//a[contains(@class, 'add_to_cart')]"), "Add to cart", elementState); diff --git a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/TestApp/AutomationPractice/Helpers/SiteLoader.cs b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/TestApp/AutomationPractice/Helpers/SiteLoader.cs new file mode 100644 index 00000000..433f5364 --- /dev/null +++ b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/TestApp/AutomationPractice/Helpers/SiteLoader.cs @@ -0,0 +1,29 @@ +using Aquality.Selenium.Elements.Interfaces; +using OpenQA.Selenium; +using System; +using static Aquality.Selenium.Browsers.AqualityServices; + +namespace Aquality.Selenium.Tests.Integration.TestApp.AutomationPractice.Helpers +{ + internal static class SiteLoader + { + public static void OpenAutomationPracticeSite(string customUrl = null) + { + var resourceLimitLabel = Get() + .GetLabel(By.XPath("//h1[.='Resource Limit Is Reached']"), "Resource Limit Is Reached"); + Browser.GoTo(customUrl ?? Constants.UrlAutomationPractice); + Browser.WaitForPageToLoad(); + ConditionalWait.WaitForTrue(() => + { + if (resourceLimitLabel.State.IsDisplayed) + { + Browser.Refresh(); + Browser.WaitForPageToLoad(); + return false; + } + return true; + }, timeout: TimeSpan.FromMinutes(3), pollingInterval: TimeSpan.FromSeconds(15), + message: $"Failed to load [{customUrl ?? Constants.UrlAutomationPractice}] website. {resourceLimitLabel.Name} message is displayed."); + } + } +} diff --git a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/UITest.cs b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/UITest.cs index 68fb1e75..698f6d28 100644 --- a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/UITest.cs +++ b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/UITest.cs @@ -1,4 +1,5 @@ using Aquality.Selenium.Browsers; +using Aquality.Selenium.Tests.Integration.TestApp.AutomationPractice.Helpers; using NUnit.Framework; [assembly: LevelOfParallelism(10)] @@ -16,5 +17,10 @@ public void CleanUp() AqualityServices.Browser.Quit(); } } + + protected static void OpenAutomationPracticeSite() + { + SiteLoader.OpenAutomationPracticeSite(); + } } } diff --git a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Usecases/ElementExistsButNotDisplayedTests.cs b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Usecases/ElementExistsButNotDisplayedTests.cs index 625cba6e..853bc9d9 100644 --- a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Usecases/ElementExistsButNotDisplayedTests.cs +++ b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Usecases/ElementExistsButNotDisplayedTests.cs @@ -1,7 +1,6 @@ using Aquality.Selenium.Browsers; using Aquality.Selenium.Core.Elements; using Aquality.Selenium.Elements.Interfaces; -using Aquality.Selenium.Tests.Integration.TestApp; using Aquality.Selenium.Tests.Integration.TestApp.AutomationPractice.Forms; using NUnit.Framework; using OpenQA.Selenium; @@ -18,7 +17,7 @@ internal class ElementExistsButNotDisplayedTests : UITest [SetUp] public void BeforeTest() { - AqualityServices.Browser.GoTo(Constants.UrlAutomationPractice); + OpenAutomationPracticeSite(); } [Test] diff --git a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Usecases/ShoppingCartTests.cs b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Usecases/ShoppingCartTests.cs index a55bba9e..0d36ca52 100644 --- a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Usecases/ShoppingCartTests.cs +++ b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Usecases/ShoppingCartTests.cs @@ -1,8 +1,9 @@ using Aquality.Selenium.Browsers; -using Aquality.Selenium.Tests.Integration.TestApp; +using Aquality.Selenium.Core.Utilities; using Aquality.Selenium.Tests.Integration.TestApp.AutomationPractice.Forms; using Aquality.Selenium.Tests.Integration.TestApp.AutomationPractice.Modals; using NUnit.Framework; +using OpenQA.Selenium; using System; namespace Aquality.Selenium.Tests.Integration.Usecases @@ -17,18 +18,25 @@ internal class ShoppingCartTests : UITest private static readonly int DayToSelect = 29; private static readonly string State = "California"; - private string Email => $"john+{DateTime.Now.Millisecond}@doe.com"; + private static string Email => $"john+{DateTime.Now.Millisecond}@doe.com"; - [SetUp] - public void BeforeTest() + [Test] + public void Should_BePossibleTo_PerformActions() { - AqualityServices.Browser.GoTo(Constants.UrlAutomationPractice); - AqualityServices.Browser.Maximize(); + // website automationpractice.com is out of resources and unable to proceed operations sometimes + Assert.DoesNotThrow(() => + { + AqualityServices.Get().DoWithRetry(ActionsOnAutomationPractice, + new[] { typeof(NoSuchElementException), typeof(WebDriverTimeoutException), typeof(AssertionException) }); + }, "Shopping cart actions should actually work"); + } - [Test] - public void Should_BePossibleTo_PerformActions() + private void ActionsOnAutomationPractice() { + AqualityServices.Browser.Quit(); + OpenAutomationPracticeSite(); + AqualityServices.Browser.Maximize(); var sliderForm = new SliderForm(); Assert.IsTrue(sliderForm.State.WaitForDisplayed(), "Slider Form is not opened"); diff --git a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Usecases/VisualTests.cs b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Usecases/VisualTests.cs new file mode 100644 index 00000000..aba5a03e --- /dev/null +++ b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Usecases/VisualTests.cs @@ -0,0 +1,62 @@ +using Aquality.Selenium.Browsers; +using Aquality.Selenium.Tests.Integration.TestApp.AutomationPractice.Forms; +using NUnit.Framework; + +namespace Aquality.Selenium.Tests.Integration.Usecases +{ + internal class VisualTests : UITest + { + [SetUp] + public void BeforeTest() + { + OpenAutomationPracticeSite(); + AqualityServices.Browser.Maximize(); + } + + [Test] + public void Should_BePossibleTo_CheckVisualState_WhenItHasNotChanged() + { + var sliderForm = new SliderForm(); + Assume.That(sliderForm.State.WaitForDisplayed(), "Slider Form is not opened"); + var style = sliderForm.Style; + Assert.DoesNotThrow(() => sliderForm.Dump.Save(), "Should be possible to save dump"); + Assert.That(sliderForm.Dump.Compare() == 0L || sliderForm.Style != style, "Form dump should remain the same, unless the slider has already scrolled"); + } + + [Test] + public void Should_BePossibleTo_CheckVisualState_WhenItDifferes() + { + const string dumpName = "the differed slider"; + var sliderForm = new SliderForm(); + Assume.That(sliderForm.State.WaitForDisplayed(), "Slider Form is not opened"); + var style = sliderForm.Style; + Assert.DoesNotThrow(() => sliderForm.Dump.Save(dumpName), "Should be possible to save dump"); + sliderForm.ClickNextButton(); + sliderForm.WaitForSliding(); + Assert.That(sliderForm.Dump.Compare(dumpName), Is.GreaterThan(0), "After clicking on slider next button, the form dump should differ"); + } + + [Test] + public void Should_BePossibleTo_CheckVisualState_WhenItIsTheSame() + { + const string dumpName = "the same slider"; + var sliderForm = new SliderForm(); + Assume.That(sliderForm.State.WaitForDisplayed(), "Slider Form is not opened"); + sliderForm.ClickNextButton(); + sliderForm.ClickNextButton(); + sliderForm.WaitForSliding(); + var style = sliderForm.Style; + Assert.DoesNotThrow(() => sliderForm.Dump.Save(dumpName), "Should be possible to save dump"); + sliderForm.ClickNextButton(); + sliderForm.WaitForSliding(); + Assert.That(sliderForm.Dump.Compare(dumpName), Is.GreaterThan(0), "After clicking on slider next button, the form dump should differ"); + AqualityServices.ConditionalWait.WaitForTrue(() => + { + sliderForm.ClickNextButton(); + sliderForm.WaitForSliding(); + return style == sliderForm.Style; + }, message: "After some sliding, slider should get back to first slide"); + Assert.That(sliderForm.Dump.Compare(dumpName), Is.AtMost(0.02), "After slider returned to initial state, the form dump should be almost the same"); + } + } +} diff --git a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Resources/settings.azure.json b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Resources/settings.azure.json index 35d8b343..36435db8 100644 --- a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Resources/settings.azure.json +++ b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Resources/settings.azure.json @@ -85,7 +85,7 @@ }, "timeouts": { "timeoutImplicit": 0, - "timeoutCondition": 30, + "timeoutCondition": 45, "timeoutScript": 10, "timeoutPageLoad": 60, "timeoutPollingInterval": 300, @@ -101,5 +101,11 @@ }, "elementCache": { "isEnabled": false + }, + "visualization": { + "defaultThreshold": 0.012, + "comparisonWidth": 16, + "comparisonHeight": 16, + "pathToDumps": "../../../Resources/VisualDumps/" } } \ No newline at end of file diff --git a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Resources/settings.json b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Resources/settings.json index 22043435..06b84ebe 100644 --- a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Resources/settings.json +++ b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Resources/settings.json @@ -104,5 +104,11 @@ }, "elementCache": { "isEnabled": false + }, + "visualization": { + "defaultThreshold": 0.012, + "comparisonWidth": 16, + "comparisonHeight": 16, + "pathToDumps": "../../../Resources/VisualDumps/" } } diff --git a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Resources/settings.local.json b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Resources/settings.local.json index ae24f1be..354ee5e7 100644 --- a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Resources/settings.local.json +++ b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Resources/settings.local.json @@ -103,5 +103,11 @@ }, "elementCache": { "isEnabled": false + }, + "visualization": { + "defaultThreshold": 0.012, + "comparisonWidth": 16, + "comparisonHeight": 16, + "pathToDumps": "../../../Resources/VisualDumps/" } }