зеркало из https://github.com/dotnet/aspnetcore.git
Upgrade Playwright (#38414)
* Upgrade `playwright-sharp-tool`
https://www.nuget.org/packages/playwright-sharp-tool
Contributes towards https://github.com/dotnet/aspnetcore/issues/30882.
* Update to latest v1.16.1 from GitHub
https://github.com/microsoft/playwright-dotnet/releases/tag/v1.16.1
* Update to use Microsoft.Playwright
* Update references to reflect `Microsoft.Playwright`
* Update dotnet-tools.json
* Upgrade System.CommandLine
* Adapt to breaking API changes in Playwright
* Upgrade dotnet-serve
* Add Microsoft.Playwright.CLI
* Revert "Upgrade System.CommandLine"
This reverts commit cc46e9cfb7
.
* Fix build
The build failed. Fix the build errors and run again.
C:\h\w\AA180980\w\9ED808A4\e\RunTests\RunTests.csproj : warning NU1604: Project dependency Microsoft.Playwright does not contain an inclusive lower bound. Include a lower bound in the dependency version to ensure consistent restore results.
C:\h\w\AA180980\w\9ED808A4\e\RunTests\TestRunner.cs(124,35): error CS7036: There is no argument given that corresponds to the required formal parameter 'arguments' of 'ProcessUtil.RunAsync(string, string, string?, string?, bool, IDictionary<string, string?>?, Action<string>?, Action<string>?, Action<int>?, CancellationToken)' [C:\h\w\AA180980\w\9ED808A4\e\RunTests\RunTests.csproj]
* Remove semaphore for websocket events
* Update playwrightSettings based on breaking changes
* npx based playwright install
* npm install playwright
* Install node in helix env
* Use DOTNET_ROLL_FORWARD with `dotnet` `playwright` tool
* Cleanup
* Update playwright tool usage
* DOTNET_ROLL_FORWARD in TestRunner
* Specify project dir
* Playwright install without cli
* Update TestRunner.cs
* Update TestRunner.cs
* Re-enable helix playwright tests
* Upgrade Playwright to 1.17.3, CLI to 1.2.2
* Fix spacing
* Remove DOTNET_ROLL_FORWARD
* PR Feedback
* Remove temp project workaround.
* Fix package lowerbound issue
* Update Versions.props
* Update BrowserManager.cs
* Remove `Installing Microsoft.Playwright.CLI`
* Disable playwright tests in helix
This commit is contained in:
Родитель
b4dc2153d7
Коммит
3129207847
|
@ -3,15 +3,15 @@
|
|||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-serve": {
|
||||
"version": "1.7.139",
|
||||
"version": "1.8.15",
|
||||
"commands": [
|
||||
"dotnet-serve"
|
||||
]
|
||||
},
|
||||
"playwright-sharp-tool": {
|
||||
"version": "0.170.2",
|
||||
"Microsoft.Playwright.CLI": {
|
||||
"version": "1.2.2",
|
||||
"commands": [
|
||||
"playwright-sharp"
|
||||
"playwright"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -192,7 +192,7 @@ and are generated based on the last package release.
|
|||
<LatestPackageReference Include="NuGet.Frameworks" />
|
||||
<LatestPackageReference Include="NuGet.Versioning" />
|
||||
<LatestPackageReference Include="Photino.NET" />
|
||||
<LatestPackageReference Include="PlaywrightSharp" />
|
||||
<LatestPackageReference Include="Microsoft.Playwright" />
|
||||
<LatestPackageReference Include="Polly" />
|
||||
<LatestPackageReference Include="Polly.Extensions.Http" />
|
||||
<LatestPackageReference Include="Selenium.Support" />
|
||||
|
|
|
@ -260,7 +260,7 @@
|
|||
<NewtonsoftJsonVersion>13.0.1</NewtonsoftJsonVersion>
|
||||
<NSwagApiDescriptionClientVersion>13.0.4</NSwagApiDescriptionClientVersion>
|
||||
<PhotinoNETVersion>1.1.6</PhotinoNETVersion>
|
||||
<PlaywrightSharpVersion>0.192.0</PlaywrightSharpVersion>
|
||||
<MicrosoftPlaywrightVersion>1.17.3</MicrosoftPlaywrightVersion>
|
||||
<PollyExtensionsHttpVersion>3.0.0</PollyExtensionsHttpVersion>
|
||||
<PollyVersion>7.2.2</PollyVersion>
|
||||
<SeleniumSupportVersion>4.1.0</SeleniumSupportVersion>
|
||||
|
|
|
@ -8,6 +8,6 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20158.1" />
|
||||
<PackageReference Condition=" '$(InstallPlaywright)' == 'true' " Include="PlaywrightSharp" Version="0.192.0" />
|
||||
<PackageReference Condition=" '$(InstallPlaywright)' == 'true' " Include="Microsoft.Playwright" Version="1.17.3" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -9,7 +9,7 @@ using System.Runtime.InteropServices;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
#if INSTALLPLAYWRIGHT
|
||||
using PlaywrightSharp;
|
||||
using Microsoft.Playwright;
|
||||
#endif
|
||||
|
||||
namespace RunTests
|
||||
|
@ -55,9 +55,6 @@ namespace RunTests
|
|||
var playwrightBrowsers = Environment.GetEnvironmentVariable("PLAYWRIGHT_BROWSERS_PATH");
|
||||
Console.WriteLine($"Setting PLAYWRIGHT_BROWSERS_PATH: {playwrightBrowsers}");
|
||||
EnvironmentVariables.Add("PLAYWRIGHT_BROWSERS_PATH", playwrightBrowsers);
|
||||
var playrightDriver = Environment.GetEnvironmentVariable("PLAYWRIGHT_DRIVER_PATH");
|
||||
Console.WriteLine($"Setting PLAYWRIGHT_DRIVER_PATH: {playrightDriver}");
|
||||
EnvironmentVariables.Add("PLAYWRIGHT_DRIVER_PATH", playrightDriver);
|
||||
#else
|
||||
Console.WriteLine($"Skipping setting PLAYWRIGHT_BROWSERS_PATH");
|
||||
#endif
|
||||
|
@ -112,8 +109,10 @@ namespace RunTests
|
|||
{
|
||||
try
|
||||
{
|
||||
Console.WriteLine($"Installing Playwright to Browsers: {Environment.GetEnvironmentVariable("PLAYWRIGHT_BROWSERS_PATH")} Driver: {Environment.GetEnvironmentVariable("PLAYWRIGHT_DRIVER_PATH")}");
|
||||
await Playwright.InstallAsync(Environment.GetEnvironmentVariable("PLAYWRIGHT_BROWSERS_PATH"), Environment.GetEnvironmentVariable("PLAYWRIGHT_DRIVER_PATH"));
|
||||
Console.WriteLine($"Installing Playwright Browsers to {Environment.GetEnvironmentVariable("PLAYWRIGHT_BROWSERS_PATH")}");
|
||||
|
||||
var exitCode = Microsoft.Playwright.Program.Main(new[] { "install" });
|
||||
|
||||
DisplayContents(Environment.GetEnvironmentVariable("PLAYWRIGHT_BROWSERS_PATH"));
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ set DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
|
|||
set DOTNET_MULTILEVEL_LOOKUP=0
|
||||
set InstallPlaywright=%$installPlaywright%
|
||||
set PLAYWRIGHT_BROWSERS_PATH=%CD%\ms-playwright
|
||||
set PLAYWRIGHT_DRIVER_PATH=%CD%\.playwright\win-x64\native\playwright.cmd
|
||||
|
||||
set "PATH=%HELIX_WORKITEM_ROOT%;%PATH%;%HELIX_WORKITEM_ROOT%\node\bin"
|
||||
echo Set path to: "%PATH%"
|
||||
|
|
|
@ -18,7 +18,6 @@ export PATH="$PATH:$DIR:$DIR/node/bin"
|
|||
# Set playwright stuff
|
||||
export PLAYWRIGHT_BROWSERS_PATH="$DIR/ms-playwright"
|
||||
if [[ "$helixQueue" == *"OSX"* ]]; then
|
||||
export PLAYWRIGHT_DRIVER_PATH="$DIR/.playwright/osx/native/playwright.sh"
|
||||
PLAYWRIGHT_NODE_PATH=$DIR/.playwright/osx/native/node
|
||||
else
|
||||
export PLAYWRIGHT_DRIVER_PATH="$DIR/.playwright/unix/native/playwright.sh"
|
||||
|
|
|
@ -8,7 +8,7 @@ using System.Net;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.BrowserTesting;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using PlaywrightSharp;
|
||||
using Microsoft.Playwright;
|
||||
using ProjectTemplates.Tests.Infrastructure;
|
||||
using Templates.Test.Helpers;
|
||||
using Xunit;
|
||||
|
@ -136,20 +136,31 @@ public class BlazorServerTemplateTest : BlazorTemplateTest
|
|||
|
||||
private async Task TestBasicNavigation(Project project, IPage page)
|
||||
{
|
||||
var socket = BrowserContextInfo.Pages[page].WebSockets.SingleOrDefault() ??
|
||||
(await page.WaitForEventAsync(PageEvent.WebSocket)).WebSocket;
|
||||
var socket = await page.WaitForWebSocketAsync();
|
||||
|
||||
var framesReceived = 0;
|
||||
var framesSent = 0;
|
||||
|
||||
void FrameReceived(object sender, IWebSocketFrame frame) { framesReceived++; }
|
||||
void FrameSent(object sender, IWebSocketFrame frame) { framesSent++; }
|
||||
|
||||
socket.FrameReceived += FrameReceived;
|
||||
socket.FrameSent += FrameSent;
|
||||
|
||||
// Receive render batch
|
||||
await socket.WaitForEventAsync(WebSocketEvent.FrameReceived);
|
||||
await socket.WaitForEventAsync(WebSocketEvent.FrameSent);
|
||||
await page.WaitForWebSocketAsync(new() { Predicate = (s) => framesReceived == 1 });
|
||||
await page.WaitForWebSocketAsync(new() { Predicate = (s) => framesSent == 1 });
|
||||
|
||||
// JS interop call to intercept navigation
|
||||
await socket.WaitForEventAsync(WebSocketEvent.FrameReceived);
|
||||
await socket.WaitForEventAsync(WebSocketEvent.FrameSent);
|
||||
await page.WaitForWebSocketAsync(new() { Predicate = (s) => framesReceived == 2 });
|
||||
await page.WaitForWebSocketAsync(new() { Predicate = (s) => framesSent == 2 });
|
||||
|
||||
socket.FrameReceived -= FrameReceived;
|
||||
socket.FrameSent -= FrameSent;
|
||||
|
||||
await page.WaitForSelectorAsync("nav");
|
||||
// <title> element gets project ID injected into it during template execution
|
||||
Assert.Equal("Index", (await page.GetTitleAsync()).Trim());
|
||||
Assert.Equal("Index", (await page.TitleAsync()).Trim());
|
||||
|
||||
// Initially displays the home page
|
||||
await page.WaitForSelectorAsync("h1 >> text=Hello, world!");
|
||||
|
@ -168,7 +179,7 @@ public class BlazorServerTemplateTest : BlazorTemplateTest
|
|||
|
||||
// Asynchronously loads and displays the table of weather forecasts
|
||||
await page.WaitForSelectorAsync("table>tbody>tr");
|
||||
Assert.Equal(5, (await page.QuerySelectorAllAsync("p+table>tbody>tr")).Count());
|
||||
Assert.Equal(5, await page.Locator("p+table>tbody>tr").CountAsync());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
<!-- https://github.com/dotnet/aspnetcore/issues/38818 -->
|
||||
<BuildHelixPayload>false</BuildHelixPayload>
|
||||
|
||||
|
||||
<!-- Properties that affect test runs -->
|
||||
<!-- TestTemplateCreationFolder is the folder where the templates will be created. Will point out to $(OutputDir)$(TestTemplateCreationFolder) -->
|
||||
<TestTemplateCreationFolder>TestTemplates\</TestTemplateCreationFolder>
|
||||
|
@ -47,8 +47,8 @@
|
|||
<Reference Include="Microsoft.Extensions.Configuration.Json" />
|
||||
<Reference Include="AngleSharp" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="PlaywrightSharp" Condition="'$(IsPlaywrightAvailable)' == 'true'" />
|
||||
<Reference Include="PlaywrightSharp" ExcludeAssets="build" Condition="'$(IsPlaywrightAvailable)' != 'true'" />
|
||||
<Reference Include="Microsoft.Playwright" Condition="'$(IsPlaywrightAvailable)' == 'true'" />
|
||||
<Reference Include="Microsoft.Playwright" ExcludeAssets="build" Condition="'$(IsPlaywrightAvailable)' != 'true'" />
|
||||
<ProjectReference Include="$(RepoRoot)src\Framework\App.Runtime\src\Microsoft.AspNetCore.App.Runtime.csproj"
|
||||
Private="false"
|
||||
ReferenceOutputAssembly="false"
|
||||
|
|
|
@ -11,7 +11,7 @@ using Microsoft.AspNetCore.Internal;
|
|||
using Microsoft.AspNetCore.Testing;
|
||||
using Microsoft.Extensions.CommandLineUtils;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PlaywrightSharp;
|
||||
using Microsoft.Playwright;
|
||||
using Templates.Test.Helpers;
|
||||
|
||||
namespace BlazorTemplates.Tests;
|
||||
|
@ -56,7 +56,7 @@ public class BlazorWasmTemplateTest : BlazorTemplateTest
|
|||
private static async Task<IPage> NavigateToPage(IBrowserContext browser, string listeningUri)
|
||||
{
|
||||
var page = await browser.NewPageAsync();
|
||||
await page.GoToAsync(listeningUri, LifecycleEvent.Networkidle);
|
||||
await page.GotoAsync(listeningUri, new() { WaitUntil = WaitUntilState.NetworkIdle });
|
||||
return page;
|
||||
}
|
||||
|
||||
|
@ -133,9 +133,9 @@ public class BlazorWasmTemplateTest : BlazorTemplateTest
|
|||
|
||||
// The PWA template supports offline use. By now, the browser should have cached everything it needs,
|
||||
// so we can continue working even without the server.
|
||||
await page.GoToAsync("about:blank");
|
||||
await page.GotoAsync("about:blank");
|
||||
await browser.SetOfflineAsync(true);
|
||||
await page.GoToAsync(listeningUri);
|
||||
await page.GotoAsync(listeningUri);
|
||||
await TestBasicNavigation(project.ProjectName, page, skipFetchData: true);
|
||||
await page.CloseAsync();
|
||||
}
|
||||
|
@ -181,9 +181,9 @@ public class BlazorWasmTemplateTest : BlazorTemplateTest
|
|||
// The PWA template supports offline use. By now, the browser should have cached everything it needs,
|
||||
// so we can continue working even without the server.
|
||||
// Since this is the hosted project, backend APIs won't work offline, so we need to skip "fetchdata"
|
||||
await page.GoToAsync("about:blank");
|
||||
await page.GotoAsync("about:blank");
|
||||
await browser.SetOfflineAsync(true);
|
||||
await page.GoToAsync(listeningUri);
|
||||
await page.GotoAsync(listeningUri);
|
||||
await TestBasicNavigation(project.ProjectName, page, skipFetchData: true);
|
||||
await page.CloseAsync();
|
||||
}
|
||||
|
@ -416,11 +416,11 @@ public class BlazorWasmTemplateTest : BlazorTemplateTest
|
|||
// Initially displays the home page
|
||||
await page.WaitForSelectorAsync("h1 >> text=Hello, world!");
|
||||
|
||||
Assert.Equal("Index", (await page.GetTitleAsync()).Trim());
|
||||
Assert.Equal("Index", (await page.TitleAsync()).Trim());
|
||||
|
||||
// Can navigate to the counter page
|
||||
await Task.WhenAll(
|
||||
page.WaitForNavigationAsync("**/counter"),
|
||||
page.WaitForNavigationAsync(new() { UrlString = "**/counter" }),
|
||||
page.WaitForSelectorAsync("h1 >> text=Counter"),
|
||||
page.WaitForSelectorAsync("p >> text=Current count: 0"),
|
||||
page.ClickAsync("a[href=counter]"));
|
||||
|
@ -433,12 +433,12 @@ public class BlazorWasmTemplateTest : BlazorTemplateTest
|
|||
if (usesAuth)
|
||||
{
|
||||
await Task.WhenAll(
|
||||
page.WaitForNavigationAsync("**/Identity/Account/Login**", LifecycleEvent.Networkidle),
|
||||
page.WaitForNavigationAsync(new() { UrlString = "**/Identity/Account/Login**", WaitUntil = WaitUntilState.NetworkIdle }),
|
||||
page.ClickAsync("text=Log in"));
|
||||
|
||||
await Task.WhenAll(
|
||||
page.WaitForSelectorAsync("[name=\"Input.Email\"]"),
|
||||
page.WaitForNavigationAsync("**/Identity/Account/Register**", LifecycleEvent.Networkidle),
|
||||
page.WaitForNavigationAsync(new() { UrlString = "**/Identity/Account/Register**", WaitUntil = WaitUntilState.NetworkIdle }),
|
||||
page.ClickAsync("text=Register as a new user"));
|
||||
|
||||
var userName = $"{Guid.NewGuid()}@example.com";
|
||||
|
@ -450,12 +450,12 @@ public class BlazorWasmTemplateTest : BlazorTemplateTest
|
|||
|
||||
// We will be redirected to the RegisterConfirmation
|
||||
await Task.WhenAll(
|
||||
page.WaitForNavigationAsync("**/Identity/Account/RegisterConfirmation**", LifecycleEvent.Networkidle),
|
||||
page.WaitForNavigationAsync(new() { UrlString = "**/Identity/Account/RegisterConfirmation**", WaitUntil = WaitUntilState.NetworkIdle }),
|
||||
page.ClickAsync("#registerSubmit"));
|
||||
|
||||
// We will be redirected to the ConfirmEmail
|
||||
await Task.WhenAll(
|
||||
page.WaitForNavigationAsync("**/Identity/Account/ConfirmEmail**", LifecycleEvent.Networkidle),
|
||||
page.WaitForNavigationAsync(new() { UrlString = "**/Identity/Account/ConfirmEmail**", WaitUntil = WaitUntilState.NetworkIdle }),
|
||||
page.ClickAsync("text=Click here to confirm your account"));
|
||||
|
||||
// Now we can login
|
||||
|
@ -466,21 +466,21 @@ public class BlazorWasmTemplateTest : BlazorTemplateTest
|
|||
await page.ClickAsync("#login-submit");
|
||||
|
||||
// Need to navigate to fetch page
|
||||
await page.GoToAsync(new Uri(page.Url).GetLeftPart(UriPartial.Authority));
|
||||
Assert.Equal(appName.Trim(), (await page.GetTitleAsync()).Trim());
|
||||
await page.GotoAsync(new Uri(page.Url).GetLeftPart(UriPartial.Authority));
|
||||
Assert.Equal(appName.Trim(), (await page.TitleAsync()).Trim());
|
||||
}
|
||||
|
||||
if (!skipFetchData)
|
||||
{
|
||||
// Can navigate to the 'fetch data' page
|
||||
await Task.WhenAll(
|
||||
page.WaitForNavigationAsync("**/fetchdata"),
|
||||
page.WaitForNavigationAsync(new() { UrlString = "**/fetchdata" }),
|
||||
page.WaitForSelectorAsync("h1 >> text=Weather forecast"),
|
||||
page.ClickAsync("text=Fetch data"));
|
||||
|
||||
// Asynchronously loads and displays the table of weather forecasts
|
||||
await page.WaitForSelectorAsync("table>tbody>tr");
|
||||
Assert.Equal(5, (await page.QuerySelectorAllAsync("p+table>tbody>tr")).Count());
|
||||
Assert.Equal(5, await page.Locator("p+table>tbody>tr").CountAsync());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,27 +4,18 @@
|
|||
"BaseArtifactsFolder": ".",
|
||||
"GlobalBrowserOptions": {
|
||||
"ChromiumSandbox": true,
|
||||
"DumpIO": true,
|
||||
"IgnoreHTTPSErrors": true,
|
||||
"Headless": true,
|
||||
"Timeout": 30000
|
||||
},
|
||||
"GlobalContextOptions": {
|
||||
"RecordVideo": {
|
||||
"Dir": "videos"
|
||||
},
|
||||
"RecordHar": {
|
||||
"Path": "har"
|
||||
},
|
||||
"RecordVideoDir": "videos",
|
||||
"RecordHarPath": "har",
|
||||
"IgnoreHTTPSErrors": true
|
||||
},
|
||||
"BrowserOptions": {
|
||||
"Chromium": {
|
||||
"BrowserKind": "Chromium",
|
||||
"IsEnabled": true,
|
||||
"Args": {
|
||||
"--ignore-certificate-errors": true
|
||||
}
|
||||
"IsEnabled": true
|
||||
},
|
||||
"Firefox": {
|
||||
"BrowserKind": "Firefox",
|
||||
|
|
|
@ -17,7 +17,7 @@ using Microsoft.AspNetCore.Server.IntegrationTesting;
|
|||
using Microsoft.Extensions.CommandLineUtils;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using PlaywrightSharp;
|
||||
using Microsoft.Playwright;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
|
@ -109,7 +109,7 @@ public class AspNetProcess : IDisposable
|
|||
public async Task VisitInBrowserAsync(IPage page)
|
||||
{
|
||||
_output.WriteLine($"Opening browser at {ListeningUri}...");
|
||||
await page.GoToAsync(ListeningUri.AbsoluteUri);
|
||||
await page.GotoAsync(ListeningUri.AbsoluteUri);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using PlaywrightSharp;
|
||||
using Microsoft.Playwright;
|
||||
|
||||
namespace Microsoft.AspNetCore.BrowserTesting;
|
||||
|
||||
|
@ -47,20 +47,12 @@ public class BrowserManager
|
|||
|
||||
async Task InitializeCore()
|
||||
{
|
||||
var driverPath = Environment.GetEnvironmentVariable("PLAYWRIGHT_DRIVER_PATH");
|
||||
if (!string.IsNullOrEmpty(driverPath))
|
||||
{
|
||||
Playwright = await PlaywrightSharp.Playwright.CreateAsync(_loggerFactory, driverExecutablePath: driverPath, debug: "pw:api");
|
||||
}
|
||||
else
|
||||
{
|
||||
Playwright = await PlaywrightSharp.Playwright.CreateAsync(_loggerFactory, debug: "pw:api");
|
||||
}
|
||||
Playwright = await Microsoft.Playwright.Playwright.CreateAsync();
|
||||
foreach (var (browserName, options) in _browserManagerConfiguration.BrowserOptions)
|
||||
{
|
||||
if (!_launchBrowsers.ContainsKey(browserName))
|
||||
{
|
||||
var effectiveLaunchOptions = _browserManagerConfiguration.GetLaunchOptions(options.BrowserLaunchOptions);
|
||||
var effectiveLaunchOptions = _browserManagerConfiguration.GetBrowserTypeLaunchOptions(options.BrowserLaunchOptions);
|
||||
|
||||
var browser = options.BrowserKind switch
|
||||
{
|
||||
|
@ -108,10 +100,10 @@ public class BrowserManager
|
|||
contextInfo);
|
||||
}
|
||||
|
||||
public Task<IBrowserContext> GetBrowserInstance(BrowserKind browserInstance, string contextName, BrowserContextOptions options, ContextInformation contextInfo) =>
|
||||
public Task<IBrowserContext> GetBrowserInstance(BrowserKind browserInstance, string contextName, BrowserNewContextOptions options, ContextInformation contextInfo) =>
|
||||
GetBrowserInstance(browserInstance.ToString(), contextName, options, contextInfo);
|
||||
|
||||
public Task<IBrowserContext> GetBrowserInstance(string browserInstance, string contextName, BrowserContextOptions options, ContextInformation contextInfo)
|
||||
public Task<IBrowserContext> GetBrowserInstance(string browserInstance, string contextName, BrowserNewContextOptions options, ContextInformation contextInfo)
|
||||
{
|
||||
if (_launchBrowsers.TryGetValue(browserInstance, out var browser))
|
||||
{
|
||||
|
@ -126,9 +118,10 @@ public class BrowserManager
|
|||
private async Task<IBrowserContext> AttachContextInfo(Task<IBrowserContext> browserContextTask, ContextInformation contextInfo)
|
||||
{
|
||||
var context = await browserContextTask;
|
||||
context.DefaultTimeout = HasFailedTests ?
|
||||
var defaultTimeout = HasFailedTests ?
|
||||
_browserManagerConfiguration.TimeoutAfterFirstFailureInMilliseconds :
|
||||
_browserManagerConfiguration.TimeoutInMilliseconds;
|
||||
context.SetDefaultTimeout(defaultTimeout);
|
||||
|
||||
contextInfo.Attach(context);
|
||||
return context;
|
||||
|
|
|
@ -6,7 +6,7 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using PlaywrightSharp;
|
||||
using Microsoft.Playwright;
|
||||
|
||||
namespace Microsoft.AspNetCore.BrowserTesting;
|
||||
|
||||
|
@ -25,9 +25,9 @@ public class BrowserManagerConfiguration
|
|||
|
||||
public bool IsDisabled { get; private set; }
|
||||
|
||||
public LaunchOptions GlobalBrowserOptions { get; private set; }
|
||||
public BrowserTypeLaunchOptions GlobalBrowserOptions { get; private set; }
|
||||
|
||||
public BrowserContextOptions GlobalContextOptions { get; private set; }
|
||||
public BrowserNewContextOptions GlobalContextOptions { get; private set; }
|
||||
|
||||
public IDictionary<string, BrowserOptions> BrowserOptions { get; } =
|
||||
new Dictionary<string, BrowserOptions>(StringComparer.OrdinalIgnoreCase);
|
||||
|
@ -35,10 +35,10 @@ public class BrowserManagerConfiguration
|
|||
public ISet<string> DisabledBrowsers { get; } =
|
||||
new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public IDictionary<string, BrowserContextOptions> ContextOptions { get; private set; } =
|
||||
new Dictionary<string, BrowserContextOptions>(StringComparer.OrdinalIgnoreCase);
|
||||
public IDictionary<string, BrowserNewContextOptions> ContextOptions { get; private set; } =
|
||||
new Dictionary<string, BrowserNewContextOptions>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public LaunchOptions GetLaunchOptions(LaunchOptions browserLaunchOptions)
|
||||
public BrowserTypeLaunchOptions GetBrowserTypeLaunchOptions(BrowserTypeLaunchOptions browserLaunchOptions)
|
||||
{
|
||||
if (browserLaunchOptions == null)
|
||||
{
|
||||
|
@ -50,7 +50,7 @@ public class BrowserManagerConfiguration
|
|||
}
|
||||
}
|
||||
|
||||
public BrowserContextOptions GetContextOptions(string browser)
|
||||
public BrowserNewContextOptions GetContextOptions(string browser)
|
||||
{
|
||||
if (!BrowserOptions.TryGetValue(browser, out var browserOptions))
|
||||
{
|
||||
|
@ -66,10 +66,10 @@ public class BrowserManagerConfiguration
|
|||
}
|
||||
}
|
||||
|
||||
public BrowserContextOptions GetContextOptions(string browser, string contextName) =>
|
||||
public BrowserNewContextOptions GetContextOptions(string browser, string contextName) =>
|
||||
Combine(GetContextOptions(browser.ToString()), ContextOptions.TryGetValue(contextName, out var context) ? context : throw new InvalidOperationException("Invalid context name"));
|
||||
|
||||
public BrowserContextOptions GetContextOptions(string browser, string contextName, BrowserContextOptions options) =>
|
||||
public BrowserNewContextOptions GetContextOptions(string browser, string contextName, BrowserNewContextOptions options) =>
|
||||
Combine(GetContextOptions(browser, contextName), options);
|
||||
|
||||
private void Load(IConfiguration configuration)
|
||||
|
@ -126,37 +126,37 @@ public class BrowserManagerConfiguration
|
|||
}
|
||||
}
|
||||
|
||||
private BrowserContextOptions LoadContextOptions(IConfiguration configuration) => EnsureFoldersExist(new BrowserContextOptions
|
||||
private BrowserNewContextOptions LoadContextOptions(IConfiguration configuration) => EnsureFoldersExist(new BrowserNewContextOptions
|
||||
{
|
||||
Proxy = BindValue<ProxySettings>(configuration, nameof(BrowserContextOptions.Proxy)),
|
||||
RecordVideo = BindValue<RecordVideoOptions>(configuration, nameof(BrowserContextOptions.RecordVideo)),
|
||||
RecordHar = BindValue<RecordHarOptions>(configuration, nameof(BrowserContextOptions.RecordHar)),
|
||||
Proxy = BindValue<Proxy>(configuration, nameof(BrowserNewContextOptions.Proxy)),
|
||||
RecordVideoDir = configuration.GetValue<string>(nameof(BrowserNewContextOptions.RecordVideoDir)),
|
||||
RecordVideoSize = BindValue<RecordVideoSize>(configuration, nameof(BrowserNewContextOptions.RecordVideoSize)),
|
||||
RecordHarPath = configuration.GetValue<string>(nameof(BrowserNewContextOptions.RecordHarPath)),
|
||||
RecordHarOmitContent = configuration.GetValue<bool?>(nameof(BrowserNewContextOptions.RecordHarOmitContent)),
|
||||
ExtraHTTPHeaders = BindMultiValueMap(
|
||||
configuration.GetSection(nameof(BrowserContextOptions.ExtraHTTPHeaders)),
|
||||
configuration.GetSection(nameof(BrowserNewContextOptions.ExtraHTTPHeaders)),
|
||||
argsMap => argsMap.ToDictionary(kvp => kvp.Key, kvp => string.Join(", ", kvp.Value))),
|
||||
Locale = configuration.GetValue<string>(nameof(BrowserContextOptions.Locale)),
|
||||
ColorScheme = configuration.GetValue<ColorScheme?>(nameof(BrowserContextOptions.ColorScheme)),
|
||||
AcceptDownloads = configuration.GetValue<bool?>(nameof(BrowserContextOptions.AcceptDownloads)),
|
||||
HasTouch = configuration.GetValue<bool?>(nameof(BrowserContextOptions.HasTouch)),
|
||||
HttpCredentials = configuration.GetValue<Credentials>(nameof(BrowserContextOptions.HttpCredentials)),
|
||||
DeviceScaleFactor = configuration.GetValue<decimal?>(nameof(BrowserContextOptions.DeviceScaleFactor)),
|
||||
Offline = configuration.GetValue<bool?>(nameof(BrowserContextOptions.Offline)),
|
||||
IsMobile = configuration.GetValue<bool?>(nameof(BrowserContextOptions.IsMobile)),
|
||||
Locale = configuration.GetValue<string>(nameof(BrowserNewContextOptions.Locale)),
|
||||
ColorScheme = configuration.GetValue<ColorScheme?>(nameof(BrowserNewContextOptions.ColorScheme)),
|
||||
AcceptDownloads = configuration.GetValue<bool?>(nameof(BrowserNewContextOptions.AcceptDownloads)),
|
||||
HasTouch = configuration.GetValue<bool?>(nameof(BrowserNewContextOptions.HasTouch)),
|
||||
HttpCredentials = configuration.GetValue<HttpCredentials>(nameof(BrowserNewContextOptions.HttpCredentials)),
|
||||
DeviceScaleFactor = configuration.GetValue<float?>(nameof(BrowserNewContextOptions.DeviceScaleFactor)),
|
||||
Offline = configuration.GetValue<bool?>(nameof(BrowserNewContextOptions.Offline)),
|
||||
IsMobile = configuration.GetValue<bool?>(nameof(BrowserNewContextOptions.IsMobile)),
|
||||
|
||||
// TODO: Map this properly
|
||||
Permissions = configuration.GetValue<ContextPermission[]>(nameof(BrowserContextOptions.Permissions)),
|
||||
Permissions = configuration.GetValue<IEnumerable<string>>(nameof(BrowserNewContextOptions.Permissions)),
|
||||
|
||||
Geolocation = BindValue<Geolocation>(configuration, nameof(BrowserContextOptions.Geolocation)),
|
||||
TimezoneId = configuration.GetValue<string>(nameof(BrowserContextOptions.TimezoneId)),
|
||||
IgnoreHTTPSErrors = configuration.GetValue<bool?>(nameof(BrowserContextOptions.IgnoreHTTPSErrors)),
|
||||
JavaScriptEnabled = configuration.GetValue<bool?>(nameof(BrowserContextOptions.JavaScriptEnabled)),
|
||||
BypassCSP = configuration.GetValue<bool?>(nameof(BrowserContextOptions.BypassCSP)),
|
||||
UserAgent = configuration.GetValue<string>(nameof(BrowserContextOptions.UserAgent)),
|
||||
Viewport = BindValue<ViewportSize>(configuration, nameof(BrowserContextOptions.Viewport)),
|
||||
StorageStatePath = configuration.GetValue<string>(nameof(BrowserContextOptions.StorageStatePath)),
|
||||
|
||||
// TODO: Map this properly
|
||||
StorageState = BindValue<StorageState>(configuration, nameof(BrowserContextOptions.StorageState))
|
||||
Geolocation = BindValue<Geolocation>(configuration, nameof(BrowserNewContextOptions.Geolocation)),
|
||||
TimezoneId = configuration.GetValue<string>(nameof(BrowserNewContextOptions.TimezoneId)),
|
||||
IgnoreHTTPSErrors = configuration.GetValue<bool?>(nameof(BrowserNewContextOptions.IgnoreHTTPSErrors)),
|
||||
JavaScriptEnabled = configuration.GetValue<bool?>(nameof(BrowserNewContextOptions.JavaScriptEnabled)),
|
||||
BypassCSP = configuration.GetValue<bool?>(nameof(BrowserNewContextOptions.BypassCSP)),
|
||||
UserAgent = configuration.GetValue<string>(nameof(BrowserNewContextOptions.UserAgent)),
|
||||
ViewportSize = BindValue<ViewportSize>(configuration, nameof(BrowserNewContextOptions.ViewportSize)),
|
||||
StorageStatePath = configuration.GetValue<string>(nameof(BrowserNewContextOptions.StorageStatePath)),
|
||||
StorageState = configuration.GetValue<string>(nameof(BrowserNewContextOptions.StorageState))
|
||||
});
|
||||
|
||||
private static T BindValue<T>(IConfiguration configuration, string key) where T : new()
|
||||
|
@ -167,16 +167,16 @@ public class BrowserManagerConfiguration
|
|||
return section.Exists() ? instance : default;
|
||||
}
|
||||
|
||||
private BrowserContextOptions EnsureFoldersExist(BrowserContextOptions browserContextOptions)
|
||||
private BrowserNewContextOptions EnsureFoldersExist(BrowserNewContextOptions browserContextOptions)
|
||||
{
|
||||
if (browserContextOptions?.RecordVideo?.Dir != null)
|
||||
if (browserContextOptions?.RecordVideoDir != null)
|
||||
{
|
||||
browserContextOptions.RecordVideo.Dir = EnsureFolderExists(browserContextOptions.RecordVideo.Dir);
|
||||
browserContextOptions.RecordVideoDir = EnsureFolderExists(browserContextOptions.RecordVideoDir);
|
||||
}
|
||||
|
||||
if (browserContextOptions?.RecordHar?.Path != null)
|
||||
if (browserContextOptions?.RecordHarPath != null)
|
||||
{
|
||||
browserContextOptions.RecordHar.Path = EnsureFolderExists(browserContextOptions.RecordHar.Path);
|
||||
browserContextOptions.RecordHarPath = EnsureFolderExists(browserContextOptions.RecordHarPath);
|
||||
}
|
||||
|
||||
return browserContextOptions;
|
||||
|
@ -197,28 +197,25 @@ public class BrowserManagerConfiguration
|
|||
}
|
||||
}
|
||||
|
||||
private static LaunchOptions LoadBrowserLaunchOptions(IConfiguration configuration) => new LaunchOptions
|
||||
private static BrowserTypeLaunchOptions LoadBrowserLaunchOptions(IConfiguration configuration) => new BrowserTypeLaunchOptions
|
||||
{
|
||||
IgnoreDefaultArgs = BindArgumentMap(configuration.GetSection(nameof(LaunchOptions.IgnoreAllDefaultArgs))),
|
||||
ChromiumSandbox = configuration.GetValue<bool?>(nameof(LaunchOptions.ChromiumSandbox)),
|
||||
HandleSIGHUP = configuration.GetValue<bool?>(nameof(LaunchOptions.HandleSIGHUP)),
|
||||
HandleSIGTERM = configuration.GetValue<bool?>(nameof(LaunchOptions.HandleSIGTERM)),
|
||||
HandleSIGINT = configuration.GetValue<bool?>(nameof(LaunchOptions.HandleSIGINT)),
|
||||
IgnoreAllDefaultArgs = configuration.GetValue<bool?>(nameof(LaunchOptions.IgnoreAllDefaultArgs)),
|
||||
SlowMo = configuration.GetValue<int?>(nameof(LaunchOptions.SlowMo)),
|
||||
Env = configuration.GetValue<Dictionary<string, string>>(nameof(LaunchOptions.Env)),
|
||||
DumpIO = configuration.GetValue<bool?>(nameof(LaunchOptions.DumpIO)),
|
||||
IgnoreHTTPSErrors = configuration.GetValue<bool?>(nameof(LaunchOptions.IgnoreHTTPSErrors)),
|
||||
DownloadsPath = configuration.GetValue<string>(nameof(LaunchOptions.DownloadsPath)),
|
||||
ExecutablePath = configuration.GetValue<string>(nameof(LaunchOptions.ExecutablePath)),
|
||||
Devtools = configuration.GetValue<bool?>(nameof(LaunchOptions.Devtools)),
|
||||
UserDataDir = configuration.GetValue<string>(nameof(LaunchOptions.UserDataDir)),
|
||||
IgnoreDefaultArgs = BindArgumentMap(configuration.GetSection(nameof(BrowserTypeLaunchOptions.IgnoreAllDefaultArgs))),
|
||||
ChromiumSandbox = configuration.GetValue<bool?>(nameof(BrowserTypeLaunchOptions.ChromiumSandbox)),
|
||||
HandleSIGHUP = configuration.GetValue<bool?>(nameof(BrowserTypeLaunchOptions.HandleSIGHUP)),
|
||||
HandleSIGTERM = configuration.GetValue<bool?>(nameof(BrowserTypeLaunchOptions.HandleSIGTERM)),
|
||||
HandleSIGINT = configuration.GetValue<bool?>(nameof(BrowserTypeLaunchOptions.HandleSIGINT)),
|
||||
IgnoreAllDefaultArgs = configuration.GetValue<bool?>(nameof(BrowserTypeLaunchOptions.IgnoreAllDefaultArgs)),
|
||||
SlowMo = configuration.GetValue<int?>(nameof(BrowserTypeLaunchOptions.SlowMo)),
|
||||
Env = configuration.GetValue<Dictionary<string, string>>(nameof(BrowserTypeLaunchOptions.Env)),
|
||||
DownloadsPath = configuration.GetValue<string>(nameof(BrowserTypeLaunchOptions.DownloadsPath)),
|
||||
ExecutablePath = configuration.GetValue<string>(nameof(BrowserTypeLaunchOptions.ExecutablePath)),
|
||||
Devtools = configuration.GetValue<bool?>(nameof(BrowserTypeLaunchOptions.Devtools)),
|
||||
Args = BindMultiValueMap(
|
||||
configuration.GetSection(nameof(LaunchOptions.Args)),
|
||||
configuration.GetSection(nameof(BrowserTypeLaunchOptions.Args)),
|
||||
argsMap => argsMap.SelectMany(argNameValue => argNameValue.Value.Prepend(argNameValue.Key)).ToArray()),
|
||||
Headless = configuration.GetValue<bool?>(nameof(LaunchOptions.Headless)),
|
||||
Timeout = configuration.GetValue<int?>(nameof(LaunchOptions.Timeout)),
|
||||
Proxy = configuration.GetValue<ProxySettings>(nameof(LaunchOptions.Proxy))
|
||||
Headless = configuration.GetValue<bool?>(nameof(BrowserTypeLaunchOptions.Headless)),
|
||||
Timeout = configuration.GetValue<int?>(nameof(BrowserTypeLaunchOptions.Timeout)),
|
||||
Proxy = configuration.GetValue<Proxy>(nameof(BrowserTypeLaunchOptions.Proxy))
|
||||
};
|
||||
|
||||
private static T BindMultiValueMap<T>(IConfigurationSection processArgsMap, Func<Dictionary<string, HashSet<string>>, T> mapper)
|
||||
|
@ -307,20 +304,14 @@ public class BrowserManagerConfiguration
|
|||
true => configuration.Get<Dictionary<string, bool>>().Where(kvp => kvp.Value == true).Select(kvp => kvp.Key).ToArray()
|
||||
};
|
||||
|
||||
private static BrowserContextOptions Combine(BrowserContextOptions defaultOptions, BrowserContextOptions overrideOptions) =>
|
||||
private static BrowserNewContextOptions Combine(BrowserNewContextOptions defaultOptions, BrowserNewContextOptions overrideOptions) =>
|
||||
new()
|
||||
{
|
||||
Proxy = overrideOptions?.Proxy != default ? overrideOptions.Proxy : defaultOptions.Proxy,
|
||||
RecordVideo = overrideOptions?.RecordVideo != default ?
|
||||
new() { Dir = overrideOptions.RecordVideo.Dir, Size = overrideOptions.RecordVideo.Size?.Clone() } :
|
||||
defaultOptions != default ?
|
||||
new() { Dir = defaultOptions.RecordVideo.Dir, Size = defaultOptions.RecordVideo.Size?.Clone() } :
|
||||
default,
|
||||
RecordHar = overrideOptions?.RecordHar != default ?
|
||||
new() { Path = overrideOptions.RecordHar.Path, OmitContent = overrideOptions.RecordHar.OmitContent } :
|
||||
defaultOptions?.RecordHar != default ?
|
||||
new() { Path = defaultOptions.RecordHar.Path, OmitContent = defaultOptions.RecordHar.OmitContent } :
|
||||
default,
|
||||
RecordVideoDir = overrideOptions?.RecordVideoDir != default ? overrideOptions.RecordVideoDir : defaultOptions.RecordVideoDir,
|
||||
RecordVideoSize = overrideOptions?.RecordVideoSize != default ? overrideOptions.RecordVideoSize : defaultOptions.RecordVideoSize,
|
||||
RecordHarPath = overrideOptions?.RecordHarPath != default ? overrideOptions.RecordHarPath : defaultOptions.RecordHarPath,
|
||||
RecordHarOmitContent = overrideOptions?.RecordHarOmitContent != default ? overrideOptions.RecordHarOmitContent : defaultOptions.RecordHarOmitContent,
|
||||
ExtraHTTPHeaders = overrideOptions?.ExtraHTTPHeaders != default ? overrideOptions.ExtraHTTPHeaders : defaultOptions.ExtraHTTPHeaders,
|
||||
Locale = overrideOptions?.Locale != default ? overrideOptions.Locale : defaultOptions.Locale,
|
||||
ColorScheme = overrideOptions?.ColorScheme != default ? overrideOptions.ColorScheme : defaultOptions.ColorScheme,
|
||||
|
@ -337,12 +328,12 @@ public class BrowserManagerConfiguration
|
|||
JavaScriptEnabled = overrideOptions?.JavaScriptEnabled != default ? overrideOptions.JavaScriptEnabled : defaultOptions.JavaScriptEnabled,
|
||||
BypassCSP = overrideOptions?.BypassCSP != default ? overrideOptions.BypassCSP : defaultOptions.BypassCSP,
|
||||
UserAgent = overrideOptions?.UserAgent != default ? overrideOptions.UserAgent : defaultOptions.UserAgent,
|
||||
Viewport = overrideOptions?.Viewport != default ? overrideOptions.Viewport : defaultOptions.Viewport,
|
||||
ViewportSize = overrideOptions?.ViewportSize != default ? overrideOptions.ViewportSize : defaultOptions.ViewportSize,
|
||||
StorageStatePath = overrideOptions?.StorageStatePath != default ? overrideOptions.StorageStatePath : defaultOptions.StorageStatePath,
|
||||
StorageState = overrideOptions?.StorageState != default ? overrideOptions.StorageState : defaultOptions.StorageState
|
||||
};
|
||||
|
||||
private static LaunchOptions Combine(LaunchOptions defaultOptions, LaunchOptions overrideOptions) =>
|
||||
private static BrowserTypeLaunchOptions Combine(BrowserTypeLaunchOptions defaultOptions, BrowserTypeLaunchOptions overrideOptions) =>
|
||||
new()
|
||||
{
|
||||
IgnoreDefaultArgs = overrideOptions.IgnoreDefaultArgs != default ? overrideOptions.IgnoreDefaultArgs : defaultOptions.IgnoreDefaultArgs,
|
||||
|
@ -353,12 +344,9 @@ public class BrowserManagerConfiguration
|
|||
IgnoreAllDefaultArgs = overrideOptions.IgnoreAllDefaultArgs != default ? overrideOptions.IgnoreAllDefaultArgs : defaultOptions.IgnoreAllDefaultArgs,
|
||||
SlowMo = overrideOptions.SlowMo != default ? overrideOptions.SlowMo : defaultOptions.SlowMo,
|
||||
Env = overrideOptions.Env != default ? overrideOptions.Env : defaultOptions.Env,
|
||||
DumpIO = overrideOptions.DumpIO != default ? overrideOptions.DumpIO : defaultOptions.DumpIO,
|
||||
IgnoreHTTPSErrors = overrideOptions.IgnoreHTTPSErrors != default ? overrideOptions.IgnoreHTTPSErrors : defaultOptions.IgnoreHTTPSErrors,
|
||||
DownloadsPath = overrideOptions.DownloadsPath != default ? overrideOptions.DownloadsPath : defaultOptions.DownloadsPath,
|
||||
ExecutablePath = overrideOptions.ExecutablePath != default ? overrideOptions.ExecutablePath : defaultOptions.ExecutablePath,
|
||||
Devtools = overrideOptions.Devtools != default ? overrideOptions.Devtools : defaultOptions.Devtools,
|
||||
UserDataDir = overrideOptions.UserDataDir != default ? overrideOptions.UserDataDir : defaultOptions.UserDataDir,
|
||||
Args = overrideOptions.Args != default ? overrideOptions.Args : defaultOptions.Args,
|
||||
Headless = overrideOptions.Headless != default ? overrideOptions.Headless : defaultOptions.Headless,
|
||||
Timeout = overrideOptions.Timeout != default ? overrideOptions.Timeout : defaultOptions.Timeout,
|
||||
|
@ -366,4 +354,4 @@ public class BrowserManagerConfiguration
|
|||
};
|
||||
}
|
||||
|
||||
public record BrowserOptions(BrowserKind BrowserKind, LaunchOptions BrowserLaunchOptions, BrowserContextOptions DefaultContextOptions);
|
||||
public record BrowserOptions(BrowserKind BrowserKind, BrowserTypeLaunchOptions BrowserLaunchOptions, BrowserNewContextOptions DefaultContextOptions);
|
||||
|
|
|
@ -9,7 +9,7 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNetCore.BrowserTesting;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using PlaywrightSharp;
|
||||
using Microsoft.Playwright;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using PlaywrightSharp;
|
||||
using Microsoft.Playwright;
|
||||
|
||||
namespace Microsoft.AspNetCore.BrowserTesting;
|
||||
|
||||
|
@ -26,7 +26,7 @@ public class ContextInformation
|
|||
context.Page += AttachToPage;
|
||||
}
|
||||
|
||||
private void AttachToPage(object sender, PageEventArgs args)
|
||||
private void AttachToPage(object sender, IPage page)
|
||||
{
|
||||
var logger = _factory.CreateLogger<PageInformation>();
|
||||
if (_harPath != null)
|
||||
|
@ -34,15 +34,14 @@ public class ContextInformation
|
|||
logger.LogInformation($"Network trace will be saved at '{_harPath}'");
|
||||
}
|
||||
|
||||
var pageInfo = new PageInformation(args.Page, logger);
|
||||
Pages.Add(args.Page, pageInfo);
|
||||
args.Page.Close += CleanupPage;
|
||||
args.Page.Crash += CleanupPage;
|
||||
var pageInfo = new PageInformation(page, logger);
|
||||
Pages.Add(page, pageInfo);
|
||||
page.Close += CleanupPage;
|
||||
page.Crash += CleanupPage;
|
||||
}
|
||||
|
||||
private void CleanupPage(object sender, EventArgs e)
|
||||
private void CleanupPage(object sender, IPage page)
|
||||
{
|
||||
var page = (IPage)sender;
|
||||
if (Pages.TryGetValue(page, out var info))
|
||||
{
|
||||
info.Dispose();
|
||||
|
@ -50,23 +49,23 @@ public class ContextInformation
|
|||
}
|
||||
}
|
||||
|
||||
internal BrowserContextOptions ConfigureUniqueHarPath(BrowserContextOptions browserContextOptions)
|
||||
internal BrowserNewContextOptions ConfigureUniqueHarPath(BrowserNewContextOptions browserContextOptions)
|
||||
{
|
||||
var uploadDir = Environment.GetEnvironmentVariable("HELIX_WORKITEM_UPLOAD_ROOT");
|
||||
if (browserContextOptions?.RecordHar?.Path != null)
|
||||
if (browserContextOptions?.RecordHarPath != null)
|
||||
{
|
||||
var identifier = Guid.NewGuid().ToString("N");
|
||||
browserContextOptions.RecordHar.Path = Path.Combine(
|
||||
string.IsNullOrEmpty(uploadDir) ? browserContextOptions.RecordHar.Path : uploadDir,
|
||||
browserContextOptions.RecordHarPath = Path.Combine(
|
||||
string.IsNullOrEmpty(uploadDir) ? browserContextOptions.RecordHarPath : uploadDir,
|
||||
$"{identifier}.har");
|
||||
_harPath = browserContextOptions.RecordHar.Path;
|
||||
_harPath = browserContextOptions.RecordHarPath;
|
||||
}
|
||||
|
||||
if (browserContextOptions?.RecordVideo?.Dir != null)
|
||||
if (browserContextOptions?.RecordVideoDir != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(uploadDir))
|
||||
{
|
||||
browserContextOptions.RecordVideo.Dir = uploadDir;
|
||||
browserContextOptions.RecordVideoDir = uploadDir;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="PlaywrightSharp" Condition="'$(IsPlaywrightAvailable)' == 'true'" />
|
||||
<Reference Include="PlaywrightSharp" ExcludeAssets="build" Condition="'$(IsPlaywrightAvailable)' != 'true'" />
|
||||
<Reference Include="Microsoft.Playwright" Condition="'$(IsPlaywrightAvailable)' == 'true'" />
|
||||
<Reference Include="Microsoft.Playwright" ExcludeAssets="build" Condition="'$(IsPlaywrightAvailable)' != 'true'" />
|
||||
<Reference Include="Microsoft.AspNetCore.Testing" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -5,13 +5,13 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using PlaywrightSharp;
|
||||
using Microsoft.Playwright;
|
||||
|
||||
namespace Microsoft.AspNetCore.BrowserTesting;
|
||||
|
||||
public class PageInformation : IDisposable
|
||||
{
|
||||
private readonly Page _page;
|
||||
private readonly IPage _page;
|
||||
private readonly ILogger<PageInformation> _logger;
|
||||
|
||||
public List<string> FailedRequests { get; } = new();
|
||||
|
@ -22,7 +22,7 @@ public class PageInformation : IDisposable
|
|||
|
||||
public List<IWebSocket> WebSockets { get; set; } = new();
|
||||
|
||||
public PageInformation(Page page, ILogger<PageInformation> logger)
|
||||
public PageInformation(IPage page, ILogger<PageInformation> logger)
|
||||
{
|
||||
page.Console += RecordConsoleMessage;
|
||||
page.PageError += RecordPageError;
|
||||
|
@ -34,16 +34,16 @@ public class PageInformation : IDisposable
|
|||
_ = LogPageVideoPath();
|
||||
}
|
||||
|
||||
private void CaptureWebSocket(object sender, WebSocketEventArgs e)
|
||||
private void CaptureWebSocket(object sender, IWebSocket e)
|
||||
{
|
||||
WebSockets.Add(e.WebSocket);
|
||||
WebSockets.Add(e);
|
||||
}
|
||||
|
||||
private async Task LogPageVideoPath()
|
||||
{
|
||||
try
|
||||
{
|
||||
var path = _page.Video != null ? await _page.Video.GetPathAsync() : null;
|
||||
var path = _page.Video != null ? await _page.Video.PathAsync() : null;
|
||||
if (path != null)
|
||||
{
|
||||
_logger.LogInformation($"Page video recorded at: {path}");
|
||||
|
@ -63,41 +63,40 @@ public class PageInformation : IDisposable
|
|||
_page.RequestFailed -= RecordFailedRequest;
|
||||
}
|
||||
|
||||
private void RecordFailedRequest(object sender, RequestFailedEventArgs e)
|
||||
private void RecordFailedRequest(object sender, IRequest e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogError(e.FailureText);
|
||||
_logger.LogError(e.Failure);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
FailedRequests.Add(e.FailureText);
|
||||
FailedRequests.Add(e.Failure);
|
||||
}
|
||||
|
||||
private void RecordPageError(object sender, PageErrorEventArgs e)
|
||||
private void RecordPageError(object sender, string e)
|
||||
{
|
||||
// There needs to be a bit of experimentation with this, but message should be a good start.
|
||||
try
|
||||
{
|
||||
_logger.LogError(e.Message);
|
||||
_logger.LogError(e);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
PageErrors.Add(e.Message);
|
||||
PageErrors.Add(e);
|
||||
}
|
||||
|
||||
private void RecordConsoleMessage(object sender, ConsoleEventArgs e)
|
||||
private void RecordConsoleMessage(object sender, IConsoleMessage message)
|
||||
{
|
||||
try
|
||||
{
|
||||
var message = e.Message;
|
||||
var messageText = message.Text.Replace(Environment.NewLine, $"{Environment.NewLine} ");
|
||||
var location = message.Location;
|
||||
|
||||
var logMessage = $"[{_page.Url}]{Environment.NewLine} {messageText}{Environment.NewLine} ({location.URL}:{location.LineNumber}:{location.ColumnNumber})";
|
||||
var logMessage = $"[{_page.Url}]{Environment.NewLine} {messageText}{Environment.NewLine} ({location})";
|
||||
|
||||
_logger.Log(MapLogLevel(message.Type), logMessage);
|
||||
|
||||
|
|
|
@ -48,7 +48,6 @@ internal class ProcessEx : IDisposable
|
|||
proc.BeginOutputReadLine();
|
||||
proc.BeginErrorReadLine();
|
||||
|
||||
|
||||
// We greedily create a timeout exception message even though a timeout is unlikely to happen for two reasons:
|
||||
// 1. To make it less likely for Process getters to throw exceptions like "System.InvalidOperationException: Process has exited, ..."
|
||||
// 2. To ensure if/when exceptions are thrown from Process getters, these exceptions can easily be observed.
|
||||
|
|
Загрузка…
Ссылка в новой задаче