|
1 | 1 | # 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 |
18 | 29 | ``` |
19 | 30 |
|
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: |
112 | 33 |
|
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"">&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 |
198 | 35 |
|
199 | | -Ill add more examples later... |
0 commit comments