test(central-ui): fix test-host hang in CentralUI.Tests
DiffDialogTests.SetupBodyLockInterop registered bUnit SetupVoid planned invocations that were never completed; DisposeAsync_WhileOpen awaited DiffDialog.DisposeAsync -> TryUnlockBodyAsync -> InvokeVoidAsync on one of them, suspending the test forever so the test host never exited (regression from the CentralUI-023 catch-narrowing). SetupBodyLockInterop now uses Loose JSInterop mode. Also dispose the leaked WebApplication instances in the Auth tests (FileSystemWatcher + ConsoleLoggerProcessor threads) and the extra ServiceProvider in the DebugView tests. Suite now runs 281 tests in ~7s and exits cleanly.
This commit is contained in:
@@ -22,7 +22,11 @@ public class AuthEndpointsCsrfTests
|
||||
var builder = WebApplication.CreateBuilder();
|
||||
builder.Services.AddRouting();
|
||||
builder.Services.AddAntiforgery();
|
||||
var app = builder.Build();
|
||||
// Dispose the host: an undisposed WebApplication leaks its config
|
||||
// PhysicalFileProvider (appsettings reload-watch FileSystemWatcher — a
|
||||
// process-wide macOS run-loop thread) and a ConsoleLoggerProcessor
|
||||
// thread, which keep the test host process alive after the run.
|
||||
using var app = builder.Build();
|
||||
app.MapAuthEndpoints();
|
||||
|
||||
return ((IEndpointRouteBuilder)app).DataSources
|
||||
|
||||
@@ -23,7 +23,11 @@ public class AuthPingEndpointTests
|
||||
var builder = WebApplication.CreateBuilder();
|
||||
builder.Services.AddRouting();
|
||||
builder.Services.AddAntiforgery();
|
||||
var app = builder.Build();
|
||||
// Dispose the host: an undisposed WebApplication leaks its config
|
||||
// PhysicalFileProvider (appsettings reload-watch FileSystemWatcher — a
|
||||
// process-wide macOS run-loop thread) and a ConsoleLoggerProcessor
|
||||
// thread, which keep the test host process alive after the run.
|
||||
using var app = builder.Build();
|
||||
app.MapAuthEndpoints();
|
||||
|
||||
return ((IEndpointRouteBuilder)app).DataSources
|
||||
|
||||
@@ -50,8 +50,11 @@ public class DebugViewDisposalTests : BunitContext
|
||||
Services.AddSingleton(comms);
|
||||
|
||||
var grpcFactory = new SiteStreamGrpcClientFactory(NullLoggerFactory.Instance);
|
||||
// An empty throwaway provider — these tests never call StartStreamAsync,
|
||||
// so the provider is unused. (Services.BuildServiceProvider() would leak
|
||||
// an undisposed provider.)
|
||||
var debugStream = new DebugStreamService(
|
||||
comms, Services.BuildServiceProvider(), grpcFactory,
|
||||
comms, new ServiceCollection().BuildServiceProvider(), grpcFactory,
|
||||
NullLogger<DebugStreamService>.Instance);
|
||||
Services.AddSingleton(debugStream);
|
||||
|
||||
|
||||
@@ -46,8 +46,11 @@ public class DebugViewStreamRaceTests : BunitContext
|
||||
Services.AddSingleton(comms);
|
||||
|
||||
var grpcFactory = new SiteStreamGrpcClientFactory(NullLoggerFactory.Instance);
|
||||
// An empty throwaway provider — these tests drive HandleStreamEvent
|
||||
// directly and never call StartStreamAsync, so the provider is unused.
|
||||
// (Services.BuildServiceProvider() would leak an undisposed provider.)
|
||||
var debugStream = new DebugStreamService(
|
||||
comms, Services.BuildServiceProvider(), grpcFactory,
|
||||
comms, new ServiceCollection().BuildServiceProvider(), grpcFactory,
|
||||
NullLogger<DebugStreamService>.Instance);
|
||||
Services.AddSingleton(debugStream);
|
||||
|
||||
|
||||
@@ -14,16 +14,16 @@ namespace ScadaLink.CentralUI.Tests.Shared;
|
||||
public class DiffDialogTests : BunitContext
|
||||
{
|
||||
/// <summary>
|
||||
/// DiffDialog applies/removes a body scroll-lock class via JS interop on
|
||||
/// open/close. CentralUI-023 narrowed those catch blocks so they no longer
|
||||
/// swallow every exception — including bUnit's strict-mode unplanned-call
|
||||
/// exception. Tests that exercise open/close must therefore register the
|
||||
/// body-class calls so they do not surface as harness exceptions.
|
||||
/// DiffDialog applies/removes a body scroll-lock class and focuses the modal
|
||||
/// via JS interop on open/close. Loose mode auto-completes those void calls
|
||||
/// so a path that <c>await</c>s them (e.g. <c>DisposeAsync</c> →
|
||||
/// <c>TryUnlockBodyAsync</c>) resumes instead of hanging on a never-completed
|
||||
/// planned invocation, and no strict-mode unplanned-invocation exception
|
||||
/// surfaces through the narrowed CentralUI-023 catch blocks.
|
||||
/// </summary>
|
||||
private void SetupBodyLockInterop()
|
||||
{
|
||||
JSInterop.SetupVoid("document.body.classList.add", "modal-open");
|
||||
JSInterop.SetupVoid("document.body.classList.remove", "modal-open");
|
||||
JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
Reference in New Issue
Block a user