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/eng/Dependencies.props b/eng/Dependencies.props index a8aaf7a3c5ca..75502532f92f 100644 --- a/eng/Dependencies.props +++ b/eng/Dependencies.props @@ -192,7 +192,7 @@ and are generated based on the last package release. - + diff --git a/eng/Versions.props b/eng/Versions.props index 6e8977eff2cd..18514ecff684 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -260,7 +260,7 @@ 13.0.1 13.0.4 1.1.6 - 0.192.0 + 1.17.3 3.0.0 7.2.2 4.1.0 diff --git a/eng/helix/content/RunTests/RunTests.csproj b/eng/helix/content/RunTests/RunTests.csproj index 486e4bb10748..bc8b4f09cf7c 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 4713e4bb00b1..a88f4f9f455e 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"); 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 @@ public async Task InstallPlaywrightAsync() { 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; } diff --git a/eng/helix/content/runtests.cmd b/eng/helix/content/runtests.cmd index 3aab373c69c9..e105281f343f 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 set "PATH=%HELIX_WORKITEM_ROOT%;%PATH%;%HELIX_WORKITEM_ROOT%\node\bin" echo Set path to: "%PATH%" diff --git a/eng/helix/content/runtests.sh b/eng/helix/content/runtests.sh index d900837b94ba..1fd36f19974f 100644 --- a/eng/helix/content/runtests.sh +++ b/eng/helix/content/runtests.sh @@ -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" diff --git a/src/ProjectTemplates/BlazorTemplates.Tests/BlazorServerTemplateTest.cs b/src/ProjectTemplates/BlazorTemplates.Tests/BlazorServerTemplateTest.cs index 0897a48c9e2b..b59787790c8c 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; @@ -136,20 +136,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!"); @@ -168,7 +179,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 1245a4949ad2..034275768894 100644 --- a/src/ProjectTemplates/BlazorTemplates.Tests/BlazorTemplates.Tests.csproj +++ b/src/ProjectTemplates/BlazorTemplates.Tests/BlazorTemplates.Tests.csproj @@ -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" diff --git a/src/ProjectTemplates/BlazorTemplates.Tests/BlazorWasmTemplateTest.cs b/src/ProjectTemplates/BlazorTemplates.Tests/BlazorWasmTemplateTest.cs index 607e4ef598e1..e6ee6b401f7f 100644 --- a/src/ProjectTemplates/BlazorTemplates.Tests/BlazorWasmTemplateTest.cs +++ b/src/ProjectTemplates/BlazorTemplates.Tests/BlazorWasmTemplateTest.cs @@ -11,7 +11,7 @@ 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 async Task BlazorWasmStandaloneTemplate_Works(BrowserKind browserKind) 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 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(); } @@ -181,9 +181,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(); } @@ -416,11 +416,11 @@ private static async Task TestBasicNavigation(string appName, IPage page, bool u // 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 @@ private static async Task TestBasicNavigation(string appName, IPage page, bool u 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 @@ private static async Task TestBasicNavigation(string appName, IPage page, bool u // 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 @@ private static async Task TestBasicNavigation(string appName, IPage page, bool u 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 1402c2bcc01b..852e3183567a 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 150952c05389..b9296cec2411 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 fd176f36cf33..613639d0c582 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,10 +35,10 @@ 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 browserLaunchOptions) { if (browserLaunchOptions == null) { @@ -50,7 +50,7 @@ public LaunchOptions GetLaunchOptions(LaunchOptions browserLaunchOptions) } } - 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)), + 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)), - - 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 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 @@ 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 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 @@ 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,4 +354,4 @@ 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 5f3d941f5f16..6a73c5c04b78 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 d952ffaa93ed..f266edd1c055 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 29493b7aa2ce..d3eab13975b4 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="'$(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> diff --git a/src/Shared/BrowserTesting/src/PageInformation.cs b/src/Shared/BrowserTesting/src/PageInformation.cs index a5d381e6fa2f..7cd9a2c68e21 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 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 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 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); diff --git a/src/Shared/Process/ProcessEx.cs b/src/Shared/Process/ProcessEx.cs index 7b86d3b7441d..3fe20633e935 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.