-
Notifications
You must be signed in to change notification settings - Fork 44
Implement BrowserType.connect
#800
Conversation
I have a comment about propagating the Should WDYT @inancgumus @ankur22 ? |
46ccdd1
to
09a53b1
Compare
I've been mulling over what makes an error internal again. Thinking back to how I might design errors in a backend service:
So, it feels that we should be thinking about errors as whether they are temporary or permanent. In xk6-browser:
So the question now is, are the There are two actions from my viewpoint:
I think we should get the conversation started and see if others agree. |
I agree on this approach, there can be cases where there is not a clear cut, but agree on the concept.
I believe right now we are using it interchangeably. Personally I'm not sure the Would it make sense to remove this error, and change the implementations to provide context to the errors where these are defined (as you would normally do)? We could then define specific errors for specific use cases, for example a timeout error. Or for example in our case a In regards of this PR, do you think it makes sense to take this discussion away from it, move forward to it and then tackle all this error/panic handling in a separate PR, possibly the one related with issue grafana/k6#4403 ? |
@ka3de Agreed. Let's discuss this in grafana/k6#4403. |
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.
Hey, @ka3de, thanks for the PR, a long-awaited feature! 👏 I'll review this tomorrow 👍 Before that, I did the following and came up with panic: GoError: creating a new page: canceled
errors. You might be interested.
diff --git a/tests/test_browser.go b/tests/test_browser.go
index eef335f..856f51a 100644
--- a/tests/test_browser.go
+++ b/tests/test_browser.go
@@ -118,6 +118,7 @@ func newTestBrowser(tb testing.TB, opts ...any) *testBrowser {
if !ok {
panic(fmt.Errorf("testBrowser: unexpected browser %T", b))
}
+ b = bt.Connect(cb.WsURL(), rt.ToValue(launchOpts))
tb.Cleanup(func() {
select {
Thanks for the heads up! I didn't want to convert the |
@ka3de, sure! 👍 But I wasn't suggesting testing it like that and putting it into this PR 😅 I've shared the diff in case we discover some edge cases where |
Yep, sure, I understood the purpose 😄 |
Hey @inancgumus , so I ran the tests with this "hack" to use the I was taking a look and this is "expected" due to the hack. What is happening is that the "log hook" set up here for the test browser will end up collecting the logs for the "initial browser" created through If you check the logs, there are references for both generated iteration IDs, one for the "initial browser" through |
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.
Nice work 👏 Overall, LGTM. I have some suggestions and mostly questions to consider.
👍 |
Define constants for the different modes for both flags so it improves readability. Resolves: #800 (comment). Resolves: #800 (comment).
7ee3d92
to
c421358
Compare
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.
Nicely done 🙂 I just have some minor suggestions.
The one refactor suggestion (which might be too late now) is that it could have been a good opportunity to move browserprocess
into its own package like we tried here.
common/browser_options.go
Outdated
|
||
// NewLaunchOptions returns a new LaunchOptions. | ||
func NewLaunchOptions(onCloud bool) *LaunchOptions { | ||
func NewLaunchOptions(onCloud, isRemoteBrowser bool) *LaunchOptions { |
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.
Could create a new function NewRemoteBrowserLaunchOptions
where it will set isRemoteBrowser
to true
.
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.
Is another option, personally I prefer to keep a single "generic" constructor to which pass the appropriate flags, but no strong opinion. If we merge both flags and create this new constructor we can get rid of the constants defined in e24732b. But again, I prefer to keep a single constructor.
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.
+1 for adding another constructor: Clearer, more readable, and we can eliminate the constants. On the other hand, there is this, and it hiddenly implies it's better to have constants and a single constructor.
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 prefer a new constructor, but happy to leave it as is.
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 changing this, but the code in BrowserType
is a little bit "uglier" when calling to init
method due to the lack of constants, as we have to pass true
or false
values. Another alternative is to create the launchOptions
in connect
and launch
methods and then provide that to init
method so its modified in it. But don't really like it. Will push the first approach and we can discuss.
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.
See: 4d5a38f
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.
If we want to go this way, I suggest moving option parsing to Connect
and Launch
and passing the parsed launch options to init()
. This way:
- We can eliminate the ugly local/remote bool.
- More importantly. We'll move Goja stuff to the mapping layer (#271), and I wouldn't bury it in
init()
. Soon, options parsing will hopefully be in the mapping layer as it will deal with Goja values. Consider leaving it at the exported methods while changing this part of the code, OR just skip this comment since you already dealt with this PR a lot :)—we can take care of it later as well.
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.
So, as discussed, I think this is a good idea, but it's probably a considerable refactor to include it in this PR, so probably better to tackle it separately once this is merged 👍
I guess this can be done.. But I would prefer to tackle it in a separate PR if we really want to do it 😅 |
I wouldn't do that in this PR as it's unrelated to its purpose. Another PR is welcome if we export only a few fields, unlike before, and develop a nicer solution (no pun intended! :)). FYI: @grafana/k6-browser |
Define constants for the different modes for both flags so it improves readability. Resolves: #800 (comment). Resolves: #800 (comment).
c421358
to
e24732b
Compare
Define constants for the different modes for both flags so it improves readability. Resolves: #800 (comment). Resolves: #800 (comment).
This PR implements the
BrowserType.Connect
method for chromium browser type in order to, instead of launching a browser from our implementation, establish the WS connection to a remote running browser.The approach taken has been to minimize changes in the current implementation/flow. For that:
BrowserProcessMetadata
has been introduced in order to abstract the elements of the currentBrowserProcess
implementation that differ for a local/remote browser process [*].BrowserProcess
properties from other components (mainly fromBrowser
implementation).BrowserProcess
struct that references a remote browser.BrowserType.Connect
method following behavior defined by the currentlaunch
method.launch
andconnect
methods.[*] There were alternatives other than creating a new interface to abstract these differences, for example to add a
flag
inBrowserProcess
that would indicate if theos.Process
property held byBrowserProcess
was valid or not (due to being remote). But I believe the new interface definition abstracts this in a better way and prevents possible panics due toNPE
, especially considering that there is not an abstraction in place for the wholeBrowserProcess
element, and this is reachable from other elements implementations, such asBrowser
.Closes: #17.