Skip to content

Commit

Permalink
fix: support passing assigned render mode via parameter builder
Browse files Browse the repository at this point in the history
  • Loading branch information
egil authored and linkdotnet committed Dec 13, 2024
1 parent 9609439 commit 0e2dbc1
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 23 deletions.
1 change: 1 addition & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<NoWarn>CA1014,NU5104,NETSDK1138,SYSLIB0051</NoWarn>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>

<!-- Used by code coverage -->
<DebugType>full</DebugType>
Expand Down
11 changes: 11 additions & 0 deletions src/bunit.core/ComponentParameterCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ public class ComponentParameterCollection : ICollection<ComponentParameter>, IRe
/// <inheritdoc />
public bool IsReadOnly { get; }

#if NET9_0_OR_GREATER
/// <summary>
/// Gets or sets the <see cref="IComponentRenderMode"/> that will be specified in
/// the render tree for component the parameters are being passed to.
/// </summary>
public IComponentRenderMode? RenderMode { get; set; }
#endif

/// <summary>
/// Adds a <paramref name="item"/> to the collection.
/// </summary>
Expand Down Expand Up @@ -104,6 +112,9 @@ void AddComponent(RenderTreeBuilder builder)
{
builder.OpenComponent<TComponent>(0);
AddAttributes(builder);
#if NET9_0_OR_GREATER
builder.AddComponentRenderMode(RenderMode);
#endif
builder.CloseComponent();
}

