BrowserOptions and Capabilities

376 views
Skip to first unread message

Alexei Barantsev

unread,
Aug 31, 2017, 3:25:16 AM8/31/17
to Selenium Developers
Hi, devs,

At the moment in Java binding we have two ways to tune driver and browser -- using Capabilities and using BrowserOptions (FirefoxOptions, ChromeOptions etc). BrowserOptions provide type-safe API, internally they are converted to Capabilities.

I suppose we want to encourage users to use type-safe API as much as possible.

How would we acheve this?

Simon suggested to make BrowserOptions implements Capabilities, as a result a user can create BrowserOptions object and pass it to any constructor that accepts Capabilities as a parameter.

This idea is feasible but I think it does not hit the goal, it does not force users to migrate from Capabilities to the type-safe alternative.

I'd like to suggest another way to achieve this goal.

1) Introduce BrowserOptions interface implemented by all browser-specific options classes
public class FirefoxOptions implements BrowserOptions

2) Provide browser-specific constructors that accept BrowserOptions (we have already them) and deprecate constructors that accept Capabillities
public FirefoxDriver(FirefoxOptions options) { ... }

@Deprecated
public FirefoxDriver(Capabilities desiredCapabilities) {...}

3) Replace DesiredCapabilities with a new class (RemoteOptions?) that implements type-safe API to new W3C conformant features (firstMatch, alwaysMatch) and have a method to set browser-specific options
public void setBrowserOptions(BrowserOptions options) {...}

4) Provide RemoteWebDriver constructor that accepts RemoteOptions and deprecate constructors that accept Capabillities
public RemoteWebDriver(URL serverUrl, RemoteOptions options) { ... }

@Deprecated
public RemoteWebDriver(URL serverUrl, Capabilities desiredCapabilities) {...}

There deprecations will force users to migrate to the type-safe alternative eventually.

Your opinions?

Regrads,
--
Alexei Barantsev
Software-Testing.Ru
Selenium2.Ru

Simon Stewart

unread,
Aug 31, 2017, 5:27:52 AM8/31/17
to selenium-developers
Hi,

TL;DR: -1. It seems attractive, but I don't believe it's workable in practice.

The problem we rapidly run into is that we don't know beforehand what new options might become available --- for example, Firefox has just gained the ability to become headless, and we probably want to extend FirefoxOptions to support this capability. That means we'll always need the "escape hatch" of being able to specify additional, unspecified, properties on "BrowserOptions". They, essentially, become just a strongly typed "Capabilities" implementation, specific to a particular browser.

That means "BrowserOptions" is an unnecessary interface --- it brings nothing to the table.

Whatever solution we pick will also need to be backward compatible (at least over the wire) with older (and newer!) versions of the protocol[1]. They'd have to serialise as both W3C payloads and the JSON Wire Protocol payload in order to achieve this, and the deserialisation would, by necessity, be to the most general class: Capabilities too --- we'd never be able to remove the old constructors. 

I do agree that we need to encourage people to use the type-safe options wherever possible, and raising the prominence of the type-specific constructors is a Good Thing to do. We can do this with logging at the WARN level to encourage this[2], but, for the reasons above, we can't deprecate the constructors.

The W3C payload is particularly interesting. We _can_ enforce the requirement that people don't put garbage into them by ensuring that (for example), the capabilities don't contain the extension capability prefixes of more than one browser vendor. We should expose the ability to construct the payload in a meaningful way, which is why I created this class.

Cheers,

Simon

[1] As we can see on the IRC channel, SalesForce, which has two core committers working for them, is only now migrating to 3.x. If this motivated company, with this level of expertise in place, is finding it hard, who knows what's happening in our community.
[2] Or some sort of increasing Thread.sleep when using the older constructors :)

--
You received this message because you are subscribed to the Google Groups "Selenium Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to selenium-developers+unsub...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/selenium-developers/655d8c4b-b153-429d-91b6-d9933c0c09ba%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Alexei Barantsev

unread,
Aug 31, 2017, 5:45:18 AM8/31/17
to Selenium Developers
Hi,

1) Deprecation is not deletion. If someone (say, SalesForce) just start to use WebDriver API they should see what constructors are recommended and what are not.

2) BrowserOptions interface is required to be able to implement a type safe method
RemoteOptions.setBrowserOptions(BrowserOptions options)

3) BrowserOptions interface can demand all implementing classes to have toCapabilities() method, or toJson() method or toMap() method, whatever is more suitable to serialize this object for transmitting it over the wire.

