Esempio n. 1
0
        public void DisposesEventHandlersWhenAncestorElementRemoved()
        {
            // Arrange
            var            renderer         = new TestRenderer();
            var            eventCount       = 0;
            UIEventHandler origEventHandler = args => { eventCount++; };
            var            component        = new EventComponent {
                Handler = origEventHandler
            };
            var componentId = renderer.AssignComponentId(component);

            renderer.RenderNewBatch(componentId);
            var origEventHandlerId = renderer.Batches.Single()
                                     .ReferenceFrames
                                     .Where(f => f.FrameType == RenderTreeFrameType.Attribute)
                                     .Single(f => f.AttributeEventHandlerId != 0)
                                     .AttributeEventHandlerId;

            // Act/Assert 1: Event handler fires when we trigger it
            Assert.Equal(0, eventCount);
            renderer.DispatchEvent(componentId, origEventHandlerId, args: null);
            Assert.Equal(1, eventCount);

            // Now remove the ancestor element
            component.SkipElement = true;
            renderer.RenderNewBatch(componentId);

            // Act/Assert 2: Can no longer fire the original event
            Assert.Throws <ArgumentException>(() =>
            {
                renderer.DispatchEvent(componentId, origEventHandlerId, args: null);
            });
            Assert.Equal(1, eventCount);
        }
Esempio n. 2
0
        public void ReRendersChildComponentsWhenPropertiesChange()
        {
            // Arrange: First render
            var renderer    = new TestRenderer();
            var firstRender = true;
            var component   = new TestComponent(builder =>
            {
                builder.OpenComponent <MessageComponent>(1);
                builder.AddAttribute(2, nameof(MessageComponent.Message), firstRender ? "first" : "second");
                builder.CloseComponent();
            });

            var rootComponentId = renderer.AssignComponentId(component);

            renderer.RenderNewBatch(rootComponentId);

            var childComponentId = renderer.Batches.Single()
                                   .ReferenceFrames
                                   .Single(frame => frame.FrameType == RenderTreeFrameType.Component)
                                   .ComponentId;

            // Act: Second render
            firstRender = false;
            renderer.RenderNewBatch(rootComponentId);
            var diff = renderer.Batches[1].DiffsByComponentId[childComponentId].Single();

            // Assert
            Assert.Collection(diff.Edits,
                              edit =>
            {
                Assert.Equal(RenderTreeEditType.UpdateText, edit.Type);
                Assert.Equal(0, edit.ReferenceFrameIndex);
            });
            AssertFrame.Text(renderer.Batches[1].ReferenceFrames[0], "second");
        }
Esempio n. 3
0
        public void DisposesEventHandlersWhenOwnerComponentRemoved()
        {
            // Arrange
            var            renderer         = new TestRenderer();
            var            eventCount       = 0;
            UIEventHandler origEventHandler = args => { eventCount++; };
            var            component        = new ConditionalParentComponent <EventComponent>
            {
                IncludeChild    = true,
                ChildParameters = new Dictionary <string, object>
                {
                    { nameof(EventComponent.Handler), origEventHandler }
                }
            };
            var rootComponentId = renderer.AssignComponentId(component);

            renderer.RenderNewBatch(rootComponentId);
            var batch               = renderer.Batches.Single();
            var rootComponentDiff   = batch.DiffsByComponentId[rootComponentId].Single();
            var rootComponentFrame  = batch.ReferenceFrames[0];
            var childComponentFrame = rootComponentDiff.Edits
                                      .Select(e => batch.ReferenceFrames[e.ReferenceFrameIndex])
                                      .Where(f => f.FrameType == RenderTreeFrameType.Component)
                                      .Single();
            var childComponentId   = childComponentFrame.ComponentId;
            var childComponentDiff = batch.DiffsByComponentId[childComponentFrame.ComponentId].Single();
            var eventHandlerId     = batch.ReferenceFrames
                                     .Skip(childComponentDiff.Edits[0].ReferenceFrameIndex) // Search from where the child component frames start
                                     .Where(f => f.FrameType == RenderTreeFrameType.Attribute)
                                     .Single(f => f.AttributeEventHandlerId != 0)
                                     .AttributeEventHandlerId;

            // Act/Assert 1: Event handler fires when we trigger it
            Assert.Equal(0, eventCount);
            renderer.DispatchEvent(childComponentId, eventHandlerId, args: null);
            Assert.Equal(1, eventCount);

            // Now remove the EventComponent
            component.IncludeChild = false;
            renderer.RenderNewBatch(rootComponentId);

            // Act/Assert 2: Can no longer fire the original event
            Assert.Throws <ArgumentException>(() =>
            {
                renderer.DispatchEvent(eventHandlerId, eventHandlerId, args: null);
            });
            Assert.Equal(1, eventCount);
        }
