public void WithoutCascadedAuthenticationState_WrapsOutputInCascadingAuthenticationState() { // Arrange/Act var routeData = new RouteData(typeof(TestPageWithNoAuthorization), EmptyParametersDictionary); _renderer.RenderRootComponent(_authorizeRouteViewComponentId, ParameterView.FromDictionary(new Dictionary <string, object> { { nameof(AuthorizeRouteView.RouteData), routeData } })); // Assert var batch = _renderer.Batches.Single(); var componentInstances = batch.ReferenceFrames .Where(f => f.FrameType == RenderTreeFrameType.Component) .Select(f => f.Component); Assert.Collection(componentInstances, // This is the hierarchy inside the AuthorizeRouteView, which contains its // own CascadingAuthenticationState component => Assert.IsType <CascadingAuthenticationState>(component), component => Assert.IsType <CascadingValue <Task <AuthenticationState> > >(component), component => Assert.IsAssignableFrom <AuthorizeViewCore>(component), component => Assert.IsType <LayoutView>(component), component => Assert.IsType <TestPageWithNoAuthorization>(component)); }
public void WhenNotAuthorized_RendersCustomNotAuthorizedContentInsideLayout() { // Arrange var routeData = new RouteData(typeof(TestPageRequiringAuthorization), EmptyParametersDictionary); _testAuthorizationService.NextResult = AuthorizationResult.Failed(); _authenticationStateProvider.CurrentAuthStateTask = Task.FromResult(new AuthenticationState( new ClaimsPrincipal(new TestIdentity { Name = "Bert" }))); // Act RenderFragment <AuthenticationState> customNotAuthorized = state => builder => builder.AddContent(0, $"Go away, {state.User.Identity.Name}"); _renderer.RenderRootComponent(_authorizeRouteViewComponentId, ParameterView.FromDictionary(new Dictionary <string, object> { { nameof(AuthorizeRouteView.RouteData), routeData }, { nameof(AuthorizeRouteView.DefaultLayout), typeof(TestLayout) }, { nameof(AuthorizeRouteView.NotAuthorized), customNotAuthorized }, })); // Assert: renders layout containing "not authorized" message var batch = _renderer.Batches.Single(); var layoutDiff = batch.GetComponentDiffs <TestLayout>().Single(); Assert.Collection(layoutDiff.Edits, edit => AssertPrependText(batch, edit, "Layout starts here"), edit => AssertPrependText(batch, edit, "Go away, Bert"), edit => AssertPrependText(batch, edit, "Layout ends here")); }
public ParameterView DeserializeParameters(IList <ComponentParameter> parametersDefinitions, IList <object> parameterValues) { var parametersDictionary = new Dictionary <string, object?>(StringComparer.OrdinalIgnoreCase); if (parameterValues.Count != parametersDefinitions.Count) { // Mismatched number of definition/parameter values. throw new InvalidOperationException($"The number of parameter definitions '{parametersDefinitions.Count}' does not match the number parameter values '{parameterValues.Count}'."); } for (var i = 0; i < parametersDefinitions.Count; i++) { var definition = parametersDefinitions[i]; if (definition.Name == null) { throw new InvalidOperationException("The name is missing in a parameter definition."); } if (definition.TypeName == null && definition.Assembly == null) { parametersDictionary[definition.Name] = null; } else if (definition.TypeName == null || definition.Assembly == null) { throw new InvalidOperationException($"The parameter definition for '{definition.Name}' is incomplete: Type='{definition.TypeName}' Assembly='{definition.Assembly}'."); } else { var parameterType = _parametersCache.GetParameterType(definition.Assembly, definition.TypeName); if (parameterType == null) { throw new InvalidOperationException($"The parameter '{definition.Name}' with type '{definition.TypeName}' in assembly '{definition.Assembly}' could not be found."); } try { var value = (JsonElement)parameterValues[i]; var parameterValue = JsonSerializer.Deserialize( value.GetRawText(), parameterType, WebAssemblyComponentSerializationSettings.JsonSerializationOptions); parametersDictionary[definition.Name] = parameterValue; } catch (Exception e) { throw new InvalidOperationException("Could not parse the parameter value for parameter '{definition.Name}' of type '{definition.TypeName}' and assembly '{definition.Assembly}'.", e); } } } return(ParameterView.FromDictionary(parametersDictionary)); }
public void RejectsUnknownParameters() { var ex = Assert.Throws <InvalidOperationException>(() => { var parameters = new Dictionary <string, object> { { "unknownparameter", 123 } }; _ = new DynamicComponent().SetParametersAsync(ParameterView.FromDictionary(parameters)); }); Assert.StartsWith( $"{ nameof(DynamicComponent)} does not accept a parameter with the name 'unknownparameter'.", ex.Message); }
public void CanRenderComponentByType() { // Arrange var instance = new DynamicComponent(); var renderer = new TestRenderer(); var componentId = renderer.AssignRootComponentId(instance); var parameters = ParameterView.FromDictionary(new Dictionary <string, object> { { nameof(DynamicComponent.Type), typeof(TestComponent) }, }); // Act renderer.RenderRootComponent(componentId, parameters); // Assert var batch = renderer.Batches.Single(); AssertFrame.Component <TestComponent>(batch.ReferenceFrames[0], 2, 0); AssertFrame.Text(batch.ReferenceFrames[2], "Hello from TestComponent with IntProp=0", 0); }
public void UpdatesOutputWhenRouteDataChanges() { // Arrange/Act 1: Start on some route // Not asserting about the initial output, as that is covered by other tests var routeData = new RouteData(typeof(TestPageWithNoAuthorization), EmptyParametersDictionary); _renderer.RenderRootComponent(_authorizeRouteViewComponentId, ParameterView.FromDictionary(new Dictionary <string, object> { { nameof(AuthorizeRouteView.RouteData), routeData }, { nameof(AuthorizeRouteView.DefaultLayout), typeof(TestLayout) }, })); // Act 2: Move to another route var routeData2 = new RouteData(typeof(TestPageRequiringAuthorization), EmptyParametersDictionary); var render2Task = _renderer.Dispatcher.InvokeAsync(() => _authorizeRouteViewComponent.SetParametersAsync(ParameterView.FromDictionary(new Dictionary <string, object> { { nameof(AuthorizeRouteView.RouteData), routeData2 }, }))); // Assert: we retain the layout instance, and mutate its contents Assert.True(render2Task.IsCompletedSuccessfully); Assert.Equal(2, _renderer.Batches.Count); var batch2 = _renderer.Batches[1]; var diff = batch2.DiffsInOrder.Where(d => d.Edits.Any()).Single(); Assert.Collection(diff.Edits, edit => { // Inside the layout, we add the new content Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); Assert.Equal(1, edit.SiblingIndex); AssertFrame.Text(batch2.ReferenceFrames[edit.ReferenceFrameIndex], "Not authorized"); }, edit => { // ... and remove the old content Assert.Equal(RenderTreeEditType.RemoveFrame, edit.Type); Assert.Equal(2, edit.SiblingIndex); }); }
public void WhenNotAuthorized_RendersDefaultNotAuthorizedContentInsideLayout() { // Arrange var routeData = new RouteData(typeof(TestPageRequiringAuthorization), EmptyParametersDictionary); _testAuthorizationService.NextResult = AuthorizationResult.Failed(); // Act _renderer.RenderRootComponent(_authorizeRouteViewComponentId, ParameterView.FromDictionary(new Dictionary <string, object> { { nameof(AuthorizeRouteView.RouteData), routeData }, { nameof(AuthorizeRouteView.DefaultLayout), typeof(TestLayout) }, })); // Assert: renders layout containing "not authorized" message var batch = _renderer.Batches.Single(); var layoutDiff = batch.GetComponentDiffs <TestLayout>().Single(); Assert.Collection(layoutDiff.Edits, edit => AssertPrependText(batch, edit, "Layout starts here"), edit => AssertPrependText(batch, edit, "Not authorized"), edit => AssertPrependText(batch, edit, "Layout ends here")); }
public void CanRenderComponentByTypeWithParameters() { // Arrange var instance = new DynamicComponent(); var renderer = new TestRenderer(); var childParameters = new Dictionary <string, object> { { nameof(TestComponent.IntProp), 123 }, { nameof(TestComponent.ChildContent), (RenderFragment)(builder => { builder.AddContent(0, "This is some child content"); }) }, }; var parameters = ParameterView.FromDictionary(new Dictionary <string, object> { { nameof(DynamicComponent.Type), typeof(TestComponent) }, { nameof(DynamicComponent.Parameters), childParameters }, }); // Act renderer.RenderRootComponent( renderer.AssignRootComponentId(instance), parameters); // Assert var batch = renderer.Batches.Single(); // It renders a reference to the child component with its parameters AssertFrame.Component <TestComponent>(batch.ReferenceFrames[0], 4, 0); AssertFrame.Attribute(batch.ReferenceFrames[1], nameof(TestComponent.IntProp), 123, 1); AssertFrame.Attribute(batch.ReferenceFrames[2], nameof(TestComponent.ChildContent), 1); // The child component itself is rendered AssertFrame.Text(batch.ReferenceFrames[4], "Hello from TestComponent with IntProp=123", 0); AssertFrame.Text(batch.ReferenceFrames[5], "This is some child content", 0); }
public void CanAccessToChildComponentInstance() { // Arrange var instance = new DynamicComponent(); var renderer = new TestRenderer(); var childParameters = new Dictionary <string, object> { { nameof(TestComponent.IntProp), 123 }, }; var parameters = ParameterView.FromDictionary(new Dictionary <string, object> { { nameof(DynamicComponent.Type), typeof(TestComponent) }, { nameof(DynamicComponent.Parameters), childParameters }, }); // Act renderer.RenderRootComponent( renderer.AssignRootComponentId(instance), parameters); // Assert Assert.IsType <TestComponent>(instance.Instance); Assert.Equal(123, ((TestComponent)instance.Instance).IntProp); }
public void WhenAuthorized_RendersPageInsideLayout() { // Arrange var routeData = new RouteData(typeof(TestPageRequiringAuthorization), new Dictionary <string, object> { { nameof(TestPageRequiringAuthorization.Message), "Hello, world!" } }); _testAuthorizationService.NextResult = AuthorizationResult.Success(); // Act _renderer.RenderRootComponent(_authorizeRouteViewComponentId, ParameterView.FromDictionary(new Dictionary <string, object> { { nameof(AuthorizeRouteView.RouteData), routeData }, { nameof(AuthorizeRouteView.DefaultLayout), typeof(TestLayout) }, })); // Assert: renders layout var batch = _renderer.Batches.Single(); var layoutDiff = batch.GetComponentDiffs <TestLayout>().Single(); Assert.Collection(layoutDiff.Edits, edit => AssertPrependText(batch, edit, "Layout starts here"), edit => { Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); AssertFrame.Component <TestPageRequiringAuthorization>(batch.ReferenceFrames[edit.ReferenceFrameIndex]); }, edit => AssertPrependText(batch, edit, "Layout ends here")); // Assert: renders page var pageDiff = batch.GetComponentDiffs <TestPageRequiringAuthorization>().Single(); Assert.Collection(pageDiff.Edits, edit => AssertPrependText(batch, edit, "Hello from the page with message: Hello, world!")); }
static CascadingValue <T> CreateCascadingValueComponent <T>(T value, string name = null) { var supplier = new CascadingValue <T>(); var renderer = new TestRenderer(); supplier.Attach(new RenderHandle(renderer, 0)); var supplierParams = new Dictionary <string, object> { { "Value", value } }; if (name != null) { supplierParams.Add("Name", name); } renderer.Dispatcher.InvokeAsync((Action)(() => supplier.SetParametersAsync(ParameterView.FromDictionary(supplierParams)))); return(supplier); }
public void WhenAuthorizing_RendersCustomAuthorizingContentInsideLayout() { // Arrange var routeData = new RouteData(typeof(TestPageRequiringAuthorization), EmptyParametersDictionary); var authStateTcs = new TaskCompletionSource <AuthenticationState>(); _authenticationStateProvider.CurrentAuthStateTask = authStateTcs.Task; RenderFragment customAuthorizing = builder => builder.AddContent(0, "Hold on, we're checking your papers."); // Act var firstRenderTask = _renderer.RenderRootComponentAsync(_authorizeRouteViewComponentId, ParameterView.FromDictionary(new Dictionary <string, object> { { nameof(AuthorizeRouteView.RouteData), routeData }, { nameof(AuthorizeRouteView.DefaultLayout), typeof(TestLayout) }, { nameof(AuthorizeRouteView.Authorizing), customAuthorizing }, })); // Assert: renders layout containing "authorizing" message Assert.False(firstRenderTask.IsCompleted); var batch = _renderer.Batches.Single(); var layoutDiff = batch.GetComponentDiffs <TestLayout>().Single(); Assert.Collection(layoutDiff.Edits, edit => AssertPrependText(batch, edit, "Layout starts here"), edit => AssertPrependText(batch, edit, "Hold on, we're checking your papers."), edit => AssertPrependText(batch, edit, "Layout ends here")); }
public async Task WhenAuthorizing_RendersDefaultAuthorizingContentInsideLayout() { // Arrange var routeData = new RouteData(typeof(TestPageRequiringAuthorization), EmptyParametersDictionary); var authStateTcs = new TaskCompletionSource <AuthenticationState>(); _authenticationStateProvider.CurrentAuthStateTask = authStateTcs.Task; RenderFragment <AuthenticationState> customNotAuthorized = state => builder => builder.AddContent(0, $"Go away, {state.User.Identity.Name}"); // Act var firstRenderTask = _renderer.RenderRootComponentAsync(_authorizeRouteViewComponentId, ParameterView.FromDictionary(new Dictionary <string, object> { { nameof(AuthorizeRouteView.RouteData), routeData }, { nameof(AuthorizeRouteView.DefaultLayout), typeof(TestLayout) }, { nameof(AuthorizeRouteView.NotAuthorized), customNotAuthorized }, })); // Assert: renders layout containing "authorizing" message Assert.False(firstRenderTask.IsCompleted); var batch = _renderer.Batches.Single(); var layoutDiff = batch.GetComponentDiffs <TestLayout>().Single(); Assert.Collection(layoutDiff.Edits, edit => AssertPrependText(batch, edit, "Layout starts here"), edit => AssertPrependText(batch, edit, "Authorizing..."), edit => AssertPrependText(batch, edit, "Layout ends here")); // Act 2: updates when authorization completes authStateTcs.SetResult(new AuthenticationState( new ClaimsPrincipal(new TestIdentity { Name = "Bert" }))); await firstRenderTask; // Assert 2: Only the layout is updated batch = _renderer.Batches.Skip(1).Single(); var nonEmptyDiff = batch.DiffsInOrder.Where(d => d.Edits.Any()).Single(); Assert.Equal(layoutDiff.ComponentId, nonEmptyDiff.ComponentId); Assert.Collection(nonEmptyDiff.Edits, edit => { Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); Assert.Equal(1, edit.SiblingIndex); AssertFrame.Text(batch.ReferenceFrames[edit.ReferenceFrameIndex], "Go away, Bert"); }); }