Skip to content

Commit a4c5161

Browse files
linkdotnetegil
authored andcommitted
docs: Added docs and exposes via TestContext
1 parent 1e032b9 commit a4c5161

File tree

8 files changed

+187
-8
lines changed

8 files changed

+187
-8
lines changed

.vscode/tasks.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
{
77
"label": "Serve Docs (Without Build)",
88
"type": "shell",
9-
"command": "docfx metadata docs/site/docfx.json && docfx docs/site/docfx.json --serve"
9+
"command": "dotnet docfx metadata docs/site/docfx.json && dotnet docfx docs/site/docfx.json --serve"
1010
},
1111
{
1212
"label": "Serve Docs (With Build for API Documentation)",
1313
"type": "shell",
14-
"command": "dotnet build -c Release && docfx metadata docs/site/docfx.json && docfx docs/site/docfx.json --serve"
14+
"command": "dotnet build -c Release && dotnet docfx metadata docs/site/docfx.json && docfx docs/site/docfx.json --serve"
1515
},
1616
{
1717
"label": "Run all tests (Release Mode)",

docs/site/docs/interaction/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ This section covers the various ways to interact with a component under test, e.
1111
- **<xref:trigger-renders>:** This covers how to manually trigger a render cycle for a component under test.
1212
- **<xref:awaiting-async-state>:** This covers how to await one or more asynchronous changes to the state of a component under test before continuing the test.
1313
- **<xref:dispose-components>:** This covers how to dispose components and their children.
14+
- **<xref:render-modes>:** This covers the different render modes and their interaction with bUnit.
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
---
2+
uid: render-modes
3+
title: Render modes and RendererInfo
4+
---
5+
6+
# Support for render modes and `RendererInfo`
7+
This article explains how to emulate different render modes and `RendererInfo` in bUnit tests.
8+
9+
Render modes in Blazor Web Apps determine the hosting model and interactivity of components. A render mode can be applied to a component using the `@rendermode` directive. The [`RendererInfo`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.components.rendererinfo?view=aspnetcore-9.0) allows the application to determine the interactivity and location of the component. For more details, see the [Blazor render modes](https://learn.microsoft.com/en-us/aspnet/core/blazor/components/render-modes?view=aspnetcore-9.0) documentation.
10+
11+
## Setting the render mode for a component under test
12+
Setting the render mode can be done via the <xref:Bunit.ComponentParameterCollectionBuilder`1.SetAssignedRenderMode(Microsoft.AspNetCore.Components.IComponentRenderMode)> method when writing in a C# file. In a razor file use the `@rendermode` directive. Both take an [`IComponentRenderMode`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.components.icomponentrendermode?view=aspnetcore-9.0) object as a parameter. Normally this is one of the following types:
13+
* [`InteractiveAutoRenderMode`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.components.web.interactiveautorendermode?view=aspnetcore-9.0)
14+
* [`InteractiveServerRendeMode`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.components.web.interactiveserverrendermode?view=aspnetcore-9.0)
15+
* [`InteractiveWebAssemblyRenderMode`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.components.web.interactivewebassemblyrendermode?view=aspnetcore-9.0)
16+
17+
For ease of use the [`RenderMode`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.components.web.rendermode?view=aspnetcore-9.0) class defines all three of them.
18+
19+
For example `MovieComponent.razor`:
20+
```razor
21+
@if (AssignedRenderMode is null)
22+
{
23+
// The render mode is Static Server
24+
<form action="/movies">
25+
<input type="text" name="titleFilter" />
26+
<input type="submit" value="Search" />
27+
</form>
28+
}
29+
else
30+
{
31+
// The render mode is Interactive Server, WebAssembly, or Auto
32+
<input @bind="titleFilter" />
33+
<button @onclick="FilterMovies">Search</button>
34+
}
35+
```
36+
37+
The following example shows how to test the above component to check both render modes:
38+
39+
# [C# test code](#tab/csharp)
40+
41+
```csharp
42+
[Fact]
43+
public void InteractiveServer()
44+
{
45+
// Act
46+
var cut = RenderComponent<MovieComponent>(ps => ps
47+
.SetAssignedRenderMode(RenderMode.InteractiveServer));
48+
49+
// Assert
50+
cut.MarkupMatches("""
51+
<input diff:ignoreAttributes />
52+
<button>Search</button>
53+
""");
54+
}
55+
56+
[Fact]
57+
public void StaticRendering()
58+
{
59+
// Act
60+
var cut = RenderComponent<MovieComponent>();
61+
// This is the same behavior as:
62+
// var cut = RenderComponent<MovieComponent>(ps => ps
63+
// .SetAssignedRenderMode(null));
64+
65+
// Assert
66+
cut.MarkupMatches("""
67+
<form action="/movies">
68+
<input type="text" name="titleFilter" />
69+
<input type="submit" value="Search" />
70+
</form>
71+
""");
72+
}
73+
```
74+
75+
# [Razor test code](#tab/razor)
76+
77+
```razor
78+
@inherits TestContext
79+
@code {
80+
[Fact]
81+
public void InteractiveServer()
82+
{
83+
// Act
84+
var cut = Render(@<MovieComponent @rendermode="RenderMode.InteractiveServer" />);
85+
86+
// Assert
87+
cut.MarkupMatches(@<text>
88+
<input diff:ignoreAttributes />
89+
<button>Search</button>
90+
</text>);
91+
}
92+
93+
[Fact]
94+
public void StaticRendering()
95+
{
96+
// Act
97+
var cut = Render(@<MovieComponent />);
98+
99+
// Assert
100+
cut.MarkupMatches(@<form action="/movies">
101+
<input type="text" name="titleFilter" />
102+
<input type="submit" value="Search" />
103+
</form>);
104+
}
105+
}
106+
```
107+
108+
***
109+
110+
## Setting the `RendererInfo` during testing
111+
To control the `ComponentBase.RendererInfo` property during testing, use the <xref:Bunit.TestContextBase.SetRendererInfo(Microsoft.AspNetCore.Components.RendererInfo)> method on the `TestContext` class. The `SetRendererInfo` method takes an nullable `RendererInfo` object as a parameter. Passing `null` will set the `ComponentBase.RendererInfo` to `null`.
112+
113+
A component (`AssistentComponent.razor`) might check if interactivity is given to enable a button:
114+
115+
```razor
116+
@if (RendererInfo.IsInteractive)
117+
{
118+
<p>Hey I am your assistant</p>
119+
}
120+
else
121+
{
122+
<p>Loading...</p>
123+
}
124+
```
125+
126+
In the test, you can set the `RendererInfo` to enable or disable the button:
127+
128+
```csharp
129+
[Fact]
130+
public void SimulatingPreRenderingOnBlazorServer()
131+
{
132+
// Arrange
133+
SetRendererInfo(new RendererInfo(rendererName: "Static", isInteractive: false));
134+
135+
// Act
136+
var cut = RenderComponent<AssistentComponent>();
137+
138+
// Assert
139+
cut.MarkupMatches("<p>Loading...</p>");
140+
}
141+
142+
[Fact]
143+
public void SimulatingInteractiveServerRendering()
144+
{
145+
// Arrange
146+
SetRendererInfo(new RendererInfo(rendererMode: "Server", isInteractive: true));
147+
148+
// Act
149+
var cut = RenderComponent<AssistentComponent>();
150+
151+
// Assert
152+
cut.MarkupMatches("<p>Hey I am your assistant</p>");
153+
}
154+
```
155+
156+
> [!NOTE]
157+
> If a component under test uses the `ComponentBase.RendererInfo` property and the `SetRendererInfo` on `TestContext` hasn't been passed in a `RendererInfo` object, the renderer will throw an exception.

docs/site/docs/toc.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
## [Trigger renders](xref:trigger-renders)
1515
## [Awaiting an async state change](xref:awaiting-async-state)
1616
## [Disposing components](xref:dispose-components)
17+
## [Render modes and RendererInfo](xref:render-modes)
1718

1819
# [Verifying output](xref:verification)
1920
## [Verify markup](xref:verify-markup)

src/bunit.core/Rendering/MissingRendererInfoException.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,19 @@ public MissingRendererInfoException()
1818
public class SomeTestClass : TestContext
1919
{
2020
[Fact]
21-
public void SomeTestCase()
22-
{
23-
Renderer.SetRendererInfo(new RendererInfo("Server", true));
24-
...
21+
public void SomeTestCase()
22+
{
23+
SetRendererInfo(new RendererInfo("Server", true));
24+
...
2525
}
2626
}
27-
27+
2828
The four built in render names are 'Static', 'Server', 'WebAssembly', and 'WebView'.
29+
30+
Go to https://bunit.dev/docs/interaction/render-modes for more information.
2931
""")
3032
{
33+
HelpLink = "https://bunit.dev/docs/interaction/render-modes";
3134
}
3235
}
3336
#endif

src/bunit.core/TestContextBase.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,4 +118,14 @@ public void DisposeComponents()
118118
{
119119
Renderer.DisposeComponents();
120120
}
121+
122+
#if NET9_0_OR_GREATER
123+
/// <summary>
124+
/// Sets the <see cref="RendererInfo"/> for the renderer.
125+
/// </summary>
126+
public void SetRendererInfo(RendererInfo? rendererInfo)
127+
{
128+
Renderer.SetRendererInfo(rendererInfo);
129+
}
130+
#endif
121131
}

src/bunit.web/TestContextWrapper.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,13 @@ public virtual IRenderedFragment Render(RenderFragment renderFragment)
8383
/// </summary>
8484
public virtual void DisposeComponents() => TestContext?.DisposeComponents();
8585

86+
#if NET9_0_OR_GREATER
87+
/// <summary>
88+
/// Sets the <see cref="RendererInfo"/> for the renderer.
89+
/// </summary>
90+
public virtual void SetRendererInfo(RendererInfo? rendererInfo) => TestContext?.SetRendererInfo(rendererInfo);
91+
#endif
92+
8693
/// <summary>
8794
/// Dummy method required to allow Blazor's compiler to generate
8895
/// C# from .razor files.

tests/bunit.core.tests/Rendering/RenderModeTests.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
[Fact(DisplayName = "TestRenderer provides RendererInfo")]
88
public void Test001()
99
{
10-
Renderer.SetRendererInfo(new RendererInfo("Server", true));
10+
SetRendererInfo(new RendererInfo("Server", true));
1111
var cut = RenderComponent<RendererInfoComponent>();
1212

1313
cut.MarkupMatches(

0 commit comments

Comments
 (0)