192 lines
8.7 KiB
C#
192 lines
8.7 KiB
C#
// Copyright (c) .NET Foundation. All rights reserved.
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
using System;
|
|
using Microsoft.AspNetCore.Components.Rendering;
|
|
using Microsoft.AspNetCore.Components.RenderTree;
|
|
using Microsoft.AspNetCore.Components.Test.Helpers;
|
|
using Xunit;
|
|
|
|
namespace Microsoft.AspNetCore.Components.Test
|
|
{
|
|
public class RenderTreeUpdaterTest
|
|
{
|
|
[Fact]
|
|
public void IgnoresUnknownEventHandlerId()
|
|
{
|
|
// Arrange
|
|
var valuePropName = "testprop";
|
|
var renderer = new TestRenderer();
|
|
var builder = new RenderTreeBuilder();
|
|
builder.OpenElement(0, "elem");
|
|
builder.AddAttribute(1, "eventname", (Action)(() => { }));
|
|
builder.SetUpdatesAttributeName(valuePropName);
|
|
builder.AddAttribute(2, valuePropName, "initial value");
|
|
builder.CloseElement();
|
|
var frames = builder.GetFrames();
|
|
frames.Array[1] = frames.Array[1].WithAttributeEventHandlerId(123); // An unrelated event
|
|
|
|
// Act
|
|
RenderTreeUpdater.UpdateToMatchClientState(builder, 456, "new value");
|
|
|
|
// Assert
|
|
Assert.Collection(frames.AsEnumerable(),
|
|
frame => AssertFrame.Element(frame, "elem", 3, 0),
|
|
frame => AssertFrame.Attribute(frame, "eventname", v => Assert.IsType<Action>(v), 1),
|
|
frame => AssertFrame.Attribute(frame, valuePropName, "initial value", 2));
|
|
}
|
|
|
|
[Fact]
|
|
public void IgnoresUpdatesToAttributesIfUnexpectedValueTypeSupplied()
|
|
{
|
|
// Currently we only allow the client to supply a string or a bool, since those are the
|
|
// only types of values we render onto attributes
|
|
|
|
// Arrange
|
|
var valuePropName = "testprop";
|
|
var renderer = new TestRenderer();
|
|
var builder = new RenderTreeBuilder();
|
|
builder.OpenElement(0, "elem");
|
|
builder.AddAttribute(1, "eventname", (Action)(() => { }));
|
|
builder.SetUpdatesAttributeName(valuePropName);
|
|
builder.AddAttribute(2, valuePropName, "initial value");
|
|
builder.CloseElement();
|
|
var frames = builder.GetFrames();
|
|
frames.Array[1] = frames.Array[1].WithAttributeEventHandlerId(123); // An unrelated event
|
|
|
|
// Act
|
|
RenderTreeUpdater.UpdateToMatchClientState(builder, 123, new object());
|
|
|
|
// Assert
|
|
Assert.Collection(frames.AsEnumerable(),
|
|
frame => AssertFrame.Element(frame, "elem", 3, 0),
|
|
frame => AssertFrame.Attribute(frame, "eventname", v => Assert.IsType<Action>(v), 1),
|
|
frame => AssertFrame.Attribute(frame, valuePropName, "initial value", 2));
|
|
}
|
|
|
|
[Fact]
|
|
public void UpdatesOnlyMatchingAttributeValue()
|
|
{
|
|
// Arrange
|
|
var valuePropName = "testprop";
|
|
var renderer = new TestRenderer();
|
|
var builder = new RenderTreeBuilder();
|
|
builder.OpenElement(0, "elem");
|
|
builder.AddAttribute(1, "eventname", (Action)(() => { }));
|
|
builder.SetUpdatesAttributeName(valuePropName);
|
|
builder.AddAttribute(2, valuePropName, "unchanged 1");
|
|
builder.CloseElement();
|
|
builder.OpenElement(3, "elem");
|
|
builder.AddAttribute(4, "eventname", (Action)(() => { }));
|
|
builder.SetUpdatesAttributeName(valuePropName);
|
|
builder.AddAttribute(5, "unrelated prop before", "unchanged 2");
|
|
builder.AddAttribute(6, valuePropName, "initial value");
|
|
builder.AddAttribute(7, "unrelated prop after", "unchanged 3");
|
|
builder.CloseElement();
|
|
var frames = builder.GetFrames();
|
|
frames.Array[1] = frames.Array[1].WithAttributeEventHandlerId(123); // An unrelated event
|
|
frames.Array[4] = frames.Array[4].WithAttributeEventHandlerId(456);
|
|
|
|
// Act
|
|
RenderTreeUpdater.UpdateToMatchClientState(builder, 456, "new value");
|
|
|
|
// Assert
|
|
Assert.Collection(frames.AsEnumerable(),
|
|
frame => AssertFrame.Element(frame, "elem", 3, 0),
|
|
frame => AssertFrame.Attribute(frame, "eventname", v => Assert.IsType<Action>(v), 1),
|
|
frame => AssertFrame.Attribute(frame, valuePropName, "unchanged 1", 2),
|
|
frame => AssertFrame.Element(frame, "elem", 5, 3),
|
|
frame => AssertFrame.Attribute(frame, "eventname", v => Assert.IsType<Action>(v), 4),
|
|
frame => AssertFrame.Attribute(frame, "unrelated prop before", "unchanged 2", 5),
|
|
frame => AssertFrame.Attribute(frame, valuePropName, "new value", 6),
|
|
frame => AssertFrame.Attribute(frame, "unrelated prop after", "unchanged 3", 7));
|
|
}
|
|
|
|
[Fact]
|
|
public void AddsAttributeIfNotFound()
|
|
{
|
|
// Arrange
|
|
var valuePropName = "testprop";
|
|
var renderer = new TestRenderer();
|
|
var builder = new RenderTreeBuilder();
|
|
builder.OpenElement(0, "elem");
|
|
builder.AddAttribute(1, "eventname", (Action)(() => { }));
|
|
builder.SetUpdatesAttributeName(valuePropName);
|
|
builder.CloseElement();
|
|
var frames = builder.GetFrames();
|
|
frames.Array[1] = frames.Array[1].WithAttributeEventHandlerId(123);
|
|
|
|
// Act
|
|
RenderTreeUpdater.UpdateToMatchClientState(builder, 123, "new value");
|
|
frames = builder.GetFrames();
|
|
|
|
// Assert
|
|
Assert.Collection(frames.AsEnumerable(),
|
|
frame => AssertFrame.Element(frame, "elem", 3, 0),
|
|
frame => AssertFrame.Attribute(frame, valuePropName, "new value", RenderTreeDiffBuilder.SystemAddedAttributeSequenceNumber),
|
|
frame => AssertFrame.Attribute(frame, "eventname", v => Assert.IsType<Action>(v), 1));
|
|
}
|
|
|
|
[Fact]
|
|
public void OmitsAttributeIfNotFoundButValueIsOmissible()
|
|
{
|
|
// Arrange
|
|
var valuePropName = "testprop";
|
|
var renderer = new TestRenderer();
|
|
var builder = new RenderTreeBuilder();
|
|
builder.OpenElement(0, "elem");
|
|
builder.AddAttribute(1, "eventname", (Action)(() => { }));
|
|
builder.SetUpdatesAttributeName(valuePropName);
|
|
builder.CloseElement();
|
|
var frames = builder.GetFrames();
|
|
frames.Array[1] = frames.Array[1].WithAttributeEventHandlerId(123);
|
|
|
|
// Act
|
|
RenderTreeUpdater.UpdateToMatchClientState(builder, 123, false);
|
|
frames = builder.GetFrames();
|
|
|
|
// Assert
|
|
Assert.Collection(frames.AsEnumerable(),
|
|
frame => AssertFrame.Element(frame, "elem", 2, 0),
|
|
frame => AssertFrame.Attribute(frame, "eventname", v => Assert.IsType<Action>(v), 1));
|
|
}
|
|
|
|
[Fact]
|
|
public void ExpandsAllAncestorsWhenAddingAttribute()
|
|
{
|
|
// Arrange
|
|
var valuePropName = "testprop";
|
|
var renderer = new TestRenderer();
|
|
var builder = new RenderTreeBuilder();
|
|
builder.OpenElement(0, "grandparent");
|
|
builder.OpenRegion(1);
|
|
builder.OpenElement(2, "sibling before"); // To show that non-ancestors aren't expanded
|
|
builder.CloseElement();
|
|
builder.OpenElement(3, "elem with handler");
|
|
builder.AddAttribute(4, "eventname", (Action)(() => { }));
|
|
builder.SetUpdatesAttributeName(valuePropName);
|
|
builder.CloseElement(); // elem with handler
|
|
builder.CloseRegion();
|
|
builder.CloseElement(); // grandparent
|
|
var frames = builder.GetFrames();
|
|
frames.Array[4] = frames.Array[4].WithAttributeEventHandlerId(123);
|
|
|
|
// Act
|
|
RenderTreeUpdater.UpdateToMatchClientState(builder, 123, "new value");
|
|
frames = builder.GetFrames();
|
|
|
|
// Assert
|
|
Assert.Collection(frames.AsEnumerable(),
|
|
frame => AssertFrame.Element(frame, "grandparent", 6, 0),
|
|
frame => AssertFrame.Region(frame, 5, 1),
|
|
frame => AssertFrame.Element(frame, "sibling before", 1, 2),
|
|
frame => AssertFrame.Element(frame, "elem with handler", 3, 3),
|
|
frame => AssertFrame.Attribute(frame, valuePropName, "new value", RenderTreeDiffBuilder.SystemAddedAttributeSequenceNumber),
|
|
frame => AssertFrame.Attribute(frame, "eventname", v => Assert.IsType<Action>(v), 4));
|
|
}
|
|
|
|
private static ArrayRange<RenderTreeFrame> BuildFrames(params RenderTreeFrame[] frames)
|
|
=> new ArrayRange<RenderTreeFrame>(frames, frames.Length);
|
|
}
|
|
}
|