Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature]: Use Custom HttpClient to resolve requests #3089

Open
thomhurst opened this issue Dec 18, 2024 · 6 comments
Open

[Feature]: Use Custom HttpClient to resolve requests #3089

thomhurst opened this issue Dec 18, 2024 · 6 comments

Comments

@thomhurst
Copy link

🚀 Feature Request

I'm trying to test a .NET Web App using the Microsoft.AspNetCore.Mvc.Testing package, which allows you to run a TestServer and run everything in memory.

I actually thought this would've been a really common scenario, and Playwright being built by Microsoft, would have first class support for this scenario, but it doesn't seem the case.

There's hacky workarounds online of overriding the test server configuration, and building two(?) servers, and enabling kestrel, etc, and you're basically running a fully fledged server at that point instead of a simple in memory one.

The problem is:

The test server is only contactable via the HttpClient that it passes to you, so you must use this to interact with your app. So if in Playwright I go to the same URL, it will just give me an error page because it can't contact the requested resource, and that's because it's using its own mechanisms to fire network requests.

I've semi got things working using RouteAsync and requests through my custom client instead, and then trying to fulfil the responses, but it gets complicated/messy once you have any redirect logic in your app. And if those redirects go to external URLs (think authentication providers), and then back to your app, you have to figure out whether you can fulfil a 302 (because can Playwright contact the Location header you give it, or does that as well need to go through your custom client?), or whether you just have to do a 200 fulfil with the final response, but then the browser is unaware of redirects happening and your URL doesn't change, so it's not 100% emulating what your app would actually be doing. This can mess with things like CORS etc. if I'm not mistaken? As well as hindering tests .WaitForUrl logic.

A way that feels simple (from the user's perspective anyway, might be a lot of work your side) would be to be able to pass your own HttpClient when a new Context is created, through the BrowserNewContextOptions object. It should be nullable, and if not set, everything would behave as-is.

However, if set, then requests should be resolved via that.

Example

    public override BrowserNewContextOptions ContextOptions()
    {
        return new BrowserNewContextOptions
        {
            HttpClient = WebApplicationFactory.CreateDefaultClient()
        };
    }

Then this would successfully route through to my in-memory server, and I wouldn't have to do any custom RouteAsync logic:

await _page.GotoAsync("https://localhost");

Motivation

As mentioned, it would allow flexible and first-class support for testing in-memory applications, which I'm surprised isn't the case already as it's part of the Microsoft ecosystem.

@mxschmitt
Copy link
Member

When intercepting network requests you can use your custom http client as you already do. We don't plan on providing custom http client interfaces in order to replace 'APIRequestContext' or 'Route.FetchAsync'. We expect redirects to be handled on the client itself. Do you mind on elaborating on what doesn't work? Ideally a small self-contained reproducible.

@thomhurst
Copy link
Author

Here's a minimal solution reproducing problems: https://github.com/thomhurst/PlaywrightDotnet3089Repro/blob/main/ReproApp/PlaywrightTests/Tests.cs

I'm praying this doesn't just get closed with a WontFix, because this seems like something you'd want to support given the Microsoft Mvc Test package and Playwright could work together perfectly if this was supported?

@mxschmitt
Copy link
Member

mxschmitt commented Jan 27, 2025

I tried to log something with Console.WriteLine and it didn't show up - could you use an official test-runner like nunit or mstest?

In theory we should be able to make it work but thats not something we'd recommend, since mocking http traffic, esp. the whole site has its limitations.

@thomhurst
Copy link
Author

I tried to log something with Console.WriteLine and it didn't show up - could you use an official test-runner like nunit or mstest?

Is this in Visual Studio? Try dotnet run on the CLI - some Microsoft Testing Platform features are still being fleshed out. But the cli should show stuff fine.

In theory we should be able to make it work but thats not something we'd recommend, since mocking http traffic, esp. the whole site has its limitations.

The HttpClient just allows connecting to the in-memory test server, rather than having to spin up an actual http server. It's not necessarily mocked.

@mxschmitt
Copy link
Member

I'm using dotnet test.

It's not necessarily mocked

The http traffic is being mocked and there is no real http flowing - ideally end-to-end tests mimic the exact configuration where your app is deployed to.

@thomhurst
Copy link
Author

I'm using dotnet test.

Try using dotnet run

The http traffic is being mocked and there is no real http flowing - ideally end-to-end tests mimic the exact configuration where your app is deployed to.

While I don't disagree, there are other tests that people like to perform. For instance, at work we have tests where we run through the UI on a PR to make sure we haven't broken anything, but we stub/mock out external services. This also allows us to confirm that front end code that might make backend calls works too because we can override a backend service with a mock, run through the UI journey, then assert our mock received the expected calls. The Microsoft MVC Testing package allows us to do that, even allowing each test to override certain services, and because it doesn't spin up a new http server each time, you don't overload the system with port exhaustion etc.

So it would be a really useful addition 🙏🏻

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants