Skip to content

Commit 59d3038

Browse files
committed
Cleanup and updated readme
1 parent 2ad622c commit 59d3038

File tree

12 files changed

+94
-511
lines changed

12 files changed

+94
-511
lines changed

README.md

Lines changed: 30 additions & 194 deletions
Original file line numberDiff line numberDiff line change
@@ -1,199 +1,35 @@
11
# Razor Component Testing Library
2-
Prototype testing library that renders Razor Components as HTML and compare the result to an
3-
expected result, using the [XMLDiff](https://www.xmlunit.org/) library and [Shouldly](https://github.com/shouldly/shouldly) for writing out error messages.
4-
5-
## Examples
6-
The following examples uses XUnit and Shouldly for testing.
7-
8-
To test the following component:
9-
10-
```razor
11-
@code {
12-
[Parameter] public RenderFragment? ChildContent { get; set; }
13-
}
14-
@if (!(ChildContent is null))
15-
{
16-
<span class="sr-only">@ChildContent</span>
17-
}
2+
Testing library for Razor Components, that allows you to define your component under test and the expected output HTML
3+
in a `.razor` file. It will automatically compare the input with the expected output using the
4+
[XMLDiff](https://www.xmlunit.org/) library and pretty print error messages using the
5+
[Shouldly](https://github.com/shouldly/shouldly) library.
6+
7+
The library is currently tied to [xUnit](https://xunit.net/), but it is on the TODO list to make it compatible with all
8+
.NET Core testing libraries.
9+
10+
### Help and input wanted
11+
This is still early days for the library and nothing is set in stone with regards to syntax and functionality.
12+
If you have an idea, suggestion, or bug, please add an [issue](issues). Pull-requests are also very welcome.
13+
14+
## Getting started
15+
1. Install the [Razor.Components.Testing.Library](https://www.nuget.org/packages/Razor.Components.Testing.Library) library from Nuget into your xUnit test project (https://www.nuget.org/packages/Razor.Components.Testing.Library).
16+
2. Optionally, add an `_Imports.razor` to test project to avoid typing using and inherits statements in each test files.
17+
3. Write `.razor`-based tests.
18+
19+
### Example \_Imports.razor
20+
```cshtml
21+
@inherits Egil.RazorComponents.Testing.RazorComponentTest
22+
23+
@using Microsoft.Extensions.DependencyInjection
24+
@using Microsoft.JSInterop
25+
@using Xunit
26+
@using Moq
27+
@using Shouldly
28+
@using Egil.RazorComponents.Testing
1829
```
1930

20-
Write the following test fixture:
21-
22-
```csharp
23-
using Egil.RazorComponents.Testing;
24-
using Xunit;
25-
26-
public class SrOnlyTest : RazorComponentFixture
27-
{
28-
[Fact(DisplayName = "SrOnly does not render anything when ChildContent is null")]
29-
public void MyTestMethod()
30-
{
31-
var expectedHtml = string.Empty;
32-
33-
var result = Component<SrOnly>().Render();
34-
35-
result.ShouldBe(expectedHtml);
36-
}
37-
38-
[Fact(DisplayName = "SrOnly renders if ChildContent is not null")]
39-
public void SrOnlyRenderCorrectlysIfChildContentIsNotNull()
40-
{
41-
var content = "CONTENT";
42-
var expectedHtml = $@"<span class=""sr-only"">{content}</span>";
43-
44-
var result = Component<SrOnly>().WithChildContent(content).Render();
45-
46-
result.ShouldBe(expectedHtml);
47-
}
48-
49-
[Fact(DisplayName = "Fail example: SrOnly renders if ChildContent is not null")]
50-
public void MyTestMethod3()
51-
{
52-
var content = "CONTENT";
53-
//var expectedHtml = $@"<span class=""sr-only"">{content}</span>";
54-
var expectedHtml = "<div></div>";
55-
56-
var result = Component<SrOnly>().WithChildContent(content).Render();
57-
58-
result.ShouldBe(expectedHtml);
59-
}
60-
}
61-
```
62-
63-
The thrid test will fail with the following helpful error message:
64-
65-
```text
66-
Fail example: SrOnly renders if ChildContent is not null
67-
Source: SrOnlyTest.cs line: 30
68-
Duration: 122 ms
69-
70-
Message:
71-
Shouldly.ShouldAssertException : diffResult.HasDifferences()
72-
should be
73-
False
74-
but was
75-
True
76-
77-
Additional Info:
78-
should be
79-
80-
<div></div>
81-
82-
but was
83-
84-
<span class="sr-only">CONTENT</span>
85-
86-
with the following differences:
87-
88-
- Expected child nodelist length '0' but was '1' - comparing <div...> at /ROOT[1]/div[1] to <span...> at /ROOT[1]/span[1] (DIFFERENT)
89-
- Expected element tag name 'div' but was 'span' - comparing <div...> at /ROOT[1]/div[1] to <span...> at /ROOT[1]/span[1] (DIFFERENT)
90-
- Expected number of attributes '0' but was '1' - comparing <div...> at /ROOT[1]/div[1] to <span...> at /ROOT[1]/span[1] (DIFFERENT)
91-
- Expected attribute name '/ROOT[1]/div[1]' - comparing <div...> at /ROOT[1]/div[1] to <span...> at /ROOT[1]/span[1]/@class (DIFFERENT)
92-
- Expected child '' but was '#text' - comparing <NULL> to <span ...>CONTENT</span> at /ROOT[1]/span[1]/text()[1] (DIFFERENT)
93-
94-
Stack Trace:
95-
at ShouldlyRazorComponentTestExtensions.ShouldBe(ComponentRenderedText componentRenderedText, String expectedHtml) in ShouldlyRazorComponentTestExtensions.cs line: 23
96-
at SrOnlyTest.MyTestMethod3() in SrOnlyTest.cs line: 38
97-
```
98-
99-
### Testing an Bootstrap Alert component
100-
The following testing code tests an Bootstrap Alert component (not included at the moment).
101-
It will hopefully serve as an example of the other things the library can do at the momemt.
102-
103-
```csharp
104-
public class AlertTest : RazorComponentFixture
105-
{
106-
[Fact(DisplayName = "Alert render with no parameters")]
107-
public void MyTestMethod()
108-
{
109-
var expectedHtml = $@"<div class=""alert fade show"" role=""alert""></div>";
110-
111-
var result = Component<Alert>().Render();
31+
## Example
32+
The test example below uses the `[Alert](sample/ComponentLib/Alert.razor)` sample component in the sample folder:
11233

113-
result.ShouldBe(expectedHtml);
114-
}
115-
116-
[Fact(DisplayName = "Alert adds color when specified")]
117-
public void MyTestMethod2()
118-
{
119-
var expectedHtml = $@"<div class=""alert fade show alert-primary"" role=""alert""></div>";
120-
121-
var component = Component<Alert>().WithParams(("Color", "primary"));
122-
123-
var result = component.Render();
124-
125-
result.ShouldBe(expectedHtml);
126-
}
127-
128-
[Fact(DisplayName = "Providing a role overrides default role value")]
129-
public void MyTestMethod3()
130-
{
131-
var role = "ALERT";
132-
var expectedHtml = $@"<div class=""alert fade show"" role=""{role}""></div>";
133-
134-
var result = Component<Alert>().WithParams(("Role", role)).Render();
135-
136-
result.ShouldBe(expectedHtml);
137-
}
138-
139-
[Fact(DisplayName = "Setting Dismisasable to true renderes dismiss button")]
140-
public void MyTestMethod4()
141-
{
142-
var expectedHtml = $@"<div class=""alert fade show alert-dismissible"" role=""alert"">
143-
<button type=""button"" class=""close"" aria-label=""Close"">
144-
<span aria-hidden=""true"">&amp;times;</span>
145-
</button>
146-
</div>";
147-
148-
var result = Component<Alert>().WithParams(("Dismissable", true)).Render();
149-
150-
result.ShouldBe(expectedHtml);
151-
}
152-
153-
[Fact(DisplayName = "Setting DismissAriaLabel and DismissText overrides defaults")]
154-
public void MyTestMethod42()
155-
{
156-
var dismissAriaLabel = "DISMISSARIALABEL";
157-
var dismissText = "DISMISSTEXT";
158-
var expectedHtml = $@"<div class=""alert fade show alert-dismissible"" role=""alert"">
159-
<button type=""button"" class=""close"" aria-label=""{dismissAriaLabel}"">
160-
<span aria-hidden=""true"">{dismissText}</span>
161-
</button>
162-
</div>";
163-
164-
var result = Component<Alert>().WithParams(
165-
("Dismissable", true),
166-
("DismissAriaLabel", dismissAriaLabel),
167-
("DismissText", dismissText)
168-
).Render();
169-
170-
result.ShouldBe(expectedHtml);
171-
}
172-
173-
[Fact(DisplayName = "Nested A components have their DefaultCssClass set to alert-link")]
174-
public void MyTestMethod5()
175-
{
176-
var expectedHtml = $@"<div class=""alert fade show"" role=""alert"">
177-
<a class=""alert-link""></a>
178-
</div>";
179-
180-
var result = Component<Alert>().WithChildContent(Fragment<A>()).Render();
181-
182-
result.ShouldBe(expectedHtml);
183-
}
184-
185-
[Fact(DisplayName = "Nested Heading components have their DefaultCssClass set to alert-heading")]
186-
public void MyTestMethod6()
187-
{
188-
var expectedHtml = $@"<div class=""alert fade show"" role=""alert"">
189-
<h1 class=""alert-heading""></h1>
190-
</div>";
191-
192-
var result = Component<Alert>().WithChildContent(Fragment<H1>()).Render();
193-
194-
result.ShouldBe(expectedHtml);
195-
}
196-
}
197-
```
34+
https://github.com/egil/razor-component-testing-library/blob/2ad622c9ad0aa21a4454d8d4b681944c3c2e3f0a/sample/ComponentLib/Alert.razor
19835

199-
Ill add more examples later...

sample/ComponentLib/Alert.razor

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
@code {
2+
[Inject]
3+
private IJSRuntime JsRuntime { get; set; }
4+
25
[Parameter]
36
public RenderFragment? ChildContent { get; set; }
47

@@ -13,17 +16,22 @@
1316

1417
[Parameter]
1518
public string Role { get; set; } = "alert";
16-
19+
1720
[Parameter]
1821
public bool Visible { get; set; } = true;
1922

23+
public void Dismiss()
24+
{
25+
// Do something with JsRuntime
26+
}
27+
2028
private string CssClass
2129
{
2230
get
2331
{
2432
var cssClass = "alert fade";
25-
26-
if(Visible)
33+
34+
if (Visible)
2735
cssClass = $"{cssClass} show";
2836

2937
if (Color != null)

sample/ComponentLib/_Imports.razor

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@using Microsoft.JSInterop

sample/ComponentLibTests/AlertTests.razor

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ and re-render, use the component reference syntax and the Render method.
9292
bool isVisible = true;
9393

9494
[Fact(DisplayName = "When Visible is toggled to false, all child content is removed from alert")]
95-
public async Task DismissTest()
95+
public void DismissTest()
9696
{
9797
// initial assert
9898
var result = RenderResults.Single(x => x.Id == (nameof(DismissTest)));
@@ -123,4 +123,14 @@ and re-render, use the component reference syntax and the Render method.
123123
<HtmlSnippet>
124124
<div class="alert fade" role="alert"></div>
125125
</HtmlSnippet>
126-
</Fact>
126+
</Fact>
127+
128+
If the component under test needs access to services, those can be injected by
129+
overriding the AddServices method. E.g.:
130+
131+
@code {
132+
protected override void AddServices(IServiceCollection services)
133+
{
134+
services.AddScoped<IJSRuntime>(_ => Mock.Of<IJSRuntime>());
135+
}
136+
}

sample/ComponentLibTests/_Imports.razor

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
@inherits Egil.RazorComponents.Testing.RazorComponentTest
1+
@*_Imports.razor*@
2+
@inherits Egil.RazorComponents.Testing.RazorComponentTest
23

4+
@using Microsoft.Extensions.DependencyInjection
5+
@using Microsoft.JSInterop
36
@using Xunit
47
@using Moq
58
@using Shouldly

sample/Testing-Sample.sln

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
3-
# Visual Studio 15
4-
VisualStudioVersion = 15.0.26124.0
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.29123.89
55
MinimumVisualStudioVersion = 15.0.26124.0
6-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ComponentLib", "ComponentLib\ComponentLib.csproj", "{EF6DF0EB-AB3F-4ADA-B0E4-0666F428B7D0}"
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ComponentLib", "ComponentLib\ComponentLib.csproj", "{EF6DF0EB-AB3F-4ADA-B0E4-0666F428B7D0}"
77
EndProject
8-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ComponentLibTests", "ComponentLibTests\ComponentLibTests.csproj", "{5B0A2111-A311-470C-B3C7-7D8A5B511E94}"
8+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ComponentLibTests", "ComponentLibTests\ComponentLibTests.csproj", "{5B0A2111-A311-470C-B3C7-7D8A5B511E94}"
99
EndProject
10-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "razor-component-testing-library", "..\src\razor-component-testing-library.csproj", "{CE16B524-01E0-45F3-8C0E-1D1BE1639D3B}"
10+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "razor-component-testing-library", "..\src\razor-component-testing-library.csproj", "{CE16B524-01E0-45F3-8C0E-1D1BE1639D3B}"
11+
EndProject
12+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{232D6C4C-0791-4A31-AE4F-8C2C9A3C47DC}"
13+
ProjectSection(SolutionItems) = preProject
14+
..\LICENSE = ..\LICENSE
15+
..\README.md = ..\README.md
16+
EndProjectSection
1117
EndProject
1218
Global
1319
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -18,9 +24,6 @@ Global
1824
Release|x64 = Release|x64
1925
Release|x86 = Release|x86
2026
EndGlobalSection
21-
GlobalSection(SolutionProperties) = preSolution
22-
HideSolutionNode = FALSE
23-
EndGlobalSection
2427
GlobalSection(ProjectConfigurationPlatforms) = postSolution
2528
{EF6DF0EB-AB3F-4ADA-B0E4-0666F428B7D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
2629
{EF6DF0EB-AB3F-4ADA-B0E4-0666F428B7D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
@@ -59,4 +62,10 @@ Global
5962
{CE16B524-01E0-45F3-8C0E-1D1BE1639D3B}.Release|x86.ActiveCfg = Release|Any CPU
6063
{CE16B524-01E0-45F3-8C0E-1D1BE1639D3B}.Release|x86.Build.0 = Release|Any CPU
6164
EndGlobalSection
65+
GlobalSection(SolutionProperties) = preSolution
66+
HideSolutionNode = FALSE
67+
EndGlobalSection
68+
GlobalSection(ExtensibilityGlobals) = postSolution
69+
SolutionGuid = {5943901C-FA6F-4264-9E11-B423347E40AA}
70+
EndGlobalSection
6271
EndGlobal

0 commit comments

Comments
 (0)