Skip to content

Commit afc37a9

Browse files
committed
Initial docsfx
1 parent 3787369 commit afc37a9

40 files changed

+3373
-17
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ This release includes a **name change from Blazor Components Testing Library to
66

77
*Why change the name?* Naming is hard, and I initial chose a very product-namy name, that quite clearly stated what the library was for. However, the name isn't very searchable, since it just contains generic keywords, plus, bUnit is just much cooler. It also gave me the opportunity to remove my name from all the namespaces and simplify those.
88

9+
### Contributions
10+
Hugh thanks to [Rastislav Novotný (@duracellko)](https://github.com/duracellko)) for his input and review of the `WaitForX` logic added in this release.
11+
912
### NuGet
1013
The latest version of the library is availble on NuGet:
1114

README.md

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

77
# bUnit
88

99
**bUnit**, previously known as **Blazor Components Testing Library**, is a unit testing library for Blazor Components. You can easily define components under test in C# or Razor syntax and verify outcome using semantic HTML diffing/comparison logic. You can easily interact with and inspect components, trigger event handlers, provide cascading values, inject services, mock IJsRuntime, and perform snapshot testing.
1010

1111
This library's goal is to make it easy to write _comprehensive, stable unit tests_ for Blazor Components/Razor Components. To see how, head to the Wiki pages:
1212

13-
- [Home](https://github.com/egil/razor-components-testing-library/wiki)
13+
- [Home](https://bunit.egilhansen.com)
1414
- [Getting started](https://github.com/egil/razor-components-testing-library/wiki/Getting-Started)
1515
- [C# based testing](https://github.com/egil/razor-components-testing-library/wiki/C%23-based-testing)
1616
- [C# test examples](https://github.com/egil/razor-components-testing-library/wiki/C%23-test-examples)

docs/.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
###############
2+
# folder #
3+
###############
4+
/**/DROP/
5+
/**/TEMP/
6+
/**/packages/
7+
/**/bin/
8+
/**/obj/
9+
_site
10+
_exported_templates

docs/CNAME

Lines changed: 0 additions & 1 deletion
This file was deleted.

docs/api/.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
###############
2+
# temp file #
3+
###############
4+
*.yml
5+
.manifest

docs/api/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# PLACEHOLDER
2+
TODO: Add .NET projects to the *src* folder and run `docfx` to generate **REAL** *API Documentation*!

docs/docfx.json

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
{
2+
"metadata": [
3+
{
4+
"src": [
5+
{
6+
"files": [
7+
"bunit.csproj"
8+
],
9+
"src": "../src"
10+
}
11+
],
12+
"dest": "api",
13+
"disableGitFeatures": false,
14+
"disableDefaultFilter": false
15+
}
16+
],
17+
"build": {
18+
"content": [
19+
{
20+
"files": [
21+
"api/**.yml",
22+
"api/index.md"
23+
]
24+
},
25+
{
26+
"files": [
27+
"docs/**.md",
28+
"docs/**/toc.yml",
29+
"toc.yml",
30+
"*.md"
31+
]
32+
}
33+
],
34+
"resource": [
35+
{
36+
"files": [
37+
"images/**"
38+
]
39+
}
40+
],
41+
"overwrite": [
42+
{
43+
"files": [
44+
"apidoc/**.md"
45+
],
46+
"exclude": [
47+
"obj/**",
48+
"_site/**"
49+
]
50+
}
51+
],
52+
"dest": "_site",
53+
"globalMetadataFiles": [],
54+
"fileMetadataFiles": [],
55+
"template": [
56+
"default",
57+
"templates/bunit"
58+
],
59+
"globalMetadata": {
60+
"_appName": "bUnit",
61+
"_appTitle": "bUnit",
62+
"_enableSearch": true,
63+
"_appLogoPath": "/images/blazor-logo.png"
64+
},
65+
"postProcessors": [],
66+
"markdownEngineName": "markdig",
67+
"noLangKeyword": false,
68+
"keepFileLink": false,
69+
"cleanupCacheHistory": false,
70+
"disableGitFeatures": false
71+
}
72+
}

docs/docs.csproj

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netstandard2.0</TargetFramework>
5+
</PropertyGroup>
6+
7+
<ItemGroup>
8+
<PackageReference Include="docfx.console" Version="2.49.0">
9+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
10+
<PrivateAssets>all</PrivateAssets>
11+
</PackageReference>
12+
</ItemGroup>
13+
14+
</Project>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Basics of Blazor component testing
2+
3+
To test a component, you first have to render it with parameters, cascading values, and services passed into it. Then, you need access to the component's instance and the markup it has produced, so you can inspect and interact with both.
4+
5+
There are three different ways of doing this in the library:
6+
7+
1. **C# based tests**
8+
With C# based tests, you write all your testing logic in C# files, i.e. like regular unit tests.
9+
2. **Razor based tests _(EXPERIMENTAL FEATURE)_**
10+
With Razor based tests, you write tests in `.razor` files, which allows you to declare, in Razor syntax, the component under test and other markup fragments you need. You still write your assertions via C# in the .razor file, inside `@code {...}` blocks.
11+
3. **Snapshot tests _(EXPERIMENTAL FEATURE)_**
12+
Snapshot tests are written in `.razor` files. A test contains a definition of an input markup/component and the expected output markup. The library will then automatically perform an semantic HTML comparison. Very little C# is needed in this, usually only to configure services.
13+
14+
In _Snapshot testing_, the rendering and verification is automatic.
15+
16+
For _C# based tests_ and _Razor based tests_, we have the following concepts to help us render our components and markup fragments:
17+
18+
- `ITestContext` for rendering using the RenderComponent method. The test context also allows you to configure services that should be available during rendering of components.
19+
- `IRazorTestContext` extends `ITestContext` with methods for getting the declared components under test and any (markup) fragments in Razor based tests.
20+
21+
And the following concepts to help us access the rendered markup and component:
22+
23+
- `IRenderedFragment` is returned when a fragment is rendered. It has query methods (`Find` and `FindAll`) for querying the rendered markup using CSS selectors. It also provides access to the raw markup via the `Markup` property and to a DOM tree representation of the rendered markup via the `Nodes` property. The library also provides extension methods attached to `elements` in the DOM tree, that allow you to trigger attached Razor event handlers, e.g. an `@onclick` event handler on a `<button @onclick="...">`.
24+
25+
_NOTE:_ The DOM tree implementation is provided by the [AngleSharp](https://anglesharp.github.io/) library, which provides a full HTML5 compatible implementation of DOM APIs. That means you can use all the DOM APIs you know from the browser to inspect the rendered nodes.
26+
27+
- `IRenderedComponent<TComponent>` extends `IRenderedFragment` with methods for rendering a component again with new parameters if needed, and a property for accessing the instance of the component.
28+
29+
The diagram below shows the four interfaces, their relationships to each other, and available methods.
30+
31+
![Test context and rendered fragment/component diagram](/images/test-context-rendered-fragment-diagram.png)
32+
33+
This is the basics of how components and markup is rendered and afterword's accessed for verification and further inspection.

docs/docs/CSharp-based-testing.md

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
# C# based testing
2+
3+
This pages documents how to do Blazor/Razor component testing using just C#.
4+
5+
Before you get started, make sure you have read the [Getting started](/docs/Getting-Started.html) page and in particular the [Basics of Blazor component testing](/docs/Basics-of-Blazor-component-testing.html) section. It wont take long, and it will ensure you get a good start at component testing.
6+
7+
> **NOTE:** You are currently required to write your tests using the xUnit framework. If popular demand requires it, this library can be made test framework independent in the future.
8+
9+
> **TIP:** Working with and asserting against the rendered component and its output is covered on the [Working with rendered components and fragments](/docs/Working-with-rendered-components-and-fragments.html) page.
10+
11+
**Content:**
12+
13+
- [Creating an new test class](#creating-an-new-test-class)
14+
- [Executing test cases](#executing-test-cases)
15+
- [Rendering components during tests](#rendering-components-during-tests)
16+
- [Passing parameters and services to components during render](#passing-parameters-to-components-during-render)
17+
- [Registering and injecting services into components during render](#registering-and-injecting-services-into-components-during-render)
18+
19+
**Further reading:**
20+
21+
- [Working with rendered components and fragments](/docs/Working-with-rendered-components-and-fragments.html)
22+
- [Semantic HTML markup comparison](/docs/Semantic-HTML-markup-comparison.html)
23+
- [Mocking JsRuntime](/docs/Mocking-JsRuntime.html)
24+
- [C# test examples](/docs/CSharp-test-examples.html)
25+
26+
## Creating an new test class
27+
28+
All test classes are expected to inherit from `ComponentTestFixture`, which implements the `ITestContext` interface. The example below includes the needed using statements as well:
29+
30+
```csharp
31+
using System;
32+
using Bunit;
33+
using Bunit.Mocking.JSInterop;
34+
using Microsoft.Extensions.DependencyInjection;
35+
using Xunit;
36+
37+
public class MyComponentTest : ComponentTestFixture
38+
{
39+
[Fact]
40+
public void MyFirstTest()
41+
{
42+
// ...
43+
}
44+
}
45+
```
46+
47+
The `ComponentTestFixture` contains all the logic for rendering components and correctly dispose of renderers, components, and HTML parsers after each test.
48+
49+
## Executing test cases
50+
51+
Since Blazor component tests are just regular xUnit test/facts, you execute them in exactly the same way as you would normal tests, i.e. by running `dotnet test` from the console or running the tests through the Test Explorer in Visual Studio.
52+
53+
## Rendering components during tests
54+
55+
To render a component, we use the `RenderComponent<TComponent>(params ComponentParameter[] parameters)` method. It will take the component (`TComponent`) through its usual life-cycle from `OnInitialized` to `OnAfterRender`. For example:
56+
57+
```csharp
58+
public class ComponentTest : ComponentTestFixture // implements the ITestContext interface
59+
{
60+
[Fact]
61+
public void Test1()
62+
{
63+
// Renders a MyComponent component and assigns the result to
64+
// a cut variable. CUT is short for Component Under Test.
65+
IRenderedComponent<MyComponent> cut = RenderComponent<MyComponent>();
66+
}
67+
}
68+
```
69+
70+
The `RenderComponent<TComponent>(params ComponentParameter[] parameters) : IRenderedComponent<MyComponent>` method has these parts:
71+
72+
- `TComponent` is the type of component you want to render.
73+
- `ComponentParameter[] parameters` represents parameters that will be passed to the component during render.
74+
- `IRenderedComponent<TComponent>` is the representation of the rendered component. Working with the rendered component and its output is covered on the [Working with rendered components and fragments](/docs/Working-with-rendered-components-and-fragments.html) page.
75+
76+
### Passing parameters to components during render
77+
78+
There are four types of parameters you can pass to a component being rendered through the `RenderComponent()` method:
79+
80+
- Cascading values (normally provided by the `<CascadingValue>` component in `.razor` files).
81+
- Event callbacks (of type `EventCallback<T>` or `EventCallback`).
82+
- Child content, render fragments, or templates (of type `RenderFragment` and `RenderFragment<T>`).
83+
- All other normal parameters, including unmatched parameters.
84+
85+
In addition to parameters, services can also be registered in the `ITestContext` and injected during component render.
86+
87+
To show how, let us look at a few examples that correctly pass parameters and services to the following `AllTypesOfParams<TItem>` component:
88+
89+
```cshtml
90+
@typeparam TItem
91+
@inject IJSRuntime jsRuntime
92+
@code {
93+
[Parameter(CaptureUnmatchedValues = true)]
94+
public IReadOnlyDictionary<string, object> Attributes { get; set; }
95+
96+
[Parameter]
97+
public string RegularParam { get; set; }
98+
99+
[CascadingParameter]
100+
public int UnnamedCascadingValue { get; set; }
101+
102+
[CascadingParameter(Name = "Named")]
103+
public int NamedCascadingValue { get; set; }
104+
105+
[Parameter]
106+
public EventCallback NonGenericCallback { get; set; }
107+
108+
[Parameter]
109+
public EventCallback<EventArgs> GenericCallback { get; set; }
110+
111+
[Parameter]
112+
public RenderFragment ChildContent { get; set; }
113+
114+
[Parameter]
115+
public RenderFragment OtherContent { get; set; }
116+
117+
[Parameter]
118+
public RenderFragment<TItem> ItemTemplate { get; set; }
119+
}
120+
```
121+
122+
And to render the `AllTypesOfParams<TItem>` component with all possible parameters set, use the following code:
123+
124+
```csharp
125+
var cut = RenderComponent<AllTypesOfParams<string>>(
126+
// pass name-value attribute to be captured by the Attributes parameter
127+
("some-unmatched-attribute", "unmatched value"),
128+
// pass value to the RegularParam parameter
129+
("RegularParam", "some value"),
130+
// pass value to the UnnamedCascadingValue cascading parameter
131+
CascadingValue(42),
132+
// pass value to the NamedCascadingValue cascading parameter
133+
CascadingValue("Named", 1337),
134+
// pass action callback to the NonGenericCallback parameter
135+
EventCallback("NonGenericCallback", () => { /* logic here */ }),
136+
// pass action callback to the GenericCallback parameter
137+
EventCallback("GenericCallback", (EventArgs args) => { /* logic here */ }),
138+
// pass render fragment to the ChildContent parameter
139+
ChildContent("<h1>hello world</h1>"),
140+
// paas render fragment to the OtherContent parameter
141+
RenderFragment("OtherContent", "<h1>hello world</h1>"),
142+
// pass an template render fragment to the ItemTemplate parameter
143+
Template<string>("ItemTemplate", (item) => (builder) => { })
144+
);
145+
```
146+
147+
- **Regular parameters** can easily be passed as `(string name, object? value)` pairs (they are automatically converted to a ComponentParameter). We see two examples of that with the _"RegularParam"_ and the unmatched attribute _"some-unmatched-attribute"_.
148+
- **Cascading values** can be passed both as named and unnamed via the `CascadingValue` helper method, as we see in the example above with _"UnnamedCascadingValue"_ and _"NamedCascadingValue"_.
149+
- **Event callbacks** can be passed as `Func` and `Action` types with and without input and return types, using the `EventCallback` helper method. The example above shows two examples in _"NonGenericCallback"_ and _"GenericCallback"_
150+
- **Child content** and general **Render fragments** is passed to a component using the `ChildContent` or `RenderFragment` helper methods. The `ChildContent` and `RenderFragment` methods has two overloads, one that takes a (markup) string and a generic version, e.g. for child content, `ChildContent<TComponent>(params ComponentParameter[] parameters)`, which will generate the necessary render fragment to render a component as the child content. Note that the methods takes the same input arguments as the `RenderComponent` method, which means it too can be passed all the types of parameters shown in the example above.
151+
- **Templates** render fragments can be passed via the `Template<TValue>` method, which takes the name of the parameter and a `RenderFragment<TValue>` as input. Unfortunately, you will have to turn to the `RenderTreeBuilder` API to create templates at the moment.
152+
153+
_**TIP:**_ Use the `nameof(Component.Parameter)` method to get parameter names in a refactor-safe way. For example, if we have a component `MyComponent` with a parameter named `RegularParam`, then use this when rendering:
154+
155+
```csharp
156+
var cut = RenderComponent<MyComponent>(
157+
(nameof(MyComponent.RegularParam), "some value")
158+
);
159+
```
160+
161+
### Registering and injecting services into components during render
162+
163+
When testing components that require services to be injected into them, i.e. `@inject IJsRuntime jsRuntime`, you must register the services or a mock thereof before you render your component.
164+
165+
This is done via the `ITestContext.Services` property. Once a component has been rendered, no more services can be added to the service collection.
166+
167+
If for example we want to render the with a dependency on an `IMyService`, we first have to call one of the `AddSingleton` methods on the service collection and register it. All the normal `AddSingleton` `ServiceCollection` overloads are available.
168+
169+
In the case if a `IJsRuntime` dependency, we can however use the built-in [Mocking JsRuntime](/docs/Mocking-JsRuntime.html). For example:
170+
171+
```csharp
172+
public class ComponentTest : ComponentTestFixture // implements the ITestContext interface
173+
{
174+
[Fact]
175+
public void Test1()
176+
{
177+
// Add an custom service to the services collection
178+
Services.AddSingleton<IMyService>(new MyService());
179+
180+
// Add the Mock JsRuntime service
181+
Services.AddMockJsRuntime();
182+
183+
// Renders a MyComponent component and assigns the result to
184+
// a cut variable. CUT is short for Component Under Test.
185+
IRenderedComponent<MyComponent> cut = RenderComponent<MyComponent>();
186+
}
187+
}
188+
```
189+
190+
See the page [Mocking JsRuntime](/docs/Mocking-JsRuntime.html) for more details mock.
191+
192+
## Further reading
193+
194+
To learn how to work with and assert against `IRenderedComponent`s visit the related pages:
195+
196+
- [Working with rendered components and fragments](/docs/Working-with-rendered-components-and-fragments.html)
197+
- [Semantic HTML markup comparison](/docs/Semantic-HTML-markup-comparison.html)
198+
- [Mocking JsRuntime](/docs/Mocking-JsRuntime.html)

0 commit comments

Comments
 (0)