Skip to content

Commit 12dd487

Browse files
committed
Docs: Template, child content, and unmatched value parameters passing
1 parent 27b610f commit 12dd487

7 files changed

Lines changed: 215 additions & 7 deletions

File tree

docs/samples/components/Item.razor

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<span>@Value</span>
2+
@code
3+
{
4+
[Parameter]
5+
public string Value { get; set; }
6+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
@typeparam TItem
2+
3+
<div id="generic-list">
4+
@foreach (var item in Items)
5+
{
6+
@Template(item)
7+
}
8+
</div>
9+
10+
@code
11+
{
12+
[Parameter]
13+
public IEnumerable<TItem> Items { get; set; }
14+
15+
[Parameter]
16+
public RenderFragment<TItem> Template { get; set; }
17+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using Microsoft.AspNetCore.Components;
6+
using Microsoft.AspNetCore.Components.Web;
7+
8+
namespace Bunit.Docs.Samples
9+
{
10+
public class UnmatchedParams : ComponentBase
11+
{
12+
[Parameter(CaptureUnmatchedValues = true)]
13+
public Dictionary<string, object> InputAttributes { get; set; }
14+
}
15+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
@namespace Bunit.Docs.Samples
2+
@using Microsoft.AspNetCore.Components
23
@using Microsoft.AspNetCore.Components.Web

docs/samples/tests/razor/AllKindsOfParamsTest.razor

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,32 @@
9393
</Content>
9494
</RenderFragmentParams>
9595
</ComponentUnderTest>
96+
</Fixture>
97+
98+
<Fixture Test="f => {}">
99+
<ComponentUnderTest>
100+
<TemplateParams Items=@(new string[]{ "Foo", "Bar", "Baz" }) TItem="string">
101+
<Template>
102+
<span>@context</span>
103+
</Template>
104+
</TemplateParams>
105+
</ComponentUnderTest>
106+
</Fixture>
107+
108+
<Fixture Test="f => {}">
109+
<ComponentUnderTest>
110+
<TemplateParams Items=@(new string[]{ "Foo", "Bar", "Baz" }) TItem="string">
111+
<Template>
112+
<div class="item">
113+
<Item Value=@context></Item>
114+
</div>
115+
</Template>
116+
</TemplateParams>
117+
</ComponentUnderTest>
118+
</Fixture>
119+
120+
<Fixture Test="f => {}">
121+
<ComponentUnderTest>
122+
<UnmatchedParams some-unknown-param="a value" />
123+
</ComponentUnderTest>
96124
</Fixture>

docs/samples/tests/xunit/AllKindsOfParamsTest.cs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,5 +213,73 @@ public void ComponentAndMarkupAsRenderFragment()
213213
}))
214214
);
215215
}
216+
217+
[Fact]
218+
public void HtmlTemplateParams()
219+
{
220+
using var ctx = new TestContext();
221+
222+
// Using factory method
223+
var cut1 = ctx.RenderComponent<TemplateParams<string>>(
224+
("Items", new string[] { "Foo", "Bar", "Baz" }),
225+
Template<string>("Template", item => $"<span>{item}</span>")
226+
);
227+
228+
// Using parameter builder
229+
var cut2 = ctx.RenderComponent<TemplateParams<string>>(parameters => parameters
230+
.Add(p => p.Items, new[] { "Foo", "Bar", "Baz" })
231+
.Add(p => p.Template, item => $"<span>{item}</span>")
232+
);
233+
}
234+
235+
[Fact]
236+
public void HtmlAndComponentTemplateParams()
237+
{
238+
using var ctx = new TestContext();
239+
240+
// Using factory method
241+
var cut1 = ctx.RenderComponent<TemplateParams<string>>(
242+
("Items", new string[] { "Foo", "Bar", "Baz" }),
243+
Template<string>("Template", item => builder =>
244+
{
245+
builder.OpenElement(1, "div");
246+
builder.AddAttribute(2, "class", "item");
247+
builder.OpenComponent<Item>(3);
248+
builder.AddAttribute(4, "Value", item);
249+
builder.CloseComponent();
250+
builder.CloseElement();
251+
})
252+
);
253+
254+
// Using parameter builder
255+
var cut2 = ctx.RenderComponent<TemplateParams<string>>(parameters => parameters
256+
.Add(p => p.Items, new[] { "Foo", "Bar", "Baz" })
257+
.Add(p => p.Template, item => builder =>
258+
{
259+
builder.OpenElement(1, "div");
260+
builder.AddAttribute(2, "class", "item");
261+
builder.OpenComponent<Item>(3);
262+
builder.AddAttribute(4, "Value", item);
263+
builder.CloseComponent();
264+
builder.CloseElement();
265+
})
266+
);
267+
}
268+
269+
[Fact]
270+
public void UnmatchedParamsTest()
271+
{
272+
using var ctx = new TestContext();
273+
274+
// Using factory method
275+
var cut1 = ctx.RenderComponent<UnmatchedParams>(
276+
("some-unknown-param", "a value")
277+
);
278+
279+
// Using parameter builder
280+
var cut2 = ctx.RenderComponent<UnmatchedParams>(parameters => parameters
281+
.AddUnmatched("some-unknown-param", "a value")
282+
);
283+
}
216284
}
217285
}

