I've been stuck with this issue the whole day and I can't find a solution. What I am trying to solve is exactly the same problem that is supposedly solved in this Article.
It is also related to this issue with a very similar solution. Although in this issue they are using Selenium.
The solution is basically overriding the CreateHost
method from WebApplicationfactory<Program>
as demonstrated here:
protected override IHost CreateHost(IHostBuilder builder)
{
// Create the host for TestServer now before we
// modify the builder to use Kestrel instead.
var testHost = builder.Build();
// Modify the host builder to use Kestrel instead
// of TestServer so we can listen on a real address.
builder.ConfigureWebHost(webHostBuilder => webHostBuilder.UseKestrel());
// Create and start the Kestrel server before the test server,
// otherwise due to the way the deferred host builder works
// for minimal hosting, the server will not get "initialized
// enough" for the address it is listening on to be available.
// See https://github.com/dotnet/aspnetcore/issues/33846.
_host = builder.Build();
_host.Start();
// Extract the selected dynamic port out of the Kestrel server
// and assign it onto the client options for convenience so it
// "just works" as otherwise it'll be the default http://localhost
// URL, which won't route to the Kestrel-hosted HTTP server.
var server = _host.Services.GetRequiredService<IServer>();
var addresses = server.Features.Get<IServerAddressesFeature>();
ClientOptions.BaseAddress = addresses!.Addresses
.Select(x => new Uri(x))
.Last();
// Return the host that uses TestServer, rather than the real one.
// Otherwise the internals will complain about the host's server
// not being an instance of the concrete type TestServer.
// See https://github.com/dotnet/aspnetcore/pull/34702.
testHost.Start();
return testHost;
}
I am however, getting an error “Build can only be called once” at the moment I call the Build()
method in the IHostBuilder
. Other people also have commented in the blog post that they got this error but no response was found.
I read through the comments and documentation online and tried to modify for the following:
protected override IHost CreateHost(IHostBuilder builder)
{
// Create the host for TestServer now before we
// modify the builder to use Kestrel instead.
var testHost = builder.Build();
// Modify the host builder to use Kestrel instead
// of TestServer so we can listen on a real address.
//builder.ConfigureWebHost(webHostBuilder => webHostBuilder.UseKestrel());
// Create and start the Kestrel server before the test server,
// otherwise due to the way the deferred host builder works
// for minimal hosting, the server will not get "initialized
// enough" for the address it is listening on to be available.
// See https://github.com/dotnet/aspnetcore/issues/33846.
Host = Program.CreateHostBuilder(null)
.ConfigureWebHost(ConfigureWebHost)
.Build();
Host.Start();
// Extract the selected dynamic port out of the Kestrel server
// and assign it onto the client options for convenience so it
// "just works" as otherwise it'll be the default http://localhost
// URL, which won't route to the Kestrel-hosted HTTP server.
var server = Host.Services.GetRequiredService<Microsoft.AspNetCore.Hosting.Server.IServer>();
var addresses = server.Features.Get<IServerAddressesFeature>();
ClientOptions.BaseAddress = addresses!.Addresses
.Select(x => new Uri(x))
.Last();
// Return the host that uses TestServer, rather than the real one.
// Otherwise the internals will complain about the host's server
// not being an instance of the concrete type TestServer.
// See https://github.com/dotnet/aspnetcore/pull/34702.
testHost.Start();
return testHost;
}
Notice I created the IHost
directly from the Program class.
Now when I run the following lines in my test:
var playwright = await Playwright.CreateAsync();
var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions { Headless = false, SlowMo = 50 });
var page = await browser.NewPageAsync();
await page.GotoAsync(webApplicationSuitFixture.BaseUrl);
I can actually see that Playwright opens a Chrome page (Which would not happen without the CreateHost
override above). However the application is not running this way, it gives me a Fatal page without much more to go on.
Obs: The blazor app runs normally when I just start it. It is currently on .Net 6. The test project is currently in .Net 7. I tried to switch the .Net versions and update the packages accordingly, but the same problem persists.
Any help is appreciated!
After more testing, I figure out that the problem was actually on the target project of the tests.
The project was created prior to .Net 6 and then migrated, therefore it still had the "Old" Initialization from Host:
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
// Code here...
}
This will not work. Instead, the IHostBuilder
is replaced by the new WebApplication
var builder = WebApplication.CreateBuilder(args);
This will allow the call of the Build()
to be performed more than once. And the solution proposed by Daniel Donbavand will work.