Expand Down
29 changes: 21 additions & 8 deletions src/bunit.core/ComponentParameterCollectionBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public ComponentParameterCollectionBuilder<TComponent> Add<TChildComponent>(Expr
/// <param name="parameterSelector">A lambda function that selects the parameter.</param>
/// <param name="markup">The markup string to pass to the <see cref="RenderFragment"/>.</param>
/// <returns>This <see cref="ComponentParameterCollectionBuilder{TComponent}"/>.</returns>
public ComponentParameterCollectionBuilder<TComponent> Add(Expression<Func<TComponent, RenderFragment?>> parameterSelector, [StringSyntax("Html")]string markup)
public ComponentParameterCollectionBuilder<TComponent> Add(Expression<Func<TComponent, RenderFragment?>> parameterSelector, [StringSyntax("Html")] string markup)
=> Add(parameterSelector, markup.ToMarkupRenderFragment());

/// <summary>
Expand Down Expand Up @@ -266,7 +266,7 @@ public ComponentParameterCollectionBuilder<TComponent> AddChildContent(RenderFra
/// </summary>
/// <param name="markup">The markup string to pass the ChildContent parameter wrapped in a <see cref="RenderFragment"/>.</param>
/// <returns>This <see cref="ComponentParameterCollectionBuilder{TComponent}"/>.</returns>
public ComponentParameterCollectionBuilder<TComponent> AddChildContent([StringSyntax("Html")]string markup)
public ComponentParameterCollectionBuilder<TComponent> AddChildContent([StringSyntax("Html")] string markup)
=> AddChildContent(markup.ToMarkupRenderFragment());

/// <summary>
Expand Down Expand Up @@ -344,11 +344,11 @@ public ComponentParameterCollectionBuilder<TComponent> Bind<TValue>(
Action<TValue> changedAction,
Expression<Func<TValue>>? valueExpression = null)
{
#if !NET8_0_OR_GREATER
#if !NET8_0_OR_GREATER
var (parameterName, _, isCascading) = GetParameterInfo(parameterSelector);
#else
#else
var (parameterName, _, isCascading) = GetParameterInfo(parameterSelector, initialValue);
#endif
#endif

if (isCascading)
throw new ArgumentException("Using Bind with a cascading parameter is not allowed.", parameterName);
Expand Down Expand Up @@ -397,6 +397,19 @@ static string TrimEnd(string source, string value)
: source;
}

#if NET9_0_OR_GREATER
/// <summary>
/// Sets (or unsets) the <see cref="IComponentRenderMode"/> for the component and child components.
/// </summary>
/// <param name="renderMode">The render mode to assign to the component, e.g. <c>RenderMode.InteractiveServer</c>, or <see langword="null"/>, to not assign a specific render mode.</param>
/// <returns>This <see cref="ComponentParameterCollectionBuilder{TComponent}"/>.</returns>
public ComponentParameterCollectionBuilder<TComponent> SetAssignedRenderMode(IComponentRenderMode? renderMode)
{
parameters.RenderMode = renderMode;
return this;
}
#endif

/// <summary>
/// Try to add a <paramref name="value"/> for a parameter with the <paramref name="name"/>, if
/// <typeparamref name="TComponent"/> has a property with that name, AND that property has a <see cref="ParameterAttribute"/>
Expand Down Expand Up @@ -454,14 +467,14 @@ Expression<Func<TComponent, TValue>> parameterSelector
: propInfoCandidate;

var paramAttr = propertyInfo?.GetCustomAttribute<ParameterAttribute>(inherit: true);
#if !NET8_0_OR_GREATER
#if !NET8_0_OR_GREATER
var cascadingParamAttr = propertyInfo?.GetCustomAttribute<CascadingParameterAttribute>(inherit: true);

if (propertyInfo is null || (paramAttr is null && cascadingParamAttr is null))
throw new ArgumentException($"The parameter selector '{parameterSelector}' does not resolve to a public property on the component '{typeof(TComponent)}' with a [Parameter] or [CascadingParameter] attribute.", nameof(parameterSelector));

return (propertyInfo.Name, CascadingValueName: cascadingParamAttr?.Name, IsCascading: cascadingParamAttr is not null);
#else
#else
var cascadingParamAttrBase = propertyInfo?.GetCustomAttribute<CascadingParameterAttributeBase>(inherit: true);

if (propertyInfo is null || (paramAttr is null && cascadingParamAttrBase is null))
Expand Down Expand Up @@ -494,7 +507,7 @@ static ArgumentException CreateErrorMessageForSupplyFromQuery(
NavigationManager.NavigateTo(uri);
""");
}
#endif
#endif
}

private static bool HasChildContentParameter()
Expand Down
40 changes: 37 additions & 3 deletions tests/bunit.core.tests/Rendering/RenderModeTests.razor
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
@code{
#if NET9_0_OR_GREATER
}
@using Bunit.TestAssets.RenderModes;
@inherits TestContext
@code {
#if NET9_0_OR_GREATER
[Fact(DisplayName = "TestRenderer provides RendererInfo")]
public void Test001()
{
Expand Down Expand Up @@ -104,7 +106,7 @@
public void Test009()
{
// See: https://learn.microsoft.com/en-us/aspnet/core/blazor/components/sections?view=aspnetcore-8.0#section-interaction-with-other-blazor-features
var cut = Render(@<SectionOutletComponent />);
var cut = Render(@<SectionOutletComponent><ComponentThatPrintsAssignedRenderMode/></SectionOutletComponent>);

cut.MarkupMatches(@<p>Assigned Render Mode: InteractiveWebAssemblyRenderMode</p>);
}
Expand All @@ -125,6 +127,36 @@
</text>);
}

[Fact(DisplayName = "SetAssignedRenderMode on root component")]
public void Test011()
{
var cut = RenderComponent<ComponentThatPrintsAssignedRenderMode>(ps => ps.SetAssignedRenderMode(RenderMode.InteractiveServer));
cut.MarkupMatches(@<p>Assigned Render Mode: InteractiveServerRenderMode</p>);
}

[Fact(DisplayName = "SetAssignedRenderMode on parent component cascades to children")]
public void Test012()
{
var cut = RenderComponent<ComponentWithChildContent>(ps => ps
.SetAssignedRenderMode(RenderMode.InteractiveWebAssembly)
.AddChildContent<ComponentThatPrintsAssignedRenderMode>());

cut.MarkupMatches(@<p>Assigned Render Mode: InteractiveWebAssemblyRenderMode</p>);
}

[Fact(DisplayName = "SetAssignedRenderMode child components")]
public void Test013()
{
var cut = RenderComponent<ComponentWithChildContent>(ps => ps
.AddChildContent<ComponentThatPrintsAssignedRenderMode>(pps => pps.SetAssignedRenderMode(RenderMode.InteractiveServer))
.AddChildContent<ComponentThatPrintsAssignedRenderMode>(pps => pps.SetAssignedRenderMode(RenderMode.InteractiveWebAssembly)));

cut.MarkupMatches(
@<text>
<p>Assigned Render Mode: InteractiveServerRenderMode</p>
<p>Assigned Render Mode: InteractiveWebAssemblyRenderMode</p>
</text>);
}

[Fact(DisplayName = "Different assigned RenderMode between child and parent throws")]
public void Test020()
Expand All @@ -138,5 +170,7 @@

act.ShouldThrow<RenderModeMisMatchException>(); // todo: figure out good exception to use
}
#endif
}
@code{
#endif
}
30 changes: 30 additions & 0 deletions tests/bunit.testassets/RenderModes/SectionOutletComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Microsoft.AspNetCore.Components.Web;

#if NET8_0_OR_GREATER
using Microsoft.AspNetCore.Components.Sections;
#endif

namespace Bunit.TestAssets.RenderModes;

public class SectionOutletComponent : ComponentBase
{
#if NET8_0_OR_GREATER
private static readonly Guid SectionId = Guid.NewGuid();
#endif

[Parameter] public RenderFragment ChildContent { get; set; }

protected override void BuildRenderTree(RenderTreeBuilder builder)
{
#if NET8_0_OR_GREATER
builder.OpenComponent<SectionOutlet>(0);
builder.AddComponentParameter(1, nameof(SectionOutlet.SectionId), SectionId);
builder.AddComponentRenderMode(RenderMode.InteractiveWebAssembly);
builder.CloseComponent();
builder.OpenComponent<SectionContent>(10);
builder.AddComponentParameter(11, nameof(SectionContent.SectionId), SectionId);
builder.AddAttribute(12, nameof(SectionContent.ChildContent), ChildContent);
builder.CloseComponent();
#endif
}
}
12 changes: 0 additions & 12 deletions tests/bunit.testassets/RenderModes/SectionOutletComponent.razor

This file was deleted.

1 change: 1 addition & 0 deletions tests/bunit.testassets/bunit.testassets.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<PackageReference Include="xunit.abstractions" />
<PackageReference Include="xunit.assert" />
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" />
<PackageReference Include="Microsoft.AspNetCore.Components" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" />
<PackageReference Include="System.Text.Json" />
Expand Down

0 comments on commit 0e2dbc1

Please sign in to comment.