docs/site/docs/providing-input/passing-parameters-to-components.md

Lines changed: 80 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ Using either C# or Razor test code, this can be done like this:
8888
8989
[!code-csharp[](../../../samples/tests/xunit/AllKindsOfParamsTest.cs#L46-L64)]
9090
91-
All of these examples o the same thing, here is what is going on:
91+
These examples o the same thing, here is what is going on:
9292
9393
1. The first and second example uses the `EventCallback` factory method in <xref:Bunit.ComponentParameterFactory> (there are many overloads that take different kinds of `Action` and `Func` delegates), to pass a lambda as the event callback to the specified parameter.
9494
2. The second example uses the <xref:Bunit.ComponentParameterBuilder`1>'s `Add` method, which takes a parameter selector expression that selects the parameter using a lambda, and forces you to provide the correct type of callback method. This makes the builders methods strongly typed and refactor safe.
@@ -115,7 +115,7 @@ The following subsections has different examples of child content being passed t
115115
116116
[!code-csharp[](../../../samples/tests/xunit/AllKindsOfParamsTest.cs#L70-L80)]
117117
118-
All of these examples do the same thing, here is what is going on:
118+
These examples do the same thing, here is what is going on:
119119
120120
1. The first example uses the `ChildContent` factory method in <xref:Bunit.ComponentParameterFactory>, to pass a HTML markup string as the input to the `ChildContent` parameter.
121121
2. The second example uses the <xref:Bunit.ComponentParameterBuilder`1>'s `AddChildContent` method to pass a HTML markup string as the input to the `ChildContent` parameter.
@@ -136,7 +136,7 @@ To pass a component, e.g. the classic `<Counter>` component, that does not take
136136
137137
[!code-csharp[](../../../samples/tests/xunit/AllKindsOfParamsTest.cs#L86-L96)]
138138
139-
All of these examples do the same thing, here is what is going on:
139+
These examples do the same thing, here is what is going on:
140140
141141
1. The first example uses the `ChildContent<TChildComponent>` factory method in <xref:Bunit.ComponentParameterFactory>, where `TChildComponent` is the (child) component that should be passed to the component under test's `ChildContent` parameter.
142142
2. The second example uses the <xref:Bunit.ComponentParameterBuilder`1>'s `AddChildContent<TChildComponent>` method, where `TChildComponent` is the (child) component that should be passed to the component under test's `ChildContent` parameter.
@@ -159,7 +159,7 @@ To pass a component with parameters to a component under test, e.g. the `<Alert>
159159
160160
[!code-csharp[](../../../samples/tests/xunit/AllKindsOfParamsTest.cs#L102-L120)]
161161
162-
All of these examples do the same thing, here is what is going on:
162+
These examples do the same thing, here is what is going on:
163163
164164
1. The first example uses the `ChildContent<TChildComponent>` factory method in <xref:Bunit.ComponentParameterFactory>, where `TChildComponent` is the (child) component that should be passed to the component under test. `ChildContent<TChildComponent>` factory method can take zero or more component parameters as input itself, which will be passed to the `TChildComponent` component, in this case, the `<Alert>` component.
165165
2. The second example uses the <xref:Bunit.ComponentParameterBuilder`1>'s `AddChildContent<TChildComponent>` method, where `TChildComponent` is the (child) component that should be passed to the component under test. The `AddChildContent<TChildComponent>` method takes an optional <xref:Bunit.ComponentParameterBuilder`1> as input, which can be used to pass parameters to the `TChildComponent` component, in this case, the `<Alert>` component.
@@ -206,7 +206,7 @@ The following subsections has different examples of content being passed to the
206206
207207
[!code-csharp[](../../../samples/tests/xunit/AllKindsOfParamsTest.cs#L145-L155)]
208208
209-
All of these examples do the same thing, here is what is going on:
209+
These examples do the same thing, here is what is going on:
210210
211211
1. The first example uses the `RenderFragment` factory method in <xref:Bunit.ComponentParameterFactory>, to pass a HTML markup string as the input to the `RenderFragment` parameter.
212212
2. The second example uses the <xref:Bunit.ComponentParameterBuilder`1>'s `Add` method to pass a HTML markup string as the input to the `RenderFragment` parameter.
@@ -227,7 +227,7 @@ To pass a component, e.g. the classic `<Counter>` component, which does not take
227227
228228
[!code-csharp[](../../../samples/tests/xunit/AllKindsOfParamsTest.cs#L161-L171)]
229229
230-
All of these examples do the same thing, here is what is going on:
230+
These examples do the same thing, here is what is going on:
231231
232232
1. The first example uses the `Add<TChildComponent>` factory method in <xref:Bunit.ComponentParameterFactory>, where `TChildComponent` is the (child) component that should be passed to the `RenderFragment` parameter.
233233
2. The second example uses the <xref:Bunit.ComponentParameterBuilder`1>'s `Add<TChildComponent>` method, where `TChildComponent` is the (child) component that should be passed to the `RenderFragment` parameter.
@@ -250,7 +250,7 @@ To pass a component with parameters to a `RenderFragment` parameter, e.g. the `<
250250
251251
[!code-csharp[](../../../samples/tests/xunit/AllKindsOfParamsTest.cs#L177-L195)]
252252
253-
All of these examples do the same thing, here is what is going on:
253+
These examples do the same thing, here is what is going on:
254254
255255
1. The first example uses the `RenderFragment<TChildComponent>` factory method in <xref:Bunit.ComponentParameterFactory>, where `TChildComponent` is the (child) component that should be passed to the `RenderFragment` parameter. `RenderFragment<TChildComponent>` factory method takes the name of the parameter and zero or more component parameters as input, which will be passed to the `TChildComponent` component, in this case, the `<Alert>` component.
256256
2. The second example uses the <xref:Bunit.ComponentParameterBuilder`1>'s `Add<TChildComponent>` method, where `TChildComponent` is the (child) component that should be passed to the `RenderFragment` parameter. The `Add<TChildComponent>` method takes an optional <xref:Bunit.ComponentParameterBuilder`1> as input, which can be used to pass parameters to the `TChildComponent` component, in this case, the `<Alert>` component.
@@ -283,8 +283,81 @@ This is just regular Blazor `RenderFragment` parameter passing, where regular HT
283283
284284
### Templates Parameters
285285
286+
Template parameters are closely related to `RenderFragment` parameters described in the previous section. The difference is that a template parameter is of type `RenderFragment<TValue>`. Like with regular `RenderFragment`, a `RenderFragment<TValue>` template parameter can be regular HTML markup, it can be Razor markup, e.g. other component declarations, or a mix of the two. If it is another component, then that component can also receive child content, and so forth.
287+
288+
The following examples renders this template component, which has a `RenderFragment<TValue>` template parameter:
289+
290+
[!code-csharp[TemplateParams.razor](../../../samples/components/TemplateParams.razor)]
291+
292+
#### Passing a HTML based templates
293+
294+
To pass a template into a `RenderFragment<TValue>` parameter, that just consists of regular HTML markup, do the following:
295+
296+
# [C# test code](#tab/csharp)
297+
298+
[!code-csharp[](../../../samples/tests/xunit/AllKindsOfParamsTest.cs#L220-L232)]
299+
300+
These examples do the same thing, i.e. pass a HTML markup template into the component under test. This is done with the help of a `Func<TValue, string>` delegate, that takes whatever the template value is as input, and returns a (markup) string. The delegate is automatically turned into a `RenderFragment<TValue>` type and pass to the template parameter.
301+
302+
1. The first example passes data to the `Items` parameter, and then it uses the `Template<TValue>` factory method in <xref:Bunit.ComponentParameterFactory>, that takes the name of the `RenderFragment<TValue>` template parameter, and the `Func<TValue, string>` delegate as input.
303+
2. The second example uses the <xref:Bunit.ComponentParameterBuilder`1>'s `Add` method to first add the data to `Items` parameter and then a `Func<TValue, string>` delegate.
304+
305+
The delegate creates a simple markup string in both examples.
306+
307+
# [Razor test code](#tab/razor)
308+
309+
[!code-html[](../../../samples/tests/razor/AllKindsOfParamsTest.razor#L98-L109)]
310+
311+
This is just regular Blazor `RenderFragment<TValue>` parameter passing, in this case, to the `Template` parameter. This is the same for both `Fixture` and `SnapshotTest` razor tests.
312+
313+
***
314+
315+
#### Passing HTML and Components based templates
316+
317+
To pass a template into a `RenderFragment<TValue>` parameter, which consists of both regular HTML markup and components, in this case, the `<Item>` component listed below, do the following:
318+
319+
[!code-csharp[Item.razor](../../../samples/components/Item.razor)]
320+
321+
# [C# test code](#tab/csharp)
322+
323+
[!code-csharp[](../../../samples/tests/xunit/AllKindsOfParamsTest.cs#L238-L266)]
324+
325+
These examples do the same thing, i.e. create a template which consist of a `<div>` element which wraps the `<Item>` component listed above. In both cases, must construct the `RenderFragemnt<TValue>` type manually. Here is what is going on:
326+
327+
1. The first example passes data to the `Items` parameter, and then it uses the `Template<TValue>` factory method in <xref:Bunit.ComponentParameterFactory>, which takes the name of the `RenderFragment<TValue>` template parameter and a `RenderFragment<TValue>` type as input.
328+
2. The second example uses the <xref:Bunit.ComponentParameterBuilder`1>'s `Add` method to first add the data to `Items` parameter and then a `RenderFragment<TValue>` type as input.
329+
330+
# [Razor test code](#tab/razor)
331+
332+
[!code-html[](../../../samples/tests/razor/AllKindsOfParamsTest.razor#L108-L118)]
333+
334+
This is just regular Blazor `RenderFragment<TValue>` parameter passing, in this case, to the `Template` parameter. This is the same for both `Fixture` and `SnapshotTest` razor tests.
335+
336+
***
337+
286338
### Unmatched Parameters
287339
340+
An unmatched parameter is a parameter passed to a component under test, which does not have an explicit `[Parameter]` parameter, but instead is captured by a `[Parameter(CaptureUnmatchedValues = true)]` parameter.
341+
342+
In the follow examples, we will pass a unmatched parameter to the following component:
343+
344+
[!code-csharp[UnmatchedParams](../../../samples/components/UnmatchedParams.cs#L10-L14)]
345+
346+
347+
# [C# test code](#tab/csharp)
348+
349+
[!code-csharp[](../../../samples/tests/xunit/AllKindsOfParamsTest.cs#L272-L282)]
350+
351+
These examples do the same thing, i.e. pass in the parameter `some-unknown-param` with the value `a value` to the component under test.
352+
353+
# [Razor test code](#tab/razor)
354+
355+
[!code-html[](../../../samples/tests/razor/AllKindsOfParamsTest.razor#L120-L124)]
356+
357+
This is just regular Blazor parameter passing, which is the same for both `Fixture` and `SnapshotTest` razor tests. In this case, the parameter `some-unknown-param` with the value `a value` is passed to the component under test.
358+
359+
***
360+
288361
## Cascading Value Parameters
289362
290363
## Render Component Test inside other Components

0 commit comments

Comments
 (0)