-
Notifications
You must be signed in to change notification settings - Fork 16
[java] implement Sauce Configs for Chrome #243
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
Conversation
Ok, actually we might want to update this implementation to distinguish w3c from sauce settings like #237 , which will be useful when we add visual and mobile. I think we can literally merge the implementation of 237 and then add this on top |
sauceOptions = new SauceOptions(chromeOptions); | ||
} | ||
|
||
public SauceConfigsChrome setCapturePerformance(Boolean bool) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did document a bug related to this #241
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
latest commit throws an exception if setCapturePerformance()
is called before setName()
we can remove this if/when we implement the automatic naming idea for the test runners.
} | ||
|
||
|
||
public T setVideoUploadOnPass(Boolean bool) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if this is the time to do it, but I've been wondering if it makes sense to be passing Booleans in our setters. All of these capabilities are either enabled or disabled by default. So our methods only really do one of the options. . Does it make sense for a user to do setVideoUploadOnPass(true)
when the only reasonable option is disableVideoUploadOnPass()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes! I like this! Passing in Boolean parameters has always seemed clunky to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, updated the code to use disable
when the default is true and set
when the default is false; neither takes an argument
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall I think that this makes sense. I've left a few minor comments unrelated to the main API.
import java.time.Duration; | ||
import java.util.Map; | ||
|
||
public class SauceConfigsBrowser<T extends SauceConfigsBrowser<T>> extends SauceConfigs<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you all think about calling this BrowserConfiguration
and child classes ChromeConfiguration
...?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I named them before I put them in a separate configs package, so I wanted them all grouped together...
Rethinking from big picture, this is probably how to break it up to best fit the capabilities spreadsheet:
Either Configs or Configurations is fine for me. It probably isn't the biggest issue either way since we theoretically don't want users to even know about the names of the classes. :)
Configs
----> VDCConfigs
--------> DesktopConfigs
------------> ChromeConfigs, EdgeConfigs, SafariConfigs, IEConfigs, FirefoxConfigs
--------> EmulatorConfigs, SimulatorConfigs
----> RDCConfigs
--------> AndroidConfigs, iOSConfigs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left a few comments, sorry for not being more helpfult but I probably miss a lot of context.
* @deprecated Not for public use | ||
* Use: {@link SauceOptions#chrome()}} or {@link SauceOptions#chrome(ChromeOptions)}} | ||
*/ | ||
@Deprecated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't you leave only with package visibility? Instead of deprecating it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@diemol I don't understand what the impact of that is. The idea of deprecating it is so that people can still use it but know they need to update their behavior before the next major release. What does changing the package visibility do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I moved SauceOptions into a new package, which I think is *bad. I think it is ok if we release this as a 2.0?
@@ -129,6 +130,22 @@ | |||
knownCITools.put("TeamCity", "TEAMCITY_PROJECT_NAME"); | |||
} | |||
|
|||
/** | |||
* @return SauceConfigsChrome, | |||
* note: constructor implementation is deprecated for public use, but usage here is intentional |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can leave the constructor protected
or package visibility to avoid the need of deprecating it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, right, I see what you are saying. We're going to deprecate it for the next release, then change it to protected/private for next major release. Wanted to give a warning about it first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, right, this is a new method. got it. (trying to remember what I was doing 2 months ago is hard)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and... it's because I have it in a separate package (com.saucelabs.saucebindings.configs
vs com.saucelabs.saucebindings
. Any advice on a better way to organize this? I feel like everything should probably be in an options package, but I also think it is considered bad to change the package from one version to another? :) Would it make sense to have everything in the main package?
@@ -20,6 +21,10 @@ public SauceSession() { | |||
this(new SauceOptions()); | |||
} | |||
|
|||
public SauceSession(SauceConfigs configs) { | |||
this(configs.build()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this is not really following the builder patter, where one of the ideas is that calling the .build()
returns an instanciated object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is kind of a hack in case people "do it wrong." We want them to build it themselves and pass it in, but we were concerned that they would get a weird error message if they didn't, and it didn't seem that hard to just add a constructor to make it just work.
return (T) this; | ||
} | ||
|
||
public SauceOptions build() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It feels you'd like to follow the same structure of browser options in Selenium (where EdgeOptions
extends ChromiumOptions
, etc...), so maybe you can get rid of this build
method and only pass instanciated objects?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The goal is to only show users allowed capabilities. So SauceOptions allows everything, and the config class is restricted to only applicable values, but rather than a bunch of other constructors, we just convert the configs class into a sauce options and have that get passed into the session.
Also, the Google Docs link is only accessible to Sauce employees, which is not OSS friendly, please consider making it either read only for everyone or add that information to the repo's Wiki. |
f2a070e
to
5cd044f
Compare
Well, the second commit here is bigger than the first one, because I rearranged the packages to make more sense. Except it isn't backward compatible, so maybe I'll want to put everything back, or maybe we push forward and do a 2.0 release next and hope we don't upset too many people already. :-/
|
This is subsumed by #246 |
Ok, I was definitely making this too hard... We were trying to decide between option 4 & option 6 from this list, and this PR I think takes the best from each of them and does it in a rather light weight solution.
The point of these changes is to provide a way for a user to only have access to the methods/parameters that make sense for the type of test being run. (e.g. Chrome tests can't set IE Driver Version, etc)
This isn't as much of an issue with just browser implementations, but will be essential for dealing with Mobile & Visual, etc.
So, SauceOptions is going to store the state of *everything, but access to the everything is going to be controlled by the config classes.
Config classes will only have setters, no getters and is only going to store state within a SauceOptions instance (which means we can't use lombok setters since we aren't setting state on fields directly). We're also using generics to return an instance of the subclass rather than having it return the superclass. Then the user calls
build()
to generate theSauceOptions
instance, so they don't ever need to know which class of configs they are using under the hood.I've marked the configs class constructor as "Deprecated" to encourage users to use it from the static method in SauceOptions, but if someone *does use the config class directly, or doesn't call
build()
on it, the code still lets them pass it into aSauceSession
constructor and the constructor will just call the build method on it.The capabilities are defined based on: https://docs.google.com/spreadsheets/d/1u_28C3lqLlmZElBDb6KuG6qSYuCEK32R40RyjOvWnBE/edit
Hierarchy:
SauceConfigs
----> SauceConfigsBrowser
--------> SauceConfigsChrome
There isn't any way that we're going to be able to avoid all duplication going forward (especially once we add in mobile things), but this approach should do a fair job of removing most of the duplication.
Next steps:
setPlatformName(SaucePlatform:MAC_SIERRA)
on aSauceConfigsChrome
instance).SauceOptions
andSauceBrowserConfigs
SauceOptions
and new subclasses ofSauceConfigs
Considerations:
SauceOptions
to ensure everyone goes through the Configs classesSauceOptionsFactory
class instead ofSauceOptions
if that makes more sense