Skip to content

Commit e9263fb

Browse files
committed
update docs
1 parent d885fe5 commit e9263fb

File tree

4 files changed

+138
-69
lines changed

4 files changed

+138
-69
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/egil/razor-components-testing-library/CI)](https://github.com/egil/razor-components-testing-library/actions?query=workflow%3ACI)
2-
[![GitHub Tag](https://img.shields.io/github/tag/egil/razor-components-testing-library.svg?style=flat-square)](https://github.com/egil/razor-components-testing-library/releases)
2+
[![GitHub tag (latest SemVer pre-release)](https://img.shields.io/github/v/tag/egil/razor-components-testing-library?include_prereleases)](https://github.com/egil/razor-components-testing-library/releases)
33
[![Nuget](https://img.shields.io/nuget/vpre/Razor.Components.Testing.Library)](https://www.nuget.org/packages/Razor.Components.Testing.Library/)
44
[![Issues Open](https://img.shields.io/github/issues/egil/razor-components-testing-library.svg?style=flat-square)](https://github.com/egil/razor-components-testing-library/issues)
55
[![Gitter](https://badges.gitter.im/razor-components-testing-library/community.svg)](https://gitter.im/razor-components-testing-library/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)

docs/csharp-examples.md

Lines changed: 127 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ In the following examples, the terminology **component under test** (abbreviated
44

55
All examples can be found in the [CodeOnlyTests](../sample/tests/CodeOnlyTests) folder in the [Sample project](../sample/).
66

7-
1. [Creating new test classes](creating-new-test-classes)
8-
2. [Testing components without parameters](testing-components-without-parameters)
9-
3. [Testing components with regular parameters](testing-components-with-regular-parameters)
10-
4. [Testing components with child content](testing-components-with-child-content)
7+
1. [Creating new test classes](#creating-new-test-classes)
8+
2. [Testing components without parameters](#testing-components-without-parameters)
9+
3. [Testing components with regular parameters](#testing-components-with-regular-parameters)
10+
4. [Testing components with child content](#testing-components-with-child-content)
11+
5. [Testing components with `EventCallback` parameters](#testing-components-with-eventcallback-parameters)
12+
6. [Testing components with cascading-value parameters](#testing-components-with-cascading value-parameters)
1113

1214
## Creating new test classes
1315

@@ -49,7 +51,7 @@ The following unit-tests verifies that the [Counter.razor](../sample/src/Pages/C
4951
}
5052
```
5153

52-
These are the unit tests:
54+
The [CounterTest.cs](../sample/test/CodeOnlyTests/Pages/CounterTest.cs) looks like this:
5355

5456
```csharp
5557
public class CounterTest : ComponentTestFixture
@@ -151,7 +153,7 @@ The component under test will be the [Aside.razor](../sample/src/Components/Asid
151153
}
152154
```
153155

154-
Here is a test:
156+
The [AsideTest.cs](../sample/test/CodeOnlyTests/Components/AsideTest.cs) looks like this:
155157

156158
```csharp
157159
public class AsideTest : ComponentTestFixture
@@ -190,7 +192,7 @@ The second parameter, `class` is explicitly declared in the `Aside` class. It is
190192

191193
## Testing components with child content
192194

193-
The `Aside` component listed in the previous section also has a `ChildContent` parameter, so lets add a few tests that passes markup and components to it through that.
195+
The [Aside.razor](../sample/src/Components/Aside.razor) component listed in the previous section also has a `ChildContent` parameter, so lets add a few tests that passes markup and components to it through that.
194196

195197
```csharp
196198
public class AsideTest : ComponentTestFixture
@@ -253,4 +255,121 @@ public class AsideTest : ComponentTestFixture
253255
}
254256
```
255257

256-
In `Test002` above we use the `ChildContent(...)` helper method to create a ChildContent parameter and pass that to the `Aside` component. The overload, `ChildContent<TComponent>(component params)`, used in `Test003`, allows us to create render fragment that will render a component (of type `TComponent`) with the specified parameters. The `ChildContent<TComponent>(...)` has the same parameter options as the `RenderComponent<TComponent>` method has.
258+
- In `Test002` above we use the `ChildContent(...)` helper method to create a ChildContent parameter and pass that to the `Aside` component.
259+
- The overload, `ChildContent<TComponent>(...)`, used in `Test003`, allows us to create a render fragment that will render a component (of type `TComponent`) with the specified parameters.
260+
The `ChildContent<TComponent>(...)` has the same parameter options as the `RenderComponent<TComponent>` method has.
261+
262+
## Testing components with `EventCallback` parameters
263+
264+
To show how to pass an `EventCallback` to a component under test, we will use the [ThemedButton.razor](../sample/src/Components/ThemedButton.razor), which looks like this:
265+
266+
```cshtml
267+
<button @onclick="HandleOnClick"
268+
class=@Theme?.Value
269+
title=@Title?.Value
270+
@attributes="Attributes">
271+
@ChildContent
272+
</button>
273+
@code {
274+
[Parameter(CaptureUnmatchedValues = true)]
275+
public IReadOnlyDictionary<string, object>? Attributes { get; set; }
276+
277+
[CascadingParameter] public ThemeInfo? Theme { get; set; }
278+
[CascadingParameter(Name = nameof(Title))] public ThemeInfo? Title { get; set; }
279+
[Parameter] public RenderFragment? ChildContent { get; set; }
280+
[Parameter] public EventCallback<MouseEventArgs> OnClick { get; set; }
281+
282+
private Task HandleOnClick(MouseEventArgs args) => OnClick.InvokeAsync(args);
283+
}
284+
```
285+
286+
The relevant part of [ThemedButtonTest.cs](../sample/test/CodeOnlyTests/Components/ThemedButtonTest.cs) looks like this:
287+
288+
```csharp
289+
public class ThemedButtonTest : ComponentTestFixture
290+
{
291+
[Fact(DisplayName = "When button is clicked, the OnClick event callback is triggered")]
292+
public void Test001()
293+
{
294+
var wasCalled = false;
295+
// Arrange - pass a lambda in as parameter to the OnClick parameter.
296+
//
297+
// This is equivalent to the follow Razor code:
298+
//
299+
// <ThemedButton OnClick="(_) => wasCalled = true"></ThemedButton>
300+
var cut = RenderComponent<ThemedButton>(
301+
EventCallback(nameof(ThemedButton.OnClick), (MouseEventArgs _) => wasCalled = true)
302+
);
303+
304+
// Act - click the button in CUT
305+
cut.Find("button").Click();
306+
307+
// Assert - check if callback was triggered
308+
wasCalled.ShouldBeTrue();
309+
}
310+
}
311+
```
312+
313+
`Test001` above uses the `EventCallback(parammeterName, callback)` helper method the generate a proper `EventCallback` object. There are many overloads, that should enable all the normal scenarios that is possible via Razor code.
314+
315+
## Testing components with cascading-value parameters
316+
317+
If a component under test accepts cascading values, like [ThemedButton.razor](../sample/src/Components/ThemedButton.razor) listed above, we can pass one or more cascading values to it like so:
318+
319+
```csharp
320+
public class ThemedButtonTest : ComponentTestFixture
321+
{
322+
[Fact(DisplayName = "Themed button uses provided theme info to set class attribute")]
323+
public void Test002()
324+
{
325+
// Arrange - create an instance of the ThemeInfo class to passs to the ThemedButton
326+
var theme = new ThemeInfo() { Value = "BUTTON" };
327+
328+
// Act - Render the ThemedButton component, passing in the instance of ThemeInfo
329+
// as an _unnamed_ cascading value.
330+
//
331+
// This is equivalent to the follow Razor code:
332+
//
333+
// <CascadingValue Value="theme">
334+
// <ThemedButton></ThemedButton>
335+
// </CascadingValue>
336+
var cut = RenderComponent<ThemedButton>(
337+
CascadingValue(theme)
338+
);
339+
340+
// Assert - check that the class specified in the cascading value was indeed used.
341+
cut.Find("button").ClassList.ShouldContain(theme.Value);
342+
}
343+
344+
[Fact(DisplayName = "Named cascading values are passed to components")]
345+
public void Test003()
346+
{
347+
// Arrange - create two instances of the ThemeInfo class to passs to the ThemedButton
348+
var theme = new ThemeInfo() { Value = "BUTTON" };
349+
var titleTheme = new ThemeInfo() { Value = "BAR" };
350+
351+
// Act - Render the ThemedButton component, passing in the instances of ThemeInfo
352+
// as an _unnamed_ and a _named_ cascading value.
353+
//
354+
// This is equivalent to the follow Razor code:
355+
//
356+
// <CascadingValue Value="theme">
357+
// <CascadingValue Name="Title" Value="titleTheme">
358+
// <ThemedButton></ThemedButton>
359+
// </CascadingValue>
360+
// </CascadingValue>
361+
var cut = RenderComponent<ThemedButton>(
362+
CascadingValue(theme),
363+
CascadingValue(nameof(ThemedButton.Title), titleTheme)
364+
);
365+
366+
// Assert - check that the class and title specified in the cascading values was indeed used.
367+
var elm = cut.Find("button");
368+
elm.ClassList.ShouldContain(theme.Value);
369+
elm.GetAttribute("title").ShouldContain(titleTheme.Value);
370+
}
371+
}
372+
```
373+
374+
- `Test002` above uses the `CascadingValue(object value)` helper method to pass an **unnamed** cascading value to the CUT.
375+
- `Test003` above demonstrates how multiple (named) cascading values can be passed to a component under test.
Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-
<button class=@(Theme?.Value ?? "NO-THEME") @attributes="Attributes">
1+
<button @onclick="HandleOnClick"
2+
class=@Theme?.Value
3+
title=@Title?.Value
4+
@attributes="Attributes">
25
@ChildContent
36
</button>
47
@code {
58
[Parameter(CaptureUnmatchedValues = true)]
69
public IReadOnlyDictionary<string, object>? Attributes { get; set; }
710

8-
[CascadingParameter]
9-
public ThemeInfo? Theme { get; set; }
11+
[CascadingParameter] public ThemeInfo? Theme { get; set; }
12+
[CascadingParameter(Name = nameof(Title))] public ThemeInfo? Title { get; set; }
13+
[Parameter] public RenderFragment? ChildContent { get; set; }
14+
[Parameter] public EventCallback<MouseEventArgs> OnClick { get; set; }
1015

11-
[Parameter]
12-
public RenderFragment? ChildContent { get; set; }
13-
14-
protected override void OnAfterRender(bool firstRender)
15-
{
16-
base.OnAfterRender(firstRender);
17-
}
18-
}
16+
private Task HandleOnClick(MouseEventArgs args) => OnClick.InvokeAsync(args);
17+
}

sample/tests/CodeOnlyTests/Components/CascadingValueTest.cs

Lines changed: 0 additions & 49 deletions
This file was deleted.

0 commit comments

Comments
 (0)