Skip to content

Commit

Permalink
- draft integration of playwright for kiota web
Browse files Browse the repository at this point in the history
Signed-off-by: Vincent Biret <[email protected]>
  • Loading branch information
baywet committed Nov 17, 2022
1 parent 61c8de1 commit 523e5c4
Show file tree
Hide file tree
Showing 5 changed files with 308 additions and 0 deletions.
7 changes: 7 additions & 0 deletions kiota.sln
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{EAAC5CEA-33B
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kiota.Web", "src\Kiota.Web\Kiota.Web.csproj", "{C27E6F75-8E64-4F3D-8EA0-E632BFAFF600}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kiota.Web.Tests", "tests\Kiota.Web.Tests\Kiota.Web.Tests.csproj", "{A2584ED3-5C92-4BC7-9120-D97F5404B52C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -49,6 +51,10 @@ Global
{C27E6F75-8E64-4F3D-8EA0-E632BFAFF600}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C27E6F75-8E64-4F3D-8EA0-E632BFAFF600}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C27E6F75-8E64-4F3D-8EA0-E632BFAFF600}.Release|Any CPU.Build.0 = Release|Any CPU
{A2584ED3-5C92-4BC7-9120-D97F5404B52C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A2584ED3-5C92-4BC7-9120-D97F5404B52C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A2584ED3-5C92-4BC7-9120-D97F5404B52C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A2584ED3-5C92-4BC7-9120-D97F5404B52C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -59,5 +65,6 @@ Global
GlobalSection(NestedProjects) = preSolution
{E4C108A5-A13F-4C3F-B32A-86210A4EC52A} = {2DF34BB8-B19F-4623-9E3D-9F59A14C0660}
{C27E6F75-8E64-4F3D-8EA0-E632BFAFF600} = {EAAC5CEA-33B8-495D-9CD0-B36794B8AFE7}
{A2584ED3-5C92-4BC7-9120-D97F5404B52C} = {2DF34BB8-B19F-4623-9E3D-9F59A14C0660}
EndGlobalSection
EndGlobal
26 changes: 26 additions & 0 deletions tests/Kiota.Web.Tests/Kiota.Web.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.8.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="Microsoft.Playwright" Version="1.27.2" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

</Project>
250 changes: 250 additions & 0 deletions tests/Kiota.Web.Tests/PlaywrightFixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
using FluentAssertions;
using Microsoft.Playwright;
using System.Diagnostics;
using System.Text.RegularExpressions;

namespace Kiota.Web.Tests;
/// <summary>
/// Playwright fixture implementing an asynchronous life cycle.
/// </summary>
public class PlaywrightFixture : IAsyncLifetime
{
/// <summary>
/// Playwright module.
/// </summary>
public IPlaywright? Playwright
{
get; private set;
}
/// <summary>
/// Chromium lazy initializer.
/// </summary>
public IBrowser? ChromiumBrowser
{
get; private set;
}

/// <summary>
/// Firefox lazy initializer.
/// </summary>
public IBrowser? FirefoxBrowser
{
get; private set;
}

/// <summary>
/// Webkit lazy initializer.
/// </summary>
public IBrowser? WebkitBrowser
{
get; private set;
}
/// <summary>
/// The process running the blazor app.
/// </summary>
public Process? DotnetRunProcess { get; private set; }
/// <summary>
/// The URL the app is hosted at
/// </summary>
public string? DotnetUrl { get; private set; }
private static readonly Regex urlRegex = new Regex(@"Now listening on: (?<url>.*)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
/// <summary>
/// Initialize the Playwright fixture.
/// </summary>
public async Task InitializeAsync()
{
var launchOptions = new BrowserTypeLaunchOptions
{
Headless = true,
};

// Install Playwright and its dependencies.
InstallPlaywright();
// Create Playwright module.
Playwright = await Microsoft.Playwright.Playwright.CreateAsync();
// Setup Browser lazy initializers.
ChromiumBrowser = await Playwright.Chromium.LaunchAsync(launchOptions);
FirefoxBrowser = await Playwright.Firefox.LaunchAsync(launchOptions);
WebkitBrowser = await Playwright.Webkit.LaunchAsync(launchOptions);

// Start the blazor app.
DotnetRunProcess = new();
DotnetRunProcess.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
{
// Prepend line numbers to each line of the output.
if (!string.IsNullOrEmpty(e.Data) && urlRegex.IsMatch(e.Data))
{
var match = urlRegex.Match(e.Data);
DotnetUrl = match.Groups["url"].Value;
}
});
DotnetRunProcess.StartInfo = new() {
FileName = "dotnet",
Arguments = "run",
WorkingDirectory = Path.GetFullPath("../../../../../src/Kiota.Web"),
RedirectStandardOutput = true,
};
DotnetRunProcess.Start();
DotnetRunProcess.BeginOutputReadLine();
var secondsToWaitForRunToStart = 30;
while (DotnetUrl == null && secondsToWaitForRunToStart > 0)
{
secondsToWaitForRunToStart--;
await Task.Delay(1000);
}
if (DotnetUrl == null) {
DotnetRunProcess.Kill(true);
throw new Exception("Failed to start the blazor app.");
}
DotnetRunProcess.CancelOutputRead();
}
/// <summary>
/// Dispose all Playwright module resources.
/// </summary>
public async Task DisposeAsync()
{
await (ChromiumBrowser?.CloseAsync() ?? Task.CompletedTask);
await (FirefoxBrowser?.CloseAsync() ?? Task.CompletedTask);
await (WebkitBrowser?.CloseAsync() ?? Task.CompletedTask);
Playwright?.Dispose();
Playwright = null;
DotnetRunProcess?.Kill(true);
DotnetRunProcess?.Dispose();
}

/// <summary>
/// Install and deploy all binaries Playwright may need.
/// </summary>
private static void InstallPlaywright()
{
var exitCode = Microsoft.Playwright.Program.Main(
new[] { "install-deps" });
if (exitCode != 0)
{
throw new Exception(
$"Playwright exited with code {exitCode} on install-deps");
}
exitCode = Microsoft.Playwright.Program.Main(new[] { "install" });
if (exitCode != 0)
{
throw new Exception(
$"Playwright exited with code {exitCode} on install");
}
}

/// <summary>
/// PlaywrightCollection name that is used in the Collection
/// attribute on each test classes.
/// Like "[Collection(PlaywrightFixture.PlaywrightCollection)]"
/// </summary>
public const string PlaywrightCollection =
nameof(PlaywrightCollection);
[CollectionDefinition(PlaywrightCollection)]
public class PlaywrightCollectionDefinition
: ICollectionFixture<PlaywrightFixture>
{
// This class is just xUnit plumbing code to apply
// [CollectionDefinition] and the ICollectionFixture<>
// interfaces. Witch in our case is parametrized
// with the PlaywrightFixture.
}

/// <summary>
/// Open a Browser page and navigate to the given URL before
/// applying the given test handler.
/// </summary>
/// <param name="url">URL to navigate to.</param>
/// <param name="testHandler">Test handler to apply on the page.
/// </param>
/// <param name="browserType">The Browser to use to open the page.
/// </param>
/// <returns>The GotoPage task.</returns>
public async Task GotoPageAsync(
string url,
Func<IPage, Task> testHandler,
Browser browserType)
{
// select and launch the browser.
var browser = SelectBrowser(browserType);

// Open a new page with an option to ignore HTTPS errors
await using var context = await browser.NewContextAsync(
new BrowserNewContextOptions
{
IgnoreHTTPSErrors = true
}).ConfigureAwait(false);

// Start tracing before creating the page.
await context.Tracing.StartAsync(new TracingStartOptions()
{
Screenshots = true,
Snapshots = true,
Sources = true
});

var page = await context.NewPageAsync().ConfigureAwait(false);

page.Should().NotBeNull();
try
{
// Navigate to the given URL and wait until loading
// network activity is done.
var gotoResult = await page.GotoAsync(
url,
new PageGotoOptions
{
WaitUntil = WaitUntilState.NetworkIdle
});
if (gotoResult == null)
{
throw new Exception(
$"Failed to navigate to {url}.");
}
gotoResult.Should().NotBeNull();
await gotoResult.FinishedAsync();
gotoResult.Ok.Should().BeTrue();
// Run the actual test logic.
await testHandler(page);
}
finally
{
// Make sure the page is closed
await page.CloseAsync();

// Stop tracing and save data into a zip archive.
await context.Tracing.StopAsync(new TracingStopOptions()
{
Path = "trace.zip"
});
}
}
/// <summary>
/// Select the IBrowser instance depending on the given browser
/// enumeration value.
/// </summary>
/// <param name="browser">The browser to select.</param>
/// <returns>The selected IBrowser instance.</returns>
private IBrowser SelectBrowser(Browser browser)
{
return browser switch
{
Browser.Chromium => ChromiumBrowser ?? throw new Exception(
"Chromium browser is not initialized"),
Browser.Firefox => FirefoxBrowser ?? throw new Exception(
"Firefox browser is not initialized"),
Browser.Webkit => WebkitBrowser ?? throw new Exception(
"Webkit browser is not initialized"),
_ => throw new NotImplementedException(),
};
}
}

/// <summary>
/// Browser types we can use in the PlaywrightFixture.
/// </summary>
public enum Browser
{
Chromium,
Firefox,
Webkit,
}
24 changes: 24 additions & 0 deletions tests/Kiota.Web.Tests/UnitTest1.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace Kiota.Web.Tests;

[Collection(PlaywrightFixture.PlaywrightCollection)]
public class UnitTest1
{
private readonly PlaywrightFixture playwrightFixture;
public UnitTest1(PlaywrightFixture playwrightFixture)
{
this.playwrightFixture = playwrightFixture;
}
[Fact]
public async Task MyFirstTest()
{
// Open a page and run test logic.
await playwrightFixture.GotoPageAsync(
playwrightFixture.DotnetUrl!,
async (page) =>
{
await page.Locator("text=Search").ClickAsync();
},
Browser.Chromium);
await playwrightFixture.DisposeAsync(); //TODO run that at the end of the test suite
}
}
1 change: 1 addition & 0 deletions tests/Kiota.Web.Tests/Usings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
global using Xunit;

0 comments on commit 523e5c4

Please sign in to comment.