5
5
using Microsoft . AspNetCore . Http . Connections . Client ;
6
6
using Microsoft . AspNetCore . Mvc . Testing ;
7
7
using Microsoft . AspNetCore . SignalR . Client ;
8
+ using Microsoft . Extensions . Configuration ;
8
9
using Microsoft . Extensions . DependencyInjection ;
9
10
using Microsoft . Extensions . Hosting ;
10
11
using Microsoft . Playwright ;
11
12
12
13
namespace ManagedCode . IntegrationTestBaseKit ;
13
14
14
- public abstract class BaseTestApp < TEntryPoint > : WebApplicationFactory < TEntryPoint >
15
- where TEntryPoint : class
15
+ public abstract class BaseTestApp < TEntryPoint > : WebApplicationFactory < TEntryPoint > where TEntryPoint : class
16
16
{
17
17
private IHost ? _host ;
18
18
19
+ private readonly ConfigurationBuilder ConfigurationBuilder = new ( ) ;
20
+
21
+ protected virtual bool UsePlaywright { get ; } = true ;
19
22
private PlaywrightWrapper Fixture { get ; } = new ( ) ;
20
23
21
24
protected Dictionary < string , DockerContainer > Containers { get ; } = new ( ) ;
@@ -62,18 +65,44 @@ public T GetContainer<T>() where T : DockerContainer
62
65
public virtual async Task InitializeAsync ( )
63
66
{
64
67
await ConfigureTestContainers ( ) ;
65
- await Fixture . InitializeAsync ( ) ;
68
+
69
+ if ( UsePlaywright )
70
+ await Fixture . InitializeAsync ( ) ;
71
+
66
72
foreach ( var container in Containers )
67
73
await container . Value . StartAsync ( ) ;
68
74
}
69
75
70
76
protected override IHost CreateHost ( IHostBuilder builder )
71
77
{
78
+ ConfigureConfiguration ( ) ;
79
+ var configuration = ConfigurationBuilder . Build ( ) ;
80
+ builder . ConfigureWebHost ( hostBuilder =>
81
+ {
82
+ foreach ( var setting in configuration . AsEnumerable ( true ) )
83
+ hostBuilder . UseSetting ( setting . Key , setting . Value ) ;
84
+ } ) ;
85
+
86
+ // Create the host for TestServer now before we
87
+ // modify the builder to use Kestrel instead.
72
88
var testHost = builder . Build ( ) ;
89
+
90
+ // Modify the host builder to use Kestrel instead
91
+ // of TestServer so we can listen on a real address.
73
92
builder . ConfigureWebHost ( hostBuilder => hostBuilder . UseKestrel ( ) ) ;
74
- _host = builder . Build ( ) ;
93
+
94
+ // Create and start the Kestrel server before the test server,
95
+ // otherwise due to the way the deferred host builder works
96
+ // for minimal hosting, the server will not get "initialized
97
+ // enough" for the address it is listening on to be available.
98
+ // See https://github.com/dotnet/aspnetcore/issues/33846.
99
+ _host = builder . Build ( ) ; //base.CreateHost(builder);
75
100
_host . Start ( ) ;
76
101
102
+ // Extract the selected dynamic port out of the Kestrel server
103
+ // and assign it onto the client options for convenience so it
104
+ // "just works" as otherwise it'll be the default http://localhost
105
+ // URL, which won't route to the Kestrel-hosted HTTP server.
77
106
var server = _host . Services . GetRequiredService < IServer > ( ) ;
78
107
var addressFeature = server . Features . Get < IServerAddressesFeature > ( ) ;
79
108
ClientOptions . BaseAddress = addressFeature ! . Addresses
@@ -84,13 +113,9 @@ protected override IHost CreateHost(IHostBuilder builder)
84
113
return testHost ;
85
114
}
86
115
87
- protected override void ConfigureWebHost ( IWebHostBuilder builder )
88
- {
89
- builder . UseEnvironment ( "Development" ) ;
90
- }
91
-
92
116
public override async ValueTask DisposeAsync ( )
93
117
{
118
+ _host ? . Dispose ( ) ;
94
119
await Fixture . DisposeAsync ( ) ;
95
120
foreach ( var container in Containers )
96
121
{
@@ -125,6 +150,9 @@ public HubConnection CreateSignalRClient(string hubUrl, Action<HubConnectionBuil
125
150
126
151
public async Task < IPage > OpenNewPage ( string url )
127
152
{
153
+ if ( ! UsePlaywright )
154
+ throw new InvalidOperationException ( "Playwright is not enabled" ) ;
155
+
128
156
var fullUrl = new Uri ( ServerUri , url ) . ToString ( ) ;
129
157
var context = await Browser . NewContextAsync ( ) ;
130
158
var page = await context . NewPageAsync ( ) ;
@@ -144,4 +172,10 @@ protected void AddContainer(DockerContainer container)
144
172
}
145
173
146
174
protected abstract Task ConfigureTestContainers ( ) ;
175
+ protected abstract void ConfigureConfiguration ( ) ;
176
+
177
+ protected void SetConfigurationValue ( string key , string value )
178
+ {
179
+ ConfigurationBuilder . AddInMemoryCollection ( new Dictionary < string , string > { { key , value } } ! ) ;
180
+ }
147
181
}
0 commit comments