From bbdeaf36fbcd2f62c74744903d64062a3e4c2b8e Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Wed, 1 May 2024 09:33:19 +0300 Subject: [PATCH 1/3] Ability to delay the execution in headed mode --- src/OrchardCoreContrib.Testing.UI/Browser.cs | 7 +++++-- .../BrowserFactory.cs | 4 ++-- src/OrchardCoreContrib.Testing.UI/Element.cs | 15 ++++++++++++--- src/OrchardCoreContrib.Testing.UI/IBrowser.cs | 2 ++ src/OrchardCoreContrib.Testing.UI/IElement.cs | 2 ++ src/OrchardCoreContrib.Testing.UI/IPage.cs | 2 ++ src/OrchardCoreContrib.Testing.UI/Page.cs | 13 ++++++++++--- src/OrchardCoreContrib.Testing.UI/UITest.cs | 4 ++-- .../UITestOfT.cs | 4 ++-- .../BrowserFactoryTests.cs | 4 ++-- .../BrowserTests.cs | 4 ++-- .../ElementTests.cs | 19 +++++++++++++++---- .../PageTests.cs | 8 +++++--- .../PlaywrightPageHelper.cs | 7 ++++--- 14 files changed, 67 insertions(+), 28 deletions(-) diff --git a/src/OrchardCoreContrib.Testing.UI/Browser.cs b/src/OrchardCoreContrib.Testing.UI/Browser.cs index 913d242..16893d2 100644 --- a/src/OrchardCoreContrib.Testing.UI/Browser.cs +++ b/src/OrchardCoreContrib.Testing.UI/Browser.cs @@ -11,7 +11,7 @@ namespace OrchardCoreContrib.Testing.UI; /// The . /// The . /// Whether to run browser in headless mode. -public class Browser(IPlaywrightBrowserAccessor playwrightBrowserAccessor, BrowserType type, bool headless) : IBrowser +public class Browser(IPlaywrightBrowserAccessor playwrightBrowserAccessor, BrowserType type, bool headless, int delay) : IBrowser { /// public PlaywrightBrowser InnerBrowser => playwrightBrowserAccessor.PlaywrightBrowser; @@ -22,6 +22,9 @@ public class Browser(IPlaywrightBrowserAccessor playwrightBrowserAccessor, Brows /// public BrowserType Type => type; + /// + public int Delay => delay; + /// public string Version => InnerBrowser.Version; @@ -32,6 +35,6 @@ public async Task OpenPageAsync(string url) await page.GotoAsync(url); - return new Page(new PlaywrightPageAccessor(page)); + return new Page(this, new PlaywrightPageAccessor(page)); } } diff --git a/src/OrchardCoreContrib.Testing.UI/BrowserFactory.cs b/src/OrchardCoreContrib.Testing.UI/BrowserFactory.cs index da7797a..346a5fd 100644 --- a/src/OrchardCoreContrib.Testing.UI/BrowserFactory.cs +++ b/src/OrchardCoreContrib.Testing.UI/BrowserFactory.cs @@ -20,7 +20,7 @@ public static class BrowserFactory /// Whether the browser runs in headless mode or not. /// An instance of . /// - public static async Task CreateAsync(IPlaywright playwright, BrowserType browserType, bool headless) + public static async Task CreateAsync(IPlaywright playwright, BrowserType browserType, bool headless, int delay) { var browser = browserType switch { @@ -30,6 +30,6 @@ public static async Task CreateAsync(IPlaywright playwright, BrowserTy _ => throw new NotSupportedException() }; - return new Browser(new PlaywrightBrowserAccessor(browser), browserType, headless); + return new Browser(new PlaywrightBrowserAccessor(browser), browserType, headless, delay); } } diff --git a/src/OrchardCoreContrib.Testing.UI/Element.cs b/src/OrchardCoreContrib.Testing.UI/Element.cs index 77e32d8..042e1ab 100644 --- a/src/OrchardCoreContrib.Testing.UI/Element.cs +++ b/src/OrchardCoreContrib.Testing.UI/Element.cs @@ -7,8 +7,17 @@ namespace OrchardCoreContrib.Testing.UI; /// /// The . /// The . -public class Element(ILocator locator) : IElement +public class Element(IPage page, ILocator locator) : IElement { + private readonly LocatorClickOptions _locatorClickOptions = page.Browser.Delay == 0 + ? null + : new() { Delay = page.Browser.Delay }; + private readonly LocatorPressSequentiallyOptions _locatorPressSequentiallyOptions = page.Browser.Delay == 0 + ? null + : new() { Delay = page.Browser.Delay }; + + IPage IElement.Page => page; + /// public string InnerText => locator.InnerTextAsync().GetAwaiter().GetResult(); @@ -22,8 +31,8 @@ public class Element(ILocator locator) : IElement public bool Visible => locator.IsVisibleAsync().GetAwaiter().GetResult(); /// - public async Task ClickAsync() => await locator.ClickAsync(); + public async Task ClickAsync() => await locator.ClickAsync(_locatorClickOptions); /// - public async Task TypeAsync(string text) => await locator.FillAsync(text); + public async Task TypeAsync(string text) => await locator.PressSequentiallyAsync(text, _locatorPressSequentiallyOptions); } diff --git a/src/OrchardCoreContrib.Testing.UI/IBrowser.cs b/src/OrchardCoreContrib.Testing.UI/IBrowser.cs index 2c71e5c..3651103 100644 --- a/src/OrchardCoreContrib.Testing.UI/IBrowser.cs +++ b/src/OrchardCoreContrib.Testing.UI/IBrowser.cs @@ -20,6 +20,8 @@ public interface IBrowser /// public BrowserType Type { get; } + public int Delay { get; } + /// /// Gets the browser version. /// diff --git a/src/OrchardCoreContrib.Testing.UI/IElement.cs b/src/OrchardCoreContrib.Testing.UI/IElement.cs index bb4d088..57f18d0 100644 --- a/src/OrchardCoreContrib.Testing.UI/IElement.cs +++ b/src/OrchardCoreContrib.Testing.UI/IElement.cs @@ -5,6 +5,8 @@ /// public interface IElement { + internal IPage Page { get; } + /// /// Gets the inner text of the element. /// diff --git a/src/OrchardCoreContrib.Testing.UI/IPage.cs b/src/OrchardCoreContrib.Testing.UI/IPage.cs index e65559b..838027e 100644 --- a/src/OrchardCoreContrib.Testing.UI/IPage.cs +++ b/src/OrchardCoreContrib.Testing.UI/IPage.cs @@ -10,6 +10,8 @@ public interface IPage /// public Microsoft.Playwright.IPage InnerPage { get; } + internal IBrowser Browser { get; } + /// /// Gets the page title. /// diff --git a/src/OrchardCoreContrib.Testing.UI/Page.cs b/src/OrchardCoreContrib.Testing.UI/Page.cs index c88aef6..de9be69 100644 --- a/src/OrchardCoreContrib.Testing.UI/Page.cs +++ b/src/OrchardCoreContrib.Testing.UI/Page.cs @@ -9,8 +9,15 @@ namespace OrchardCoreContrib.Testing.UI; /// Creates an instance of . /// /// The . -public class Page(IPlaywrightPageAccessor playwrightPageAccessor) : IPage +public class Page(IBrowser browser, IPlaywrightPageAccessor playwrightPageAccessor) : IPage { + private readonly PageClickOptions _pageClickOptions = browser.Delay == 0 + ? null + : new() { Delay = browser.Delay }; + + /// + IBrowser IPage.Browser => browser; + /// public Microsoft.Playwright.IPage InnerPage => playwrightPageAccessor.PlaywrightPage; @@ -28,11 +35,11 @@ public IElement FindElement(string selector) { var locator = InnerPage.Locator(selector); - return new Element(locator); + return new Element(this, locator); } /// - public async Task ClickAsync(string selector) => await FindElement(selector).ClickAsync(); + public async Task ClickAsync(string selector) => await InnerPage.ClickAsync(selector, _pageClickOptions); /// public async Task ScreenShotAsync(string path, bool fullPage = false) diff --git a/src/OrchardCoreContrib.Testing.UI/UITest.cs b/src/OrchardCoreContrib.Testing.UI/UITest.cs index 1fb1cc5..d8e1446 100644 --- a/src/OrchardCoreContrib.Testing.UI/UITest.cs +++ b/src/OrchardCoreContrib.Testing.UI/UITest.cs @@ -9,7 +9,7 @@ namespace OrchardCoreContrib.Testing.UI; /// /// The browser type that will be used during the test. Defaults to . /// Whether the browser runs in headless mode or not. Defaults to true. -public class UITest(BrowserType browserType = BrowserType.Edge, bool headless = true) : IAsyncLifetime +public class UITest(BrowserType browserType = BrowserType.Edge, bool headless = true, int delay = 0) : IAsyncLifetime { private IPlaywright _playwright; @@ -23,7 +23,7 @@ public async Task InitializeAsync() { _playwright = await Playwright.CreateAsync(); - Browser = await BrowserFactory.CreateAsync(_playwright, browserType, headless); + Browser = await BrowserFactory.CreateAsync(_playwright, browserType, headless, delay); } /// diff --git a/src/OrchardCoreContrib.Testing.UI/UITestOfT.cs b/src/OrchardCoreContrib.Testing.UI/UITestOfT.cs index 09aa109..a407cf9 100644 --- a/src/OrchardCoreContrib.Testing.UI/UITestOfT.cs +++ b/src/OrchardCoreContrib.Testing.UI/UITestOfT.cs @@ -10,7 +10,7 @@ namespace OrchardCoreContrib.Testing.UI; /// The browser type that will be used during the test. Defaults to . /// Whether the browser runs in headless mode or not. Defaults to true. /// The startup class type that will be used as entry point. -public class UITest(BrowserType browserType = BrowserType.Edge, bool headless = true) : +public class UITest(BrowserType browserType = BrowserType.Edge, bool headless = true, int delay = 0) : UITestBase(new WebApplicationFactoryFixture()), IAsyncLifetime where TStartup : class { @@ -26,7 +26,7 @@ public async Task InitializeAsync() { _playwright = await Playwright.CreateAsync(); - Browser = await BrowserFactory.CreateAsync(_playwright, browserType, headless); + Browser = await BrowserFactory.CreateAsync(_playwright, browserType, headless, delay); } /// diff --git a/test/OrchardCoreContrib.Testing.UI.Tests/BrowserFactoryTests.cs b/test/OrchardCoreContrib.Testing.UI.Tests/BrowserFactoryTests.cs index 3991792..ee06f92 100644 --- a/test/OrchardCoreContrib.Testing.UI.Tests/BrowserFactoryTests.cs +++ b/test/OrchardCoreContrib.Testing.UI.Tests/BrowserFactoryTests.cs @@ -17,7 +17,7 @@ public async Task CreateBrowser(BrowserType browserType, string playwrightBrowse var playwright = await Playwright.CreateAsync(); // Act - var browser = await BrowserFactory.CreateAsync(playwright, browserType, headless); + var browser = await BrowserFactory.CreateAsync(playwright, browserType, headless, delay: 0); // Assert Assert.NotNull(browser); @@ -35,7 +35,7 @@ public async Task CreateBrowser_ThrowsException_WhenBrowserTypeInvalid() // Act & Assert await Assert.ThrowsAsync(async () => { - await BrowserFactory.CreateAsync(playwright, BrowserType.NotSet, headless: true); + await BrowserFactory.CreateAsync(playwright, BrowserType.NotSet, headless: true, delay: 0); }); } } diff --git a/test/OrchardCoreContrib.Testing.UI.Tests/BrowserTests.cs b/test/OrchardCoreContrib.Testing.UI.Tests/BrowserTests.cs index 6b2c430..4c7c21e 100644 --- a/test/OrchardCoreContrib.Testing.UI.Tests/BrowserTests.cs +++ b/test/OrchardCoreContrib.Testing.UI.Tests/BrowserTests.cs @@ -22,7 +22,7 @@ public void ShouldCreateBrowser() var playwrightBrowserAccessor = new PlaywrightBrowserAccessor(_browserMock.Object); // Act - var browser = new Browser(playwrightBrowserAccessor, BrowserType.Edge, headless: true); + var browser = new Browser(playwrightBrowserAccessor, BrowserType.Edge, headless: true, delay: 0); // Assert Assert.NotNull(browser); @@ -37,7 +37,7 @@ public async Task ShouldOpenPage() { // Arrange var playwrightBrowserAccessor = new PlaywrightBrowserAccessor(_browserMock.Object); - var browser = new Browser(playwrightBrowserAccessor, BrowserType.Edge, headless: true); + var browser = new Browser(playwrightBrowserAccessor, BrowserType.Edge, headless: true, delay: 0); // Act var page = await browser.OpenPageAsync("https://www.orchardcore.net"); diff --git a/test/OrchardCoreContrib.Testing.UI.Tests/ElementTests.cs b/test/OrchardCoreContrib.Testing.UI.Tests/ElementTests.cs index d667fa1..bffec10 100644 --- a/test/OrchardCoreContrib.Testing.UI.Tests/ElementTests.cs +++ b/test/OrchardCoreContrib.Testing.UI.Tests/ElementTests.cs @@ -2,6 +2,17 @@ public class ElementTests { + private readonly Mock _pageMock; + + public ElementTests() + { + var playwrightPage = Mock.Of(); + var playwrightPageAccessorMock = new Mock(playwrightPage); + _pageMock = new(Mock.Of(), playwrightPageAccessorMock.Object); + //_pageMock.Setup(p => p.InnerPage) + // .Returns(playwrightPage); + } + [Fact] public void GetElementInformation() { @@ -20,7 +31,7 @@ public void GetElementInformation() .ReturnsAsync(true); // Act - var element = new Element(locatorMock.Object); + var element = new Element(_pageMock.Object, locatorMock.Object); // Assert Assert.Equal("

