diff --git a/.azure/pipelines/jobs/default-build.yml b/.azure/pipelines/jobs/default-build.yml index 2f54dd99ad3c..15e0f1690ff5 100644 --- a/.azure/pipelines/jobs/default-build.yml +++ b/.azure/pipelines/jobs/default-build.yml @@ -95,7 +95,7 @@ jobs: # See https://github.com/dotnet/arcade/blob/master/Documentation/ChoosingAMachinePool.md pool: ${{ if eq(parameters.agentOs, 'macOS') }}: - vmImage: macOS-11 + vmImage: macOS-12 ${{ if eq(parameters.agentOs, 'Linux') }}: ${{ if and(eq(parameters.useHostedUbuntu, true), in(variables['Build.Reason'], 'Manual', 'PullRequest', 'Schedule')) }}: vmImage: ubuntu-20.04 @@ -156,8 +156,8 @@ jobs: - script: df -h displayName: Disk size - ${{ if eq(parameters.agentOs, 'macOS') }}: - - script: sudo xcode-select -s /Applications/Xcode_12.5.1.app/Contents/Developer - displayName: Use XCode 12.5.1 + - script: sudo xcode-select -s /Applications/Xcode_14.2.0.app/Contents/Developer + displayName: Use XCode 14.2.0 - checkout: self clean: true - ${{ if and(eq(parameters.agentOs, 'Windows'), eq(parameters.isTestingJob, true)) }}: @@ -311,7 +311,7 @@ jobs: pool: ${{ if eq(parameters.agentOs, 'macOS') }}: name: Azure Pipelines - image: macOS-11 + image: macOS-12 os: macOS ${{ if eq(parameters.agentOs, 'Linux') }}: name: NetCore1ESPool-Svc-Internal @@ -382,8 +382,8 @@ jobs: - script: df -h displayName: Disk size - ${{ if eq(parameters.agentOs, 'macOS') }}: - - script: sudo xcode-select -s /Applications/Xcode_12.5.1.app/Contents/Developer - displayName: Use XCode 12.5.1 + - script: sudo xcode-select -s /Applications/Xcode_14.2.0.app/Contents/Developer + displayName: Use XCode 14.2.0 - checkout: self clean: true - ${{ if and(eq(parameters.agentOs, 'Windows'), eq(parameters.isTestingJob, true)) }}: diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 7010490e921e..00a32e6c111f 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -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" ] } } diff --git a/docs/Helix.md b/docs/Helix.md index 4265628ba7b8..9f5888562a4f 100644 --- a/docs/Helix.md +++ b/docs/Helix.md @@ -2,7 +2,7 @@ Helix is the distributed test platform that we use to run tests. We build a helix payload that contains the publish directory of every test project that we want to test send a job with with this payload to a set of queues for the various combinations of OS that we want to test -for example: `Windows.10.Amd64.ClientRS4.VS2017.Open`, `OSX.1100.Amd64.Open`, `Ubuntu.1804.Amd64.Open`. Helix takes care of unzipping, running the job, and reporting results. +for example: `Windows.10.Amd64.ClientRS4.VS2017.Open`, `OSX.1200.Amd64.Open`, `Ubuntu.1804.Amd64.Open`. Helix takes care of unzipping, running the job, and reporting results. For more info about helix see: [SDK](https://github.com/dotnet/arcade/blob/master/src/Microsoft.DotNet.Helix/Sdk/Readme.md), [JobSender](https://github.com/dotnet/arcade/blob/master/src/Microsoft.DotNet.Helix/Sdk/Readme.md) diff --git a/eng/Dependencies.props b/eng/Dependencies.props index 602c32ec12a4..13c753d0df48 100644 --- a/eng/Dependencies.props +++ b/eng/Dependencies.props @@ -188,7 +188,7 @@ and are generated based on the last package release. - + diff --git a/eng/Versions.props b/eng/Versions.props index 9369f8bc00d3..2efe8ee37ade 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -249,7 +249,7 @@ 13.0.1 13.0.4 1.1.6 - 0.192.0 + 1.17.3 3.0.0 7.2.2 4.3.0 diff --git a/eng/helix/content/RunTests/RunTests.csproj b/eng/helix/content/RunTests/RunTests.csproj index db5888e80343..d18c6f515176 100644 --- a/eng/helix/content/RunTests/RunTests.csproj +++ b/eng/helix/content/RunTests/RunTests.csproj @@ -8,6 +8,6 @@ - + diff --git a/eng/helix/content/RunTests/TestRunner.cs b/eng/helix/content/RunTests/TestRunner.cs index d951ea512f93..55cba0a4fa6d 100644 --- a/eng/helix/content/RunTests/TestRunner.cs +++ b/eng/helix/content/RunTests/TestRunner.cs @@ -9,7 +9,7 @@ using System.Threading; using System.Threading.Tasks; #if INSTALLPLAYWRIGHT -using PlaywrightSharp; +using Microsoft.Playwright; #endif namespace RunTests @@ -55,9 +55,6 @@ public bool SetupEnvironment() var playwrightBrowsers = Environment.GetEnvironmentVariable("PLAYWRIGHT_BROWSERS_PATH"); ProcessUtil.PrintMessage($"Setting PLAYWRIGHT_BROWSERS_PATH: {playwrightBrowsers}"); EnvironmentVariables.Add("PLAYWRIGHT_BROWSERS_PATH", playwrightBrowsers); - var playrightDriver = Environment.GetEnvironmentVariable("PLAYWRIGHT_DRIVER_PATH"); - ProcessUtil.PrintMessage($"Setting PLAYWRIGHT_DRIVER_PATH: {playrightDriver}"); - EnvironmentVariables.Add("PLAYWRIGHT_DRIVER_PATH", playrightDriver); #else ProcessUtil.PrintMessage($"Skipping setting PLAYWRIGHT_BROWSERS_PATH"); #endif @@ -112,8 +109,10 @@ public async Task InstallPlaywrightAsync() { try { - ProcessUtil.PrintMessage($"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; } diff --git a/eng/helix/content/runtests.cmd b/eng/helix/content/runtests.cmd index a3c6de9c0a45..22d533626ef7 100644 --- a/eng/helix/content/runtests.cmd +++ b/eng/helix/content/runtests.cmd @@ -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 REM Avoid https://github.com/dotnet/aspnetcore/issues/41937 in current session. set ASPNETCORE_ENVIRONMENT= diff --git a/eng/helix/content/runtests.sh b/eng/helix/content/runtests.sh index 286b9abfe998..e268e78f2361 100644 --- a/eng/helix/content/runtests.sh +++ b/eng/helix/content/runtests.sh @@ -21,7 +21,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" diff --git a/eng/scripts/RunHelix.ps1 b/eng/scripts/RunHelix.ps1 index 8716f8443855..b29dec9ec80f 100644 --- a/eng/scripts/RunHelix.ps1 +++ b/eng/scripts/RunHelix.ps1 @@ -12,7 +12,7 @@ Mariner Redhat.7.Amd64.Open Ubuntu.2004.Amd64.Open - OSX.1100.Amd64.Open + OSX.1200.Amd64.Open Windows.10.Amd64.Server20H2.Open Windows.11.Amd64.Client.Open Windows.Amd64.Server2022.Open diff --git a/eng/targets/Helix.Common.props b/eng/targets/Helix.Common.props index 60bbb0c7b21b..6a462b3b71ad 100644 --- a/eng/targets/Helix.Common.props +++ b/eng/targets/Helix.Common.props @@ -22,7 +22,7 @@ - + diff --git a/src/ProjectTemplates/BlazorTemplates.Tests/BlazorServerTemplateTest.cs b/src/ProjectTemplates/BlazorTemplates.Tests/BlazorServerTemplateTest.cs index bf5d3fc8d32a..a4224de6d16b 100644 --- a/src/ProjectTemplates/BlazorTemplates.Tests/BlazorServerTemplateTest.cs +++ b/src/ProjectTemplates/BlazorTemplates.Tests/BlazorServerTemplateTest.cs @@ -8,7 +8,7 @@ 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; @@ -137,20 +137,31 @@ public async Task BlazorServerTemplateWorks_IndividualAuth(BrowserKind browserKi 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"); // 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!"); @@ -169,7 +180,7 @@ private async Task TestBasicNavigation(Project project, IPage page) // 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] diff --git a/src/ProjectTemplates/BlazorTemplates.Tests/BlazorTemplates.Tests.csproj b/src/ProjectTemplates/BlazorTemplates.Tests/BlazorTemplates.Tests.csproj index a488e4073861..1ba24e3b8b2e 100644 --- a/src/ProjectTemplates/BlazorTemplates.Tests/BlazorTemplates.Tests.csproj +++ b/src/ProjectTemplates/BlazorTemplates.Tests/BlazorTemplates.Tests.csproj @@ -47,8 +47,8 @@ <Reference Include="Microsoft.Extensions.Configuration.Json" /> <Reference Include="AngleSharp" /> <Reference Include="System.Net.Http" /> - <Reference Include="PlaywrightSharp" Condition="'$(TargetOsName)' != 'linux-musl'" /> - <Reference Include="PlaywrightSharp" ExcludeAssets="build" Condition="'$(TargetOsName)' == 'linux-musl'" /> + <Reference Include="Microsoft.Playwright" Condition="'$(TargetOsName)' != 'linux-musl'" /> + <Reference Include="Microsoft.Playwright" ExcludeAssets="build" Condition="'$(TargetOsName)' == 'linux-musl'" /> <ProjectReference Include="$(RepoRoot)src\Framework\App.Runtime\src\Microsoft.AspNetCore.App.Runtime.csproj"> <ReferenceOutputAssembly>false</ReferenceOutputAssembly> <SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties> diff --git a/src/ProjectTemplates/BlazorTemplates.Tests/BlazorWasmTemplateTest.cs b/src/ProjectTemplates/BlazorTemplates.Tests/BlazorWasmTemplateTest.cs index 80827924f662..19ef2c1d50f7 100644 --- a/src/ProjectTemplates/BlazorTemplates.Tests/BlazorWasmTemplateTest.cs +++ b/src/ProjectTemplates/BlazorTemplates.Tests/BlazorWasmTemplateTest.cs @@ -16,7 +16,7 @@ using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.CommandLineUtils; using Newtonsoft.Json.Linq; -using PlaywrightSharp; +using Microsoft.Playwright; using Templates.Test.Helpers; using Xunit; using Xunit.Abstractions; @@ -64,7 +64,7 @@ public async Task BlazorWasmStandaloneTemplate_Works(BrowserKind browserKind) private 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; } @@ -141,9 +141,9 @@ public async Task BlazorWasmStandalonePwaTemplate_Works(BrowserKind browserKind) // 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(); } @@ -189,9 +189,9 @@ public async Task BlazorWasmHostedPwaTemplate_Works(BrowserKind browserKind) // 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(); } @@ -424,11 +424,11 @@ private async Task TestBasicNavigation(string appName, IPage page, bool usesAuth // 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]")); @@ -441,12 +441,12 @@ private async Task TestBasicNavigation(string appName, IPage page, bool usesAuth 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"; @@ -458,12 +458,12 @@ private async Task TestBasicNavigation(string appName, IPage page, bool usesAuth // 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 @@ -474,21 +474,21 @@ private async Task TestBasicNavigation(string appName, IPage page, bool usesAuth 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()); } } diff --git a/src/ProjectTemplates/BlazorTemplates.Tests/playwrightSettings.json b/src/ProjectTemplates/BlazorTemplates.Tests/playwrightSettings.json index 48f1423de9fb..f97e60263b22 100644 --- a/src/ProjectTemplates/BlazorTemplates.Tests/playwrightSettings.json +++ b/src/ProjectTemplates/BlazorTemplates.Tests/playwrightSettings.json @@ -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", diff --git a/src/ProjectTemplates/Shared/AspNetProcess.cs b/src/ProjectTemplates/Shared/AspNetProcess.cs index a620f008fe6d..c8dec11d304f 100644 --- a/src/ProjectTemplates/Shared/AspNetProcess.cs +++ b/src/ProjectTemplates/Shared/AspNetProcess.cs @@ -17,7 +17,7 @@ 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); } diff --git a/src/Shared/BrowserTesting/src/BrowserManager.cs b/src/Shared/BrowserTesting/src/BrowserManager.cs index 9a290689c424..5b3bf0503b3d 100644 --- a/src/Shared/BrowserTesting/src/BrowserManager.cs +++ b/src/Shared/BrowserTesting/src/BrowserManager.cs @@ -9,7 +9,7 @@ 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 @@ private async Task InitializeAsync() 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 Task<IBrowserContext> GetBrowserInstance(string browserInstance, string c 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 Task<IBrowserContext> GetBrowserInstance(string browserInstance, string c 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; diff --git a/src/Shared/BrowserTesting/src/BrowserManagerConfiguration.cs b/src/Shared/BrowserTesting/src/BrowserManagerConfiguration.cs index 331de7624157..3e0112907b85 100644 --- a/src/Shared/BrowserTesting/src/BrowserManagerConfiguration.cs +++ b/src/Shared/BrowserTesting/src/BrowserManagerConfiguration.cs @@ -6,7 +6,7 @@ using System.IO; using System.Linq; using Microsoft.Extensions.Configuration; -using PlaywrightSharp; +using Microsoft.Playwright; namespace Microsoft.AspNetCore.BrowserTesting { @@ -25,9 +25,9 @@ public BrowserManagerConfiguration(IConfiguration configuration) 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,22 +35,22 @@ public BrowserManagerConfiguration(IConfiguration configuration) 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 browserBrowserTypeLaunchOptions) { - if (browserLaunchOptions == null) + if (browserBrowserTypeLaunchOptions == null) { return GlobalBrowserOptions; } else { - return Combine(GlobalBrowserOptions, browserLaunchOptions); + return Combine(GlobalBrowserOptions, browserBrowserTypeLaunchOptions); } } - public BrowserContextOptions GetContextOptions(string browser) + public BrowserNewContextOptions GetContextOptions(string browser) { if (!BrowserOptions.TryGetValue(browser, out var browserOptions)) { @@ -66,10 +66,10 @@ public BrowserContextOptions GetContextOptions(string browser) } } - 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 @@ private void Load(IConfiguration configuration) } } - 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)), - 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)), + configuration.GetSection(nameof(BrowserNewContextOptions.ExtraHTTPHeaders)), + argsMap => argsMap.ToDictionary(kvp => kvp.Key, kvp => string.Join(", ", kvp.Value))), + 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)), - - 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)) + Permissions = configuration.GetValue<IEnumerable<string>>(nameof(BrowserNewContextOptions.Permissions)), + + 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 @@ private static T BindValue<T>(IConfiguration configuration, string key) where T 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 @@ string EnsureFolderExists(string folderPath) } } - private LaunchOptions LoadBrowserLaunchOptions(IConfiguration configuration) => new LaunchOptions + private 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)), - 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)) + configuration.GetSection(nameof(BrowserTypeLaunchOptions.Args)), + argsMap => argsMap.SelectMany(argNameValue => argNameValue.Value.Prepend(argNameValue.Key)).ToArray()), + Headless = configuration.GetValue<bool?>(nameof(BrowserTypeLaunchOptions.Headless)), + Timeout = configuration.GetValue<int?>(nameof(BrowserTypeLaunchOptions.Timeout)), + Proxy = configuration.GetValue<Proxy>(nameof(BrowserTypeLaunchOptions.Proxy)) }; private T BindMultiValueMap<T>(IConfigurationSection processArgsMap, Func<Dictionary<string, HashSet<string>>, T> mapper) @@ -307,20 +304,14 @@ static HashSet<string> InitializeMapValue(Dictionary<string, HashSet<string>> ar 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 @@ static HashSet<string> InitializeMapValue(Dictionary<string, HashSet<string>> ar 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 LaunchOptions Combine(LaunchOptions defaultOptions, LaunchOptions overrideOptions) => + private BrowserTypeLaunchOptions Combine(BrowserTypeLaunchOptions defaultOptions, BrowserTypeLaunchOptions overrideOptions) => new() { IgnoreDefaultArgs = overrideOptions.IgnoreDefaultArgs != default ? overrideOptions.IgnoreDefaultArgs : defaultOptions.IgnoreDefaultArgs, @@ -353,12 +344,9 @@ static HashSet<string> InitializeMapValue(Dictionary<string, HashSet<string>> ar 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,5 +354,5 @@ static HashSet<string> InitializeMapValue(Dictionary<string, HashSet<string>> ar }; } - public record BrowserOptions(BrowserKind BrowserKind, LaunchOptions BrowserLaunchOptions, BrowserContextOptions DefaultContextOptions); + public record BrowserOptions(BrowserKind BrowserKind, BrowserTypeLaunchOptions BrowserLaunchOptions, BrowserNewContextOptions DefaultContextOptions); } diff --git a/src/Shared/BrowserTesting/src/BrowserTestBase.cs b/src/Shared/BrowserTesting/src/BrowserTestBase.cs index 1b3a29d1694f..3e443b00077f 100644 --- a/src/Shared/BrowserTesting/src/BrowserTestBase.cs +++ b/src/Shared/BrowserTesting/src/BrowserTestBase.cs @@ -9,7 +9,7 @@ using Microsoft.AspNetCore.BrowserTesting; using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.Configuration; -using PlaywrightSharp; +using Microsoft.Playwright; using Xunit; using Xunit.Abstractions; diff --git a/src/Shared/BrowserTesting/src/ContextInformation.cs b/src/Shared/BrowserTesting/src/ContextInformation.cs index d8264d3248f9..6476a8aa9800 100644 --- a/src/Shared/BrowserTesting/src/ContextInformation.cs +++ b/src/Shared/BrowserTesting/src/ContextInformation.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.IO; using Microsoft.Extensions.Logging; -using PlaywrightSharp; +using Microsoft.Playwright; namespace Microsoft.AspNetCore.BrowserTesting { @@ -26,7 +26,7 @@ internal void Attach(IBrowserContext context) 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 @@ private void AttachToPage(object sender, PageEventArgs args) 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 @@ private void CleanupPage(object sender, EventArgs e) } } - 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; } } diff --git a/src/Shared/BrowserTesting/src/Microsoft.AspNetCore.BrowserTesting.csproj b/src/Shared/BrowserTesting/src/Microsoft.AspNetCore.BrowserTesting.csproj index c027e9ee1e27..595483b51d9b 100644 --- a/src/Shared/BrowserTesting/src/Microsoft.AspNetCore.BrowserTesting.csproj +++ b/src/Shared/BrowserTesting/src/Microsoft.AspNetCore.BrowserTesting.csproj @@ -9,8 +9,8 @@ </PropertyGroup> <ItemGroup> - <Reference Include="PlaywrightSharp" Condition="'$(TargetOsName)' != 'linux-musl'" /> - <Reference Include="PlaywrightSharp" ExcludeAssets="build" Condition="'$(TargetOsName)' == 'linux-musl'" /> + <Reference Include="Microsoft.Playwright" Condition="'$(TargetOsName)' != 'linux-musl'" /> + <Reference Include="Microsoft.Playwright" ExcludeAssets="build" Condition="'$(TargetOsName)' == 'linux-musl'" /> <Reference Include="Microsoft.AspNetCore.Testing" /> </ItemGroup> diff --git a/src/Shared/BrowserTesting/src/PageInformation.cs b/src/Shared/BrowserTesting/src/PageInformation.cs index f02724a9c101..b2e2d70eef4b 100644 --- a/src/Shared/BrowserTesting/src/PageInformation.cs +++ b/src/Shared/BrowserTesting/src/PageInformation.cs @@ -5,13 +5,13 @@ 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 PageInformation(Page page, ILogger<PageInformation> logger) _ = LogPageVideoPath(); } - private void CaptureWebSocket(object sender, WebSocketEventArgs e) + private void CaptureWebSocket(object sender, IWebSocket webSocket) { - WebSockets.Add(e.WebSocket); + WebSockets.Add(webSocket); } 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 void Dispose() _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 message) { // There needs to be a bit of experimentation with this, but message should be a good start. try { - _logger.LogError(e.Message); + _logger.LogError(message); } catch { } - PageErrors.Add(e.Message); + PageErrors.Add(message); } - 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); diff --git a/src/Shared/Process/ProcessEx.cs b/src/Shared/Process/ProcessEx.cs index f0bef370692b..b04957ba0ef3 100644 --- a/src/Shared/Process/ProcessEx.cs +++ b/src/Shared/Process/ProcessEx.cs @@ -48,7 +48,6 @@ public ProcessEx(ITestOutputHelper output, Process proc, TimeSpan timeout) 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.