Have RenderTreeDiff build its own array of referenced frames rather than pointing to the latest render tree
This is in preparation for supporting multiple diffs for the same component in a single batch (which means we can't rely on there being at most only new render tree per component)
This commit is contained in:
parent
33932f41fc
commit
83fa72bc7e
|
|
@ -229,7 +229,7 @@ function removeAttributeFromDOM(parent: Element, childIndex: number, attributeNa
|
|||
element.removeAttribute(attributeName);
|
||||
}
|
||||
|
||||
function raiseEvent(browserRendererId: number, componentId: number, renderTreeFrameIndex: number, eventInfoType: EventInfoType, eventInfo: any) {
|
||||
function raiseEvent(browserRendererId: number, componentId: number, referenceTreeFrameIndex: number, eventInfoType: EventInfoType, eventInfo: any) {
|
||||
if (!raiseEventMethod) {
|
||||
raiseEventMethod = platform.findMethod(
|
||||
'Microsoft.AspNetCore.Blazor.Browser', 'Microsoft.AspNetCore.Blazor.Browser.Rendering', 'BrowserRendererEventDispatcher', 'DispatchEvent'
|
||||
|
|
@ -239,7 +239,7 @@ function raiseEvent(browserRendererId: number, componentId: number, renderTreeFr
|
|||
const eventDescriptor = {
|
||||
BrowserRendererId: browserRendererId,
|
||||
ComponentId: componentId,
|
||||
RenderTreeFrameIndex: renderTreeFrameIndex,
|
||||
ReferenceTreeFrameIndex: referenceTreeFrameIndex,
|
||||
EventArgsType: eventInfoType
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ namespace Microsoft.AspNetCore.Blazor.Browser.Rendering
|
|||
_browserRendererId = BrowserRendererRegistry.Add(this);
|
||||
}
|
||||
|
||||
internal void DispatchBrowserEvent(int componentId, int renderTreeIndex, UIEventArgs eventArgs)
|
||||
=> DispatchEvent(componentId, renderTreeIndex, eventArgs);
|
||||
internal void DispatchBrowserEvent(int componentId, int referenceTreeIndex, UIEventArgs eventArgs)
|
||||
=> DispatchEvent(componentId, referenceTreeIndex, eventArgs);
|
||||
|
||||
internal void RenderNewBatchInternal(int componentId)
|
||||
=> RenderNewBatch(componentId);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Blazor.Browser.Rendering
|
|||
var browserRenderer = BrowserRendererRegistry.Find(eventDescriptor.BrowserRendererId);
|
||||
browserRenderer.DispatchBrowserEvent(
|
||||
eventDescriptor.ComponentId,
|
||||
eventDescriptor.RenderTreeFrameIndex,
|
||||
eventDescriptor.ReferenceTreeFrameIndex,
|
||||
eventArgs);
|
||||
}
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.Blazor.Browser.Rendering
|
|||
{
|
||||
public int BrowserRendererId { get; set; }
|
||||
public int ComponentId { get; set; }
|
||||
public int RenderTreeFrameIndex { get; set; }
|
||||
public int ReferenceTreeFrameIndex { get; set; }
|
||||
public string EventArgsType { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,15 +51,40 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
/// Appends a new item, automatically resizing the underlying array if necessary.
|
||||
/// </summary>
|
||||
/// <param name="item">The item to append.</param>
|
||||
/// <returns>The index of the appended item.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] // Just like System.Collections.Generic.List<T>
|
||||
public void Append(in T item)
|
||||
public int Append(in T item)
|
||||
{
|
||||
if (_itemsInUse == _items.Length)
|
||||
{
|
||||
SetCapacity(_itemsInUse * 2, preserveContents: true);
|
||||
}
|
||||
|
||||
_items[_itemsInUse++] = item;
|
||||
var indexOfAppendedItem = _itemsInUse++;
|
||||
_items[indexOfAppendedItem] = item;
|
||||
return indexOfAppendedItem;
|
||||
}
|
||||
|
||||
internal int Append(T[] source, int startIndex, int length)
|
||||
{
|
||||
// Expand storage if needed. Using same doubling approach as would
|
||||
// be used if you inserted the items one-by-one.
|
||||
var requiredCapacity = _itemsInUse + length;
|
||||
if (_items.Length < requiredCapacity)
|
||||
{
|
||||
var candidateCapacity = _itemsInUse * 2;
|
||||
while (candidateCapacity < requiredCapacity)
|
||||
{
|
||||
candidateCapacity *= 2;
|
||||
}
|
||||
|
||||
SetCapacity(candidateCapacity, preserveContents: true);
|
||||
}
|
||||
|
||||
Array.Copy(source, startIndex, _items, _itemsInUse, length);
|
||||
var startIndexOfAppendedItems = _itemsInUse;
|
||||
_itemsInUse += length;
|
||||
return startIndexOfAppendedItems;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -94,9 +119,9 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
{
|
||||
SetCapacity((previousItemsInUse + _items.Length) / 2, preserveContents: false);
|
||||
}
|
||||
else
|
||||
else if (previousItemsInUse > 0)
|
||||
{
|
||||
Array.Clear(_items, 0, _itemsInUse); // Release to GC
|
||||
Array.Clear(_items, 0, previousItemsInUse); // Release to GC
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
// 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;
|
||||
|
||||
namespace Microsoft.AspNetCore.Blazor.RenderTree
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes changes to a component's render tree between successive renders,
|
||||
/// as well as the resulting state.
|
||||
/// Describes changes to a component's render tree between successive renders.
|
||||
/// </summary>
|
||||
public readonly struct RenderTreeDiff
|
||||
{
|
||||
|
|
@ -22,19 +19,20 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
public ArrayRange<RenderTreeEdit> Edits { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the latest render tree. That is, the result of applying the <see cref="Edits"/>
|
||||
/// to the previous state.
|
||||
/// Gets render frames that may be referenced by entries in <see cref="Edits"/>.
|
||||
/// For example, edit entries of type <see cref="RenderTreeEditType.PrependFrame"/>
|
||||
/// will point to an entry in this array to specify the subtree to be prepended.
|
||||
/// </summary>
|
||||
public ArrayRange<RenderTreeFrame> CurrentState { get; }
|
||||
public ArrayRange<RenderTreeFrame> ReferenceFrames { get; }
|
||||
|
||||
internal RenderTreeDiff(
|
||||
int componentId,
|
||||
ArrayRange<RenderTreeEdit> entries,
|
||||
ArrayRange<RenderTreeFrame> referenceTree)
|
||||
ArrayRange<RenderTreeFrame> referenceFrames)
|
||||
{
|
||||
ComponentId = componentId;
|
||||
Edits = entries;
|
||||
CurrentState = referenceTree;
|
||||
ReferenceFrames = referenceFrames;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
{
|
||||
private readonly Renderer _renderer;
|
||||
private readonly ArrayBuilder<RenderTreeEdit> _entries = new ArrayBuilder<RenderTreeEdit>(10);
|
||||
private readonly ArrayBuilder<RenderTreeFrame> _referenceFrames = new ArrayBuilder<RenderTreeFrame>(10);
|
||||
|
||||
public RenderTreeDiffComputer(Renderer renderer)
|
||||
{
|
||||
|
|
@ -31,13 +32,14 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
ArrayRange<RenderTreeFrame> newTree)
|
||||
{
|
||||
_entries.Clear();
|
||||
_referenceFrames.Clear();
|
||||
var siblingIndex = 0;
|
||||
|
||||
var slotId = batchBuilder.ReserveUpdatedComponentSlotId();
|
||||
AppendDiffEntriesForRange(batchBuilder, oldTree.Array, 0, oldTree.Count, newTree.Array, 0, newTree.Count, ref siblingIndex);
|
||||
batchBuilder.SetUpdatedComponent(
|
||||
slotId,
|
||||
new RenderTreeDiff(componentId, _entries.ToRange(), newTree));
|
||||
new RenderTreeDiff(componentId, _entries.ToRange(), _referenceFrames.ToRange()));
|
||||
}
|
||||
|
||||
private void AppendDiffEntriesForRange(
|
||||
|
|
@ -136,7 +138,8 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
var newFrameType = newFrame.FrameType;
|
||||
if (newFrameType == RenderTreeFrameType.Attribute)
|
||||
{
|
||||
Append(RenderTreeEdit.SetAttribute(siblingIndex, newStartIndex));
|
||||
var referenceFrameIndex = _referenceFrames.Append(newFrame);
|
||||
Append(RenderTreeEdit.SetAttribute(siblingIndex, referenceFrameIndex));
|
||||
newStartIndex++;
|
||||
}
|
||||
else
|
||||
|
|
@ -146,7 +149,8 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
InstantiateChildComponents(batchBuilder, newTree, newStartIndex);
|
||||
}
|
||||
|
||||
Append(RenderTreeEdit.PrependFrame(siblingIndex, newStartIndex));
|
||||
var referenceFrameIndex = AppendSubtreeToReferenceFrames(newTree, newStartIndex);
|
||||
Append(RenderTreeEdit.PrependFrame(siblingIndex, referenceFrameIndex));
|
||||
newStartIndex = NextSiblingIndex(newFrame, newStartIndex);
|
||||
siblingIndex++;
|
||||
}
|
||||
|
|
@ -180,6 +184,35 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
}
|
||||
}
|
||||
|
||||
public UIEventHandler TemporaryGetEventHandlerMethod(int referenceFrameIndex)
|
||||
{
|
||||
// TODO: Change how event handlers are referenced
|
||||
// The approach used here is invalid. We can't really assume that the event handler exists
|
||||
// in the most recent diff's _referenceFrames. Nor can we assume that its index in the
|
||||
// ComponentState's _renderTreeBuilderCurrent frames array is unchanged (any number of rerenders
|
||||
// might have taken place since then, inserting frames before it, but not actually changing
|
||||
// the delegate instance and therefore not including it in any _referenceFrames).
|
||||
// Need some way of referencing event handlers that is independent of this.
|
||||
var eventHandler = _referenceFrames.Buffer[referenceFrameIndex].AttributeValue as UIEventHandler;
|
||||
return eventHandler
|
||||
?? throw new ArgumentException($"The reference frame at index {referenceFrameIndex} does not specify a {nameof(UIEventHandler)}.");
|
||||
}
|
||||
|
||||
private int AppendSubtreeToReferenceFrames(RenderTreeFrame[] fromTree, int fromIndex)
|
||||
{
|
||||
ref var rootFrame = ref fromTree[fromIndex];
|
||||
var subtreeLength = rootFrame.ElementSubtreeLength;
|
||||
if (subtreeLength == 0)
|
||||
{
|
||||
// It's just a single frame (e.g., a text frame)
|
||||
return _referenceFrames.Append(rootFrame);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _referenceFrames.Append(fromTree, fromIndex, subtreeLength);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateRetainedChildComponent(
|
||||
RenderBatchBuilder batchBuilder,
|
||||
RenderTreeFrame[] oldTree, int oldComponentIndex,
|
||||
|
|
@ -340,7 +373,8 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
var newText = newFrame.TextContent;
|
||||
if (!string.Equals(oldText, newText, StringComparison.Ordinal))
|
||||
{
|
||||
Append(RenderTreeEdit.UpdateText(siblingIndex, newFrameIndex));
|
||||
var referenceFrameIndex = _referenceFrames.Append(newFrame);
|
||||
Append(RenderTreeEdit.UpdateText(siblingIndex, referenceFrameIndex));
|
||||
}
|
||||
siblingIndex++;
|
||||
break;
|
||||
|
|
@ -390,7 +424,9 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
// Elements with different names are treated as completely unrelated
|
||||
InstantiateChildComponents(batchBuilder, newTree, newFrameIndex);
|
||||
DisposeChildComponents(batchBuilder, oldTree, oldFrameIndex);
|
||||
Append(RenderTreeEdit.PrependFrame(siblingIndex, newFrameIndex));
|
||||
|
||||
var referenceFrameIndex = AppendSubtreeToReferenceFrames(newTree, newFrameIndex);
|
||||
Append(RenderTreeEdit.PrependFrame(siblingIndex, referenceFrameIndex));
|
||||
siblingIndex++;
|
||||
Append(RenderTreeEdit.RemoveFrame(siblingIndex));
|
||||
}
|
||||
|
|
@ -415,7 +451,9 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
// Child components of different types are treated as completely unrelated
|
||||
InstantiateChildComponents(batchBuilder, newTree, newFrameIndex);
|
||||
DisposeChildComponents(batchBuilder, oldTree, oldFrameIndex);
|
||||
Append(RenderTreeEdit.PrependFrame(siblingIndex, newFrameIndex));
|
||||
|
||||
var referenceFrameIndex = AppendSubtreeToReferenceFrames(newTree, newFrameIndex);
|
||||
Append(RenderTreeEdit.PrependFrame(siblingIndex, referenceFrameIndex));
|
||||
siblingIndex++;
|
||||
Append(RenderTreeEdit.RemoveFrame(siblingIndex));
|
||||
}
|
||||
|
|
@ -432,7 +470,8 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
var valueChanged = !Equals(oldFrame.AttributeValue, newFrame.AttributeValue);
|
||||
if (valueChanged)
|
||||
{
|
||||
Append(RenderTreeEdit.SetAttribute(siblingIndex, newFrameIndex));
|
||||
var referenceFrameIndex = _referenceFrames.Append(newFrame);
|
||||
Append(RenderTreeEdit.SetAttribute(siblingIndex, referenceFrameIndex));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -440,7 +479,8 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
// Since this code path is never reachable for Razor components (because you
|
||||
// can't have two different attribute names from the same source sequence), we
|
||||
// could consider removing the 'name equality' check entirely for perf
|
||||
Append(RenderTreeEdit.SetAttribute(siblingIndex, newFrameIndex));
|
||||
var referenceFrameIndex = _referenceFrames.Append(newFrame);
|
||||
Append(RenderTreeEdit.SetAttribute(siblingIndex, referenceFrameIndex));
|
||||
Append(RenderTreeEdit.RemoveAttribute(siblingIndex, oldName));
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -19,11 +19,11 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
public readonly int SiblingIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the index of related data in an associated render tree. For example, if the
|
||||
/// Gets the index of related data in an associated render frames array. For example, if the
|
||||
/// <see cref="Type"/> value is <see cref="RenderTreeEditType.PrependFrame"/>, gets the
|
||||
/// index of the new frame data in an associated render tree.
|
||||
/// </summary>
|
||||
public readonly int NewTreeIndex;
|
||||
public readonly int ReferenceFrameIndex;
|
||||
|
||||
/// <summary>
|
||||
/// If the <see cref="Type"/> value is <see cref="RenderTreeEditType.RemoveAttribute"/>,
|
||||
|
|
@ -42,11 +42,11 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
SiblingIndex = siblingIndex;
|
||||
}
|
||||
|
||||
private RenderTreeEdit(RenderTreeEditType type, int siblingIndex, int newTreeIndex) : this()
|
||||
private RenderTreeEdit(RenderTreeEditType type, int siblingIndex, int referenceFrameIndex) : this()
|
||||
{
|
||||
Type = type;
|
||||
SiblingIndex = siblingIndex;
|
||||
NewTreeIndex = newTreeIndex;
|
||||
ReferenceFrameIndex = referenceFrameIndex;
|
||||
}
|
||||
|
||||
private RenderTreeEdit(RenderTreeEditType type, int siblingIndex, string removedAttributeName) : this()
|
||||
|
|
@ -59,14 +59,14 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
internal static RenderTreeEdit RemoveFrame(int siblingIndex)
|
||||
=> new RenderTreeEdit(RenderTreeEditType.RemoveFrame, siblingIndex);
|
||||
|
||||
internal static RenderTreeEdit PrependFrame(int siblingIndex, int newTreeIndex)
|
||||
=> new RenderTreeEdit(RenderTreeEditType.PrependFrame, siblingIndex, newTreeIndex);
|
||||
internal static RenderTreeEdit PrependFrame(int siblingIndex, int referenceFrameIndex)
|
||||
=> new RenderTreeEdit(RenderTreeEditType.PrependFrame, siblingIndex, referenceFrameIndex);
|
||||
|
||||
internal static RenderTreeEdit UpdateText(int siblingIndex, int newTreeIndex)
|
||||
=> new RenderTreeEdit(RenderTreeEditType.UpdateText, siblingIndex, newTreeIndex);
|
||||
internal static RenderTreeEdit UpdateText(int siblingIndex, int referenceFrameIndex)
|
||||
=> new RenderTreeEdit(RenderTreeEditType.UpdateText, siblingIndex, referenceFrameIndex);
|
||||
|
||||
internal static RenderTreeEdit SetAttribute(int siblingIndex, int newTreeIndex)
|
||||
=> new RenderTreeEdit(RenderTreeEditType.SetAttribute, siblingIndex, newTreeIndex);
|
||||
internal static RenderTreeEdit SetAttribute(int siblingIndex, int referenceFrameIndex)
|
||||
=> new RenderTreeEdit(RenderTreeEditType.SetAttribute, siblingIndex, referenceFrameIndex);
|
||||
|
||||
internal static RenderTreeEdit RemoveAttribute(int siblingIndex, string name)
|
||||
=> new RenderTreeEdit(RenderTreeEditType.RemoveAttribute, siblingIndex, name);
|
||||
|
|
|
|||
|
|
@ -58,22 +58,16 @@ namespace Microsoft.AspNetCore.Blazor.Rendering
|
|||
/// <summary>
|
||||
/// Invokes the handler corresponding to an event.
|
||||
/// </summary>
|
||||
/// <param name="renderTreeIndex">The index of the current render tree frame that holds the event handler to be invoked.</param>
|
||||
/// <param name="referenceTreeIndex">The index of the frame in the latest diff reference tree that holds the event handler to be invoked.</param>
|
||||
/// <param name="eventArgs">Arguments to be passed to the event handler.</param>
|
||||
public void DispatchEvent(int renderTreeIndex, UIEventArgs eventArgs)
|
||||
public void DispatchEvent(int referenceTreeIndex, UIEventArgs eventArgs)
|
||||
{
|
||||
if (eventArgs == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(eventArgs));
|
||||
}
|
||||
|
||||
var frames = _renderTreeBuilderCurrent.GetFrames();
|
||||
var eventHandler = frames.Array[renderTreeIndex].AttributeValue as UIEventHandler;
|
||||
if (eventHandler == null)
|
||||
{
|
||||
throw new ArgumentException($"The render tree frame at index {renderTreeIndex} does not specify a {nameof(UIEventHandler)}.");
|
||||
}
|
||||
|
||||
var eventHandler = _diffComputer.TemporaryGetEventHandlerMethod(referenceTreeIndex);
|
||||
eventHandler.Invoke(eventArgs);
|
||||
|
||||
// After any event, we synchronously re-render. Most of the time this means that
|
||||
|
|
|
|||
|
|
@ -106,10 +106,10 @@ namespace Microsoft.AspNetCore.Blazor.Rendering
|
|||
/// Notifies the specified component that an event has occurred.
|
||||
/// </summary>
|
||||
/// <param name="componentId">The unique identifier for the component within the scope of this <see cref="Renderer"/>.</param>
|
||||
/// <param name="renderTreeIndex">The index into the component's current render tree that specifies which event handler to invoke.</param>
|
||||
/// <param name="referenceTreeIndex">The index into the component's latest diff reference tree that specifies which event handler to invoke.</param>
|
||||
/// <param name="eventArgs">Arguments to be passed to the event handler.</param>
|
||||
protected void DispatchEvent(int componentId, int renderTreeIndex, UIEventArgs eventArgs)
|
||||
=> GetRequiredComponentState(componentId).DispatchEvent(renderTreeIndex, eventArgs);
|
||||
protected void DispatchEvent(int componentId, int referenceTreeIndex, UIEventArgs eventArgs)
|
||||
=> GetRequiredComponentState(componentId).DispatchEvent(referenceTreeIndex, eventArgs);
|
||||
|
||||
internal void InstantiateChildComponent(RenderTreeFrame[] frames, int componentFrameIndex)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -74,7 +74,8 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 1);
|
||||
Assert.Equal(1, entry.NewTreeIndex);
|
||||
Assert.Equal(0, entry.ReferenceFrameIndex);
|
||||
AssertFrame.Text(result.ReferenceFrames.Array[0], "text1", 1);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -120,12 +121,12 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
public void RecognizesTrailingSequenceWithinLoopBlockBeingAppended()
|
||||
{
|
||||
// Arrange
|
||||
oldTree.AddText(0, "x"); // Loop start
|
||||
oldTree.AddText(0, "x"); // Loop start
|
||||
newTree.AddText(0, "x"); // Loop start
|
||||
newTree.AddText(1, "x"); // Will be added
|
||||
newTree.AddText(2, "x"); // Will be added
|
||||
newTree.AddText(0, "x"); // Loop start
|
||||
oldTree.AddText(10, "x"); // Loop start
|
||||
oldTree.AddText(10, "x"); // Loop start
|
||||
newTree.AddText(10, "x"); // Loop start
|
||||
newTree.AddText(11, "x"); // Will be added
|
||||
newTree.AddText(12, "x"); // Will be added
|
||||
newTree.AddText(10, "x"); // Loop start
|
||||
|
||||
// Act
|
||||
var result = GetSingleUpdatedComponent();
|
||||
|
|
@ -135,13 +136,16 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 1);
|
||||
Assert.Equal(1, entry.NewTreeIndex);
|
||||
Assert.Equal(0, entry.ReferenceFrameIndex);
|
||||
},
|
||||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 2);
|
||||
Assert.Equal(2, entry.NewTreeIndex);
|
||||
Assert.Equal(1, entry.ReferenceFrameIndex);
|
||||
});
|
||||
Assert.Collection(result.ReferenceFrames,
|
||||
frame => AssertFrame.Text(frame, "x", 11),
|
||||
frame => AssertFrame.Text(frame, "x", 12));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -168,12 +172,12 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
public void RecognizesTrailingLoopBlockBeingAdded()
|
||||
{
|
||||
// Arrange
|
||||
oldTree.AddText(0, "x");
|
||||
oldTree.AddText(1, "x");
|
||||
newTree.AddText(0, "x");
|
||||
newTree.AddText(1, "x");
|
||||
newTree.AddText(0, "x"); // Will be added
|
||||
newTree.AddText(1, "x"); // Will be added
|
||||
oldTree.AddText(10, "x");
|
||||
oldTree.AddText(11, "x");
|
||||
newTree.AddText(10, "x");
|
||||
newTree.AddText(11, "x");
|
||||
newTree.AddText(10, "x"); // Will be added
|
||||
newTree.AddText(11, "x"); // Will be added
|
||||
|
||||
// Act
|
||||
var result = GetSingleUpdatedComponent();
|
||||
|
|
@ -183,25 +187,28 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 2);
|
||||
Assert.Equal(2, entry.NewTreeIndex);
|
||||
Assert.Equal(0, entry.ReferenceFrameIndex);
|
||||
},
|
||||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 3);
|
||||
Assert.Equal(3, entry.NewTreeIndex);
|
||||
Assert.Equal(1, entry.ReferenceFrameIndex);
|
||||
});
|
||||
Assert.Collection(result.ReferenceFrames,
|
||||
frame => AssertFrame.Text(frame, "x", 10),
|
||||
frame => AssertFrame.Text(frame, "x", 11));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RecognizesLeadingLoopBlockItemsBeingAdded()
|
||||
{
|
||||
// Arrange
|
||||
oldTree.AddText(2, "x");
|
||||
oldTree.AddText(2, "x"); // Note that the '0' and '1' items are not present on this iteration
|
||||
newTree.AddText(2, "x");
|
||||
newTree.AddText(0, "x");
|
||||
newTree.AddText(1, "x");
|
||||
newTree.AddText(2, "x");
|
||||
oldTree.AddText(12, "x");
|
||||
oldTree.AddText(12, "x"); // Note that the '0' and '1' items are not present on this iteration
|
||||
newTree.AddText(12, "x");
|
||||
newTree.AddText(10, "x");
|
||||
newTree.AddText(11, "x");
|
||||
newTree.AddText(12, "x");
|
||||
|
||||
// Act
|
||||
var result = GetSingleUpdatedComponent();
|
||||
|
|
@ -211,13 +218,16 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 1);
|
||||
Assert.Equal(1, entry.NewTreeIndex);
|
||||
Assert.Equal(0, entry.ReferenceFrameIndex);
|
||||
},
|
||||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 2);
|
||||
Assert.Equal(2, entry.NewTreeIndex);
|
||||
Assert.Equal(1, entry.ReferenceFrameIndex);
|
||||
});
|
||||
Assert.Collection(result.ReferenceFrames,
|
||||
frame => AssertFrame.Text(frame, "x", 10),
|
||||
frame => AssertFrame.Text(frame, "x", 11));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -273,12 +283,12 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.UpdateText, 0);
|
||||
Assert.Equal(0, entry.NewTreeIndex);
|
||||
Assert.Equal(0, entry.ReferenceFrameIndex);
|
||||
},
|
||||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.UpdateText, 1);
|
||||
Assert.Equal(1, entry.NewTreeIndex);
|
||||
Assert.Equal(1, entry.ReferenceFrameIndex);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -303,7 +313,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 0);
|
||||
Assert.Equal(0, entry.NewTreeIndex);
|
||||
Assert.Equal(0, entry.ReferenceFrameIndex);
|
||||
},
|
||||
entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 1));
|
||||
}
|
||||
|
|
@ -333,8 +343,8 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 0);
|
||||
Assert.Equal(0, entry.NewTreeIndex);
|
||||
Assert.IsType<FakeComponent2>(updatedComponent1.CurrentState.Array[0].Component);
|
||||
Assert.Equal(0, entry.ReferenceFrameIndex);
|
||||
Assert.IsType<FakeComponent2>(updatedComponent1.ReferenceFrames.Array[0].Component);
|
||||
},
|
||||
entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 1));
|
||||
|
||||
|
|
@ -344,7 +354,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 0);
|
||||
Assert.Equal(0, entry.NewTreeIndex);
|
||||
Assert.Equal(0, entry.ReferenceFrameIndex);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -368,8 +378,10 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.SetAttribute, 0);
|
||||
Assert.Equal(2, entry.NewTreeIndex);
|
||||
Assert.Equal(0, entry.ReferenceFrameIndex);
|
||||
});
|
||||
Assert.Collection(result.ReferenceFrames,
|
||||
frame => AssertFrame.Attribute(frame, "added", "added value"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -417,8 +429,10 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.SetAttribute, 0);
|
||||
Assert.Equal(2, entry.NewTreeIndex);
|
||||
Assert.Equal(0, entry.ReferenceFrameIndex);
|
||||
});
|
||||
Assert.Collection(result.ReferenceFrames,
|
||||
frame => AssertFrame.Attribute(frame, "will change", "did change value"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -445,8 +459,10 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.SetAttribute, 0);
|
||||
Assert.Equal(2, entry.NewTreeIndex);
|
||||
Assert.Equal(0, entry.ReferenceFrameIndex);
|
||||
});
|
||||
Assert.Collection(result.ReferenceFrames,
|
||||
frame => AssertFrame.Attribute(frame, "will change", addedHandler));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -468,13 +484,15 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.SetAttribute, 0);
|
||||
Assert.Equal(1, entry.NewTreeIndex);
|
||||
Assert.Equal(0, entry.ReferenceFrameIndex);
|
||||
},
|
||||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.RemoveAttribute, 0);
|
||||
Assert.Equal("oldname", entry.RemovedAttributeName);
|
||||
});
|
||||
Assert.Collection(result.ReferenceFrames,
|
||||
frame => AssertFrame.Attribute(frame, "newname", "same value"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -510,11 +528,13 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.UpdateText, 0);
|
||||
Assert.Equal(4, entry.NewTreeIndex);
|
||||
Assert.Equal(0, entry.ReferenceFrameIndex);
|
||||
},
|
||||
entry => AssertEdit(entry, RenderTreeEditType.StepOut, 0),
|
||||
entry => AssertEdit(entry, RenderTreeEditType.StepOut, 0),
|
||||
entry => AssertEdit(entry, RenderTreeEditType.StepOut, 0));
|
||||
Assert.Collection(result.ReferenceFrames,
|
||||
frame => AssertFrame.Text(frame, "grandchild new text", 13));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -548,9 +568,11 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.UpdateText, 0);
|
||||
Assert.Equal(1, entry.NewTreeIndex);
|
||||
Assert.Equal(0, entry.ReferenceFrameIndex);
|
||||
},
|
||||
entry => AssertEdit(entry, RenderTreeEditType.StepOut, 0));
|
||||
Assert.Collection(result.ReferenceFrames,
|
||||
frame => AssertFrame.Text(frame, "Text that has changed", 11));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -574,8 +596,10 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.UpdateText, 1);
|
||||
Assert.Equal(1, entry.NewTreeIndex);
|
||||
Assert.Equal(0, entry.ReferenceFrameIndex);
|
||||
});
|
||||
Assert.Collection(result.ReferenceFrames,
|
||||
frame => AssertFrame.Text(frame, "text2modified", 11));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -606,35 +630,30 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 0);
|
||||
Assert.Equal(2, entry.NewTreeIndex);
|
||||
|
||||
var newTreeFrame = newTree.GetFrames().Array[entry.NewTreeIndex];
|
||||
Assert.Equal(0, newTreeFrame.ComponentId);
|
||||
Assert.IsType<FakeComponent>(newTreeFrame.Component);
|
||||
Assert.Equal(0, entry.ReferenceFrameIndex);
|
||||
},
|
||||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 1);
|
||||
Assert.Equal(3, entry.NewTreeIndex);
|
||||
|
||||
var newTreeFrame = newTree.GetFrames().Array[entry.NewTreeIndex];
|
||||
Assert.Equal(1, newTreeFrame.ComponentId);
|
||||
Assert.IsType<FakeComponent2>(newTreeFrame.Component);
|
||||
Assert.Equal(1, entry.ReferenceFrameIndex);
|
||||
},
|
||||
entry => AssertEdit(entry, RenderTreeEditType.StepOut, 0));
|
||||
Assert.Collection(firstComponentDiff.ReferenceFrames,
|
||||
frame => AssertFrame.ComponentWithInstance<FakeComponent>(frame, 0, 12),
|
||||
frame => AssertFrame.ComponentWithInstance<FakeComponent2>(frame, 1, 13));
|
||||
|
||||
// Second in batch is the first child component
|
||||
var secondComponentDiff = renderBatch.UpdatedComponents.Array[1];
|
||||
Assert.Equal(0, secondComponentDiff.ComponentId);
|
||||
Assert.Empty(secondComponentDiff.Edits); // Because FakeComponent produces no frames
|
||||
Assert.Empty(secondComponentDiff.CurrentState); // Because FakeComponent produces no frames
|
||||
Assert.Empty(secondComponentDiff.ReferenceFrames); // Because FakeComponent produces no frames
|
||||
|
||||
// Third in batch is the second child component
|
||||
var thirdComponentDiff = renderBatch.UpdatedComponents.Array[2];
|
||||
Assert.Equal(1, thirdComponentDiff.ComponentId);
|
||||
Assert.Collection(thirdComponentDiff.Edits,
|
||||
entry => AssertEdit(entry, RenderTreeEditType.PrependFrame, 0));
|
||||
Assert.Collection(thirdComponentDiff.CurrentState,
|
||||
Assert.Collection(thirdComponentDiff.ReferenceFrames,
|
||||
frame => AssertFrame.Text(frame, $"Hello from {nameof(FakeComponent2)}"));
|
||||
}
|
||||
|
||||
|
|
@ -776,7 +795,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
var diffForChildComponent = batch.UpdatedComponents.Array[1];
|
||||
|
||||
// Assert
|
||||
Assert.Collection(diffForChildComponent.CurrentState,
|
||||
Assert.Collection(diffForChildComponent.ReferenceFrames,
|
||||
frame => AssertFrame.Text(frame, "Notifications: 1", 0));
|
||||
}
|
||||
|
||||
|
|
@ -799,10 +818,10 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
// Act/Assert 0: Initial render
|
||||
var batch0 = GetRenderedBatch(new RenderTreeBuilder(renderer), oldTree);
|
||||
var diffForChildComponent0 = batch0.UpdatedComponents.Array[1];
|
||||
var childComponentFrame = batch0.UpdatedComponents.Array[0].CurrentState.Array[0];
|
||||
var childComponentFrame = batch0.UpdatedComponents.Array[0].ReferenceFrames.Array[0];
|
||||
var childComponentInstance = (HandlePropertiesChangedComponent)childComponentFrame.Component;
|
||||
Assert.Equal(1, childComponentInstance.NotificationsCount);
|
||||
Assert.Collection(diffForChildComponent0.CurrentState,
|
||||
Assert.Collection(diffForChildComponent0.ReferenceFrames,
|
||||
frame => AssertFrame.Text(frame, "Notifications: 1", 0));
|
||||
|
||||
// Act/Assert 1: If properties didn't change, we don't notify
|
||||
|
|
@ -813,7 +832,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
var batch2 = GetRenderedBatch(newTree1, newTree2);
|
||||
var diffForChildComponent2 = batch2.UpdatedComponents.Array[1];
|
||||
Assert.Equal(2, childComponentInstance.NotificationsCount);
|
||||
Assert.Collection(diffForChildComponent2.CurrentState,
|
||||
Assert.Collection(diffForChildComponent2.ReferenceFrames,
|
||||
frame => AssertFrame.Text(frame, "Notifications: 2", 0));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,14 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
renderer.RenderNewBatch(componentId);
|
||||
|
||||
// Assert
|
||||
Assert.Collection(renderer.Batches.Single().RenderTreesByComponentId[componentId],
|
||||
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"));
|
||||
}
|
||||
|
|
@ -52,15 +59,23 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
// Act/Assert
|
||||
var componentId = renderer.AssignComponentId(component);
|
||||
renderer.RenderNewBatch(componentId);
|
||||
var componentFrame = renderer.Batches.Single().RenderTreesByComponentId[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(renderer.Batches.Single().RenderTreesByComponentId[nestedComponentId],
|
||||
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"));
|
||||
}
|
||||
|
||||
|
|
@ -74,13 +89,27 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
|
||||
// Act/Assert: first render
|
||||
renderer.RenderNewBatch(componentId);
|
||||
Assert.Collection(renderer.Batches.Single().RenderTreesByComponentId[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);
|
||||
Assert.Collection(renderer.Batches[1].RenderTreesByComponentId[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"));
|
||||
}
|
||||
|
||||
|
|
@ -96,21 +125,37 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
});
|
||||
var parentComponentId = renderer.AssignComponentId(parentComponent);
|
||||
renderer.RenderNewBatch(parentComponentId);
|
||||
var nestedComponentFrame = renderer.Batches.Single().RenderTreesByComponentId[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;
|
||||
|
||||
// Act/Assert: inital render
|
||||
// Assert: inital render
|
||||
nestedComponent.Message = "Render 1";
|
||||
renderer.RenderNewBatch(nestedComponentId);
|
||||
Assert.Collection(renderer.Batches[1].RenderTreesByComponentId[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);
|
||||
Assert.Collection(renderer.Batches[2].RenderTreesByComponentId[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"));
|
||||
}
|
||||
|
||||
|
|
@ -129,7 +174,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
renderer.RenderNewBatch(componentId);
|
||||
|
||||
var (eventHandlerFrameIndex, _) = FirstWithIndex(
|
||||
renderer.Batches.Single().RenderTreesByComponentId[componentId],
|
||||
renderer.Batches.Single().DiffsByComponentId[componentId].Single().ReferenceFrames,
|
||||
frame => frame.AttributeValue != null);
|
||||
|
||||
// Assert: Event not yet fired
|
||||
|
|
@ -157,7 +202,9 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
renderer.RenderNewBatch(parentComponentId);
|
||||
|
||||
// Arrange: Render nested component
|
||||
var nestedComponentFrame = renderer.Batches.Single().RenderTreesByComponentId[parentComponentId]
|
||||
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; };
|
||||
|
|
@ -166,7 +213,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
|
||||
// Find nested component's event handler ndoe
|
||||
var (eventHandlerFrameIndex, _) = FirstWithIndex(
|
||||
renderer.Batches[1].RenderTreesByComponentId[nestedComponentId],
|
||||
renderer.Batches[1].DiffsByComponentId[nestedComponentId].Single().ReferenceFrames,
|
||||
frame => frame.AttributeValue != null);
|
||||
|
||||
// Assert: Event not yet fired
|
||||
|
|
@ -217,12 +264,12 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
|
||||
// Act/Assert: Render component in renderer1
|
||||
renderer1.RenderNewBatch(renderer1ComponentId);
|
||||
Assert.True(renderer1.Batches.Single().RenderTreesByComponentId.ContainsKey(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().RenderTreesByComponentId.ContainsKey(renderer2ComponentId));
|
||||
Assert.True(renderer2.Batches.Single().DiffsByComponentId.ContainsKey(renderer2ComponentId));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -313,18 +360,29 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
var rootComponentId = renderer.AssignComponentId(component);
|
||||
renderer.RenderNewBatch(rootComponentId);
|
||||
|
||||
var nestedComponentInstance = (MessageComponent)renderer.Batches.Single().RenderTreesByComponentId[rootComponentId]
|
||||
.Single(frame => frame.FrameType == RenderTreeFrameType.Component)
|
||||
.Component;
|
||||
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
|
||||
Assert.Collection(renderer.Batches[1].RenderTreesByComponentId[rootComponentId],
|
||||
frame => AssertFrame.Text(frame, "Modified message"),
|
||||
frame => Assert.Same(nestedComponentInstance, frame.Component));
|
||||
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));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -346,28 +404,25 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
var rootComponentId = renderer.AssignComponentId(component);
|
||||
renderer.RenderNewBatch(rootComponentId);
|
||||
|
||||
var originalComponentInstance = (FakeComponent)renderer.Batches.Single().RenderTreesByComponentId[rootComponentId]
|
||||
.Single(frame => frame.FrameType == RenderTreeFrameType.Component)
|
||||
.Component;
|
||||
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, originalComponentInstance.IntProperty);
|
||||
Assert.Equal("String that will change", originalComponentInstance.StringProperty);
|
||||
Assert.Same(objectThatWillNotChange, originalComponentInstance.ObjectProperty);
|
||||
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);
|
||||
|
||||
var updatedComponentInstance = (FakeComponent)renderer.Batches[1].RenderTreesByComponentId[rootComponentId]
|
||||
.Single(frame => frame.FrameType == RenderTreeFrameType.Component)
|
||||
.Component;
|
||||
|
||||
// Assert
|
||||
Assert.Same(originalComponentInstance, updatedComponentInstance);
|
||||
Assert.Equal(256, updatedComponentInstance.IntProperty);
|
||||
Assert.Equal("String that did change", updatedComponentInstance.StringProperty);
|
||||
Assert.Same(objectThatWillNotChange, updatedComponentInstance.ObjectProperty);
|
||||
Assert.Equal(256, childComponentInstance.IntProperty);
|
||||
Assert.Equal("String that did change", childComponentInstance.StringProperty);
|
||||
Assert.Same(objectThatWillNotChange, childComponentInstance.ObjectProperty);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -386,19 +441,25 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
var rootComponentId = renderer.AssignComponentId(component);
|
||||
renderer.RenderNewBatch(rootComponentId);
|
||||
|
||||
var childComponentId = renderer.Batches.Single().RenderTreesByComponentId[rootComponentId]
|
||||
var childComponentId = renderer.Batches.Single().DiffsByComponentId[rootComponentId]
|
||||
.Single()
|
||||
.ReferenceFrames
|
||||
.Single(frame => frame.FrameType == RenderTreeFrameType.Component)
|
||||
.ComponentId;
|
||||
|
||||
// Act: Second render
|
||||
firstRender = false;
|
||||
renderer.RenderNewBatch(rootComponentId);
|
||||
|
||||
var updatedComponentFrame = renderer.Batches[1].RenderTreesByComponentId[rootComponentId]
|
||||
.Single(frame => frame.FrameType == RenderTreeFrameType.Component);
|
||||
var diff = renderer.Batches[1].DiffsByComponentId[childComponentId].Single();
|
||||
|
||||
// Assert
|
||||
Assert.Collection(renderer.Batches[1].RenderTreesByComponentId[updatedComponentFrame.ComponentId],
|
||||
Assert.Collection(diff.Edits,
|
||||
edit =>
|
||||
{
|
||||
Assert.Equal(RenderTreeEditType.UpdateText, edit.Type);
|
||||
Assert.Equal(0, edit.ReferenceFrameIndex);
|
||||
});
|
||||
Assert.Collection(diff.ReferenceFrames,
|
||||
frame => AssertFrame.Text(frame, "second"));
|
||||
}
|
||||
|
||||
|
|
@ -427,7 +488,9 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
|
||||
// Act/Assert 1: First render, capturing child component IDs
|
||||
renderer.RenderNewBatch(rootComponentId);
|
||||
var childComponentIds = renderer.Batches.Single().RenderTreesByComponentId[rootComponentId]
|
||||
var childComponentIds = renderer.Batches.Single().DiffsByComponentId[rootComponentId]
|
||||
.Single()
|
||||
.ReferenceFrames
|
||||
.Where(frame => frame.FrameType == RenderTreeFrameType.Component)
|
||||
.Select(frame => frame.ComponentId)
|
||||
.ToList();
|
||||
|
|
@ -476,8 +539,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
for (var i = 0; i < renderBatch.UpdatedComponents.Count; i++)
|
||||
{
|
||||
ref var renderTreeDiff = ref renderBatch.UpdatedComponents.Array[i];
|
||||
capturedBatch.RenderTreesByComponentId[renderTreeDiff.ComponentId] =
|
||||
renderTreeDiff.CurrentState.ToArray();
|
||||
capturedBatch.AddDiff(renderTreeDiff);
|
||||
}
|
||||
|
||||
capturedBatch.DisposedComponentIDs = renderBatch.DisposedComponentIDs.ToList();
|
||||
|
|
@ -486,10 +548,20 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
|
||||
private class CapturedBatch
|
||||
{
|
||||
public IDictionary<int, RenderTreeFrame[]> RenderTreesByComponentId { get; }
|
||||
= new Dictionary<int, RenderTreeFrame[]>();
|
||||
public IDictionary<int, List<RenderTreeDiff>> DiffsByComponentId { get; }
|
||||
= new Dictionary<int, List<RenderTreeDiff>>();
|
||||
|
||||
public IList<int> DisposedComponentIDs { get; set; }
|
||||
|
||||
internal void AddDiff(RenderTreeDiff diff)
|
||||
{
|
||||
var componentId = diff.ComponentId;
|
||||
if (!DiffsByComponentId.ContainsKey(componentId))
|
||||
{
|
||||
DiffsByComponentId.Add(componentId, new List<RenderTreeDiff>());
|
||||
}
|
||||
DiffsByComponentId[componentId].Add(diff);
|
||||
}
|
||||
}
|
||||
|
||||
private class TestComponent : IComponent
|
||||
|
|
|
|||
|
|
@ -60,6 +60,13 @@ namespace Microsoft.AspNetCore.Blazor.Test.Shared
|
|||
AssertFrame.Sequence(frame, sequence);
|
||||
}
|
||||
|
||||
public static void ComponentWithInstance<T>(RenderTreeFrame frame, int componentId, int? sequence = null) where T : IComponent
|
||||
{
|
||||
AssertFrame.Component<T>(frame, sequence);
|
||||
Assert.IsType<T>(frame.Component);
|
||||
Assert.Equal(componentId, frame.ComponentId);
|
||||
}
|
||||
|
||||
public static void Whitespace(RenderTreeFrame frame, int? sequence = null)
|
||||
{
|
||||
Assert.Equal(RenderTreeFrameType.Text, frame.FrameType);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
@using System.Collections.Generic
|
||||
@using Microsoft.AspNetCore.Blazor.RenderTree
|
||||
Type here: <input onkeypress=@OnKeyPressed />
|
||||
Type here: <input onkeypress=@CreateNewDelegateInstance() />
|
||||
<ul>
|
||||
@foreach (var key in keysPressed)
|
||||
{
|
||||
|
|
@ -11,7 +11,22 @@ Type here: <input onkeypress=@OnKeyPressed />
|
|||
@functions {
|
||||
List<string> keysPressed = new List<string>();
|
||||
|
||||
void OnKeyPressed(UIEventArgs eventArgs)
|
||||
// TODO: Fix this
|
||||
// Currently, you can only trigger an event handler whose value changed in the most
|
||||
// recent render cycle. That's because we reference the event handlers by their index
|
||||
// into the current diff's ReferenceFrames array. We need some better mechanism of
|
||||
// locating the delegates that is independent of whether the corresponding attribute
|
||||
// changed in the last diff, and not assuming the attribute in the original render
|
||||
// tree is still at the same index.
|
||||
// Once that's fixed, remove the 'CreateNewDelegateInstance' method entirely and
|
||||
// the 'irrelevantObject' arg from below, and simplify to onkeypress=@OnKeyPressed
|
||||
UIEventHandler CreateNewDelegateInstance()
|
||||
{
|
||||
var irrelevantObject = new object();
|
||||
return args => OnKeyPressed(args, irrelevantObject);
|
||||
}
|
||||
|
||||
void OnKeyPressed(UIEventArgs eventArgs, object irrelevantObject)
|
||||
{
|
||||
keysPressed.Add(((UIKeyboardEventArgs)eventArgs).Key);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue