Component does not re-render if InputFile control included in Razor markup #318
-
Describe the bug Per the razor component below, simply add an Note that the For reference: Microsoft.AspnetCore.Components.Forms.InputFile Also, occasionally, I saw a Bunit recursive render stack overflow, but that seemed to be caused by the Example: @if (Forecasts == null) { <p id="LoadingMessage"><em>Loading...</em></p> } else { <InputFile Id="sampleInputFileIdbad" /> <input type="file" id="sampleInputFileId" /> <table id="forecasttable" class="table"> <thead> <tr> <th>Date</th> <th>Temp. (C)</th> <th>Temp. (F)</th> <th>Summary</th> </tr> </thead> <tbody> @foreach (var forecast in Forecasts) { <tr> <td>@forecast.Date.ToShortDateString()</td> <td>@forecast.TemperatureC</td> <td>@forecast.TemperatureF</td> <td>@forecast.Summary</td> </tr> } </tbody> </table> } @code { [Inject] public HttpClient Http { get; set; } public List<WeatherForecast> Forecasts; protected override async Task OnInitializedAsync() { await LoadForecasts(); } public async Task LoadForecasts() { var results = await Http.GetFromJsonAsync<WeatherForecast[]>("sample-data/weather.json"); Forecasts = results.ToList(); } public class WeatherForecast { public DateTime Date { get; set; } public int TemperatureC { get; set; } public string Summary { get; set; } public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); } } With this test: using System; using System.Collections.Generic; using System.Threading.Tasks; using BBINS.Shared; using Bunit; using RichardSzalay.MockHttp; using Xunit; namespace Client.Test { public class WeatherDisplayTests : TestContext { public WeatherDisplayTests() { var mock = Services.AddMockHttpClient(); mock.When("/sample-data/weather.json").RespondJson(new List<WeatherDisplay.WeatherForecast> { new() { Date = new DateTime(1990, 12, 31), Summary = "Freezing", TemperatureC = 1 }, new() { Date = new DateTime(2001, 12, 31), Summary = "Freezing", TemperatureC = 2 } }); } [Fact] public void WeatherDisplayInitializeTest() { var cut = RenderComponent<WeatherDisplay>(); // Is this a race condition? Assert.Equal("Loading...", cut.Find("p#LoadingMessage").TextContent); } [Fact] public void WeatherDisplayInitializeTest2() { var cut = RenderComponent<WeatherDisplay>(); cut.WaitForState(() => cut.Instance.Forecasts != null); // Will not find the table if InputFile included in Razor cut.WaitForAssertion(() => cut.Find("#forecasttable")); } } } Results in this output:
Expected behavior:
Version info: Test Project <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <IsPackable>false</IsPackable> </PropertyGroup> <ItemGroup> <PackageReference Include="bunit.web" Version="1.0.0-preview-01" /> <PackageReference Include="bunit.xunit" Version="1.0.0-preview-01" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" /> <PackageReference Include="RichardSzalay.MockHttp" Version="6.0.0" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3"> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <PrivateAssets>all</PrivateAssets> </PackageReference> <PackageReference Include="coverlet.collector" Version="1.3.0"> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <PrivateAssets>all</PrivateAssets> </PackageReference> </ItemGroup> <ItemGroup> <ProjectReference Include="..\BBINS-bUnit\BBINS-bUnit.csproj" /> </ItemGroup> </Project> Version Info: Blazor WASM project <Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly"> <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <AssemblyName>BBINS</AssemblyName> <RootNamespace>BBINS</RootNamespace> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.2" /> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.2" PrivateAssets="all" /> <PackageReference Include="System.Net.Http.Json" Version="5.0.0" /> </ItemGroup> </Project>
|
Beta Was this translation helpful? Give feedback.
Replies: 6 comments 7 replies
-
Forgot to include project files: |
Beta Was this translation helpful? Give feedback.
-
First of, excellent bug report writing, thanks for adding all the details @mrakestraw-bbins 🥇🥇 I just did a read through the InputFile component, and it has some JSInterop magic going on, which might be causing the problems... I wonder if this is related to preview-01 adding support for This should be a fun one investigating. And just to clarify, when awaiting something that just returns a completed task immediately, the usage of |
Beta Was this translation helpful? Give feedback.
-
Thanks @egil. Nice library by the way. Wish I had more time to dig in and try to patch it myself. |
Beta Was this translation helpful? Give feedback.
-
This is probably related to this error that sometimes happens when running the tests here in GitHub Actions:
I know this test used to work all the time, so I will have to investigate where a possible regression has been introduced. Gotta love those subtle race condition bugs 😒 |
Beta Was this translation helpful? Give feedback.
-
@mrakestraw-bbins, if I reduce the test case even more, we get a different exception/error, which I actually thing is the root cause, because the error indicate a missing Our CUT: @if (!show) { <div id="loading"/> } else { <InputFile Id="sampleInputFileIdbad" /> <div id="showing"/> } @code { bool show = false; protected override async Task OnInitializedAsync() { await Task.CompletedTask; show = true; } } The test: [Fact] public async Task WeatherDisplayInitializeTest2() { var cut = RenderComponent<WeatherDisplay>(); Assert.Equal(1, cut.FindAll("#showing").Count); } The output:
|
Beta Was this translation helpful? Give feedback.
-
OK, this turns out not to be a race condition or a bug, per say... but more a problem with bUnit not having built in support for the Here is how to write the test, using a mocking framework of choice, to create a mock of the using System; using System.Collections.Generic; using BBINS.Shared; using Bunit; using Bunit.JSInterop; using Microsoft.AspNetCore.Components.Forms; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using NSubstitute; using RichardSzalay.MockHttp; using Xunit; namespace Client.Test { public class WeatherDisplayTests : TestContext { public WeatherDisplayTests() { var mock = Services.AddMockHttpClient(); mock.When("/sample-data/weather.json").RespondJson(new List<WeatherDisplay.WeatherForecast> { new() { Date = new DateTime(1990, 12, 31), Summary = "Freezing", TemperatureC = 1 }, new() { Date = new DateTime(2001, 12, 31), Summary = "Freezing", TemperatureC = 2 } }); var optionsMock = Substitute.For<IOptions<RemoteBrowserFileStreamOptions>>(); Services.AddSingleton<IOptions<RemoteBrowserFileStreamOptions>>(optionsMock); JSInterop.SetupVoid("Blazor._internal.InputFile.init", x => true); } [Fact] public void WeatherDisplayInitializeTest() { var cut = RenderComponent<WeatherDisplay>(); // Is this a race condition? Assert.Equal("Loading...", cut.Find("p#LoadingMessage").TextContent); } [Fact] public void WeatherDisplayInitializeTest2() { var cut = RenderComponent<WeatherDisplay>(); cut.WaitForState(() => cut.Instance.Forecasts != null); // Will not find the table if InputFile included in Razor cut.WaitForAssertion(() => cut.Find("#forecasttable")); } [Fact] public void WeatherDisplayInitializeTest3() { var cut = RenderComponent<WeatherDisplay>(); cut.WaitForAssertion(() => cut.Find("#forecasttable")); } } } |
Beta Was this translation helpful? Give feedback.
OK, this turns out not to be a race condition or a bug, per say... but more a problem with bUnit not having built in support for the
<InputFile>
component.Here is how to write the test, using a mocking framework of choice, to create a mock of the
IOptions<RemoteBrowserFileStreamOptions>
thatInputFile
requires.