().Single().ComponentId;
+ var frames = renderer.GetCurrentRenderTreeFrames(errorBoundaryId).AsEnumerable();
+ Assert.Collection(frames,
+ frame => AssertFrame.Element(frame, "div", subtreeLength: 2),
+ frame => AssertFrame.Attribute(frame, "class", "blazor-error-boundary"));
+ }
+
[Fact]
public async Task ComponentBaseDoesntRenderWhenOnInitializedAsyncFaultedTask()
{
@@ -729,6 +814,8 @@ private class TestComponentErrorBuildRenderTree : ComponentBase
[Parameter] public bool FaultedTaskOnInitializedAsync { get; set; } = false;
[Parameter] public bool FaultedTaskOnParametersSetAsync { get; set; } = false;
+ [Parameter] public bool ThrowDuringRender { get; set; } = true;
+
public int StateHasChangedCalled { get; set; } = 0;
protected new void StateHasChanged()
@@ -739,7 +826,10 @@ private class TestComponentErrorBuildRenderTree : ComponentBase
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
- throw new InvalidOperationException("Error in BuildRenderTree");
+ if (ThrowDuringRender)
+ {
+ throw new InvalidOperationException("Error in BuildRenderTree");
+ }
}
protected override Task OnInitializedAsync()
diff --git a/src/Components/test/E2ETest/Tests/ErrorBoundaryTest.cs b/src/Components/test/E2ETest/Tests/ErrorBoundaryTest.cs
index 80402e38bf54..a658ba834595 100644
--- a/src/Components/test/E2ETest/Tests/ErrorBoundaryTest.cs
+++ b/src/Components/test/E2ETest/Tests/ErrorBoundaryTest.cs
@@ -114,6 +114,16 @@ public void CanHandleErrorsInlineInErrorBoundaryContent()
AssertGlobalErrorState(true);
}
+ [Fact]
+ public void CanHandleMultipleExceptionsForOnce()
+ {
+ var container = Browser.Exists(By.Id("throw-multiple-errors-foreach-test"));
+ container.FindElement(By.ClassName("throw-multiple-errors-foreach")).Click();
+ Browser.Collection(() => container.FindElements(By.ClassName("error-message")),
+ elem => Assert.Equal("There was an error.", elem.Text));
+ AssertGlobalErrorState(false);
+ }
+
[Fact]
public void CanHandleErrorsAfterDisposingComponent()
{
diff --git a/src/Components/test/testassets/BasicTestApp/ErrorBoundaryTest/ErrorBoundaryCases.razor b/src/Components/test/testassets/BasicTestApp/ErrorBoundaryTest/ErrorBoundaryCases.razor
index 6b1916019d06..c775385128c6 100644
--- a/src/Components/test/testassets/BasicTestApp/ErrorBoundaryTest/ErrorBoundaryCases.razor
+++ b/src/Components/test/testassets/BasicTestApp/ErrorBoundaryTest/ErrorBoundaryCases.razor
@@ -52,6 +52,26 @@
+
+Error boundary can handle multiple errors thrown
+
+
+
+ @if (throwMultipleErrorsForeach)
+ {
+ @foreach (var item in Enumerable.Range(1, 3))
+ {
+
+ }
+ }
+
+
+ There was an error.
+
+
+
throwMultipleErrorsForeach = true)">Throw multiple errors from child
+
+
Exception inline in error boundary markup
This shows that, if an ErrorBoundary itself fails while rendering its own ChildContent, then it can catch its own exception. But if the error comes from the error content, this triggers the "infinite error loop" detection logic and becomes fatal.
@@ -140,6 +160,8 @@
private bool multipleChildrenBeginDelayedError;
private bool twoErrorsInChild;
+ private bool throwMultipleErrorsForeach;
+
void EventHandlerErrorSync()
=> throw new InvalidTimeZoneException("Synchronous error from event handler");
diff --git a/src/Components/test/testassets/BasicTestApp/ErrorBoundaryTest/ForeachErrorsChild.razor b/src/Components/test/testassets/BasicTestApp/ErrorBoundaryTest/ForeachErrorsChild.razor
new file mode 100644
index 000000000000..e2a1d8209ec5
--- /dev/null
+++ b/src/Components/test/testassets/BasicTestApp/ErrorBoundaryTest/ForeachErrorsChild.razor
@@ -0,0 +1,8 @@
+Subcomponent
+
+@code {
+ protected override void OnInitialized()
+ {
+ throw new Exception("Error from foreach child");
+ }
+}