4) BrowserOptions can have a method setCapability() to pass an arbitrary capability, but if there a type-safe method in the same class suggested by auto-completion -- I'm sure users will prefer more specific methods.

5) BrowserOptions can have (and sometimes already have, e.g. via FirefoxBinary) a method to set browser CLI switches (like '-headless'), at the same time we can provide type-save methods for frequently used switches (like '-headless')

Regrads,
--
Alexei Barantsev

Simon Stewart

unread,
Aug 31, 2017, 5:57:22 AM8/31/17
to selenium-developers
Hi,

Inline :)


I don't under

On Thu, Aug 31, 2017 at 10:45 AM, Alexei Barantsev <bara...@gmail.com> wrote:
Hi,

1) Deprecation is not deletion. If someone (say, SalesForce) just start to use WebDriver API they should see what constructors are recommended and what are not.

Deprecation is the first step on the road to deletion. It's disingenuous to say that people won't believe a deprecated interface is not going to be deleted. Also, most teams I've worked with don't care about deprecation.
 
2) BrowserOptions interface is required to be able to implement a type safe method
RemoteOptions.setBrowserOptions(BrowserOptions options)

I don't understand this point.
 
3) BrowserOptions interface can demand all implementing classes to have toCapabilities() method, or toJson() method or toMap() method, whatever is more suitable to serialize this object for transmitting it over the wire.
 
You mean like Capabilities already has? I'm not seeing the difference here....
 
4) BrowserOptions can have a method setCapability() to pass an arbitrary capability, but if there a type-safe method in the same class suggested by auto-completion -- I'm sure users will prefer more specific methods.

I'm not saying that we should have FirefoxOptions, or ChromeOptions, or even HtmlUnitOptions. I'm saying that each of them will need an escape hatch for setting random capabilities, so they end up just being strongly-typed Capability instances. Even without a BrowserOptions interface, you'd still have autocompletion.
 
5) BrowserOptions can have (and sometimes already have, e.g. via FirefoxBinary) a method to set browser CLI switches (like '-headless'), at the same time we can provide type-save methods for frequently used switches (like '-headless')

Again, I'm not saying we don't have driver-specific options. I'm saying that the idea of deprecating methods and adding a new interface are unnecessary.

I'm a huge fan of strong-typing. We should be encouraging people to adopt it where possible. But I'm also a fan of simplicity[1], and this seems like additional complexity with no benefits beyond what we have already.

Cheers,

Simon
 
[1] Yeah, yeah, yeah. I know that doesn't always seem to be true :)

Regrads,
--
To unsubscribe from this group and stop receiving emails from it, send an email to selenium-developers+unsubscribe...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Selenium Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to selenium-developers+unsub...@googlegroups.com.

Jim Evans

unread,
Aug 31, 2017, 6:50:04 AM8/31/17
to Selenium Developers
Let's leave Salesforce out of this, if you please. Our reasons for delaying our upgrade have little to do with technical complexity.

I've been making this argument for quite some time now, and have been moving parts of the project for which I'm responsible in the direction of a type-safe API. I fear Simon and I fundamentally disagree on this subject on a couple of points, and I don't see us reconciling our views on that anytime soon.

I don't believe the existence of an "escape hatch" to be a problem. If a user has to use it, they should do so knowing it's a temporary workaround until a type-safe alternative is available. In the .NET case, if you try to use the escape hatch (the AddAdditionalCapability method), and you use a string that's a known capability name for which there is a type-safe alternative, you'll get a runtime error with a very clear message. Yes, that means some users may have to change their code after updating to a new version of Selenium, but I don't see that as a Bad Thing on the face of it[1].

Having said that, I'm not necessarily opposed to having the Options classes implement the Capabilities interface. The interface is read-only, and doesn't allow setting of capabilities anyway.

To my mind, the main missing piece is a construct to allow the user to create a spec-compliant remote new session request that may have the complex matching rules the spec allows. Also, the construct needs a mechanism for third parties (cloud providers, other intermediate node projects, etc.) to add their required pieces to the request. I created a straw man, proof-of-concept prototype just to see what such an API would look like for .NET, and while there are things that need refinement, it's not too bad.

