Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Ability to delay the execution in headed mode #8

Merged
merged 4 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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