Skip to content

Commit

Permalink
Merge pull request #8 from OrchardCoreContrib/delay-execution
Browse files Browse the repository at this point in the history
Ability to delay the execution in headed mode
  • Loading branch information
hishamco authored May 1, 2024
2 parents 0f1d717 + d770bd1 commit 8526ad5
Show file tree
Hide file tree
Showing 16 changed files with 156 additions and 96 deletions.
5 changes: 4 additions & 1 deletion src/OrchardCoreContrib.Testing.UI/Browser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,17 @@ public class Browser(IPlaywrightBrowserAccessor playwrightBrowserAccessor) : IBr
/// <inheritdoc/>
public string Version { get; set; } = playwrightBrowserAccessor.PlaywrightBrowser.Version;

/// <inheritdoc/>
public UITestOptions TestOptions { get; set; }

/// <inheritdoc/>
public async Task<IPage> OpenPageAsync(string url)
{
var playwrightPage = await InnerBrowser.NewPageAsync();

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()
Expand Down
6 changes: 5 additions & 1 deletion src/OrchardCoreContrib.Testing.UI/BrowserFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ public static async Task<IBrowser> 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
};
}
}
16 changes: 13 additions & 3 deletions src/OrchardCoreContrib.Testing.UI/Element.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,18 @@ namespace OrchardCoreContrib.Testing.UI;
/// </summary>
/// <remarks>The <see cref="Element"/>.</remarks>
/// <param name="locator">The <see cref="ILocator"/>.</param>
public class Element(ILocator locator) : IElement
/// <param name="IPage">The <see cref="page"/>.</param>
public class Element(ILocator locator, IPage page) : IElement
{
private readonly LocatorClickOptions _locatorClickOptions = page.Browser.TestOptions.Delay == 0
? null
: new() { Delay = page.Browser.TestOptions.Delay };
private readonly LocatorPressSequentiallyOptions _locatorPressSequentiallyOptions = page.Browser.TestOptions.Delay == 0
? null
: new() { Delay = page.Browser.TestOptions.Delay };

IPage IElement.Page => page;

/// <inheritdoc/>
public string InnerText { get; set; }

Expand All @@ -22,12 +32,12 @@ public class Element(ILocator locator) : IElement
public bool Visible { get; set; }

/// <inheritdoc/>
public async Task ClickAsync() => await locator.ClickAsync();
public async Task ClickAsync() => await locator.ClickAsync(_locatorClickOptions);

/// <inheritdoc/>
public async Task TypeAsync(string text)
{
await locator.FillAsync(text);
await locator.PressSequentiallyAsync(text, _locatorPressSequentiallyOptions);

InnerText = await locator.InnerTextAsync();
InnerHtml = await locator.InnerHTMLAsync();
Expand Down
5 changes: 5 additions & 0 deletions src/OrchardCoreContrib.Testing.UI/IBrowser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ public interface IBrowser
/// </summary>
public Microsoft.Playwright.IBrowser InnerBrowser { get; }

/// <summary>
/// Gets the test options that will be applied;
/// </summary>
public UITestOptions TestOptions { get; set; }

/// <summary>
/// Gets or sets the browser type.
/// </summary>
Expand Down
2 changes: 2 additions & 0 deletions src/OrchardCoreContrib.Testing.UI/IElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
/// </summary>
public interface IElement
{
internal IPage Page { get; }

/// <summary>
/// Gets the inner text of the element.
/// </summary>
Expand Down
2 changes: 2 additions & 0 deletions src/OrchardCoreContrib.Testing.UI/IPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public interface IPage
/// </summary>
public Microsoft.Playwright.IPage InnerPage { get; }

internal IBrowser Browser { get; }

/// <summary>
/// Gets or sets the page title.
/// </summary>
Expand Down
19 changes: 19 additions & 0 deletions src/OrchardCoreContrib.Testing.UI/IUITest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Xunit;

namespace OrchardCoreContrib.Testing.UI;

/// <summary>
/// Represents a contract for UI test.
/// </summary>
public interface IUITest : IAsyncLifetime
{
/// <summary>
/// Gets or sets the browser instance to be used during the test.
/// </summary>
public IBrowser Browser { get; set; }

/// <summary>
/// Gets the options used during the test.
/// </summary>
public UITestOptions Options { get; }
}
7 changes: 5 additions & 2 deletions src/OrchardCoreContrib.Testing.UI/Page.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@ namespace OrchardCoreContrib.Testing.UI;
/// Creates an instance of <see cref="Page"/>.
/// </remarks>
/// <param name="playwrightPageAccessor">The <see cref="IPlaywrightPageAccessor"/>.</param>
public class Page(IPlaywrightPageAccessor playwrightPageAccessor) : IPage
/// <param name="browser">The <see cref="IBrowser"/>.</param>
public class Page(IPlaywrightPageAccessor playwrightPageAccessor, IBrowser browser) : IPage
{
/// <inheritdoc/>
public Microsoft.Playwright.IPage InnerPage => playwrightPageAccessor.PlaywrightPage;

IBrowser IPage.Browser => browser;

/// <inheritdoc/>
public string Title { get; set; }

Expand All @@ -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(),
Expand Down
44 changes: 9 additions & 35 deletions src/OrchardCoreContrib.Testing.UI/UITest.cs
Original file line number Diff line number Diff line change
@@ -1,43 +1,17 @@
using Microsoft.Playwright;
using Xunit;

namespace OrchardCoreContrib.Testing.UI;
namespace OrchardCoreContrib.Testing.UI;

/// <summary>
/// Represents a UI testing class.
/// </summary>
/// <param name="browserType">The browser type that will be used during the test. Defaults to <see cref="BrowserType.Edge"/>.</param>
/// <param name="headless">Whether the browser runs in headless mode or not. Defaults to <c>true</c>.</param>
public class UITest(BrowserType browserType = BrowserType.Edge, bool headless = true) : IAsyncLifetime
{
private IPlaywright _playwright;

/// <summary>
/// Gets the browser instance to be used during the test.
/// </summary>
public IBrowser Browser { get; private set; }

public UITestOptions Options { get; private set; }

/// <inheritdoc/>
public async Task InitializeAsync()
/// <param name="delay">The amount of time to wait between execute two actions. Defaults to <c>0</c>.</param>
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);
}

/// <inheritdoc/>
public async Task DisposeAsync()
{
_playwright.Dispose();

await Task.CompletedTask;
}
BrowserType = browserType,
Headless = headless,
Delay = delay
})
{
}
36 changes: 26 additions & 10 deletions src/OrchardCoreContrib.Testing.UI/UITestBase.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,34 @@
using OrchardCoreContrib.Testing.UI.Infrastructure;
using Microsoft.Playwright;

namespace OrchardCoreContrib.Testing.UI;

/// <summary>
/// Represents a base class for UI testing.
/// </summary>
/// <typeparam name="TStartup">The startup class that will be used as entry point.</typeparam>
/// <param name="fixture">The <see cref="WebApplicationFactoryFixture{TStartup}"/>.</param>
public abstract class UITestBase<TStartup>(WebApplicationFactoryFixture<TStartup> fixture) where TStartup : class
public abstract class UITestBase(UITestOptions testOptions) : IUITest
{
private IPlaywright _playwright;

/// <summary>
/// Gets or sets the browser instance to be used during the test.
/// </summary>
public IBrowser Browser { get; set; }

/// <summary>
/// Gets the base URL used for the tested website.
/// Gets the options used during the test.
/// </summary>
public string BaseUrl => fixture.ServerAddress;
public UITestOptions Options => testOptions;

/// <inheritdoc/>
public virtual async Task InitializeAsync()
{
_playwright = await Playwright.CreateAsync();

Browser = await BrowserFactory.CreateAsync(_playwright, Options);
}

/// <inheritdoc/>
public virtual async Task DisposeAsync()
{
_playwright.Dispose();

public UITestOptions Options { get; protected set; }
await Task.CompletedTask;
}
}
17 changes: 17 additions & 0 deletions src/OrchardCoreContrib.Testing.UI/UITestBaseOfT.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using OrchardCoreContrib.Testing.UI.Infrastructure;

namespace OrchardCoreContrib.Testing.UI;

/// <summary>
/// Represents a base class for UI testing.
/// </summary>
/// <typeparam name="TStartup">The startup class that will be used as entry point.</typeparam>
/// <param name="fixture">The <see cref="WebApplicationFactoryFixture{TStartup}"/>.</param>
public abstract class UITestBase<TStartup>(WebApplicationFactoryFixture<TStartup> fixture, UITestOptions testOptions)
: UITestBase(testOptions) where TStartup : class
{
/// <summary>
/// Gets the base URL used for the tested website.
/// </summary>
public string BaseUrl => fixture.ServerAddress;
}
43 changes: 9 additions & 34 deletions src/OrchardCoreContrib.Testing.UI/UITestOfT.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using Microsoft.Playwright;
using OrchardCoreContrib.Testing.UI.Infrastructure;
using Xunit;
using OrchardCoreContrib.Testing.UI.Infrastructure;

namespace OrchardCoreContrib.Testing.UI;

Expand All @@ -9,37 +7,14 @@ namespace OrchardCoreContrib.Testing.UI;
/// </summary>
/// <param name="browserType">The browser type that will be used during the test. Defaults to <see cref="BrowserType.Edge"/>.</param>
/// <param name="headless">Whether the browser runs in headless mode or not. Defaults to <c>true</c>.</param>
/// <param name="delay">The amount of time to wait between execute two actions. Defaults to <c>0</c>.</param>
/// <typeparam name="TStartup">The startup class type that will be used as entry point.</typeparam>
public class UITest<TStartup>(BrowserType browserType = BrowserType.Edge, bool headless = true) :
UITestBase<TStartup>(new WebApplicationFactoryFixture<TStartup>()),
IAsyncLifetime where TStartup : class
{
private IPlaywright _playwright;

/// <summary>
/// Gets the browser instance to be used during the test.
/// </summary>
public IBrowser Browser { get; private set; }

/// <inheritdoc/>
public async Task InitializeAsync()
public class UITest<TStartup>(BrowserType browserType = BrowserType.Edge, bool headless = true, int delay = 0) :
UITestBase<TStartup>(new WebApplicationFactoryFixture<TStartup>(), new UITestOptions
{
Options = new UITestOptions
{
BrowserType = browserType,
Headless = headless
};

_playwright = await Playwright.CreateAsync();

Browser = await BrowserFactory.CreateAsync(_playwright, Options);
}

/// <inheritdoc/>
public async Task DisposeAsync()
{
_playwright.Dispose();

await Task.CompletedTask;
}
BrowserType = browserType,
Headless = headless,
Delay = delay
}), IUITest where TStartup : class
{
}
5 changes: 5 additions & 0 deletions src/OrchardCoreContrib.Testing.UI/UITestOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,9 @@ public class UITestOptions
/// Gets or sets the browser type to run the test on. Defaults <see cref="BrowserType.Edge"/>.
/// </summary>
public BrowserType BrowserType { get; set; } = BrowserType.Edge;

/// <summary>
/// Gets or sets amount of time to wait before executing each event on the page. Defaults <c>0</c>.
/// </summary>
public int Delay { get; set; } = 0;
}
19 changes: 15 additions & 4 deletions test/OrchardCoreContrib.Testing.UI.Tests/ElementTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,22 @@