Orchard Core Contrib

", element.InnerHtml); @@ -34,7 +45,7 @@ public async Task ClickElement() { // Arrange var locatorMock = new Mock(); - var element = new Element(locatorMock.Object); + var element = new Element(_pageMock.Object, locatorMock.Object); // Act await element.ClickAsync(); @@ -48,13 +59,13 @@ public async Task TypeTextIntoElement() { // Arrange var locatorMock = new Mock(); - locatorMock.Setup(l => l.FillAsync(It.IsAny(), null)) + locatorMock.Setup(l => l.PressSequentiallyAsync(It.IsAny(), null)) .Callback(() => { locatorMock.Setup(l => l.InnerTextAsync(null)) .ReturnsAsync("Orchard Core Contrib"); }); - var element = new Element(locatorMock.Object); + var element = new Element(_pageMock.Object, locatorMock.Object); // Act await element.TypeAsync("Orchard Core Contrib"); diff --git a/test/OrchardCoreContrib.Testing.UI.Tests/PageTests.cs b/test/OrchardCoreContrib.Testing.UI.Tests/PageTests.cs index 0c19299..40a8ed4 100644 --- a/test/OrchardCoreContrib.Testing.UI.Tests/PageTests.cs +++ b/test/OrchardCoreContrib.Testing.UI.Tests/PageTests.cs @@ -2,6 +2,8 @@ namespace OrchardCoreContrib.Testing.UI.Tests; public class PageTests { + private readonly IBrowser _browser = Mock.Of(); + [Fact] public void ShouldCreatePage() { @@ -9,7 +11,7 @@ public void ShouldCreatePage() var playwrightPageAccessor = new PlaywrightPageAccessor(Mock.Of()); // Act - var page = new Page(playwrightPageAccessor); + var page = new Page(_browser, playwrightPageAccessor); // Assert Assert.NotNull(page); @@ -31,7 +33,7 @@ public async Task GetPageInformation() var playwrightPageAccessor = new PlaywrightPageAccessor(pageMock.Object); // Act - var page = new Page(playwrightPageAccessor); + var page = new Page(_browser, playwrightPageAccessor); await page.GoToAsync("www.occ.com"); // Assert @@ -50,7 +52,7 @@ public void ShouldFindElement() var playwrightPageAccessor = new PlaywrightPageAccessor(pageMock.Object); - var page = new Page(playwrightPageAccessor); + var page = new Page(_browser, playwrightPageAccessor); // Act var result = page.FindElement("selector"); diff --git a/test/OrchardCoreContrib.Testing.UI.Tests/PlaywrightPageHelper.cs b/test/OrchardCoreContrib.Testing.UI.Tests/PlaywrightPageHelper.cs index 45b18f7..37e7f21 100644 --- a/test/OrchardCoreContrib.Testing.UI.Tests/PlaywrightPageHelper.cs +++ b/test/OrchardCoreContrib.Testing.UI.Tests/PlaywrightPageHelper.cs @@ -5,12 +5,13 @@ internal class PlaywrightPageHelper public static async Task GotoAsync(string pageName) { var playwright = await Playwright.CreateAsync(); - var browser = await playwright.Chromium.LaunchAsync(); + var playwrightBrowser = await playwright.Chromium.LaunchAsync(); + var browser = new Browser(new PlaywrightBrowserAccessor(playwrightBrowser), BrowserType.Edge, headless: true, delay: 0); - var page = await browser.NewPageAsync(); + var page = await playwrightBrowser.NewPageAsync(); await page.GotoAsync(PageHelper.GetFullPath(pageName)); - return new Page(new PlaywrightPageAccessor(page)); + return new Page(browser, new PlaywrightPageAccessor(page)); } } From e63f00558cf0a6a81d7b02986a27505d389b4899 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Wed, 1 May 2024 14:57:58 +0300 Subject: [PATCH 2/3] Fix merge conflict --- src/OrchardCoreContrib.Testing.UI/Browser.cs | 8 ++++---- .../BrowserFactory.cs | 6 +++++- src/OrchardCoreContrib.Testing.UI/Element.cs | 13 +++++++------ src/OrchardCoreContrib.Testing.UI/IBrowser.cs | 5 +++++ src/OrchardCoreContrib.Testing.UI/Page.cs | 7 +++++-- .../UITestOptions.cs | 5 +++++ .../ElementTests.cs | 19 +++++++++++++++---- .../PageTests.cs | 16 ++++++++++++---- .../PlaywrightPageHelper.cs | 7 +++++-- 9 files changed, 63 insertions(+), 23 deletions(-) diff --git a/src/OrchardCoreContrib.Testing.UI/Browser.cs b/src/OrchardCoreContrib.Testing.UI/Browser.cs index 2211910..416e313 100644 --- a/src/OrchardCoreContrib.Testing.UI/Browser.cs +++ b/src/OrchardCoreContrib.Testing.UI/Browser.cs @@ -11,7 +11,7 @@ namespace OrchardCoreContrib.Testing.UI; /// The . /// The . /// Whether to run browser in headless mode. -public class Browser(IPlaywrightBrowserAccessor playwrightBrowserAccessor, int delay) : IBrowser +public class Browser(IPlaywrightBrowserAccessor playwrightBrowserAccessor) : IBrowser { /// public PlaywrightBrowser InnerBrowser => playwrightBrowserAccessor.PlaywrightBrowser; @@ -20,10 +20,10 @@ public class Browser(IPlaywrightBrowserAccessor playwrightBrowserAccessor, int d public BrowserType Type { get; set; } /// - public int Delay => delay; + public string Version { get; set; } = playwrightBrowserAccessor.PlaywrightBrowser.Version; /// - public string Version { get; set; } = playwrightBrowserAccessor.PlaywrightBrowser.Version; + public UITestOptions TestOptions { get; set; } /// public async Task OpenPageAsync(string url) @@ -32,7 +32,7 @@ public async Task OpenPageAsync(string url) await playwrightPage.GotoAsync(url); - var page = new Page(new PlaywrightPageAccessor(playwrightPage)) + var page = new Page(new PlaywrightPageAccessor(playwrightPage), this) { Title = await playwrightPage.TitleAsync(), Content = await playwrightPage.ContentAsync() diff --git a/src/OrchardCoreContrib.Testing.UI/BrowserFactory.cs b/src/OrchardCoreContrib.Testing.UI/BrowserFactory.cs index fbc951f..7bd959d 100644 --- a/src/OrchardCoreContrib.Testing.UI/BrowserFactory.cs +++ b/src/OrchardCoreContrib.Testing.UI/BrowserFactory.cs @@ -39,6 +39,10 @@ public static async Task CreateAsync(IPlaywright playwright, UITestOpt _ => throw new NotSupportedException() }; - return new Browser(new PlaywrightBrowserAccessor(browser)) { Type = testOptions.BrowserType }; + return new Browser(new PlaywrightBrowserAccessor(browser)) + { + Type = testOptions.BrowserType, + TestOptions = testOptions + }; } } diff --git a/src/OrchardCoreContrib.Testing.UI/Element.cs b/src/OrchardCoreContrib.Testing.UI/Element.cs index 0cf7c0b..c6e23ba 100644 --- a/src/OrchardCoreContrib.Testing.UI/Element.cs +++ b/src/OrchardCoreContrib.Testing.UI/Element.cs @@ -7,14 +7,15 @@ namespace OrchardCoreContrib.Testing.UI; /// /// The . /// The . -public class Element(IPage page, ILocator locator) : IElement +/// The . +public class Element(ILocator locator, IPage page) : IElement { - private readonly LocatorClickOptions _locatorClickOptions = page.Browser.Delay == 0 + private readonly LocatorClickOptions _locatorClickOptions = page.Browser.TestOptions.Delay == 0 ? null - : new() { Delay = page.Browser.Delay }; - private readonly LocatorPressSequentiallyOptions _locatorPressSequentiallyOptions = page.Browser.Delay == 0 + : new() { Delay = page.Browser.TestOptions.Delay }; + private readonly LocatorPressSequentiallyOptions _locatorPressSequentiallyOptions = page.Browser.TestOptions.Delay == 0 ? null - : new() { Delay = page.Browser.Delay }; + : new() { Delay = page.Browser.TestOptions.Delay }; IPage IElement.Page => page; @@ -36,7 +37,7 @@ public class Element(IPage page, ILocator locator) : IElement /// public async Task TypeAsync(string text) { - await locator.FillAsync(text); + await locator.PressSequentiallyAsync(text, _locatorPressSequentiallyOptions); InnerText = await locator.InnerTextAsync(); InnerHtml = await locator.InnerHTMLAsync(); diff --git a/src/OrchardCoreContrib.Testing.UI/IBrowser.cs b/src/OrchardCoreContrib.Testing.UI/IBrowser.cs index 11946e4..1b78e1f 100644 --- a/src/OrchardCoreContrib.Testing.UI/IBrowser.cs +++ b/src/OrchardCoreContrib.Testing.UI/IBrowser.cs @@ -10,6 +10,11 @@ public interface IBrowser /// public Microsoft.Playwright.IBrowser InnerBrowser { get; } + /// + /// Gets the test options that will be applied; + /// + public UITestOptions TestOptions { get; set; } + /// /// Gets or sets the browser type. /// diff --git a/src/OrchardCoreContrib.Testing.UI/Page.cs b/src/OrchardCoreContrib.Testing.UI/Page.cs index 979f5ad..52ac48e 100644 --- a/src/OrchardCoreContrib.Testing.UI/Page.cs +++ b/src/OrchardCoreContrib.Testing.UI/Page.cs @@ -9,11 +9,14 @@ namespace OrchardCoreContrib.Testing.UI; /// Creates an instance of . /// /// The . -public class Page(IPlaywrightPageAccessor playwrightPageAccessor) : IPage +/// The . +public class Page(IPlaywrightPageAccessor playwrightPageAccessor, IBrowser browser) : IPage { /// public Microsoft.Playwright.IPage InnerPage => playwrightPageAccessor.PlaywrightPage; + IBrowser IPage.Browser => browser; + /// public string Title { get; set; } @@ -33,7 +36,7 @@ public async Task GoToAsync(string url) public IElement FindElement(string selector) { var locator = InnerPage.Locator(selector); - var element = new Element(locator) + var element = new Element(locator, this) { InnerText = locator.InnerTextAsync().GetAwaiter().GetResult(), InnerHtml = locator.InnerHTMLAsync().GetAwaiter().GetResult(), diff --git a/src/OrchardCoreContrib.Testing.UI/UITestOptions.cs b/src/OrchardCoreContrib.Testing.UI/UITestOptions.cs index 068244c..598e587 100644 --- a/src/OrchardCoreContrib.Testing.UI/UITestOptions.cs +++ b/src/OrchardCoreContrib.Testing.UI/UITestOptions.cs @@ -14,4 +14,9 @@ public class UITestOptions /// Gets or sets the browser type to run the test on. Defaults . /// public BrowserType BrowserType { get; set; } = BrowserType.Edge; + + /// + /// Gets or sets amount of time to wait before executing each event on the page. Defaults 0. + /// + public int Delay { get; set; } = 0; } diff --git a/test/OrchardCoreContrib.Testing.UI.Tests/ElementTests.cs b/test/OrchardCoreContrib.Testing.UI.Tests/ElementTests.cs index 79a8d48..b608829 100644 --- a/test/OrchardCoreContrib.Testing.UI.Tests/ElementTests.cs +++ b/test/OrchardCoreContrib.Testing.UI.Tests/ElementTests.cs @@ -2,11 +2,22 @@ public class ElementTests { + private readonly Page _page; + + public ElementTests() + { + var browser = new Browser(new PlaywrightBrowserAccessor(Mock.Of())) + { + TestOptions = new UITestOptions() + }; + _page = new Page(new PlaywrightPageAccessor(Mock.Of()), browser); + } + [Fact] public void GetElementInformation() { // Act - var element = new Element(Mock.Of()) + var element = new Element(Mock.Of(), _page) { InnerHtml = "

