diff --git a/src/Components/test/E2ETest/Infrastructure/SeleniumStandaloneServer.cs b/src/Components/test/E2ETest/Infrastructure/SeleniumStandaloneServer.cs index 752b0ce5c8..e263e4e5ea 100644 --- a/src/Components/test/E2ETest/Infrastructure/SeleniumStandaloneServer.cs +++ b/src/Components/test/E2ETest/Infrastructure/SeleniumStandaloneServer.cs @@ -1,20 +1,23 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.Extensions.Internal; using System; using System.Diagnostics; using System.Net; using System.Net.Http; using System.Net.Sockets; -using System.Threading; +using System.Runtime.InteropServices; +using System.Text; using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing; +using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Components.E2ETest.Infrastructure { class SeleniumStandaloneServer { - private static object _instanceCreationLock = new object(); + private static readonly TimeSpan Timeout = TimeSpan.FromSeconds(30); + private static readonly object _instanceCreationLock = new object(); private static SeleniumStandaloneServer _instance; public Uri Uri { get; } @@ -40,15 +43,30 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Infrastructure var port = FindAvailablePort(); Uri = new UriBuilder("http", "localhost", port, "/wd/hub").Uri; - var process = Process.Start(new ProcessStartInfo + var psi = new ProcessStartInfo { FileName = "npm", Arguments = $"run selenium-standalone start -- -- -port {port}", - UseShellExecute = true, - }); + RedirectStandardOutput = true, + RedirectStandardError = true, + }; - PollUntilProcessStarted(); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + psi.FileName = "cmd"; + psi.Arguments = $"/c npm {psi.Arguments}"; + } + var process = Process.Start(psi); + + var builder = new StringBuilder(); + process.OutputDataReceived += LogOutput; + process.ErrorDataReceived += LogOutput; + + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + + // The Selenium sever has to be up for the entirety of the tests and is only shutdown when the application (i.e. the test) exits. AppDomain.CurrentDomain.ProcessExit += (sender, e) => { if (!process.HasExited) @@ -57,34 +75,56 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Infrastructure process.Dispose(); } }; - } - private void PollUntilProcessStarted() - { - var timeoutAt = DateTime.Now.AddSeconds(30); - Exception lastException = null; - while (true) + void LogOutput(object sender, DataReceivedEventArgs e) { - if (DateTime.Now > timeoutAt) + lock (builder) { - throw new TimeoutException($"The selenium server instance did not start accepting requests at {Uri} before the timeout occurred. The last exception was: {lastException?.ToString() ?? "NULL"}"); + builder.AppendLine(e.Data); + } + } + + var waitForStart = Task.Run(async () => + { + var httpClient = new HttpClient + { + Timeout = TimeSpan.FromSeconds(1), + }; + + while (true) + { + try + { + var responseTask = httpClient.GetAsync(Uri); + + var response = await responseTask; + if (response.StatusCode == HttpStatusCode.OK) + { + return; + } + } + catch (OperationCanceledException) + { + + } + await Task.Delay(1000); + + } + }); + + try + { + waitForStart.TimeoutAfter(Timeout).Wait(); + } + catch (Exception ex) + { + string output; + lock (builder) + { + output = builder.ToString(); } - var httpClient = new HttpClient(); - try - { - var timeoutAfter1Second = new CancellationTokenSource(3000); - var response = httpClient.GetAsync( - Uri, timeoutAfter1Second.Token).Result; - response.EnsureSuccessStatusCode(); - return; - } - catch (Exception ex) - { - lastException = ex; - } - - Thread.Sleep(1000); + throw new InvalidOperationException($"Failed to start selenium sever. {Environment.NewLine}{output}", ex.GetBaseException()); } } diff --git a/src/Components/test/E2ETest/Infrastructure/ServerFixtures/ToggleExecutionModeServerFixture.cs b/src/Components/test/E2ETest/Infrastructure/ServerFixtures/ToggleExecutionModeServerFixture.cs index 3a2f908509..9fb9863f60 100644 --- a/src/Components/test/E2ETest/Infrastructure/ServerFixtures/ToggleExecutionModeServerFixture.cs +++ b/src/Components/test/E2ETest/Infrastructure/ServerFixtures/ToggleExecutionModeServerFixture.cs @@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures public override void Dispose() { - _serverToDispose.Dispose(); + _serverToDispose?.Dispose(); } } } diff --git a/src/Components/test/testassets/BasicTestApp/wwwroot/js/jsinteroptests.js b/src/Components/test/testassets/BasicTestApp/wwwroot/js/jsinteroptests.js index 10882d9e61..97a7b0118b 100644 --- a/src/Components/test/testassets/BasicTestApp/wwwroot/js/jsinteroptests.js +++ b/src/Components/test/testassets/BasicTestApp/wwwroot/js/jsinteroptests.js @@ -1,5 +1,3 @@ -/// - // We'll store the results from the tests here var results = {}; var assemblyName = 'BasicTestApp'; diff --git a/src/Components/test/testassets/ComponentsApp.App/ComponentsApp.App.csproj b/src/Components/test/testassets/ComponentsApp.App/ComponentsApp.App.csproj index 7819d3b088..e845bc60d4 100644 --- a/src/Components/test/testassets/ComponentsApp.App/ComponentsApp.App.csproj +++ b/src/Components/test/testassets/ComponentsApp.App/ComponentsApp.App.csproj @@ -1,8 +1,10 @@  + + + netstandard2.0 - true diff --git a/src/Components/test/testassets/TestContentPackage/TestContentPackage.csproj b/src/Components/test/testassets/TestContentPackage/TestContentPackage.csproj index 7ef3a85690..f61c27f865 100644 --- a/src/Components/test/testassets/TestContentPackage/TestContentPackage.csproj +++ b/src/Components/test/testassets/TestContentPackage/TestContentPackage.csproj @@ -1,9 +1,11 @@  + + + netstandard2.0 library - true @@ -22,6 +24,4 @@ - -