Esempio n. 4
0
        public void CanDispatchEventsToTopLevelComponents()
        {
            // Arrange: Render a component with an event handler
            var         renderer     = new TestRenderer();
            UIEventArgs receivedArgs = null;

            var component = new EventComponent
            {
                Handler = args => { receivedArgs = args; }
            };
            var componentId = renderer.AssignComponentId(component);

            renderer.RenderNewBatch(componentId);

            var(eventHandlerFrameIndex, _) = FirstWithIndex(
                renderer.Batches.Single().DiffsByComponentId[componentId].Single().ReferenceFrames,
                frame => frame.AttributeValue != null);

            // Assert: Event not yet fired
            Assert.Null(receivedArgs);

            // Act/Assert: Event can be fired
            var eventArgs = new UIEventArgs();

            renderer.DispatchEvent(componentId, eventHandlerFrameIndex, eventArgs);
            Assert.Same(eventArgs, receivedArgs);
        }
Esempio n. 5
0
        public void CanRenderTopLevelComponents()
        {
            // Arrange
            var renderer  = new TestRenderer();
            var component = new TestComponent(builder =>
            {
                builder.OpenElement(0, "my element");
                builder.AddText(1, "some text");
                builder.CloseElement();
            });

            // Act
            var componentId = renderer.AssignComponentId(component);

            renderer.RenderNewBatch(componentId);

            // Assert
            var diff = renderer.Batches.Single().DiffsByComponentId[componentId].Single();

            Assert.Collection(diff.Edits,
                              edit =>
            {
                Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type);
                Assert.Equal(0, edit.ReferenceFrameIndex);
            });
            Assert.Collection(diff.ReferenceFrames,
                              frame => AssertFrame.Element(frame, "my element", 2),
                              frame => AssertFrame.Text(frame, "some text"));
        }
Esempio n. 6
0
        public void CanRenderNestedComponents()
        {
            // Arrange
            var renderer  = new TestRenderer();
            var component = new TestComponent(builder =>
            {
                builder.AddText(0, "Hello");
                builder.OpenComponent <MessageComponent>(1);
                builder.AddAttribute(2, nameof(MessageComponent.Message), "Nested component output");
                builder.CloseComponent();
            });

            // Act/Assert
            var componentId = renderer.AssignComponentId(component);

            renderer.RenderNewBatch(componentId);
            var batch          = renderer.Batches.Single();
            var componentFrame = batch.DiffsByComponentId[componentId].Single().ReferenceFrames
                                 .Single(frame => frame.FrameType == RenderTreeFrameType.Component);
            var nestedComponentId   = componentFrame.ComponentId;
            var nestedComponentDiff = batch.DiffsByComponentId[nestedComponentId].Single();

            // The nested component exists
            Assert.IsType <MessageComponent>(componentFrame.Component);

            // The nested component was rendered as part of the batch
            Assert.Collection(nestedComponentDiff.Edits,
                              edit =>
            {
                Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type);
                Assert.Equal(0, edit.ReferenceFrameIndex);
            });
            Assert.Collection(nestedComponentDiff.ReferenceFrames,
                              frame => AssertFrame.Text(frame, "Nested component output"));
        }
Esempio n. 7
0
        public void CanReRenderNestedComponents()
        {
            // Arrange: parent component already rendered
            var renderer        = new TestRenderer();
            var parentComponent = new TestComponent(builder =>
            {
                builder.OpenComponent <MessageComponent>(0);
                builder.CloseComponent();
            });
            var parentComponentId = renderer.AssignComponentId(parentComponent);

            renderer.RenderNewBatch(parentComponentId);
            var nestedComponentFrame = renderer.Batches.Single().DiffsByComponentId[parentComponentId]
                                       .Single()
                                       .ReferenceFrames
                                       .Single(frame => frame.FrameType == RenderTreeFrameType.Component);
            var nestedComponent   = (MessageComponent)nestedComponentFrame.Component;
            var nestedComponentId = nestedComponentFrame.ComponentId;

            // Assert: inital render
            nestedComponent.Message = "Render 1";
            renderer.RenderNewBatch(nestedComponentId);
            var firstDiff = renderer.Batches[1].DiffsByComponentId[nestedComponentId].Single();

            Assert.Collection(firstDiff.Edits,
                              edit =>
            {
                Assert.Equal(RenderTreeEditType.UpdateText, edit.Type);
                Assert.Equal(0, edit.ReferenceFrameIndex);
            });
            Assert.Collection(firstDiff.ReferenceFrames,
                              frame => AssertFrame.Text(frame, "Render 1"));

            // Act/Assert: re-render
            nestedComponent.Message = "Render 2";
            renderer.RenderNewBatch(nestedComponentId);
            var secondDiff = renderer.Batches[2].DiffsByComponentId[nestedComponentId].Single();

            Assert.Collection(firstDiff.Edits,
                              edit =>
            {
                Assert.Equal(RenderTreeEditType.UpdateText, edit.Type);
                Assert.Equal(0, edit.ReferenceFrameIndex);
            });
            Assert.Collection(firstDiff.ReferenceFrames,
                              frame => AssertFrame.Text(frame, "Render 2"));
        }
Esempio n. 8
0
        public void NotifiesIHandlePropertiesChangedWhenChanged()
        {
            // Arrange
            var renderer  = new TestRenderer();
            var component = new ConditionalParentComponent <HandlePropertiesChangedComponent>
            {
                IncludeChild    = true,
                ChildParameters = new Dictionary <string, object>
                {
                    { nameof(HandlePropertiesChangedComponent.IntProperty), 123 }
                }
            };
            var rootComponentId = renderer.AssignComponentId(component);

            // Act/Assert 0: Initial render
            renderer.RenderNewBatch(rootComponentId);
            var batch1 = renderer.Batches.Single();
            var childComponentFrame = batch1
                                      .ReferenceFrames.Where(frame => frame.FrameType == RenderTreeFrameType.Component).Single();
            var childComponentId       = childComponentFrame.ComponentId;
            var diffForChildComponent0 = batch1.DiffsByComponentId[childComponentId].Single();
            var childComponentInstance = (HandlePropertiesChangedComponent)childComponentFrame.Component;

            Assert.Equal(1, childComponentInstance.NotificationsCount);
            Assert.Collection(diffForChildComponent0.Edits,
                              edit =>
            {
                Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type);
                AssertFrame.Text(batch1.ReferenceFrames[edit.ReferenceFrameIndex], "Notifications: 1", 0);
            });

            // Act/Assert 1: If properties didn't change, we don't notify
            renderer.RenderNewBatch(rootComponentId);
            Assert.Equal(1, childComponentInstance.NotificationsCount);

            // Act/Assert 2: If properties did change, we do notify
            component.ChildParameters[nameof(HandlePropertiesChangedComponent.IntProperty)] = 456;
            renderer.RenderNewBatch(rootComponentId);
            Assert.Equal(2, childComponentInstance.NotificationsCount);
            var batch3 = renderer.Batches.Skip(2).Single();
            var diffForChildComponent2 = batch3.DiffsByComponentId[childComponentId].Single();

            Assert.Equal(2, childComponentInstance.NotificationsCount);
            AssertFrame.Text(batch3.ReferenceFrames[0], "Notifications: 2", 0);
        }
