From 5a8b3f1ef57f904d8358abb52b17aedfb37d4f1c Mon Sep 17 00:00:00 2001 From: Maya Kirova Date: Thu, 23 Jul 2026 13:31:39 +0300 Subject: [PATCH 1/5] Make sure left-over connections are dropped on teradown and suppress any non-critical errors from the logs. --- .../Infrastructure/BlazorApplicationFactory.cs | 7 +++++++ .../Infrastructure/BlazorPageTest.cs | 10 +++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/tests/IgniteUI.Blazor.Lite.IntegrationTests/Infrastructure/BlazorApplicationFactory.cs b/tests/IgniteUI.Blazor.Lite.IntegrationTests/Infrastructure/BlazorApplicationFactory.cs index 561aef64..0a16a4eb 100644 --- a/tests/IgniteUI.Blazor.Lite.IntegrationTests/Infrastructure/BlazorApplicationFactory.cs +++ b/tests/IgniteUI.Blazor.Lite.IntegrationTests/Infrastructure/BlazorApplicationFactory.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; namespace IgniteUI.Blazor.Lite.IntegrationTests.Infrastructure { @@ -36,6 +37,12 @@ protected override void ConfigureWebHost(IWebHostBuilder builder) base.ConfigureWebHost(builder); configureWebHost?.Invoke(builder); + builder.ConfigureLogging(logging => + { + logging.AddFilter("Microsoft.AspNetCore.SignalR.HubConnectionHandler", LogLevel.Critical); + logging.AddFilter("Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionManager", LogLevel.Critical); + }); + // Setting port to 0 means that Kestrel will pick any free a port. // but we don't want freedom, just use to use same port builder.UseUrls("http://127.0.0.1:5249"); diff --git a/tests/IgniteUI.Blazor.Lite.IntegrationTests/Infrastructure/BlazorPageTest.cs b/tests/IgniteUI.Blazor.Lite.IntegrationTests/Infrastructure/BlazorPageTest.cs index 7832d2ae..30089f4d 100644 --- a/tests/IgniteUI.Blazor.Lite.IntegrationTests/Infrastructure/BlazorPageTest.cs +++ b/tests/IgniteUI.Blazor.Lite.IntegrationTests/Infrastructure/BlazorPageTest.cs @@ -47,13 +47,17 @@ public async Task HostTearDown() { host = null; - // Navigate to about:blank to ensure any SignalR - // connections are dropped. - //await Page.GotoAsync("about:blank"); + if (Page != null) + { + await Page.GotoAsync("about:blank").ConfigureAwait(false); + await Page.CloseAsync().ConfigureAwait(false); + } + if (Context != null) { await Context.DisposeAsync().ConfigureAwait(false); } + await currentHost.DisposeAsync().ConfigureAwait(false); } } From 468956e37d2c4f2bfc9c354b79a08c4ed68894b5 Mon Sep 17 00:00:00 2001 From: Maya Kirova Date: Thu, 23 Jul 2026 14:15:12 +0300 Subject: [PATCH 2/5] Attempt to fix flicker by waiting for blazor render completion instead of a fixed delay. --- .../Components/Pages/Home.razor | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/tests/IgniteUI.Blazor.Lite.TestBed/Components/Pages/Home.razor b/tests/IgniteUI.Blazor.Lite.TestBed/Components/Pages/Home.razor index be63b693..4e96b062 100644 --- a/tests/IgniteUI.Blazor.Lite.TestBed/Components/Pages/Home.razor +++ b/tests/IgniteUI.Blazor.Lite.TestBed/Components/Pages/Home.razor @@ -26,6 +26,7 @@ private Dictionary componentParameters = new(); private List errorMessages = new List(); private string eventMessage = string.Empty; + private TaskCompletionSource? pendingRender; private IConfigurationRoot config; @@ -40,6 +41,8 @@ protected override async Task OnAfterRenderAsync(bool firstRender) { + this.pendingRender?.TrySetResult(true); + if (firstRender) { await JS.InvokeVoidAsync("onAfterRender"); @@ -254,8 +257,7 @@ } // set prop and wait for state to change parameters.Add(p.Name, value!); - StateHasChanged(); - await Task.Delay(1); + await WaitForRenderAsync(p.Name); var clientPropName = ReflectionUtils.GetActualPropertyName(p); var clientValue = await GetClientPropValue(clientPropName); @@ -270,6 +272,24 @@ } } + private async Task WaitForRenderAsync(string propName, int timeoutMs = 1000) + { + // new TaskCompletionSource that will wait for render + var renderTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + this.pendingRender = renderTcs; + + // trigger StateHasChanged to request a render. + await InvokeAsync(StateHasChanged); + + + // when render task finishes in OnAfterRenderAsync (or on timeout) continue. + var completed = await Task.WhenAny(renderTcs.Task, Task.Delay(timeoutMs)); + if (completed != renderTcs.Task) + { + this.errorMessages.Add("Timed out waiting for component render after setting property: " + propName); + } + } + // in cases of slower operations, connection closes and execution stops, hence adding a try catch with a 5 second timeout and retry if needed. public async Task GetClientPropValue(string propName, int retry = 1) { @@ -358,4 +378,4 @@ { eventMessage = $"Event fired."; } -} \ No newline at end of file +} From 7ebc692d2735142eaa1bc2e45bc6c49bea8fe2cd Mon Sep 17 00:00:00 2001 From: Maya Kirova Date: Thu, 23 Jul 2026 16:43:27 +0300 Subject: [PATCH 3/5] Try without explicitly filtering log. --- .../Infrastructure/BlazorApplicationFactory.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/IgniteUI.Blazor.Lite.IntegrationTests/Infrastructure/BlazorApplicationFactory.cs b/tests/IgniteUI.Blazor.Lite.IntegrationTests/Infrastructure/BlazorApplicationFactory.cs index 0a16a4eb..561aef64 100644 --- a/tests/IgniteUI.Blazor.Lite.IntegrationTests/Infrastructure/BlazorApplicationFactory.cs +++ b/tests/IgniteUI.Blazor.Lite.IntegrationTests/Infrastructure/BlazorApplicationFactory.cs @@ -4,7 +4,6 @@ using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; namespace IgniteUI.Blazor.Lite.IntegrationTests.Infrastructure { @@ -37,12 +36,6 @@ protected override void ConfigureWebHost(IWebHostBuilder builder) base.ConfigureWebHost(builder); configureWebHost?.Invoke(builder); - builder.ConfigureLogging(logging => - { - logging.AddFilter("Microsoft.AspNetCore.SignalR.HubConnectionHandler", LogLevel.Critical); - logging.AddFilter("Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionManager", LogLevel.Critical); - }); - // Setting port to 0 means that Kestrel will pick any free a port. // but we don't want freedom, just use to use same port builder.UseUrls("http://127.0.0.1:5249"); From de78f9ba62f3095a5f28068cec49d7c1ae99c8be Mon Sep 17 00:00:00 2001 From: Maya Kirova Date: Thu, 6 Aug 2026 16:23:18 +0300 Subject: [PATCH 4/5] chore(*): Apply copilot review suggestions. --- .../Infrastructure/BlazorPageTest.cs | 18 ++++++++++++++++-- .../Components/Pages/Home.razor | 19 ++++++++++++++----- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/tests/IgniteUI.Blazor.Lite.IntegrationTests/Infrastructure/BlazorPageTest.cs b/tests/IgniteUI.Blazor.Lite.IntegrationTests/Infrastructure/BlazorPageTest.cs index 30089f4d..1677a959 100644 --- a/tests/IgniteUI.Blazor.Lite.IntegrationTests/Infrastructure/BlazorPageTest.cs +++ b/tests/IgniteUI.Blazor.Lite.IntegrationTests/Infrastructure/BlazorPageTest.cs @@ -49,8 +49,22 @@ public async Task HostTearDown() if (Page != null) { - await Page.GotoAsync("about:blank").ConfigureAwait(false); - await Page.CloseAsync().ConfigureAwait(false); + try + { + await Page.GotoAsync("about:blank").ConfigureAwait(false); + } + catch (PlaywrightException) + { + // Best-effort teardown. + } + try + { + await Page.CloseAsync().ConfigureAwait(false); + } + catch (PlaywrightException) + { + // Best-effort teardown. + } } if (Context != null) diff --git a/tests/IgniteUI.Blazor.Lite.TestBed/Components/Pages/Home.razor b/tests/IgniteUI.Blazor.Lite.TestBed/Components/Pages/Home.razor index d7f23186..b9fdfb7b 100644 --- a/tests/IgniteUI.Blazor.Lite.TestBed/Components/Pages/Home.razor +++ b/tests/IgniteUI.Blazor.Lite.TestBed/Components/Pages/Home.razor @@ -41,7 +41,9 @@ protected override async Task OnAfterRenderAsync(bool firstRender) { - this.pendingRender?.TrySetResult(true); + var renderTcs = this.pendingRender; + this.pendingRender = null; + renderTcs?.TrySetResult(true); if (firstRender) { @@ -320,18 +322,25 @@ private async Task WaitForRenderAsync(string propName, int timeoutMs = 1000) { - // new TaskCompletionSource that will wait for render - var renderTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - this.pendingRender = renderTcs; + var renderTcs = this.pendingRender; + if (renderTcs == null || renderTcs.Task.IsCompleted) + { + renderTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + this.pendingRender = renderTcs; + } // trigger StateHasChanged to request a render. await InvokeAsync(StateHasChanged); - // when render task finishes in OnAfterRenderAsync (or on timeout) continue. var completed = await Task.WhenAny(renderTcs.Task, Task.Delay(timeoutMs)); if (completed != renderTcs.Task) { + if (ReferenceEquals(this.pendingRender, renderTcs)) + { + this.pendingRender = null; + } + this.errorMessages.Add("Timed out waiting for component render after setting property: " + propName); } } From c0470627b84633c3ed9b4b526e215d624d276f58 Mon Sep 17 00:00:00 2001 From: Maya Kirova Date: Fri, 7 Aug 2026 14:49:30 +0300 Subject: [PATCH 5/5] Revert teardown fixes. --- .../Infrastructure/BlazorPageTest.cs | 24 +++---------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/tests/IgniteUI.Blazor.Lite.IntegrationTests/Infrastructure/BlazorPageTest.cs b/tests/IgniteUI.Blazor.Lite.IntegrationTests/Infrastructure/BlazorPageTest.cs index 1677a959..7832d2ae 100644 --- a/tests/IgniteUI.Blazor.Lite.IntegrationTests/Infrastructure/BlazorPageTest.cs +++ b/tests/IgniteUI.Blazor.Lite.IntegrationTests/Infrastructure/BlazorPageTest.cs @@ -47,31 +47,13 @@ public async Task HostTearDown() { host = null; - if (Page != null) - { - try - { - await Page.GotoAsync("about:blank").ConfigureAwait(false); - } - catch (PlaywrightException) - { - // Best-effort teardown. - } - try - { - await Page.CloseAsync().ConfigureAwait(false); - } - catch (PlaywrightException) - { - // Best-effort teardown. - } - } - + // Navigate to about:blank to ensure any SignalR + // connections are dropped. + //await Page.GotoAsync("about:blank"); if (Context != null) { await Context.DisposeAsync().ConfigureAwait(false); } - await currentHost.DisposeAsync().ConfigureAwait(false); } }