diff --git a/sample/tests/Tests/Components/FocussingInputTest.cs b/sample/tests/Tests/Components/FocussingInputTest.cs index eaac8ba87..bc84d316b 100644 --- a/sample/tests/Tests/Components/FocussingInputTest.cs +++ b/sample/tests/Tests/Components/FocussingInputTest.cs @@ -6,6 +6,7 @@ using Egil.RazorComponents.Testing.Asserting; using Egil.RazorComponents.Testing.Mocking.JSInterop; using Egil.RazorComponents.Testing.SampleApp.Components; +using Egil.RazorComponents.Testing.Mocking.JSInterop; using Xunit; namespace Egil.RazorComponents.Testing.SampleApp.CodeOnlyTests.Components diff --git a/sample/tests/Tests/Components/TodoListTest.cs b/sample/tests/Tests/Components/TodoListTest.cs index 34b4ac5b2..a0946c64b 100644 --- a/sample/tests/Tests/Components/TodoListTest.cs +++ b/sample/tests/Tests/Components/TodoListTest.cs @@ -3,6 +3,7 @@ using Egil.RazorComponents.Testing.Asserting; using Egil.RazorComponents.Testing.Mocking.JSInterop; using Egil.RazorComponents.Testing.EventDispatchExtensions; +using Egil.RazorComponents.Testing.Mocking.JSInterop; using Egil.RazorComponents.Testing.SampleApp.Components; using Egil.RazorComponents.Testing.SampleApp.Data; using Microsoft.AspNetCore.Components; diff --git a/src/Components/ContainerComponent.cs b/src/Components/ContainerComponent.cs index 6a9092469..7a789580f 100644 --- a/src/Components/ContainerComponent.cs +++ b/src/Components/ContainerComponent.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Threading.Tasks; using Egil.RazorComponents.Testing.Extensions; +using AngleSharp.Css.Dom; namespace Egil.RazorComponents.Testing { @@ -32,7 +33,7 @@ public ContainerComponent(TestRenderer renderer) { if (renderer is null) throw new ArgumentNullException(nameof(renderer)); _renderer = renderer; - ComponentId = _renderer.AttachTestRootComponent(this); + ComponentId = _renderer.AttachTestRootComponent(this); } /// @@ -58,17 +59,14 @@ public void Render(RenderFragment renderFragment) /// component is found, its child content is also searched recursively. /// /// The type of component to find - /// When there are more than one component of type found or if none are found. + /// When a component of type was not found. public (int Id, TComponent Component) GetComponent() where TComponent : IComponent { - var result = GetComponents(); - - if (result.Count == 1) - return result[0]; - else if (result.Count == 0) - throw new InvalidOperationException($"No components of type {typeof(TComponent)} were found in the render tree."); + var result = GetComponent(ComponentId); + if (result.HasValue) + return result.Value; else - throw new InvalidOperationException($"More than one component of type {typeof(TComponent)} was found in the render tree."); + throw new InvalidOperationException($"No components of type {typeof(TComponent)} were found in the render tree."); } /// @@ -84,7 +82,7 @@ public void Render(RenderFragment renderFragment) var ownFrames = _renderer.GetCurrentRenderTreeFrames(componentId); if (ownFrames.Count == 0) { - throw new InvalidOperationException($"{nameof(ContainerComponent)} hasn't yet rendered"); + return Array.Empty<(int Id, TComponent Component)>(); } var result = new List<(int Id, TComponent Component)>(); @@ -97,20 +95,32 @@ public void Render(RenderFragment renderFragment) { result.Add((frame.ComponentId, component)); } - else if (frame.Component.IsCascadingValueComponent()) + result.AddRange(GetComponents(frame.ComponentId)); + } + } + + return result; + } + + private (int Id, TComponent Component)? GetComponent(int componentId) where TComponent : IComponent + { + var ownFrames = _renderer.GetCurrentRenderTreeFrames(componentId); + + for (int i = 0; i < ownFrames.Count; i++) + { + ref var frame = ref ownFrames.Array[i]; + if (frame.FrameType == RenderTreeFrameType.Component) + { + if (frame.Component is TComponent component) { - // It seems as if CascadingValue components works a little different - // than regular components with child content is not rendered - // and available via GetCurrentRenderTreeFrames for the componentId - // of the component that had the CascadingValue as a child. - // Thus we call GetComponents recursively with the CascadingValue's - // componentId to see if the TComponent is inside it. - result.AddRange(GetComponents(frame.ComponentId)); + return (frame.ComponentId, component); } + var result = GetComponent(frame.ComponentId); + if (result != null) return result; } } - return result; + return null; } } } diff --git a/src/Egil.RazorComponents.Testing.Library.csproj b/src/Egil.RazorComponents.Testing.Library.csproj index 77e01d21a..a25b4cb6a 100644 --- a/src/Egil.RazorComponents.Testing.Library.csproj +++ b/src/Egil.RazorComponents.Testing.Library.csproj @@ -51,7 +51,7 @@ This library's goal is to make it easy to write comprehensive, stable unit tests - + diff --git a/src/ElementNotFoundException.cs b/src/ElementNotFoundException.cs index 1a3caf9fe..a4792322c 100644 --- a/src/ElementNotFoundException.cs +++ b/src/ElementNotFoundException.cs @@ -5,7 +5,7 @@ using System.Text; using System.Threading.Tasks; -namespace Egil.RazorComponents.Testing +namespace Xunit.Sdk { /// /// Represents a failure to find an element in the searched target diff --git a/src/Rendering/IRenderedFragment.cs b/src/Rendering/IRenderedFragment.cs index 9742bb918..7ddc8af4c 100644 --- a/src/Rendering/IRenderedFragment.cs +++ b/src/Rendering/IRenderedFragment.cs @@ -3,6 +3,7 @@ using System.Linq; using AngleSharp.Diffing.Core; using AngleSharp.Dom; +using Xunit.Sdk; namespace Egil.RazorComponents.Testing { diff --git a/src/Rendering/RenderedFragmentBase.cs b/src/Rendering/RenderedFragmentBase.cs index e02050b5b..8801b371b 100644 --- a/src/Rendering/RenderedFragmentBase.cs +++ b/src/Rendering/RenderedFragmentBase.cs @@ -93,7 +93,6 @@ public IReadOnlyList GetChangesSinceSnapshot() return Nodes.CompareTo(_snapshotNodes); } - /// public IReadOnlyList GetChangesSinceFirstRender() { @@ -104,24 +103,30 @@ public IReadOnlyList GetChangesSinceFirstRender() private void ComponentMarkupChanged(in RenderBatch renderBatch) { - if (renderBatch.HasUpdatesTo(ComponentId) || HasChildComponentUpdated(renderBatch)) + if (renderBatch.HasUpdatesTo(ComponentId) || HasChildComponentUpdated(renderBatch, ComponentId)) { ResetLatestRenderCache(); } } - private bool HasChildComponentUpdated(in RenderBatch renderBatch) + private bool HasChildComponentUpdated(in RenderBatch renderBatch, int componentId) { - var frames = TestContext.Renderer.GetCurrentRenderTreeFrames(ComponentId); + var frames = TestContext.Renderer.GetCurrentRenderTreeFrames(componentId); + for (int i = 0; i < frames.Count; i++) { var frame = frames.Array[i]; - - if (renderBatch.HasUpdatesTo(frame.ComponentId)) + if (frame.FrameType == RenderTreeFrameType.Component) { - return true; + if (renderBatch.HasUpdatesTo(frame.ComponentId)) + { + return true; + } + if (HasChildComponentUpdated(in renderBatch, frame.ComponentId)) + { + return true; + } } - } return false; } diff --git a/tests/Components/TestComponentBaseTest/BlazorElementReferencesIncludedInRenderedMarkup.razor b/tests/Components/TestComponentBaseTest/BlazorElementReferencesIncludedInRenderedMarkup.razor index 3133f8108..b74d0f841 100644 --- a/tests/Components/TestComponentBaseTest/BlazorElementReferencesIncludedInRenderedMarkup.razor +++ b/tests/Components/TestComponentBaseTest/BlazorElementReferencesIncludedInRenderedMarkup.razor @@ -1,6 +1,5 @@ @inherits TestComponentBase -
diff --git a/tests/RenderComponentTest.cs b/tests/RenderComponentTest.cs index 33379530d..e9bd2cb64 100644 --- a/tests/RenderComponentTest.cs +++ b/tests/RenderComponentTest.cs @@ -22,7 +22,7 @@ public void Test003() [Fact(DisplayName = "Nodes should return new instance " + "when a SetParametersAndRender has caused changes to DOM tree")] - public void Tets004() + public void Test004() { var cut = RenderComponent(ChildContent("
")); var initialNodes = cut.Nodes; @@ -35,7 +35,7 @@ public void Tets004() [Fact(DisplayName = "Nodes should return new instance " + "when a Render has caused changes to DOM tree")] - public void Tets005() + public void Test005() { var cut = RenderComponent(); var initialNodes = cut.Nodes; @@ -44,20 +44,5 @@ public void Tets005() Assert.NotSame(initialNodes, cut.Nodes); } - - [Fact(DisplayName = "Nodes should return new instance " + - "when a event handler trigger has caused changes to DOM tree")] - public void Tets006() - { - var cut = RenderComponent(); - var initialNodes = cut.Nodes; - - cut.Find("button").Click(); - - Assert.NotSame(initialNodes, cut.Nodes); - } - - } - } diff --git a/tests/RenderedFragmentTest.cs b/tests/RenderedFragmentTest.cs index ac8075e5e..2ca8f452e 100644 --- a/tests/RenderedFragmentTest.cs +++ b/tests/RenderedFragmentTest.cs @@ -1,6 +1,8 @@ -using Egil.RazorComponents.Testing.Extensions; +using Egil.RazorComponents.Testing.EventDispatchExtensions; +using Egil.RazorComponents.Testing.Extensions; using Egil.RazorComponents.Testing.SampleComponents; using Egil.RazorComponents.Testing.SampleComponents.Data; +using Microsoft.AspNetCore.Components; using Microsoft.Extensions.DependencyInjection; using Shouldly; using System; @@ -8,6 +10,7 @@ using System.Linq; using System.Text; using Xunit; +using Xunit.Sdk; namespace Egil.RazorComponents.Testing { @@ -70,6 +73,51 @@ public void Test005() Assert.NotSame(initialValue, cut.Nodes); } + + + [Fact(DisplayName = "Nodes should return new instance " + + "when a event handler trigger has caused changes to DOM tree")] + public void Test006() + { + var cut = RenderComponent(); + var initialNodes = cut.Nodes; + + cut.Find("button").Click(); + + Assert.NotSame(initialNodes, cut.Nodes); + } + + [Fact(DisplayName = "Nodes should return new instance " + + "when a nested component has caused the DOM tree to change")] + public void Test007() + { + var cut = RenderComponent( + ChildContent>( + ("Value", "FOO"), + ChildContent() + ) + ); + var initialNodes = cut.Nodes; + + cut.Find("button").Click(); + + Assert.NotSame(initialNodes, cut.Nodes); + } + + [Fact(DisplayName = "Nodes should return the same instance " + + "when a re-render does not causes the DOM to change")] + public void Test008() + { + var cut = RenderComponent(); + var initialNodes = cut.Nodes; + + cut.Find("button").Click(); + + cut.Instance.RenderCount.ShouldBe(2); + Assert.Same(initialNodes, cut.Nodes); + } + + } } diff --git a/tests/SampleComponents/RenderOnClick.razor b/tests/SampleComponents/RenderOnClick.razor new file mode 100644 index 000000000..d5ed71b16 --- /dev/null +++ b/tests/SampleComponents/RenderOnClick.razor @@ -0,0 +1,9 @@ + + +@code { + public int RenderCount { get; private set; } + + void IncreaseCount() { } + + protected override void OnAfterRender(bool firstRender) => RenderCount++; +} \ No newline at end of file diff --git a/tests/_Imports.razor b/tests/_Imports.razor index 94baed4ea..7c7ad8e8b 100644 --- a/tests/_Imports.razor +++ b/tests/_Imports.razor @@ -1,5 +1,9 @@ @using Microsoft.AspNetCore.Components.Web @using Microsoft.Extensions.DependencyInjection +@using Egil.RazorComponents.Testing +@using Egil.RazorComponents.Testing.Asserting +@using Egil.RazorComponents.Testing.EventDispatchExtensions +@using Egil.RazorComponents.Testing.Mocking.JSInterop @using Egil.RazorComponents.Testing.SampleComponents @using Egil.RazorComponents.Testing.SampleComponents.Data @using Shouldly