Esempio n. 9
0
        public void CannotRenderUnknownComponents()
        {
            // Arrange
            var renderer = new TestRenderer();

            // Act/Assert
            Assert.Throws <ArgumentException>(() =>
            {
                renderer.RenderNewBatch(123);
            });
        }
Esempio n. 10
0
        public void PreservesChildComponentInstancesWithNoAttributes()
        {
            // Arrange: First render, capturing child component instance
            var renderer  = new TestRenderer();
            var message   = "Hello";
            var component = new TestComponent(builder =>
            {
                builder.AddText(0, message);
                builder.OpenComponent <MessageComponent>(1);
                builder.CloseComponent();
            });

            var rootComponentId = renderer.AssignComponentId(component);

            renderer.RenderNewBatch(rootComponentId);

            var nestedComponentFrame = renderer.Batches.Single()
                                       .DiffsByComponentId[rootComponentId]
                                       .Single()
                                       .ReferenceFrames
                                       .Single(frame => frame.FrameType == RenderTreeFrameType.Component);
            var nestedComponentInstance = (MessageComponent)nestedComponentFrame.Component;

            // Act: Second render
            message = "Modified message";
            renderer.RenderNewBatch(rootComponentId);

            // Assert
            var batch = renderer.Batches[1];
            var diff  = batch.DiffsByComponentId[rootComponentId].Single();

            Assert.Collection(diff.Edits,
                              edit =>
            {
                Assert.Equal(RenderTreeEditType.UpdateText, edit.Type);
                Assert.Equal(0, edit.ReferenceFrameIndex);
            });
            Assert.Collection(diff.ReferenceFrames,
                              frame => AssertFrame.Text(frame, "Modified message"));
            Assert.False(batch.DiffsByComponentId.ContainsKey(nestedComponentFrame.ComponentId));
        }
Esempio n. 11
0
        public void CanDispatchEventsToNestedComponents()
        {
            UIEventArgs receivedArgs = null;

            // Arrange: Render parent component
            var renderer        = new TestRenderer();
            var parentComponent = new TestComponent(builder =>
            {
                builder.OpenComponent <EventComponent>(0);
                builder.CloseComponent();
            });
            var parentComponentId = renderer.AssignComponentId(parentComponent);

            renderer.RenderNewBatch(parentComponentId);

            // Arrange: Render nested component
            var nestedComponentFrame = renderer.Batches.Single().DiffsByComponentId[parentComponentId]
                                       .Single()
                                       .ReferenceFrames
                                       .Single(frame => frame.FrameType == RenderTreeFrameType.Component);
            var nestedComponent = (EventComponent)nestedComponentFrame.Component;

            nestedComponent.Handler = args => { receivedArgs = args; };
            var nestedComponentId = nestedComponentFrame.ComponentId;

            renderer.RenderNewBatch(nestedComponentId);

            // Find nested component's event handler ndoe
            var(eventHandlerFrameIndex, _) = FirstWithIndex(
                renderer.Batches[1].DiffsByComponentId[nestedComponentId].Single().ReferenceFrames,
                frame => frame.AttributeValue != null);

            // Assert: Event not yet fired
            Assert.Null(receivedArgs);

            // Act/Assert: Event can be fired
            var eventArgs = new UIEventArgs();

            renderer.DispatchEvent(nestedComponentId, eventHandlerFrameIndex, eventArgs);
            Assert.Same(eventArgs, receivedArgs);
        }
Esempio n. 12
0
        public void RenderBatchIncludesListOfDisposedComponents()
        {
            // Arrange
            var renderer    = new TestRenderer();
            var firstRender = true;
            var component   = new TestComponent(builder =>
            {
                builder.OpenElement(7, "some element");
                if (firstRender)
                {
                    builder.OpenComponent <FakeComponent>(100);
                    builder.CloseComponent();
                    builder.OpenComponent <FakeComponent>(150);
                    builder.CloseComponent();
                }
                builder.OpenComponent <FakeComponent>(200);
                builder.CloseComponent();
                builder.CloseElement();
            });

            var rootComponentId = renderer.AssignComponentId(component);

            // Act/Assert 1: First render, capturing child component IDs
            renderer.RenderNewBatch(rootComponentId);
            var childComponentIds = renderer.Batches.Single().DiffsByComponentId[rootComponentId]
                                    .Single()
                                    .ReferenceFrames
                                    .Where(frame => frame.FrameType == RenderTreeFrameType.Component)
                                    .Select(frame => frame.ComponentId)
                                    .ToList();

            Assert.Equal(childComponentIds, new[] { 1, 2, 3 });

            // Act: Second render
            firstRender = false;
            renderer.RenderNewBatch(rootComponentId);

            // Assert: Applicable children are included in disposal list
            Assert.Equal(renderer.Batches[1].DisposedComponentIDs, new[] { 1, 2 });
        }
Esempio n. 13
0
        public void RenderBatchIncludesListOfDisposedComponents()
        {
            // Arrange
            var renderer    = new TestRenderer();
            var firstRender = true;
            var component   = new TestComponent(builder =>
            {
                if (firstRender)
                {
                    // Nested descendants
                    builder.OpenComponent <ConditionalParentComponent <FakeComponent> >(100);
                    builder.AddAttribute(101, nameof(ConditionalParentComponent <FakeComponent> .IncludeChild), true);
                    builder.CloseComponent();
                }
                builder.OpenComponent <FakeComponent>(200);
                builder.CloseComponent();
            });

            var rootComponentId = renderer.AssignComponentId(component);

            // Act/Assert 1: First render, capturing child component IDs
            renderer.RenderNewBatch(rootComponentId);
            var batch             = renderer.Batches.Single();
            var rootComponentDiff = batch.DiffsByComponentId[rootComponentId].Single();
            var childComponentIds = rootComponentDiff
                                    .Edits
                                    .Select(edit => batch.ReferenceFrames[edit.ReferenceFrameIndex])
                                    .Where(frame => frame.FrameType == RenderTreeFrameType.Component)
                                    .Select(frame => frame.ComponentId)
                                    .ToList();

            Assert.Equal(new[] { 1, 2 }, childComponentIds);

            // Act: Second render
            firstRender = false;
            renderer.RenderNewBatch(rootComponentId);

            // Assert: Applicable children are included in disposal list
            Assert.Equal(new[] { 1, 3 }, renderer.Batches[1].DisposedComponentIDs);
        }