I'm less concerned about allowing any arbitrary version of the language bindings being able to seamlessly talk to any random remote end. Putting a stake in the ground and saying, "You need at least version X to play nice," is not out of line, as far as I'm concerned. I know I'm at odds with some on that, but I doubt I'll be changing my (or anyone else's) mind.

[1] That's an argument I'm willing to have over a pint sometime. I'm not doing it here.
[2] https://github.com/jimevans/webdriver-remote-api-prototype

Simon Stewart

unread,
Aug 31, 2017, 7:25:02 AM8/31/17
to selenium-developers
On Thu, Aug 31, 2017 at 11:50 AM, Jim Evans <james.h....@gmail.com> wrote:
Let's leave Salesforce out of this, if you please. Our reasons for delaying our upgrade have little to do with technical complexity.

My apologies. The argument in more general terms was meant to be "people have a ton of reasons for not moving to 3.x yet, and we shouldn't leave those people behind". It wasn't meant as a comment about SF as a company.
 
I've been making this argument for quite some time now, and have been moving parts of the project for which I'm responsible in the direction of a type-safe API. I fear Simon and I fundamentally disagree on this subject on a couple of points, and I don't see us reconciling our views on that anytime soon.

I love a type-safe API. One of the main driving forces behind the WebDriver APIs was to encourage people to Do The Right Thing. I just think that when you actually look at things carefully, "BrowserOptions" and "Capabilities" are the same thing. That doesn't preclude having strongly-typed subclasses that lead people in the right direction.
 
I don't believe the existence of an "escape hatch" to be a problem. If a user has to use it, they should do so knowing it's a temporary workaround until a type-safe alternative is available. In the .NET case, if you try to use the escape hatch (the AddAdditionalCapability method), and you use a string that's a known capability name for which there is a type-safe alternative, you'll get a runtime error with a very clear message. Yes, that means some users may have to change their code after updating to a new version of Selenium, but I don't see that as a Bad Thing on the face of it[1].

I'll take you up on that pint some time :)
 
Having said that, I'm not necessarily opposed to having the Options classes implement the Capabilities interface. The interface is read-only, and doesn't allow setting of capabilities anyway.

Indeed.
 
To my mind, the main missing piece is a construct to allow the user to create a spec-compliant remote new session request that may have the complex matching rules the spec allows.

This is also an important conversation to have.
 
Also, the construct needs a mechanism for third parties (cloud providers, other intermediate node projects, etc.) to add their required pieces to the request. I created a straw man, proof-of-concept prototype just to see what such an API would look like for .NET, and while there are things that need refinement, it's not too bad.

I had a W3CCapabilities class that would also start to edge things in the right direction. Perhaps I should have waved it around a bit more. The main thing missing was the ability to set metadata, and the validation of inputs was weak (for example, it would allow you to create a capabilities object which would, when merged, be unmatchable because different vendor-prefixes would be mixed)
 
I'm less concerned about allowing any arbitrary version of the language bindings being able to seamlessly talk to any random remote end. Putting a stake in the ground and saying, "You need at least version X to play nice," is not out of line, as far as I'm concerned. I know I'm at odds with some on that, but I doubt I'll be changing my (or anyone else's) mind.

Quite possibly. I have a dogged belief that it should be possible to mix-and-match parts of a selenium-based infrastructure, allowing staged and managed updates, and enabling those who, for whatever reason, can't upgrade to still derive benefit from the project as bits move forward. My view is probably coloured by the fact that Server and Grid are both in the Java tree, and my experiences dragging folks to a newer version of the APIs at places I've worked.

Cheers,

Simon
 
[1] That's an argument I'm willing to have over a pint sometime. I'm not doing it here.
[2] https://github.com/jimevans/webdriver-remote-api-prototype
--
You received this message because you are subscribed to the Google Groups "Selenium Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to selenium-developers+unsub...@googlegroups.com.

Alexei Barantsev

unread,
Aug 31, 2017, 7:26:21 AM8/31/17
to Selenium Developers
After some chatting on IRC, let me correct the suggestion:

1) We should allow to use any information contained in payload to match a node.
That means, if we have a class RemoteOptions, or W3CCapabilities, we should allow to do something like
capabilities.setFirstMatch(new FirefoxOptions().setHeadless(true))
and the grid might use this information to choose a node that is able to run headless Firefox.

That means, there is no strict border between "capabilities" and "options". Such is the spec.

In view of this fact, yes, it makes sense to inherit options classes from Capabilities or even MulableCapabilities.

If we implement this inheritance, we should (contrary to my suggestion) deprecate and delete in future constructors that accept browser specific options classes. Users can use FirefoxDriver(Capabilities desiredCapabilities) constructor to pass either MutableCapabilities or FirefoxOptions parameter.

Unfortunately, this solution in itself will not encourage people to use FirefoxOptions. So we can just put irate messages to the log as a soft motivation to migrate to a better solution.

2) At the same time we need a new class (RemoteOptions, or W3CCapabilities) to generate valid W3C conformant payload with alwaysMatch, firstMatch and other whistles required for cloud providers and custom grid makers.

