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();
|
var builder = WebApplication.CreateBuilder();
|
||||||
builder.Services.AddRouting();
|
builder.Services.AddRouting();
|
||||||
builder.Services.AddAntiforgery();
|
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();
|
app.MapAuthEndpoints();
|
||||||
|
|
||||||
return ((IEndpointRouteBuilder)app).DataSources
|
return ((IEndpointRouteBuilder)app).DataSources
|
||||||
|
|||||||
@@ -23,7 +23,11 @@ public class AuthPingEndpointTests
|
|||||||
var builder = WebApplication.CreateBuilder();
|
var builder = WebApplication.CreateBuilder();
|
||||||
builder.Services.AddRouting();
|
builder.Services.AddRouting();
|
||||||
builder.Services.AddAntiforgery();
|
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();
|
app.MapAuthEndpoints();
|
||||||
|
|
||||||
return ((IEndpointRouteBuilder)app).DataSources
|
return ((IEndpointRouteBuilder)app).DataSources
|
||||||
|
|||||||
@@ -50,8 +50,11 @@ public class DebugViewDisposalTests : BunitContext
|
|||||||
Services.AddSingleton(comms);
|
Services.AddSingleton(comms);
|
||||||
|
|
||||||
var grpcFactory = new SiteStreamGrpcClientFactory(NullLoggerFactory.Instance);
|
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(
|
var debugStream = new DebugStreamService(
|
||||||
comms, Services.BuildServiceProvider(), grpcFactory,
|
comms, new ServiceCollection().BuildServiceProvider(), grpcFactory,
|
||||||
NullLogger<DebugStreamService>.Instance);
|
NullLogger<DebugStreamService>.Instance);
|
||||||
Services.AddSingleton(debugStream);
|
Services.AddSingleton(debugStream);
|
||||||
|
|
||||||
|
|||||||
@@ -46,8 +46,11 @@ public class DebugViewStreamRaceTests : BunitContext
|
|||||||
Services.AddSingleton(comms);
|
Services.AddSingleton(comms);
|
||||||
|
|
||||||
var grpcFactory = new SiteStreamGrpcClientFactory(NullLoggerFactory.Instance);
|
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(
|
var debugStream = new DebugStreamService(
|
||||||
comms, Services.BuildServiceProvider(), grpcFactory,
|
comms, new ServiceCollection().BuildServiceProvider(), grpcFactory,
|
||||||
NullLogger<DebugStreamService>.Instance);
|
NullLogger<DebugStreamService>.Instance);
|
||||||
Services.AddSingleton(debugStream);
|
Services.AddSingleton(debugStream);
|
||||||
|
|
||||||
|
|||||||
@@ -14,16 +14,16 @@ namespace ScadaLink.CentralUI.Tests.Shared;
|
|||||||
public class DiffDialogTests : BunitContext
|
public class DiffDialogTests : BunitContext
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// DiffDialog applies/removes a body scroll-lock class via JS interop on
|
/// DiffDialog applies/removes a body scroll-lock class and focuses the modal
|
||||||
/// open/close. CentralUI-023 narrowed those catch blocks so they no longer
|
/// via JS interop on open/close. Loose mode auto-completes those void calls
|
||||||
/// swallow every exception — including bUnit's strict-mode unplanned-call
|
/// so a path that <c>await</c>s them (e.g. <c>DisposeAsync</c> →
|
||||||
/// exception. Tests that exercise open/close must therefore register the
|
/// <c>TryUnlockBodyAsync</c>) resumes instead of hanging on a never-completed
|
||||||
/// body-class calls so they do not surface as harness exceptions.
|
/// planned invocation, and no strict-mode unplanned-invocation exception
|
||||||
|
/// surfaces through the narrowed CentralUI-023 catch blocks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void SetupBodyLockInterop()
|
private void SetupBodyLockInterop()
|
||||||
{
|
{
|
||||||
JSInterop.SetupVoid("document.body.classList.add", "modal-open");
|
JSInterop.Mode = JSRuntimeMode.Loose;
|
||||||
JSInterop.SetupVoid("document.body.classList.remove", "modal-open");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|||||||
Reference in New Issue
Block a user