public class ElementTests
{
private readonly Page _page;

public ElementTests()
{
var browser = new Browser(new PlaywrightBrowserAccessor(Mock.Of<Microsoft.Playwright.IBrowser>()))
{
TestOptions = new UITestOptions()
};
_page = new Page(new PlaywrightPageAccessor(Mock.Of<Microsoft.Playwright.IPage>()), browser);
}

[Fact]
public void GetElementInformation()
{
// Act
var element = new Element(Mock.Of<ILocator>())
var element = new Element(Mock.Of<ILocator>(), _page)
{
InnerHtml = "<h1>Orchard Core Contrib</h1>",
InnerText = "Orchard Core Contrib",
Expand All @@ -26,7 +37,7 @@ public async Task ClickElement()
{
// Arrange
var locatorMock = new Mock<ILocator>();
var element = new Element(locatorMock.Object);
var element = new Element(locatorMock.Object, _page);

// Act
await element.ClickAsync();
Expand All @@ -40,13 +51,13 @@ public async Task TypeTextIntoElement()
{
// Arrange
var locatorMock = new Mock<ILocator>();
locatorMock.Setup(l => l.FillAsync(It.IsAny<string>(), null))
locatorMock.Setup(l => l.PressSequentiallyAsync(It.IsAny<string>(), 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");
Expand Down
Loading

0 comments on commit 8526ad5

Please sign in to comment.