Orchard Core Contrib

", InnerText = "Orchard Core Contrib", @@ -26,7 +37,7 @@ public async Task ClickElement() { // Arrange var locatorMock = new Mock(); - var element = new Element(locatorMock.Object); + var element = new Element(locatorMock.Object, _page); // Act await element.ClickAsync(); @@ -40,13 +51,13 @@ public async Task TypeTextIntoElement() { // Arrange var locatorMock = new Mock(); - locatorMock.Setup(l => l.FillAsync(It.IsAny(), null)) + locatorMock.Setup(l => l.PressSequentiallyAsync(It.IsAny(), null)) .Callback(() => { locatorMock.Setup(l => l.InnerTextAsync(null)) .ReturnsAsync("Orchard Core Contrib"); }); - var element = new Element(locatorMock.Object); + var element = new Element(locatorMock.Object, _page); // Act await element.TypeAsync("Orchard Core Contrib"); diff --git a/test/OrchardCoreContrib.Testing.UI.Tests/PageTests.cs b/test/OrchardCoreContrib.Testing.UI.Tests/PageTests.cs index 40a8ed4..6a3702b 100644 --- a/test/OrchardCoreContrib.Testing.UI.Tests/PageTests.cs +++ b/test/OrchardCoreContrib.Testing.UI.Tests/PageTests.cs @@ -2,7 +2,15 @@ namespace OrchardCoreContrib.Testing.UI.Tests; public class PageTests { - private readonly IBrowser _browser = Mock.Of(); + private readonly Browser _browser; + + public PageTests() + { + _browser = new Browser(new PlaywrightBrowserAccessor(Mock.Of())) + { + TestOptions = new UITestOptions() + }; + } [Fact] public void ShouldCreatePage() @@ -11,7 +19,7 @@ public void ShouldCreatePage() var playwrightPageAccessor = new PlaywrightPageAccessor(Mock.Of()); // Act - var page = new Page(_browser, playwrightPageAccessor); + var page = new Page(playwrightPageAccessor, _browser); // Assert Assert.NotNull(page); @@ -33,7 +41,7 @@ public async Task GetPageInformation() var playwrightPageAccessor = new PlaywrightPageAccessor(pageMock.Object); // Act - var page = new Page(_browser, playwrightPageAccessor); + var page = new Page(playwrightPageAccessor, _browser); await page.GoToAsync("www.occ.com"); // Assert @@ -52,7 +60,7 @@ public void ShouldFindElement() var playwrightPageAccessor = new PlaywrightPageAccessor(pageMock.Object); - var page = new Page(_browser, playwrightPageAccessor); + var page = new Page(playwrightPageAccessor, _browser); // Act var result = page.FindElement("selector"); diff --git a/test/OrchardCoreContrib.Testing.UI.Tests/PlaywrightPageHelper.cs b/test/OrchardCoreContrib.Testing.UI.Tests/PlaywrightPageHelper.cs index 37e7f21..bf87057 100644 --- a/test/OrchardCoreContrib.Testing.UI.Tests/PlaywrightPageHelper.cs +++ b/test/OrchardCoreContrib.Testing.UI.Tests/PlaywrightPageHelper.cs @@ -6,12 +6,15 @@ public static async Task GotoAsync(string pageName) { var playwright = await Playwright.CreateAsync(); var playwrightBrowser = await playwright.Chromium.LaunchAsync(); - var browser = new Browser(new PlaywrightBrowserAccessor(playwrightBrowser), BrowserType.Edge, headless: true, delay: 0); + var browser = new Browser(new PlaywrightBrowserAccessor(playwrightBrowser)) + { + TestOptions = new UITestOptions() + }; var page = await playwrightBrowser.NewPageAsync(); await page.GotoAsync(PageHelper.GetFullPath(pageName)); - return new Page(browser, new PlaywrightPageAccessor(page)); + return new Page(new PlaywrightPageAccessor(page), browser); } } From d770bd18e986dde1c14636fe39cdcfc768c3b242 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Thu, 2 May 2024 00:07:11 +0300 Subject: [PATCH 3/3] Refactor UITest abstraction & implementation APIs --- src/OrchardCoreContrib.Testing.UI/IUITest.cs | 19 ++++++++ src/OrchardCoreContrib.Testing.UI/UITest.cs | 44 ++++--------------- .../UITestBase.cs | 36 ++++++++++----- .../UITestBaseOfT.cs | 17 +++++++ .../UITestOfT.cs | 43 ++++-------------- 5 files changed, 80 insertions(+), 79 deletions(-) create mode 100644 src/OrchardCoreContrib.Testing.UI/IUITest.cs create mode 100644 src/OrchardCoreContrib.Testing.UI/UITestBaseOfT.cs diff --git a/src/OrchardCoreContrib.Testing.UI/IUITest.cs b/src/OrchardCoreContrib.Testing.UI/IUITest.cs new file mode 100644 index 0000000..990f653 --- /dev/null +++ b/src/OrchardCoreContrib.Testing.UI/IUITest.cs @@ -0,0 +1,19 @@ +using Xunit; + +namespace OrchardCoreContrib.Testing.UI; + +/// +/// Represents a contract for UI test. +/// +public interface IUITest : IAsyncLifetime +{ + /// + /// Gets or sets the browser instance to be used during the test. + /// + public IBrowser Browser { get; set; } + + /// + /// Gets the options used during the test. + /// + public UITestOptions Options { get; } +} diff --git a/src/OrchardCoreContrib.Testing.UI/UITest.cs b/src/OrchardCoreContrib.Testing.UI/UITest.cs index e6cfe53..9e98153 100644 --- a/src/OrchardCoreContrib.Testing.UI/UITest.cs +++ b/src/OrchardCoreContrib.Testing.UI/UITest.cs @@ -1,43 +1,17 @@ -using Microsoft.Playwright; -using Xunit; - -namespace OrchardCoreContrib.Testing.UI; +namespace OrchardCoreContrib.Testing.UI; /// /// Represents a UI testing class. /// /// The browser type that will be used during the test. Defaults to . /// Whether the browser runs in headless mode or not. Defaults to true. -public class UITest(BrowserType browserType = BrowserType.Edge, bool headless = true) : IAsyncLifetime -{ - private IPlaywright _playwright; - - /// - /// Gets the browser instance to be used during the test. - /// - public IBrowser Browser { get; private set; } - - public UITestOptions Options { get; private set; } - - /// - public async Task InitializeAsync() +/// The amount of time to wait between execute two actions. Defaults to 0. +public class UITest(BrowserType browserType = BrowserType.Edge, bool headless = true, int delay = 0) + : UITestBase(new UITestOptions { - Options = new UITestOptions - { - BrowserType = browserType, - Headless = headless - }; - - _playwright = await Playwright.CreateAsync(); - - Browser = await BrowserFactory.CreateAsync(_playwright, Options); - } - - /// - public async Task DisposeAsync() - { - _playwright.Dispose(); - - await Task.CompletedTask; - } + BrowserType = browserType, + Headless = headless, + Delay = delay + }) +{ } diff --git a/src/OrchardCoreContrib.Testing.UI/UITestBase.cs b/src/OrchardCoreContrib.Testing.UI/UITestBase.cs index 5bd552f..5271059 100644 --- a/src/OrchardCoreContrib.Testing.UI/UITestBase.cs +++ b/src/OrchardCoreContrib.Testing.UI/UITestBase.cs @@ -1,18 +1,34 @@ -using OrchardCoreContrib.Testing.UI.Infrastructure; +using Microsoft.Playwright; namespace OrchardCoreContrib.Testing.UI; -/// -/// Represents a base class for UI testing. -/// -/// The startup class that will be used as entry point. -/// The . -public abstract class UITestBase(WebApplicationFactoryFixture fixture) where TStartup : class +public abstract class UITestBase(UITestOptions testOptions) : IUITest { + private IPlaywright _playwright; + + /// + /// Gets or sets the browser instance to be used during the test. + /// + public IBrowser Browser { get; set; } + /// - /// Gets the base URL used for the tested website. + /// Gets the options used during the test. /// - public string BaseUrl => fixture.ServerAddress; + public UITestOptions Options => testOptions; + + /// + public virtual async Task InitializeAsync() + { + _playwright = await Playwright.CreateAsync(); + + Browser = await BrowserFactory.CreateAsync(_playwright, Options); + } + + /// + public virtual async Task DisposeAsync() + { + _playwright.Dispose(); - public UITestOptions Options { get; protected set; } + await Task.CompletedTask; + } } diff --git a/src/OrchardCoreContrib.Testing.UI/UITestBaseOfT.cs b/src/OrchardCoreContrib.Testing.UI/UITestBaseOfT.cs new file mode 100644 index 0000000..b62826b --- /dev/null +++ b/src/OrchardCoreContrib.Testing.UI/UITestBaseOfT.cs @@ -0,0 +1,17 @@ +using OrchardCoreContrib.Testing.UI.Infrastructure; + +namespace OrchardCoreContrib.Testing.UI; + +/// +/// Represents a base class for UI testing. +/// +/// The startup class that will be used as entry point. +/// The . +public abstract class UITestBase(WebApplicationFactoryFixture fixture, UITestOptions testOptions) + : UITestBase(testOptions) where TStartup : class +{ + /// + /// Gets the base URL used for the tested website. + /// + public string BaseUrl => fixture.ServerAddress; +} diff --git a/src/OrchardCoreContrib.Testing.UI/UITestOfT.cs b/src/OrchardCoreContrib.Testing.UI/UITestOfT.cs index 8f3efab..7bc998d 100644 --- a/src/OrchardCoreContrib.Testing.UI/UITestOfT.cs +++ b/src/OrchardCoreContrib.Testing.UI/UITestOfT.cs @@ -1,6 +1,4 @@ -using Microsoft.Playwright; -using OrchardCoreContrib.Testing.UI.Infrastructure; -using Xunit; +using OrchardCoreContrib.Testing.UI.Infrastructure; namespace OrchardCoreContrib.Testing.UI; @@ -9,37 +7,14 @@ namespace OrchardCoreContrib.Testing.UI; /// /// The browser type that will be used during the test. Defaults to . /// Whether the browser runs in headless mode or not. Defaults to true. +/// The amount of time to wait between execute two actions. Defaults to 0. /// The startup class type that will be used as entry point. -public class UITest(BrowserType browserType = BrowserType.Edge, bool headless = true) : - UITestBase(new WebApplicationFactoryFixture()), - IAsyncLifetime where TStartup : class -{ - private IPlaywright _playwright; - - /// - /// Gets the browser instance to be used during the test. - /// - public IBrowser Browser { get; private set; } - - /// - public async Task InitializeAsync() +public class UITest(BrowserType browserType = BrowserType.Edge, bool headless = true, int delay = 0) : + UITestBase(new WebApplicationFactoryFixture(), new UITestOptions { - Options = new UITestOptions - { - BrowserType = browserType, - Headless = headless - }; - - _playwright = await Playwright.CreateAsync(); - - Browser = await BrowserFactory.CreateAsync(_playwright, Options); - } - - /// - public async Task DisposeAsync() - { - _playwright.Dispose(); - - await Task.CompletedTask; - } + BrowserType = browserType, + Headless = headless, + Delay = delay + }), IUITest where TStartup : class +{ }