using System.Diagnostics; using System.Net; using System.Net.Sockets; namespace Enciphered.Blazor.UIComponents.Tests; /// /// Launches the demo Blazor app as a separate process on a random free port. /// Shared across all tests in the assembly via [SetUpFixture]. /// public sealed class DemoServerFixture : IDisposable { private Process? _process; public string BaseUrl { get; private set; } = string.Empty; public async Task StartAsync() { var port = GetFreePort(); BaseUrl = $"http://localhost:{port}"; // Resolve the demo project directory (navigate up from test bin output) var testDir = AppContext.BaseDirectory; // …Tests/bin/Debug/net9.0 var solutionRoot = Path.GetFullPath(Path.Combine(testDir, "..", "..", "..", "..")); var demoProjectDir = Path.Combine(solutionRoot, "Enciphered.Blazor.UIComponents.Demo"); if (!Directory.Exists(demoProjectDir)) throw new DirectoryNotFoundException($"Demo project not found at: {demoProjectDir}"); _process = new Process { StartInfo = new ProcessStartInfo { FileName = "dotnet", Arguments = $"run --no-build --urls {BaseUrl}", WorkingDirectory = demoProjectDir, UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true, Environment = { ["ASPNETCORE_ENVIRONMENT"] = "Development", ["DOTNET_NOLOGO"] = "1" } } }; _process.Start(); // Wait for the server to be ready by polling the URL using var httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(2) }; var deadline = DateTime.UtcNow.AddSeconds(30); while (DateTime.UtcNow < deadline) { try { var response = await httpClient.GetAsync(BaseUrl); if (response.IsSuccessStatusCode) return; } catch { // Server not ready yet } await Task.Delay(500); } throw new TimeoutException($"Demo server did not start within 30 seconds at {BaseUrl}"); } public void Dispose() { if (_process is not null && !_process.HasExited) { _process.Kill(entireProcessTree: true); _process.WaitForExit(5000); _process.Dispose(); } } private static int GetFreePort() { using var listener = new TcpListener(IPAddress.Loopback, 0); listener.Start(); var port = ((IPEndPoint)listener.LocalEndpoint).Port; listener.Stop(); return port; } }