I have a Blazor component that performs multiple validations on an uploaded file. If both validations fail, it should show two separate alerts. In my bUnit test, I mock both validations to fail, yet Assert.Equal(1, alerts.Count())passes, even though I expect it to find 2 and fail.
It appears WaitForAssertion resolves as soon as the first error renders, rather than waiting for the logic to finish.
The Logic (Code Behind):
private void AddFilesToQueue(InputFileChangeEventArgs e){ try { var files = e.GetMultipleFiles(); foreach (var file in files) { if (!fileValidator.IsSizeValid(file.Size, ...)) { filesOverMaxSize.Add(file); } if (!fileValidator.IsTypeValid(file.Name, ...)) { filesWrongType.Add(file); } } if (filesOverMaxSize.Count > 0) { foreach (var file in filesOverMaxSize) FileSizeErrors?.Add($"Size error for {file.Name}"); } if (filesWrongType.Count > 0) { foreach (var file in filesWrongType) FileTypeErrors?.Add($"Type error for {file.Name}"); } StateHasChanged(); } catch (InvalidOperationException ex) { ErrorMessage = ex.Message; }}The Markup:
@if (!string.IsNullOrEmpty(ErrorMessage)){<div class="alert">@ErrorMessage</div>}@foreach (string message in FileSizeErrors ?? new()){<div class="alert">@message</div>}@foreach (string message in FileTypeErrors ?? new()){<div class="alert">@message</div>}The Test:
[Fact]public void SingleErrorShown_WhenSingleFileHasMultipleFailures(){ AddInjectedServices(); var serviceMock = new Mock<IFileValidator<FilingSettingsClient>>(); serviceMock.SetupProperty(m => m.FilingSettings, new FilingSettingsClient()); // Mock BOTH to fail serviceMock.Setup(m => m.IsSizeValid(It.IsAny<long>(), It.IsAny<long>())).Returns(false); serviceMock.Setup(m => m.IsTypeValid(It.IsAny<string>(), It.IsAny<string[]>())).Returns(false); Services.AddSingleton(serviceMock.Object); var component = Render<FileUploader>(); var fileToUpload = InputFileContent.CreateFromBinary(new byte[100], "invalid-type.exe"); // Act component.FindComponent<InputFile>().UploadFiles(fileToUpload); // Assert - This SHOULD fail because 2 alerts should exist, but it PASSES. component.WaitForAssertion(() => { var alerts = component.FindAll(".alert"); Assert.Equal(1, alerts.Count()); }, TimeSpan.FromSeconds(3)); serviceMock.Verify(m => m.IsTypeValid(It.IsAny<string>(), It.IsAny<string[]>()), Times.AtLeastOnce());}Observations:
Verifyconfirms both validation methods are called.If I change the assertion to
Assert.Equal(2, alerts.Count()), the test also passes, proving the second alert eventually appears.It seems
WaitForAssertionexits as soon as the firstifblock triggers a render, ignoring the subsequent state changes.
How do I ensure bUnit waits for the final render state before completing the assertion?