2
2
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3
3
4
4
using System ;
5
+ using System . Collections . Generic ;
5
6
using System . Linq ;
6
7
using System . Net ;
7
- using System . Threading ;
8
+ using System . Runtime . InteropServices ;
8
9
using System . Threading . Tasks ;
9
- using Microsoft . AspNetCore . E2ETesting ;
10
- using Microsoft . AspNetCore . Testing ;
11
- using OpenQA . Selenium ;
10
+ using Microsoft . AspNetCore . BrowserTesting ;
11
+ using PlaywrightSharp ;
12
+ using ProjectTemplates . Tests . Infrastructure ;
12
13
using Templates . Test . Helpers ;
13
14
using Xunit ;
14
15
using Xunit . Abstractions ;
15
16
16
17
namespace Templates . Test
17
18
{
18
- public class BlazorServerTemplateTest : BrowserTestBase
19
+ public class BlazorServerTemplateTest : BlazorTemplateTest
19
20
{
20
- public BlazorServerTemplateTest ( ProjectFactoryFixture projectFactory , BrowserFixture browserFixture , ITestOutputHelper output ) : base ( browserFixture , output )
21
+ public BlazorServerTemplateTest ( ProjectFactoryFixture projectFactory , PlaywrightFixture < BlazorServerTemplateTest > fixture , ITestOutputHelper output )
22
+ : base ( fixture )
21
23
{
22
- ProjectFactory = projectFactory ;
24
+ ProjectFactory = projectFactory ; ;
25
+ Output = output ;
26
+ BrowserContextInfo = new ContextInformation ( CreateFactory ( output ) ) ;
23
27
}
24
28
25
29
public ProjectFactoryFixture ProjectFactory { get ; set ; }
26
-
30
+ public ITestOutputHelper Output { get ; }
31
+ public ContextInformation BrowserContextInfo { get ; }
27
32
public Project Project { get ; private set ; }
28
33
29
- [ Fact ]
30
- public async Task BlazorServerTemplateWorks_NoAuth ( )
34
+
35
+ [ Theory ]
36
+ [ InlineData ( BrowserKind . Chromium ) ]
37
+ public async Task BlazorServerTemplateWorks_NoAuth ( BrowserKind browserKind )
31
38
{
32
39
// Additional arguments are needed. See: https://github.com/dotnet/aspnetcore/issues/24278
33
40
Environment . SetEnvironmentVariable ( "EnableDefaultScopedCssItems" , "true" ) ;
34
41
35
- Project = await ProjectFactory . GetOrCreateProject ( "blazorservernoauth" , Output ) ;
42
+ Project = await ProjectFactory . GetOrCreateProject ( "blazorservernoauth" + browserKind . ToString ( ) , Output ) ;
36
43
37
44
var createResult = await Project . RunDotNetNewAsync ( "blazorserver" ) ;
38
45
Assert . True ( 0 == createResult . ExitCode , ErrorMessages . GetFailedProcessMessage ( "create/restore" , Project , createResult ) ) ;
@@ -47,21 +54,28 @@ public async Task BlazorServerTemplateWorks_NoAuth()
47
54
var buildResult = await Project . RunDotNetBuildAsync ( ) ;
48
55
Assert . True ( 0 == buildResult . ExitCode , ErrorMessages . GetFailedProcessMessage ( "build" , Project , buildResult ) ) ;
49
56
57
+ await using var browser = Fixture . BrowserManager . IsAvailable ( browserKind ) ?
58
+ await Fixture . BrowserManager . GetBrowserInstance ( browserKind , BrowserContextInfo ) :
59
+ null ;
60
+
50
61
using ( var aspNetProcess = Project . StartBuiltProjectAsync ( ) )
51
62
{
52
63
Assert . False (
53
64
aspNetProcess . Process . HasExited ,
54
65
ErrorMessages . GetFailedProcessMessageOrEmpty ( "Run built project" , Project , aspNetProcess . Process ) ) ;
55
66
56
67
await aspNetProcess . AssertStatusCode ( "/" , HttpStatusCode . OK , "text/html" ) ;
57
- if ( BrowserFixture . IsHostAutomationSupported ( ) )
68
+
69
+ if ( Fixture . BrowserManager . IsAvailable ( browserKind ) )
58
70
{
59
- aspNetProcess . VisitInBrowser ( Browser ) ;
60
- TestBasicNavigation ( ) ;
71
+ var page = await browser . NewPageAsync ( ) ;
72
+ await aspNetProcess . VisitInBrowserAsync ( page ) ;
73
+ await TestBasicNavigation ( page ) ;
74
+ await page . CloseAsync ( ) ;
61
75
}
62
76
else
63
77
{
64
- BrowserFixture . EnforceSupportedConfigurations ( ) ;
78
+ EnsureBrowserAvailable ( browserKind ) ;
65
79
}
66
80
}
67
81
@@ -72,27 +86,31 @@ public async Task BlazorServerTemplateWorks_NoAuth()
72
86
ErrorMessages . GetFailedProcessMessageOrEmpty ( "Run published project" , Project , aspNetProcess . Process ) ) ;
73
87
74
88
await aspNetProcess . AssertStatusCode ( "/" , HttpStatusCode . OK , "text/html" ) ;
75
- if ( BrowserFixture . IsHostAutomationSupported ( ) )
89
+ if ( Fixture . BrowserManager . IsAvailable ( browserKind ) )
76
90
{
77
- aspNetProcess . VisitInBrowser ( Browser ) ;
78
- TestBasicNavigation ( ) ;
91
+ var page = await browser . NewPageAsync ( ) ;
92
+ await aspNetProcess . VisitInBrowserAsync ( page ) ;
93
+ await TestBasicNavigation ( page ) ;
94
+ await page . CloseAsync ( ) ;
79
95
}
80
96
else
81
97
{
82
- BrowserFixture . EnforceSupportedConfigurations ( ) ;
98
+ EnsureBrowserAvailable ( browserKind ) ;
83
99
}
84
100
}
85
101
}
86
102
103
+ public static IEnumerable < object [ ] > BlazorServerTemplateWorks_IndividualAuthData =>
104
+ BrowserManager . WithBrowsers ( new [ ] { BrowserKind . Chromium } , true , false ) ;
105
+
87
106
[ Theory ]
88
- [ InlineData ( true ) ]
89
- [ InlineData ( false ) ]
90
- public async Task BlazorServerTemplateWorks_IndividualAuth ( bool useLocalDB )
107
+ [ MemberData ( nameof ( BlazorServerTemplateWorks_IndividualAuthData ) ) ]
108
+ public async Task BlazorServerTemplateWorks_IndividualAuth ( BrowserKind browserKind , bool useLocalDB )
91
109
{
92
110
// Additional arguments are needed. See: https://github.com/dotnet/aspnetcore/issues/24278
93
111
Environment . SetEnvironmentVariable ( "EnableDefaultScopedCssItems" , "true" ) ;
94
112
95
- Project = await ProjectFactory . GetOrCreateProject ( "blazorserverindividual" + ( useLocalDB ? "uld" : "" ) , Output ) ;
113
+ Project = await ProjectFactory . GetOrCreateProject ( "blazorserverindividual" + browserKind + ( useLocalDB ? "uld" : "" ) , Output ) ;
96
114
97
115
var createResult = await Project . RunDotNetNewAsync ( "blazorserver" , auth : "Individual" , useLocalDB : useLocalDB ) ;
98
116
Assert . True ( 0 == createResult . ExitCode , ErrorMessages . GetFailedProcessMessage ( "create/restore" , Project , createResult ) ) ;
@@ -107,84 +125,86 @@ public async Task BlazorServerTemplateWorks_IndividualAuth(bool useLocalDB)
107
125
var buildResult = await Project . RunDotNetBuildAsync ( ) ;
108
126
Assert . True ( 0 == buildResult . ExitCode , ErrorMessages . GetFailedProcessMessage ( "build" , Project , buildResult ) ) ;
109
127
128
+ var browser = ! Fixture . BrowserManager . IsAvailable ( browserKind ) ?
129
+ null :
130
+ await Fixture . BrowserManager . GetBrowserInstance ( browserKind , BrowserContextInfo ) ;
131
+
110
132
using ( var aspNetProcess = Project . StartBuiltProjectAsync ( ) )
111
133
{
112
134
Assert . False (
113
135
aspNetProcess . Process . HasExited ,
114
136
ErrorMessages . GetFailedProcessMessageOrEmpty ( "Run built project" , Project , aspNetProcess . Process ) ) ;
115
137
116
138
await aspNetProcess . AssertStatusCode ( "/" , HttpStatusCode . OK , "text/html" ) ;
117
- if ( BrowserFixture . IsHostAutomationSupported ( ) )
139
+ if ( Fixture . BrowserManager . IsAvailable ( browserKind ) )
118
140
{
119
- aspNetProcess . VisitInBrowser ( Browser ) ;
120
- TestBasicNavigation ( ) ;
141
+ var page = await browser . NewPageAsync ( ) ;
142
+ await aspNetProcess . VisitInBrowserAsync ( page ) ;
143
+ await TestBasicNavigation ( page ) ;
144
+ await page . CloseAsync ( ) ;
121
145
}
122
146
else
123
147
{
124
- BrowserFixture . EnforceSupportedConfigurations ( ) ;
148
+ EnsureBrowserAvailable ( browserKind ) ;
125
149
}
126
150
}
127
151
128
-
129
152
using ( var aspNetProcess = Project . StartPublishedProjectAsync ( ) )
130
153
{
131
154
Assert . False (
132
155
aspNetProcess . Process . HasExited ,
133
156
ErrorMessages . GetFailedProcessMessageOrEmpty ( "Run published project" , Project , aspNetProcess . Process ) ) ;
134
157
135
158
await aspNetProcess . AssertStatusCode ( "/" , HttpStatusCode . OK , "text/html" ) ;
136
- if ( BrowserFixture . IsHostAutomationSupported ( ) )
159
+ if ( Fixture . BrowserManager . IsAvailable ( browserKind ) )
137
160
{
138
- aspNetProcess . VisitInBrowser ( Browser ) ;
139
- TestBasicNavigation ( ) ;
161
+ var page = await browser . NewPageAsync ( ) ;
162
+ await aspNetProcess . VisitInBrowserAsync ( page ) ;
163
+ await TestBasicNavigation ( page ) ;
164
+ await page . CloseAsync ( ) ;
165
+ }
166
+ else
167
+ {
168
+ EnsureBrowserAvailable ( browserKind ) ;
140
169
}
141
170
}
142
171
}
143
172
144
- private void TestBasicNavigation ( )
173
+ private async Task TestBasicNavigation ( IPage page )
145
174
{
146
- var retries = 3 ;
147
- var connected = false ;
148
- do
149
- {
150
- try
151
- {
152
- Browser . Contains ( "Information: WebSocket connected to" ,
153
- ( ) => string . Join ( Environment . NewLine , Browser . GetBrowserLogs ( LogLevel . Info ) . Select ( b => b . Message ) ) ) ;
154
- connected = true ;
155
- }
156
- catch ( TimeoutException ) when ( retries -- > 0 )
157
- {
158
- Browser . Navigate ( ) . Refresh ( ) ;
159
- }
160
- } while ( ! connected && retries > 0 ) ;
175
+ var socket = BrowserContextInfo . Pages [ page ] . WebSockets . SingleOrDefault ( ) ??
176
+ ( await page . WaitForEventAsync ( PageEvent . WebSocket ) ) . WebSocket ;
177
+
178
+ // Receive render batch
179
+ await socket . WaitForEventAsync ( WebSocketEvent . FrameReceived ) ;
180
+ await socket . WaitForEventAsync ( WebSocketEvent . FrameSent ) ;
161
181
182
+ // JS interop call to intercept navigation
183
+ await socket . WaitForEventAsync ( WebSocketEvent . FrameReceived ) ;
184
+ await socket . WaitForEventAsync ( WebSocketEvent . FrameSent ) ;
162
185
163
- Browser . Exists ( By . TagName ( "ul" ) ) ;
186
+ await page . WaitForSelectorAsync ( "ul" ) ;
164
187
// <title> element gets project ID injected into it during template execution
165
- Browser . Equal ( Project . ProjectName . Trim ( ) , ( ) => Browser . Title . Trim ( ) ) ;
188
+ Assert . Equal ( Project . ProjectName . Trim ( ) , ( await page . GetTitleAsync ( ) ) . Trim ( ) ) ;
166
189
167
190
// Initially displays the home page
168
- Browser . Equal ( " Hello, world!", ( ) => Browser . FindElement ( By . TagName ( "h1" ) ) . Text ) ;
191
+ await page . WaitForSelectorAsync ( "h1 >> text= Hello, world!") ;
169
192
170
193
// Can navigate to the counter page
171
- Browser . Click ( By . PartialLinkText ( "Counter" ) ) ;
172
- Browser . Contains ( "counter" , ( ) => Browser . Url ) ;
173
- Browser . Equal ( "Counter" , ( ) => Browser . FindElement ( By . TagName ( "h1" ) ) . Text ) ;
194
+ await page . ClickAsync ( "a[href=counter] >> text=Counter" ) ;
195
+ await page . WaitForSelectorAsync ( "h1+p >> text=Current count: 0" ) ;
174
196
175
197
// Clicking the counter button works
176
- Browser . Equal ( "Current count: 0" , ( ) => Browser . FindElement ( By . CssSelector ( "h1 + p" ) ) . Text ) ;
177
- Browser . Click ( By . CssSelector ( "p+button" ) ) ;
178
- Browser . Equal ( "Current count: 1" , ( ) => Browser . FindElement ( By . CssSelector ( "h1 + p" ) ) . Text ) ;
198
+ await page . ClickAsync ( "p+button >> text=Click me" ) ;
199
+ await page . WaitForSelectorAsync ( "h1+p >> text=Current count: 1" ) ;
179
200
180
201
// Can navigate to the 'fetch data' page
181
- Browser . Click ( By . PartialLinkText ( "Fetch data" ) ) ;
182
- Browser . Contains ( "fetchdata" , ( ) => Browser . Url ) ;
183
- Browser . Equal ( "Weather forecast" , ( ) => Browser . FindElement ( By . TagName ( "h1" ) ) . Text ) ;
202
+ await page . ClickAsync ( "a[href=fetchdata] >> text=Fetch data" ) ;
203
+ await page . WaitForSelectorAsync ( "h1 >> text=Weather forecast" ) ;
184
204
185
205
// Asynchronously loads and displays the table of weather forecasts
186
- Browser . Exists ( By . CssSelector ( "table>tbody>tr" ) ) ;
187
- Browser . Equal ( 5 , ( ) => Browser . FindElements ( By . CssSelector ( "p+table>tbody>tr" ) ) . Count ) ;
206
+ await page . WaitForSelectorAsync ( "table>tbody>tr" ) ;
207
+ Assert . Equal ( 5 , ( await page . QuerySelectorAllAsync ( "p+table>tbody>tr" ) ) . Count ( ) ) ;
188
208
}
189
209
190
210
[ Theory ]
0 commit comments