-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Add getByRole in the browser module #4843
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
base: master
Are you sure you want to change the base?
Conversation
@@ -14,6 +14,1259 @@ | |||
* limitations under the License. |
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 main implementation is in the injected_script.js
file. The code was directly copied over from the compiled JS code from Playwright. I have added as many integration tests as possible to ensure that all the possible flows are accounted for. While i understand the jist of what is happening in the copied code, some of it is still a bit of a mystery as to why things are done this way. A lot of the code seems to be inherited behaviour from specifications, such as not being able to work with header
or footer
unless they're not encapsulated -- exact spec is unknown though.
Do we need to add the Playwright license and notice file in the browser module?
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 don't think we need to add another license note, as we already have this one:
k6/internal/js/modules/k6/browser/common/js/injected_script.js
Lines 1 to 15 in 113abf5
/** | |
* Copyright (c) Microsoft Corporation. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ |
f35ebc0
to
a07de3f
Compare
@@ -225,6 +1478,7 @@ class InjectedScript { | |||
css: new CSSQueryEngine(), | |||
text: new TextQueryEngine(), | |||
xpath: new XPathQueryEngine(), | |||
'internal:role': createRoleEngine(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.
Sticking with how Playwright has labelled it. There is also a selector without internal
which we could consider adding. It is so that users can query without the getByRole
API, and directly do something like: page.locator('role=button');
.
e684a3b
to
7919b29
Compare
@@ -0,0 +1,775 @@ | |||
package tests |
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.
Tests are failing on Windows for an unknown reason. I can run the same test in a script file and it works on Windows. I'm looking into 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.
WINDOWS! WHY ART THOU SO ANNOYING! I WANT TO LOVE YOU BUT I CAN'T 😭
I tried to run some other tests which work with page.locator
and they don't work! These tests are in keyboard_test.go
, and at the top of the file there is this comment:
// practically none of this work on windows
//go:build !windows
I will do the same for the new tests 😢
a766b35
to
e172850
Compare
@@ -1002,6 +1002,58 @@ func (f *Frame) getAttribute(selector, name string, opts *FrameBaseOptions) (str | |||
return s, true, nil | |||
} | |||
|
|||
// Locator creates and returns a new locator for this frame. |
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 GoDoc sentence looks like a leftover from copy-pasting 🤔
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.
Updated in f490d70
@@ -1002,6 +1002,58 @@ func (f *Frame) getAttribute(selector, name string, opts *FrameBaseOptions) (str | |||
return s, true, nil | |||
} | |||
|
|||
// Locator creates and returns a new locator for this frame. | |||
func (f *Frame) GetByRole(role string, opts *GetByRoleOptions) *Locator { | |||
f.log.Debugf("Frame:Locator", "fid:%s furl:%q role:%q opts:%+v", f.ID(), f.URL(), role, opts) |
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.
Should we refer to the method name instead, to keep it consistent with the other methods? 🤔
f.log.Debugf("Frame:Locator", "fid:%s furl:%q role:%q opts:%+v", f.ID(), f.URL(), role, opts) | |
f.log.Debugf("Frame:GetByRole", "fid:%s furl:%q role:%q opts:%+v", f.ID(), f.URL(), role, opts) |
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.
Updated in f490d70
if opts.Checked != nil { | ||
properties["checked"] = fmt.Sprintf("%v", *opts.Checked) | ||
} | ||
if opts.Disabled != nil { | ||
properties["disabled"] = fmt.Sprintf("%v", *opts.Disabled) | ||
} | ||
if opts.Selected != nil { | ||
properties["selected"] = fmt.Sprintf("%v", *opts.Selected) | ||
} | ||
if opts.Expanded != nil { | ||
properties["expanded"] = fmt.Sprintf("%v", *opts.Expanded) | ||
} | ||
if opts.IncludeHidden != nil { | ||
properties["include-hidden"] = fmt.Sprintf("%v", *opts.IncludeHidden) |
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 not using strconv.FormatBool
instead of string formatting here? It's slightly more idiomatic, and perhaps even a bit faster, I guess. But maybe there's a reason not to.
PS: Same, whenever it applies, with the rest of the opts parsed on this method.
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.
Yep, good spot. Changed in a098ac3
func stringPtr(s string) *string { | ||
return &s | ||
} | ||
|
||
func boolPtr(b bool) *bool { | ||
return &b | ||
} | ||
|
||
func int64Ptr(i int64) *int64 { | ||
return &i | ||
} |
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 nowadays, thanks to generics, this can be simplified into a single generic method, like:
func ptr[T any](v T) *T {
return &v
}
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.
Thanks! Great idea. Updated in dfcd80f
I basically copied the JS compiled injected script from PW, and pasted it into k6's injected script. It seems to work with basic role based selectors.
These tests include options and working with different attributes under-the-hood to do the same thing with a single option or role value.
It seems to be an issue with locator based APIs in integration tests, they just don't work. Locator based tests work perfectly when written and ran from a js test script.
The role based selector engine needs to work with ' and not " when it comes to the name option. This is automatically done for the user in the mapping layer, but in the integration test we need to ensure that we explicitly use ' and not ".
74171be
to
be4b038
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.
I focused on the easy-to-review parts of this PR :-] I'll continue reviewing the rest tomorrow.
@@ -14,6 +14,1259 @@ | |||
* limitations under the License. |
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 don't think we need to add another license note, as we already have this one:
k6/internal/js/modules/k6/browser/common/js/injected_script.js
Lines 1 to 15 in 113abf5
/** | |
* Copyright (c) Microsoft Corporation. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ |
What?
This PR adds a long awaited feature which is
page.getByRole
. It makes working with selectors slightly simpler. MoregetBy*
APIs are in the works.Why?
It is a lot simpler to work with
getByRole
instead of XPath or CSS selectors in most cases.Checklist
make check
) and all pass.Checklist: Documentation (only for k6 maintainers and if relevant)
Please do not merge this PR until the following items are filled out.
Related PR(s)/Issue(s)
#4764
#4320
#4248