Regards,
--
Alexei Barantsev

Simon Stewart

unread,
Aug 31, 2017, 7:32:50 AM8/31/17
to selenium-developers
Inline again :) Thank you for summarising the IRC conversation here.

On Thu, Aug 31, 2017 at 12:26 PM, Alexei Barantsev <bara...@gmail.com> wrote:
After some chatting on IRC, let me correct the suggestion:

1) We should allow to use any information contained in payload to match a node.
That means, if we have a class RemoteOptions, or W3CCapabilities, we should allow to do something like
capabilities.setFirstMatch(new FirefoxOptions().setHeadless(true))
and the grid might use this information to choose a node that is able to run headless Firefox.

For reference, Grid uses a Prioritizer interface to sort the list of available test slots. This takes the Map form of the capabilities to work its magic, but allows matching on any random capability.
 
That means, there is no strict border between "capabilities" and "options". Such is the spec.

In view of this fact, yes, it makes sense to inherit options classes from Capabilities or even MulableCapabilities.

I think we're all edging in this direction. The "escape hatch" API ends up looking like "MutableCapabilities.setCapability()" method. It's a shame that the Capabilities interface exposes information that's no help at all with the w3c spec. 
 
If we implement this inheritance, we should (contrary to my suggestion) deprecate and delete in future constructors that accept browser specific options classes. Users can use FirefoxDriver(Capabilities desiredCapabilities) constructor to pass either MutableCapabilities or FirefoxOptions parameter.

Unfortunately, this solution in itself will not encourage people to use FirefoxOptions. So we can just put irate messages to the log as a soft motivation to migrate to a better solution.

I think that's an argument for the specific driver interfaces to accept the specific option instances. RemoteWebDriver must always end up taking Capabilities though.
 
2) At the same time we need a new class (RemoteOptions, or W3CCapabilities) to generate valid W3C conformant payload with alwaysMatch, firstMatch and other whistles required for cloud providers and custom grid makers.

You, Jim, and I all agree on this :)

Cheers,

Simon
 

--
You received this message because you are subscribed to the Google Groups "Selenium Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to selenium-developers+unsub...@googlegroups.com.

p0deje

unread,
Aug 31, 2017, 10:27:39 AM8/31/17
to selenium-developers
Sorry if I jump into this conversation, but I’m slightly confused now.

If we’re simply to have both Options and Capabilities and the only difference between them is type-safety, what would other language bindings like Ruby/JavaScript/Python do about them? There is practically no type checks so there is not much point in implementing and maintaining 2 classes doing the same thing. The only reason to do that would be the consistency of API across the bindings. If options classes simply inherit capabilities and you can still use capabilities, why would you ever want to use options in a dynamic language?

I personally liked initial suggestion to have just an options because with Ruby anyone can still add custom string capabilities to it. Having RemoteOptions should work for Grid or cloud providers. That would allow Ruby bindings to have a clear interface of what can be passed in payload while still allowing to add arbitrary capabilities.

To unsubscribe from this group and stop receiving emails from it, send an email to selenium-develo...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Selenium Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to selenium-develo...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/selenium-developers/CAOrAhYF3adxxzDFfErL6Ga7Hzwr4%2BmF7D8DsgUn_8K86M%2BhtGA%40mail.gmail.com.

Simon Stewart

unread,
Aug 31, 2017, 11:03:29 AM8/31/17
to selenium-developers
I think this conversation is mostly about the strongly-typed languages at this point. When we've finished discussing and implementing, I bet that there will be lessons that the other bindings can learn from.

Simon

To unsubscribe from this group and stop receiving emails from it, send an email to selenium-developers+unsub...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Selenium Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to selenium-developers+unsub...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Selenium Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to selenium-developers+unsub...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/selenium-developers/CAP_8%3DB6Jwd7fVU0uYpynq1_gapVB37pFajEUt099kaB3zmDxCQ%40mail.gmail.com.
Reply all
Reply to author
Forward
0 new messages