public void RendersAuthorizingUntilAuthorizationCompleted() { // Arrange var @event = new ManualResetEventSlim(); var authorizationService = new TestAuthorizationService(); authorizationService.NextResult = AuthorizationResult.Success(); var renderer = CreateTestRenderer(authorizationService); renderer.OnUpdateDisplayComplete = () => { @event.Set(); }; var rootComponent = WrapInAuthorizeView( authorizing: builder => builder.AddContent(0, "Auth pending..."), authorized: context => builder => builder.AddContent(0, $"Hello, {context.User.Identity.Name}!")); var authTcs = new TaskCompletionSource <AuthenticationState>(); rootComponent.AuthenticationState = authTcs.Task; // Act/Assert 1: Auth pending renderer.AssignRootComponentId(rootComponent); rootComponent.TriggerRender(); var batch1 = renderer.Batches.Single(); var authorizeViewComponentId = batch1.GetComponentFrames <AuthorizeView>().Single().ComponentId; var diff1 = batch1.DiffsByComponentId[authorizeViewComponentId].Single(); Assert.Collection(diff1.Edits, edit => { Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); AssertFrame.Text( batch1.ReferenceFrames[edit.ReferenceFrameIndex], "Auth pending..."); }); // Act/Assert 2: Auth process completes asynchronously @event.Reset(); authTcs.SetResult(CreateAuthenticationState("Monsieur").Result); // We need to wait here because the continuations of SetResult will be scheduled to run asynchronously. @event.Wait(Timeout); Assert.Equal(2, renderer.Batches.Count); var batch2 = renderer.Batches[1]; var diff2 = batch2.DiffsByComponentId[authorizeViewComponentId].Single(); Assert.Collection(diff2.Edits, edit => { Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); Assert.Equal(0, edit.SiblingIndex); AssertFrame.Text( batch2.ReferenceFrames[edit.ReferenceFrameIndex], "Hello, Monsieur!"); }); // Assert: The IAuthorizationService was given expected criteria Assert.Collection(authorizationService.AuthorizeCalls, call => { Assert.Equal("Monsieur", call.user.Identity.Name); Assert.Null(call.resource); Assert.Collection(call.requirements, req => Assert.IsType <DenyAnonymousAuthorizationRequirement>(req)); }); }
public void DoesNotNotifyDescendantsOfUpdatedCascadingParameterValuesWhenFixed() { // Arrange var providedValue = "Initial value"; var shouldIncludeChild = true; var renderer = new TestRenderer(); var component = new TestComponent(builder => { builder.OpenComponent <CascadingValue <string> >(0); builder.AddAttribute(1, "Value", providedValue); builder.AddAttribute(2, "IsFixed", true); builder.AddAttribute(3, "ChildContent", new RenderFragment(childBuilder => { if (shouldIncludeChild) { childBuilder.OpenComponent <CascadingParameterConsumerComponent <string> >(0); childBuilder.AddAttribute(1, "RegularParameter", "Goodbye"); childBuilder.CloseComponent(); } })); builder.CloseComponent(); }); // Act 1: Initial render; capture nested component ID var componentId = renderer.AssignRootComponentId(component); component.TriggerRender(); var firstBatch = renderer.Batches.Single(); var nestedComponent = FindComponent <CascadingParameterConsumerComponent <string> >(firstBatch, out var nestedComponentId); Assert.Equal(1, nestedComponent.NumRenders); // Assert: Initial value is supplied to descendant var nestedComponentDiff = firstBatch.DiffsByComponentId[nestedComponentId].Single(); Assert.Collection(nestedComponentDiff.Edits, edit => { Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); AssertFrame.Text( firstBatch.ReferenceFrames[edit.ReferenceFrameIndex], "CascadingParameter=Initial value; RegularParameter=Goodbye"); }); // Act 2: Re-render CascadingValue with new value providedValue = "Updated value"; component.TriggerRender(); // Assert: We did not re-render the descendant Assert.Equal(2, renderer.Batches.Count); var secondBatch = renderer.Batches[1]; Assert.Equal(2, secondBatch.DiffsByComponentId.Count); // Root + CascadingValue, but not nested one Assert.Equal(1, nestedComponent.NumSetParametersCalls); Assert.Equal(1, nestedComponent.NumRenders); // Act 3: Dispose shouldIncludeChild = false; component.TriggerRender(); // Assert: Absence of an exception here implies we didn't cause a problem by // trying to remove a non-existent subscription }
public async Task RendersAuthorizingUntilAuthorizationCompletedAsync() { // Covers https://github.com/dotnet/aspnetcore/pull/31794 // Arrange var authorizationService = new TestAsyncAuthorizationService(); authorizationService.NextResult = AuthorizationResult.Success(); var renderer = CreateTestRenderer(authorizationService); renderer.OnUpdateDisplayComplete = () => { }; var rootComponent = WrapInAuthorizeView( authorizing: builder => builder.AddContent(0, "Auth pending..."), authorized: context => builder => builder.AddContent(0, $"Hello, {context.User.Identity.Name}!")); var authTcs = new TaskCompletionSource <AuthenticationState>(); rootComponent.AuthenticationState = authTcs.Task; // Act/Assert 1: Auth pending renderer.AssignRootComponentId(rootComponent); rootComponent.TriggerRender(); var batch1 = Assert.Single(renderer.Batches); var authorizeViewComponentId = Assert.Single(batch1.GetComponentFrames <AuthorizeView>()).ComponentId; var diff1 = Assert.Single(batch1.DiffsByComponentId[authorizeViewComponentId]); Assert.Collection(diff1.Edits, edit => { Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); AssertFrame.Text( batch1.ReferenceFrames[edit.ReferenceFrameIndex], "Auth pending..."); }); // We need to do this because the continuation from the TCS might run asynchronously // (This wouldn't happen under the sync context or in wasm) var renderTcs = new TaskCompletionSource(); renderer.OnUpdateDisplayComplete = () => renderTcs.SetResult(); authTcs.SetResult(CreateAuthenticationState("Monsieur").Result); await renderTcs.Task; Assert.Equal(2, renderer.Batches.Count); var batch2 = renderer.Batches[1]; var diff2 = Assert.Single(batch2.DiffsByComponentId[authorizeViewComponentId]); Assert.Collection(diff2.Edits, edit => { Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); Assert.Equal(0, edit.SiblingIndex); AssertFrame.Text( batch2.ReferenceFrames[edit.ReferenceFrameIndex], "Hello, Monsieur!"); }); // Assert: The IAuthorizationService was given expected criteria Assert.Collection(authorizationService.AuthorizeCalls, call => { Assert.Equal("Monsieur", call.user.Identity.Name); Assert.Null(call.resource); Assert.Collection(call.requirements, req => Assert.IsType <DenyAnonymousAuthorizationRequirement>(req)); }); }
public static void ComponentWithInstance <T>(RenderTreeFrame frame, int componentId, int?subtreeLength = null, int?sequence = null) where T : IComponent { AssertFrame.Component <T>(frame, subtreeLength, sequence); Assert.IsType <T>(frame.Component); Assert.Equal(componentId, frame.ComponentId); }
public void Render_HtmlBlock_Integration() { // Arrange AdditionalSyntaxTrees.Add(Parse(@" using Microsoft.AspNetCore.Components; namespace Test { public class MyComponent : ComponentBase { [Parameter] public RenderFragment ChildContent { get; set; } } } ")); var component = CompileToComponent(@" <html> <head><meta><meta></head> <body> <MyComponent> <div><span></span><span></span></div> <div>@(""hi"")</div> <div><span></span><span></span></div> <div></div> <div>@(""hi"")</div> <div></div> </MyComponent> </body> </html>"); // Act var frames = GetRenderTree(component); // Assert: component frames are correct Assert.Collection( frames, frame => AssertFrame.Element(frame, "html", 9, 0), frame => AssertFrame.MarkupWhitespace(frame, 1), frame => AssertFrame.Markup(frame, "<head><meta><meta></head>\n ", 2), frame => AssertFrame.Element(frame, "body", 5, 3), frame => AssertFrame.MarkupWhitespace(frame, 4), frame => AssertFrame.Component(frame, "Test.MyComponent", 2, 5), frame => AssertFrame.Attribute(frame, "ChildContent", 6), frame => AssertFrame.MarkupWhitespace(frame, 16), frame => AssertFrame.MarkupWhitespace(frame, 17)); // Assert: Captured ChildContent frames are correct var childFrames = GetFrames((RenderFragment)frames[6].AttributeValue); Assert.Collection( childFrames.AsEnumerable(), frame => AssertFrame.MarkupWhitespace(frame, 7), frame => AssertFrame.Markup(frame, "<div><span></span><span></span></div>\n ", 8), frame => AssertFrame.Element(frame, "div", 2, 9), frame => AssertFrame.Text(frame, "hi", 10), frame => AssertFrame.MarkupWhitespace(frame, 11), frame => AssertFrame.Markup(frame, "<div><span></span><span></span></div>\n <div></div>\n ", 12), frame => AssertFrame.Element(frame, "div", 2, 13), frame => AssertFrame.Text(frame, "hi", 14), frame => AssertFrame.Markup(frame, "\n <div></div>\n ", 15)); }
public static void Attribute(RenderTreeFrame frame, string attributeName, Type valueType, int?sequence = null) { AssertFrame.Attribute(frame, attributeName, sequence); Assert.IsType(valueType, frame.AttributeValue); }
public static void Attribute(RenderTreeFrame frame, string attributeName, Action <object> attributeValidator, int?sequence = null) { AssertFrame.Attribute(frame, attributeName, sequence); attributeValidator(frame.AttributeValue); }
public static void Attribute(RenderTreeFrame frame, string attributeName, Action <EventArgs> attributeEventHandlerValue, int?sequence = null) { AssertFrame.Attribute(frame, attributeName, sequence); Assert.Equal(attributeEventHandlerValue, frame.AttributeValue); }
public static void Attribute(RenderTreeFrame frame, string attributeName, object attributeValue, int?sequence = null) { AssertFrame.Attribute(frame, attributeName, sequence); Assert.Equal(attributeValue, frame.AttributeValue); }
public static void ComponentReferenceCapture(RenderTreeFrame frame, Action <object> action, int?sequence = null) { Assert.Equal(RenderTreeFrameType.ComponentReferenceCapture, frame.FrameType); Assert.Same(action, frame.ComponentReferenceCaptureAction); AssertFrame.Sequence(frame, sequence); }
public static void Attribute(RenderTreeFrame frame, string attributeName, int?sequence = null) { Assert.Equal(RenderTreeFrameType.Attribute, frame.FrameType); Assert.Equal(attributeName, frame.AttributeName); AssertFrame.Sequence(frame, sequence); }
public static void TextWhitespace(RenderTreeFrame frame, int?sequence = null) { Assert.Equal(RenderTreeFrameType.Text, frame.FrameType); AssertFrame.Sequence(frame, sequence); Assert.True(string.IsNullOrWhiteSpace(frame.TextContent)); }
public static void Region(RenderTreeFrame frame, int subtreeLength, int?sequence = null) { Assert.Equal(RenderTreeFrameType.Region, frame.FrameType); Assert.Equal(subtreeLength, frame.RegionSubtreeLength); AssertFrame.Sequence(frame, sequence); }
public void ComponentCanTriggerRenderWhenExistingBatchIsInProgress() { // Arrange var renderer = new TestRenderer(); TestComponent parent = null; var parentRenderCount = 0; parent = new TestComponent(builder => { builder.OpenComponent <ReRendersParentComponent>(0); builder.AddAttribute(1, nameof(ReRendersParentComponent.Parent), parent); builder.CloseComponent(); builder.AddContent(2, $"Parent render count: {++parentRenderCount}"); }); var parentComponentId = renderer.AssignComponentId(parent); // Act parent.TriggerRender(); // Assert var batch = renderer.Batches.Single(); Assert.Equal(4, batch.DiffsInOrder.Count); // First is the parent component's initial render var diff1 = batch.DiffsInOrder[0]; Assert.Equal(parentComponentId, diff1.ComponentId); Assert.Collection(diff1.Edits, edit => { Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); AssertFrame.Component <ReRendersParentComponent>( batch.ReferenceFrames[edit.ReferenceFrameIndex]); }, edit => { Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); AssertFrame.Text( batch.ReferenceFrames[edit.ReferenceFrameIndex], "Parent render count: 1"); }); // Second is the child component's single render var diff2 = batch.DiffsInOrder[1]; Assert.NotEqual(parentComponentId, diff2.ComponentId); var diff2edit = diff2.Edits.Single(); Assert.Equal(RenderTreeEditType.PrependFrame, diff2edit.Type); AssertFrame.Text(batch.ReferenceFrames[diff2edit.ReferenceFrameIndex], "Child is here"); // Third is the parent's triggered render var diff3 = batch.DiffsInOrder[2]; Assert.Equal(parentComponentId, diff3.ComponentId); var diff3edit = diff3.Edits.Single(); Assert.Equal(RenderTreeEditType.UpdateText, diff3edit.Type); AssertFrame.Text(batch.ReferenceFrames[diff3edit.ReferenceFrameIndex], "Parent render count: 2"); // Fourth is child's rerender due to parent rendering var diff4 = batch.DiffsInOrder[3]; Assert.NotEqual(parentComponentId, diff4.ComponentId); Assert.Empty(diff4.Edits); }
public void AllRendersTriggeredSynchronouslyDuringEventHandlerAreHandledAsSingleBatch() { // Arrange: A root component with a child whose event handler explicitly queues // a re-render of both the root component and the child var renderer = new TestRenderer(); var eventCount = 0; TestComponent rootComponent = null; EventComponent childComponent = null; rootComponent = new TestComponent(builder => { builder.AddContent(0, "Child event count: " + eventCount); builder.OpenComponent <EventComponent>(1); builder.AddAttribute(2, nameof(EventComponent.OnTest), args => { eventCount++; rootComponent.TriggerRender(); childComponent.TriggerRender(); }); builder.CloseComponent(); }); var rootComponentId = renderer.AssignComponentId(rootComponent); rootComponent.TriggerRender(); var origBatchReferenceFrames = renderer.Batches.Single().ReferenceFrames; var childComponentFrame = origBatchReferenceFrames .Single(f => f.Component is EventComponent); var childComponentId = childComponentFrame.ComponentId; childComponent = (EventComponent)childComponentFrame.Component; var origEventHandlerId = origBatchReferenceFrames .Where(f => f.FrameType == RenderTreeFrameType.Attribute) .Last(f => f.AttributeEventHandlerId != 0) .AttributeEventHandlerId; Assert.Single(renderer.Batches); // Act renderer.DispatchEvent(childComponentId, origEventHandlerId, args: null); // Assert Assert.Equal(2, renderer.Batches.Count); var batch = renderer.Batches.Last(); Assert.Collection(batch.DiffsInOrder, diff => { // First we triggered the root component to re-render Assert.Equal(rootComponentId, diff.ComponentId); Assert.Collection(diff.Edits, edit => { Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); AssertFrame.Text( batch.ReferenceFrames[edit.ReferenceFrameIndex], "Child event count: 1"); }); }, diff => { // Then the root re-render will have triggered an update to the child Assert.Equal(childComponentId, diff.ComponentId); Assert.Collection(diff.Edits, edit => { Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); AssertFrame.Text( batch.ReferenceFrames[edit.ReferenceFrameIndex], "Render count: 2"); }); }, diff => { // Finally we explicitly requested a re-render of the child Assert.Equal(childComponentId, diff.ComponentId); Assert.Collection(diff.Edits, edit => { Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); AssertFrame.Text( batch.ReferenceFrames[edit.ReferenceFrameIndex], "Render count: 3"); }); }); }
public void CanChangeLayout() { // Arrange var setParametersTask1 = _renderer.Dispatcher.InvokeAsync(() => _layoutViewComponent.SetParametersAsync(ParameterView.FromDictionary(new Dictionary <string, object> { { nameof(LayoutView.Layout), typeof(NestedLayout) }, { nameof(LayoutView.ChildContent), (RenderFragment)(builder => { builder.AddContent(0, "Some content"); }) } }))); Assert.True(setParametersTask1.IsCompletedSuccessfully); // Act var setParametersTask2 = _renderer.Dispatcher.InvokeAsync(() => _layoutViewComponent.SetParametersAsync(ParameterView.FromDictionary(new Dictionary <string, object> { { nameof(LayoutView.Layout), typeof(OtherNestedLayout) }, }))); // Assert Assert.True(setParametersTask2.IsCompletedSuccessfully); Assert.Equal(2, _renderer.Batches.Count); var batch = _renderer.Batches[1]; Assert.Equal(1, batch.DisposedComponentIDs.Count); // Disposes NestedLayout Assert.Collection(batch.DiffsInOrder, diff => Assert.Empty(diff.Edits), // LayoutView rerendered, but with no changes diff => { // RootLayout rerendered, changing child Assert.Collection(diff.Edits, edit => { Assert.Equal(RenderTreeEditType.RemoveFrame, edit.Type); Assert.Equal(1, edit.SiblingIndex); }, edit => { Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); Assert.Equal(1, edit.SiblingIndex); AssertFrame.Component <OtherNestedLayout>( batch.ReferenceFrames[edit.ReferenceFrameIndex], sequence: 0); }); }, diff => { // Inserts new OtherNestedLayout Assert.Collection(diff.Edits, edit => { Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); Assert.Equal(0, edit.SiblingIndex); AssertFrame.Text( batch.ReferenceFrames[edit.ReferenceFrameIndex], "OtherNestedLayout starts here"); }, edit => { Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); Assert.Equal(1, edit.SiblingIndex); AssertFrame.Text( batch.ReferenceFrames[edit.ReferenceFrameIndex], "Some content"); }, edit => { Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); Assert.Equal(2, edit.SiblingIndex); AssertFrame.Text( batch.ReferenceFrames[edit.ReferenceFrameIndex], "OtherNestedLayout ends here"); }); }); }