@@ -372,6 +372,126 @@ public async Task DoesNotRenderAfterOnInitAsyncTaskIsCancelledUsingCancellationT
372
372
Assert . NotEmpty ( renderer . Batches ) ;
373
373
}
374
374
375
+ [ Fact ]
376
+ public async Task ErrorBoundaryHandlesOnInitializedAsyncReturnFaultedTask ( )
377
+ {
378
+ // Arrange
379
+ var renderer = new TestRenderer ( ) ;
380
+ TestErrorBoundary capturedBoundary = null ;
381
+
382
+ // Create root component that wraps the TestComponentErrorBuildRenderTree in an TestErrorBoundary
383
+ var rootComponent = new TestComponent ( ) ;
384
+ rootComponent . ChildContent = builder =>
385
+ {
386
+ builder . OpenComponent < TestErrorBoundary > ( 0 ) ;
387
+ builder . AddComponentParameter ( 1 , nameof ( TestErrorBoundary . ChildContent ) , ( RenderFragment ) ( childBuilder =>
388
+ {
389
+ childBuilder . OpenComponent < TestComponentErrorBuildRenderTree > ( 0 ) ;
390
+ childBuilder . AddComponentParameter ( 1 , nameof ( TestComponentErrorBuildRenderTree . FaultedTaskOnInitializedAsync ) , true ) ;
391
+ childBuilder . CloseComponent ( ) ;
392
+ } ) ) ;
393
+ builder . AddComponentReferenceCapture ( 2 , inst => capturedBoundary = ( TestErrorBoundary ) inst ) ;
394
+ builder . CloseComponent ( ) ;
395
+ } ;
396
+
397
+ // Act
398
+ var rootComponentId = renderer . AssignRootComponentId ( rootComponent ) ;
399
+ await renderer . RenderRootComponentAsync ( rootComponentId ) ;
400
+
401
+ // Assert
402
+ Assert . NotNull ( capturedBoundary ) ;
403
+ Assert . NotNull ( capturedBoundary ! . ReceivedException ) ;
404
+ Assert . Equal ( typeof ( InvalidTimeZoneException ) , capturedBoundary ! . ReceivedException . GetType ( ) ) ;
405
+ }
406
+
407
+ [ Fact ]
408
+ public async Task ErrorBoundaryHandlesCallOnParametersSetAsyncReturnFaultedTask ( )
409
+ {
410
+ // Arrange
411
+ var renderer = new TestRenderer ( ) ;
412
+ TestErrorBoundary capturedBoundary = null ;
413
+
414
+ // Create root component that wraps the TestComponentErrorBuildRenderTree in an TestErrorBoundary
415
+ var rootComponent = new TestComponent ( ) ;
416
+ rootComponent . ChildContent = builder =>
417
+ {
418
+ builder . OpenComponent < TestErrorBoundary > ( 0 ) ;
419
+ builder . AddComponentParameter ( 1 , nameof ( TestErrorBoundary . ChildContent ) , ( RenderFragment ) ( childBuilder =>
420
+ {
421
+ childBuilder . OpenComponent < TestComponentErrorBuildRenderTree > ( 0 ) ;
422
+ childBuilder . AddComponentParameter ( 1 , nameof ( TestComponentErrorBuildRenderTree . FaultedTaskOnParametersSetAsync ) , true ) ;
423
+ childBuilder . CloseComponent ( ) ;
424
+ } ) ) ;
425
+ builder . AddComponentReferenceCapture ( 2 , inst => capturedBoundary = ( TestErrorBoundary ) inst ) ;
426
+ builder . CloseComponent ( ) ;
427
+ } ;
428
+
429
+ // Act
430
+ var rootComponentId = renderer . AssignRootComponentId ( rootComponent ) ;
431
+ await renderer . RenderRootComponentAsync ( rootComponentId ) ;
432
+
433
+ // Assert
434
+ Assert . NotNull ( capturedBoundary ) ;
435
+ Assert . NotNull ( capturedBoundary ! . ReceivedException ) ;
436
+ Assert . Equal ( typeof ( InvalidTimeZoneException ) , capturedBoundary ! . ReceivedException . GetType ( ) ) ;
437
+ }
438
+
439
+ [ Fact ]
440
+ public async Task ComponentBaseDoesntRenderWhenOnInitializedAsyncFaultedTask ( )
441
+ {
442
+ // Arrange
443
+ var renderer = new TestRenderer ( ) ;
444
+ renderer . ShouldHandleExceptions = true ;
445
+ TestComponentErrorBuildRenderTree testComponentErrorBuildRenderTree = null ;
446
+
447
+ // Create root component that wraps the TestComponentErrorBuildRenderTree in an TestErrorBoundary
448
+ var rootComponent = new TestComponent ( ) ;
449
+ rootComponent . ChildContent = builder =>
450
+ {
451
+ builder . OpenComponent < TestComponentErrorBuildRenderTree > ( 0 ) ;
452
+ builder . AddComponentParameter ( 1 , nameof ( TestComponentErrorBuildRenderTree . FaultedTaskOnInitializedAsync ) , true ) ;
453
+ builder . AddComponentReferenceCapture ( 2 , inst => testComponentErrorBuildRenderTree = ( TestComponentErrorBuildRenderTree ) inst ) ;
454
+ builder . CloseComponent ( ) ;
455
+ } ;
456
+
457
+ // Act
458
+ var rootComponentId = renderer . AssignRootComponentId ( rootComponent ) ;
459
+ await renderer . RenderRootComponentAsync ( rootComponentId ) ;
460
+
461
+ // Assert
462
+ Assert . IsType < InvalidTimeZoneException > ( renderer . HandledExceptions [ 0 ] ) ;
463
+ Assert . NotNull ( testComponentErrorBuildRenderTree ) ;
464
+ Assert . Equal ( 0 , testComponentErrorBuildRenderTree . StateHasChangedCalled ) ;
465
+ }
466
+
467
+ [ Fact ]
468
+ public async Task ComponentBaseDoesntRenderWhenOnSetParametersSetAsyncFaultedTask ( )
469
+ {
470
+ // Arrange
471
+ var renderer = new TestRenderer ( ) ;
472
+ renderer . ShouldHandleExceptions = true ;
473
+ TestComponentErrorBuildRenderTree testComponentErrorBuildRenderTree = null ;
474
+
475
+ // Create root component that wraps the TestComponentErrorBuildRenderTree in an TestErrorBoundary
476
+ var rootComponent = new TestComponent ( ) ;
477
+ rootComponent . ChildContent = builder =>
478
+ {
479
+ builder . OpenComponent < TestComponentErrorBuildRenderTree > ( 0 ) ;
480
+ builder . AddComponentParameter ( 1 , nameof ( TestComponentErrorBuildRenderTree . FaultedTaskOnParametersSetAsync ) , true ) ;
481
+ builder . AddComponentReferenceCapture ( 2 , inst => testComponentErrorBuildRenderTree = ( TestComponentErrorBuildRenderTree ) inst ) ;
482
+ builder . CloseComponent ( ) ;
483
+ } ;
484
+
485
+ // Act
486
+ var rootComponentId = renderer . AssignRootComponentId ( rootComponent ) ;
487
+ await renderer . RenderRootComponentAsync ( rootComponentId ) ;
488
+
489
+ // Assert
490
+ Assert . IsType < InvalidTimeZoneException > ( renderer . HandledExceptions [ 0 ] ) ;
491
+ Assert . NotNull ( testComponentErrorBuildRenderTree ) ;
492
+ Assert . Equal ( 0 , testComponentErrorBuildRenderTree . StateHasChangedCalled ) ;
493
+ }
494
+
375
495
[ Fact ]
376
496
public async Task DoesNotRenderAfterOnParametersSetAsyncTaskIsCanceled ( )
377
497
{
@@ -491,11 +611,20 @@ private class TestComponent : ComponentBase
491
611
492
612
public int Counter { get ; set ; }
493
613
614
+ public RenderFragment ChildContent { get ; set ; }
615
+
494
616
protected override void BuildRenderTree ( RenderTreeBuilder builder )
495
617
{
496
- builder . OpenElement ( 0 , "p" ) ;
497
- builder . AddContent ( 1 , Counter ) ;
498
- builder . CloseElement ( ) ;
618
+ if ( ChildContent != null )
619
+ {
620
+ builder . AddContent ( 0 , ChildContent ) ;
621
+ }
622
+ else
623
+ {
624
+ builder . OpenElement ( 0 , "p" ) ;
625
+ builder . AddContent ( 1 , Counter ) ;
626
+ builder . CloseElement ( ) ;
627
+ }
499
628
}
500
629
501
630
protected override void OnInitialized ( )
@@ -570,4 +699,65 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
570
699
}
571
700
}
572
701
}
702
+
703
+ private class TestErrorBoundary : ErrorBoundaryBase
704
+ {
705
+ public Exception ReceivedException => CurrentException ;
706
+
707
+ protected override Task OnErrorAsync ( Exception exception )
708
+ {
709
+ return Task . CompletedTask ;
710
+ }
711
+
712
+ protected override void BuildRenderTree ( RenderTreeBuilder builder )
713
+ {
714
+ if ( CurrentException == null )
715
+ {
716
+ builder . AddContent ( 0 , ChildContent ) ;
717
+ }
718
+ else
719
+ {
720
+ builder . OpenElement ( 2 , "div" ) ;
721
+ builder . AddAttribute ( 3 , "class" , "blazor-error-boundary" ) ;
722
+ builder . CloseElement ( ) ;
723
+ }
724
+ }
725
+ }
726
+
727
+ private class TestComponentErrorBuildRenderTree : ComponentBase
728
+ {
729
+ [ Parameter ] public bool FaultedTaskOnInitializedAsync { get ; set ; } = false ;
730
+ [ Parameter ] public bool FaultedTaskOnParametersSetAsync { get ; set ; } = false ;
731
+
732
+ public int StateHasChangedCalled { get ; set ; } = 0 ;
733
+
734
+ protected new void StateHasChanged ( )
735
+ {
736
+ StateHasChangedCalled ++ ;
737
+ base . StateHasChanged ( ) ;
738
+ }
739
+
740
+ protected override void BuildRenderTree ( RenderTreeBuilder builder )
741
+ {
742
+ throw new InvalidOperationException ( "Error in BuildRenderTree" ) ;
743
+ }
744
+
745
+ protected override Task OnInitializedAsync ( )
746
+ {
747
+ if ( FaultedTaskOnInitializedAsync )
748
+ {
749
+ return Task . FromException ( new InvalidTimeZoneException ( ) ) ;
750
+ }
751
+ return Task . CompletedTask ;
752
+ }
753
+
754
+ protected override Task OnParametersSetAsync ( )
755
+ {
756
+ if ( FaultedTaskOnParametersSetAsync )
757
+ {
758
+ return Task . FromException ( new InvalidTimeZoneException ( ) ) ;
759
+ }
760
+ return Task . CompletedTask ;
761
+ }
762
+ }
573
763
}
0 commit comments