|
1 | | -# Blazor/Razor Components Testing Library |
2 | | -Testing library for Blazor Components/Razor Components, that allows you to easily 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. |
5 | | - |
6 | | -The library is currently tied to [xUnit](https://xunit.net/), but it is on the TODO list to make it compatible with all |
7 | | -.NET Core testing libraries. |
8 | | - |
9 | | -### Help and input wanted |
10 | | -This is still early days for the library and nothing is set in stone with regards to syntax and functionality. |
11 | | -If you have an idea, suggestion, or bug, please add an [issue](issues) or ping me on [Gitter](https://gitter.im/razor-components-testing-library/community). Pull-requests are also very welcome. |
12 | | - |
| 1 | +[](https://github.com/egil/razor-components-testing-library/releases) |
| 2 | +[](https://www.nuget.org/packages/Razor.Components.Testing.Library/) |
| 3 | +[](https://github.com/egil/razor-components-testing-library/issues) |
13 | 4 | [](https://gitter.im/razor-components-testing-library/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) |
14 | 5 |
|
15 | | -## Getting started |
16 | | -1. Create the necessary projects (Razor Class Library and xUnit class Library). See the [sample project](/sample) for an example. |
17 | | -1. Install the [Razor.Components.Testing.Library](https://www.nuget.org/packages/Razor.Components.Testing.Library) library from Nuget into your xUnit test project. |
18 | | -2. Optionally, add an `_Imports.razor` to test project to avoid typing using and inherits statements in each test file. |
19 | | -3. Write `.razor`-based tests. |
20 | | - |
21 | | -### Example \_Imports.razor |
22 | | -```cshtml |
23 | | -@inherits Egil.RazorComponents.Testing.RazorComponentTest |
24 | | -
|
25 | | -@using Microsoft.Extensions.DependencyInjection |
26 | | -@using Microsoft.JSInterop |
27 | | -@using Xunit |
28 | | -@using Moq |
29 | | -@using Egil.RazorComponents.Testing |
30 | | -``` |
31 | | - |
32 | | -## Example |
33 | | -The test examples below tests the Bootstrap [`Alert.razor`](sample/ComponentLib/Alert.razor) sample component, using the [`AlertTests.razor`](sample/RazorComponentLibTests/AlertTests.razor) test component, both found under the sample folder. |
34 | | - |
35 | | -### Component under test - Alert.razor |
36 | | -```cshtml |
37 | | -@code { |
38 | | - [Inject] |
39 | | - private IJSRuntime JsRuntime { get; set; } |
40 | | -
|
41 | | - [Parameter] |
42 | | - public RenderFragment? ChildContent { get; set; } |
43 | | -
|
44 | | - [Parameter] |
45 | | - public string? Class { get; set; } |
46 | | -
|
47 | | - [Parameter] |
48 | | - public string? Color { get; set; } |
49 | | -
|
50 | | - [Parameter] |
51 | | - public bool Dismissable { get; set; } = false; |
52 | | -
|
53 | | - [Parameter] |
54 | | - public string Role { get; set; } = "alert"; |
55 | | -
|
56 | | - [Parameter] |
57 | | - public bool Visible { get; set; } = true; |
58 | | -
|
59 | | - public void Dismiss() |
60 | | - { |
61 | | - // Do something with JsRuntime |
62 | | - } |
63 | | -
|
64 | | - private string CssClass |
65 | | - { |
66 | | - get |
67 | | - { |
68 | | - var cssClass = "alert fade"; |
69 | | -
|
70 | | - if (Visible) |
71 | | - cssClass = $"{cssClass} show"; |
72 | | -
|
73 | | - if (Color != null) |
74 | | - cssClass = $"{cssClass} alert-{Color}"; |
75 | | -
|
76 | | - if (Dismissable) |
77 | | - cssClass = $"{cssClass} alert-dismissible"; |
78 | | -
|
79 | | - if (Class != null) |
80 | | - cssClass = $"{cssClass} {Class}"; |
81 | | -
|
82 | | - return cssClass; |
83 | | - } |
84 | | - } |
85 | | -} |
86 | | -<div class=@CssClass role=@Role> |
87 | | - @if (Visible) |
88 | | - { |
89 | | - @if (ChildContent != null) |
90 | | - { |
91 | | - @ChildContent |
92 | | - } |
93 | | - @if (Dismissable) |
94 | | - { |
95 | | - <button type="button" class="close" aria-label="Close"> |
96 | | - <span aria-hidden="true">&times;</span> |
97 | | - </button> |
98 | | - } |
99 | | - } |
100 | | -</div> |
101 | | -``` |
102 | | - |
103 | | -### Simple tests |
104 | | -To perform a simple comparison test between the HTML generated by the `<Alert />` component, add a `<Fact />` component to your `.razor`-test-file, include the `<TestSetup>` component, that should contain the setup of the component under test, and an `<ExpectedHtml/>` component that contains the expected output. |
105 | | - |
106 | | -E.g.: |
107 | | - |
108 | | -```cshtml |
109 | | -<Fact DisplayName="Alert renders as empty without child content"> |
110 | | - <TestSetup> |
111 | | - <Alert /> |
112 | | - </TestSetup> |
113 | | - <ExpectedHtml> |
114 | | - <div class="alert fade show" role="alert"></div> |
115 | | - </ExpectedHtml> |
116 | | -</Fact> |
117 | | -
|
118 | | -<Fact DisplayName="Alert renders with child content if provided"> |
119 | | - <TestSetup> |
120 | | - <Alert>FOO BAR BAZ</Alert> |
121 | | - </TestSetup> |
122 | | - <ExpectedHtml> |
123 | | - <div class="alert fade show" role="alert">FOO BAR BAZ</div> |
124 | | - </ExpectedHtml> |
125 | | -</Fact> |
126 | | -
|
127 | | -<Fact DisplayName="Alert adds color when specified"> |
128 | | - <TestSetup> |
129 | | - <Alert Color="primary" /> |
130 | | - </TestSetup> |
131 | | - <ExpectedHtml> |
132 | | - <div class="alert fade show alert-primary" role="alert"></div> |
133 | | - </ExpectedHtml> |
134 | | -</Fact> |
135 | | -
|
136 | | -<Fact DisplayName="Providing a role overrides default role value"> |
137 | | - <TestSetup> |
138 | | - <Alert Role="banner" /> |
139 | | - </TestSetup> |
140 | | - <ExpectedHtml> |
141 | | - <div class="alert fade show" role="banner"></div> |
142 | | - </ExpectedHtml> |
143 | | -</Fact> |
144 | | -
|
145 | | -<Fact DisplayName="Setting Dismisasable to true renderes dismiss button below child content"> |
146 | | - <TestSetup> |
147 | | - <Alert Dismissable> |
148 | | - <strong>Holy guacamole!</strong> You should check in on some of those fields below. |
149 | | - </Alert> |
150 | | - </TestSetup> |
151 | | - <ExpectedHtml> |
152 | | - <div class="alert fade show alert-dismissible" role="alert"> |
153 | | - <strong>Holy guacamole!</strong> You should check in on some of those fields below. |
154 | | - <button type="button" class="close" aria-label="Close"> |
155 | | - <span aria-hidden="true">&times;</span> |
156 | | - </button> |
157 | | - </div> |
158 | | - </ExpectedHtml> |
159 | | -</Fact> |
160 | | -``` |
161 | | - |
162 | | -**NOTE:** In the future, the value in the 'DisplayName' attribute will be displayed by the test-runner. |
163 | | - |
164 | | -### Custom tests |
165 | | -If you want more control over the assertion, use a `<HtmlSnippet/>` component instead of a |
166 | | -`<ExpectedHtml/>` component. Then the default unit test will not run, and you can add your |
167 | | -own, where you can access the `RenderResults` property and do any comparison of the HTML (XML) |
168 | | -you want. |
169 | | - |
170 | | -```cshtml |
171 | | -@code { |
172 | | - [Fact] |
173 | | - public void A_Custom_Test() |
174 | | - { |
175 | | - // assert |
176 | | - var result = RenderResults.Single(x => x.Id == (nameof(A_Custom_Test))); |
177 | | - result.RenderedHtml.ShouldBe(result.Snippets.First()); |
178 | | - } |
179 | | -} |
180 | | -<Fact Id=@nameof(A_Custom_Test)> |
181 | | - <TestSetup> |
182 | | - <Alert Role="banner" Color="secondary" class="my-custom-class" Dismissable> |
183 | | - <strong>Holy guacamole!</strong> You should check in on some of those fields below. |
184 | | - </Alert> |
185 | | - </TestSetup> |
186 | | - <HtmlSnippet> |
187 | | - <div class="alert fade show alert-secondary alert-dismissible my-custom-class" role="banner"> |
188 | | - <strong>Holy guacamole!</strong> You should check in on some of those fields below. |
189 | | - <button type="button" class="close" aria-label="Close"> |
190 | | - <span aria-hidden="true">&times;</span> |
191 | | - </button> |
192 | | - </div> |
193 | | - </HtmlSnippet> |
194 | | -</Fact> |
195 | | -``` |
196 | | - |
197 | | -If you want to assert directly on the rendered component or change its parameters, use the component reference syntax (`@ref`). The `Render` method allows you to trigger a synchronous re-render manually as needed. |
198 | | - |
199 | | -```cshtml |
200 | | -@code { |
201 | | - Alert sut; |
202 | | - bool isVisible = true; |
203 | | -
|
204 | | - [Fact(DisplayName = "When Visible is toggled to false, all child content is removed from alert")] |
205 | | - public void DismissTest() |
206 | | - { |
207 | | - // initial assert |
208 | | - var result = RenderResults.Single(x => x.Id == (nameof(DismissTest))); |
209 | | - result.RenderedHtml.ShouldBe(result.Snippets[0]); |
210 | | - Assert.Equal(true, sut.Visible); |
211 | | -
|
212 | | - // act |
213 | | - isVisible = false; |
214 | | - this.Render(); |
215 | | -
|
216 | | - // assert |
217 | | - var dismissResult = RenderResults.Single(x => x.Id == (nameof(DismissTest))); |
218 | | - dismissResult.RenderedHtml.ShouldBe(result.Snippets[1]); |
219 | | - Assert.Equal(false, sut.Visible); |
220 | | - } |
221 | | -} |
222 | | -<Fact Id=@nameof(DismissTest)> |
223 | | - <TestSetup> |
224 | | - <Alert @ref="sut" Visible=@isVisible> |
225 | | - <strong>Holy guacamole!</strong> You should check in on some of those fields below. |
226 | | - </Alert> |
227 | | - </TestSetup> |
228 | | - <HtmlSnippet> |
229 | | - <div class="alert fade show" role="alert"> |
230 | | - <strong>Holy guacamole!</strong> You should check in on some of those fields below. |
231 | | - </div> |
232 | | - </HtmlSnippet> |
233 | | - <HtmlSnippet> |
234 | | - <div class="alert fade" role="alert"></div> |
235 | | - </HtmlSnippet> |
236 | | -</Fact> |
237 | | -``` |
| 6 | +# Blazor Components Testing Library |
| 7 | +A testing library for Blazor Components. You can easily define components under test in C# or Razor syntax, it has intelligent 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. |
238 | 8 |
|
239 | | -### Injecting services |
240 | | -If the component under test needs access to services, those can be injected by |
241 | | -overriding the `AddServices` method. E.g.: |
| 9 | +This framework's goal is to make it easy to write _comprehensive, stable unit tests_ for Blazor Components/Razor Components. To see how, head to the documentation pages: |
242 | 10 |
|
243 | | -```cshtml |
244 | | -@code { |
245 | | - protected override void AddServices(IServiceCollection services) |
246 | | - { |
247 | | - services.AddScoped<IJSRuntime>(_ => Mock.Of<IJSRuntime>()); |
248 | | - } |
249 | | -} |
250 | | -``` |
| 11 | +1. [Introduction](docs) |
| 12 | +2. [Getting started](docs/#getting-started) |
| 13 | +3. [Examples](docs/#examples) |
| 14 | +4. [References](docs/#references) |
| 15 | +5. [Contribute](docs/#contribute) |
0 commit comments