Exemple #1
0
        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));
        }
Exemple #2
0
        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"));
        }
Exemple #3
0
        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);
        }
Exemple #6
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);
            });
        }
Exemple #7
0
        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);
        }
Exemple #10
0
        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!"));
        }
Exemple #11
0
        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);
        }
Exemple #12
0
        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"));
        }
Exemple #13
0
        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");
            });
        }