Esempio n. 14
0
        public void UpdatesPropertiesOnRetainedChildComponentInstances()
        {
            // Arrange: First render, capturing child component instance
            var renderer = new TestRenderer();
            var objectThatWillNotChange = new object();
            var firstRender             = true;
            var component = new TestComponent(builder =>
            {
                builder.OpenComponent <FakeComponent>(1);
                builder.AddAttribute(2, nameof(FakeComponent.IntProperty), firstRender ? 123 : 256);
                builder.AddAttribute(3, nameof(FakeComponent.ObjectProperty), objectThatWillNotChange);
                builder.AddAttribute(4, nameof(FakeComponent.StringProperty), firstRender ? "String that will change" : "String that did change");
                builder.CloseComponent();
            });

            var rootComponentId = renderer.AssignComponentId(component);

            renderer.RenderNewBatch(rootComponentId);

            var originalComponentFrame = renderer.Batches.Single().DiffsByComponentId[rootComponentId]
                                         .Single()
                                         .ReferenceFrames
                                         .Single(frame => frame.FrameType == RenderTreeFrameType.Component);
            var childComponentInstance = (FakeComponent)originalComponentFrame.Component;

            // Assert 1: properties were assigned
            Assert.Equal(123, childComponentInstance.IntProperty);
            Assert.Equal("String that will change", childComponentInstance.StringProperty);
            Assert.Same(objectThatWillNotChange, childComponentInstance.ObjectProperty);

            // Act: Second render
            firstRender = false;
            renderer.RenderNewBatch(rootComponentId);

            // Assert
            Assert.Equal(256, childComponentInstance.IntProperty);
            Assert.Equal("String that did change", childComponentInstance.StringProperty);
            Assert.Same(objectThatWillNotChange, childComponentInstance.ObjectProperty);
        }
Esempio n. 15
0
        public void NotifiesIHandlePropertiesChangedBeforeFirstRender()
        {
            // Arrange
            var renderer        = new TestRenderer();
            var component       = new HandlePropertiesChangedComponent();
            var rootComponentId = renderer.AssignComponentId(component);

            // Act
            renderer.RenderNewBatch(rootComponentId);

            // Assert
            AssertFrame.Text(renderer.Batches.Single().ReferenceFrames[0], "Notifications: 1", 0);
        }
Esempio n. 16
0
        public void CanReRenderTopLevelComponents()
        {
            // Arrange
            var renderer  = new TestRenderer();
            var component = new MessageComponent {
                Message = "Initial message"
            };
            var componentId = renderer.AssignComponentId(component);

            // Act/Assert: first render
            renderer.RenderNewBatch(componentId);
            var firstDiff = renderer.Batches.Single().DiffsByComponentId[componentId].Single();

            Assert.Collection(firstDiff.Edits,
                              edit =>
            {
                Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type);
                Assert.Equal(0, edit.ReferenceFrameIndex);
            });
            Assert.Collection(firstDiff.ReferenceFrames,
                              frame => AssertFrame.Text(frame, "Initial message"));

            // Act/Assert: second render
            component.Message = "Modified message";
            renderer.RenderNewBatch(componentId);
            var secondDiff = renderer.Batches.Skip(1).Single().DiffsByComponentId[componentId].Single();

            Assert.Collection(firstDiff.Edits,
                              edit =>
            {
                Assert.Equal(RenderTreeEditType.UpdateText, edit.Type);
                Assert.Equal(0, edit.ReferenceFrameIndex);
            });
            Assert.Collection(firstDiff.ReferenceFrames,
                              frame => AssertFrame.Text(frame, "Modified message"));
        }
Esempio n. 17
0
        public void ComponentsCanBeAssociatedWithMultipleRenderers()
        {
            // Arrange
            var renderer1 = new TestRenderer();
            var renderer2 = new TestRenderer();
            var component = new MessageComponent {
                Message = "Hello, world!"
            };
            var renderer1ComponentId = renderer1.AssignComponentId(component);

            renderer2.AssignComponentId(new TestComponent(null)); // Just so they don't get the same IDs
            var renderer2ComponentId = renderer2.AssignComponentId(component);

            // Act/Assert: Render component in renderer1
            renderer1.RenderNewBatch(renderer1ComponentId);
            Assert.True(renderer1.Batches.Single().DiffsByComponentId.ContainsKey(renderer1ComponentId));
            Assert.Empty(renderer2.Batches);

            // Act/Assert: Render same component in renderer2
            renderer2.RenderNewBatch(renderer2ComponentId);
            Assert.True(renderer2.Batches.Single().DiffsByComponentId.ContainsKey(renderer2ComponentId));
        }