selenium icon indicating copy to clipboard operation
selenium copied to clipboard

[🚀 Feature]: Implement high level BiDi network commands

Open titusfortner opened this issue 1 year ago • 7 comments

Feature and motivation

At the Selenium Dev Summit we agreed on this API to be generally applied across the bindings; we'll keep this labeled beta while we make sure that it works for what is needed

We want the methods to be accessible from a network() method available directly from the Driver class (e.g., driver.network.addRequestHandler(), driver.network().addRequestHandler()). We can't do everything just like this in all the languages, because, for example, .NET uses events with a += and -= for adding and removing handler events so we don't went "add" and "remove" methods.

Implementations:

Method Java NodeJS Python Ruby .NET
addRequestHandler()
removeRequestHandler()
clearRequestHandlers()
addResponseHandler()
removeResponseHandler()
clearResponseHandlers()
addAuthenticationHandler() #14334 #14345
removeAuthenticationHandler() #14334 #14345
clearAuthenticationHandlers() #14334 #14345

Considerations:

If we can figure out how to get the "add" methods return an id that can be used by the "remove" methods, that would be a lot easier for or users. Might be too complicated to implement.

titusfortner avatar May 21 '24 00:05 titusfortner

I've been thinking about this, and I think the add methods should return an id. This is going to be much easier for languages that want to pass in lambdas without storing a reference to the location os the object in memory.

This is how moz/addon/install endpoint works and the id gets passed into the payload to remove the addon.

I was looking for common wisdom here and it generally seems to match — https://softwareengineering.stackexchange.com/questions/314066/restful-api-should-i-be-returning-the-object-that-was-created-updated

titusfortner avatar May 28 '24 20:05 titusfortner

I've been thinking about this, and I think the add methods should return an id. This is going to be much easier for languages that want to pass in lambdas without storing a reference to the location os the object in memory.

Totally fine by me!

p0deje avatar May 28 '24 22:05 p0deje

Can someone help refresh my memory on the "addRequestHandler()"? - I vaguely remember us discussing the current C# implementation using the matcher and transformer https://github.com/SeleniumHQ/seleniumhq.github.io/blob/c6769ef064d8bc3ffb6343fba3c10ab4ddbad78c/examples/dotnet/SeleniumDocs/BiDi/CDP/NetworkTest.cs#L85. Is that what we want? How would that look like?

pujagani avatar Aug 02 '24 09:08 pujagani

@titusfortner @diemol @p0deje

pujagani avatar Aug 05 '24 10:08 pujagani

Can someone help refresh my memory on the "addRequestHandler()"? - I vaguely remember us discussing the current C# implementation using the matcher and transformer https://github.com/SeleniumHQ/seleniumhq.github.io/blob/c6769ef064d8bc3ffb6343fba3c10ab4ddbad78c/examples/dotnet/SeleniumDocs/BiDi/CDP/NetworkTest.cs#L85. Is that what we want? How would that look like?

I might be wrong, but IIRC the idea was to let addRequestHandler to accept two arguments:

  • filter/matcher for request to be handled
  • callback that receives an original request and return a handled request

p0deje avatar Aug 05 '24 18:08 p0deje

I've been thinking about this, and I think the add methods should return an id. This is going to be much easier for languages that want to pass in lambdas without storing a reference to the location os the object in memory.

I guess id can be any object. In .net I implemented it like:

var subscription = await context.Network.OnBeforeRequestSentAsync(Console.WriteLine);
await context.NavigateAsync("https://selenium.dev");
await subscription.UnsubscribeAsync();

Or network interception:

await using var intercept = await context.Network.AddInterceptedRequestAsync(async args =>
{
  await args.Request.Request.ContinueAsync(new() { Method = "POST" });
});

Subscription is a disposable object. The same for Intercept object. Generally saying it is object, not just magic ID.

nvborisenko avatar Sep 03 '24 17:09 nvborisenko

Can I use the INetwork-NetworkResponseReceived feature in Selenium. WebDriver version 4.24.0 in Firefox?

junjuping avatar Sep 04 '24 10:09 junjuping

Hi I am trying to replace devtools with BiDi in my project. Can I get request and response bodies from BeforeRequestSent and ResponseDetails? any form like json or byte sequence or string would be great.

image

bogishvili avatar Oct 25 '24 08:10 bogishvili

@bogishvili I understand your use case here. However, we can support what is available in the WebDriver BiDi spec https://w3c.github.io/webdriver-bidi/#module-network. Currently, there is no way defined to get the request and response bodies. There is an issue to track this though https://github.com/w3c/webdriver-bidi/issues/747. So this can be supported in the future once it is present in the spec and supported by the browsers.

pujagani avatar Oct 31 '24 11:10 pujagani

is there any update when we should be able to extract Network Response body using BiDi?

Vinodh7887 avatar Dec 18 '24 02:12 Vinodh7887

Please track the issue stated above https://github.com/w3c/webdriver-bidi/issues/747.

pujagani avatar Dec 20 '24 04:12 pujagani

@pujagani is there an issue that tracks the read request payload in Java.

The use case is -> for requests with graphql the mocking really depends on the request body rather than the request url since all the requests are sent to /graphql

thulasipavankumar avatar Mar 10 '25 15:03 thulasipavankumar

Hi all! I'd opened a PR #14738 a few months ago for the Python implementations of some request handler methods. I would really appreciate your review/feedback on it!

jkim2492 avatar Mar 15 '25 14:03 jkim2492

@pujagani is there an issue that tracks the read request payload in Java.

The use case is -> for requests with graphql the mocking really depends on the request body rather than the request url since all the requests are sent to /graphql

Thank you for this. Yes, I am working on adding those pieces so the user can get flexibility to match the request however they prefer. Since, it is part of this issue, it will not be tracked separately. But the PR will be linked to this.

pujagani avatar Apr 03 '25 04:04 pujagani

@thulasipavankumar, Please note that there is currently no way to get the request body with BiDi. So, filtering based on that is not possible since it is not part of the spec and hence not implemented by browsers. However, it is possible to filter by URL, headers and method.

pujagani avatar Apr 03 '25 05:04 pujagani

One more time for me please, this proposal is about high-level API, meaning this API should NOT expose low-level BiDi types. And meaning we should introduce abstraction layer?

nvborisenko avatar Apr 07 '25 21:04 nvborisenko

@thulasipavankumar, Please note that there is currently no way to get the request body with BiDi. So, filtering based on that is not possible since it is not part of the spec and hence not implemented by browsers. However, it is possible to filter by URL, headers and method.

@pujagani thanks for the reply.

In specific use case for testing graphql endpoints, unfortunately the headers,url and method are all same for every request

thulasipavankumar avatar Apr 08 '25 11:04 thulasipavankumar

With the merge of #14592, Python is now at the same progress as Ruby

shbenzer avatar Apr 10 '25 15:04 shbenzer