Skip to content
This repository has been archived by the owner on Jan 30, 2025. It is now read-only.

Commit

Permalink
Add error handling to wildcard selectors
Browse files Browse the repository at this point in the history
This allows us to:
- Better handle extension errors
- Leaves the decision of handling to Goja when an element is not found.
  This is how it's done in the k6-core and other extensions.

Updates: #804
Related: #688
  • Loading branch information
inancgumus committed Mar 9, 2023
1 parent 07526fb commit 7b5f51f
Show file tree
Hide file tree
Showing 10 changed files with 145 additions and 94 deletions.
4 changes: 2 additions & 2 deletions api/element_handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ type ElementHandle interface {
IsVisible() bool
OwnerFrame() Frame
Press(key string, opts goja.Value)
Query(selector string) ElementHandle
QueryAll(selector string) []ElementHandle
Query(selector string) (ElementHandle, error)
QueryAll(selector string) ([]ElementHandle, error)
Screenshot(opts goja.Value) goja.ArrayBuffer
ScrollIntoViewIfNeeded(opts goja.Value)
SelectOption(values goja.Value, opts goja.Value) []string
Expand Down
4 changes: 2 additions & 2 deletions api/frame.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ type Frame interface {
// Locator creates and returns a new locator for this frame.
Locator(selector string, opts goja.Value) Locator
Name() string
Query(selector string) ElementHandle
QueryAll(selector string) []ElementHandle
Query(selector string) (ElementHandle, error)
QueryAll(selector string) ([]ElementHandle, error)
Page() Page
ParentFrame() Frame
Press(selector string, key string, opts goja.Value)
Expand Down
4 changes: 2 additions & 2 deletions api/page.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ type Page interface {
Pause()
Pdf(opts goja.Value) []byte
Press(selector string, key string, opts goja.Value)
Query(selector string) ElementHandle
QueryAll(selector string) []ElementHandle
Query(selector string) (ElementHandle, error)
QueryAll(selector string) ([]ElementHandle, error)
Reload(opts goja.Value) Response
Route(url goja.Value, handler goja.Callable)
Screenshot(opts goja.Value) goja.ArrayBuffer
Expand Down
66 changes: 39 additions & 27 deletions browser/mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,21 +245,25 @@ func mapElementHandle(vu moduleVU, eh api.ElementHandle) mapping {
return rt.ToValue(ehm).ToObject(rt)
},
}
maps["$"] = func(selector string) *goja.Object {
eh := eh.Query(selector)
maps["$"] = func(selector string) (mapping, error) {
eh, err := eh.Query(selector)
if err != nil {
return nil, err //nolint:wrapcheck
}
ehm := mapElementHandle(vu, eh)
return rt.ToValue(ehm).ToObject(rt)
return ehm, nil
}
maps["$$"] = func(selector string) *goja.Object {
var (
mehs []mapping
ehs = eh.QueryAll(selector)
)
maps["$$"] = func(selector string) ([]mapping, error) {
ehs, err := eh.QueryAll(selector)
if err != nil {
return nil, err //nolint:wrapcheck
}
var mehs []mapping
for _, eh := range ehs {
ehm := mapElementHandle(vu, eh)
mehs = append(mehs, ehm)
}
return rt.ToValue(mehs).ToObject(rt)
return mehs, nil
}

jsHandleMap := mapJSHandle(vu, eh)
Expand Down Expand Up @@ -377,21 +381,25 @@ func mapFrame(vu moduleVU, f api.Frame) mapping {
},
"waitForTimeout": f.WaitForTimeout,
}
maps["$"] = func(selector string) *goja.Object {
eh := f.Query(selector)
maps["$"] = func(selector string) (mapping, error) {
eh, err := f.Query(selector)
if err != nil {
return nil, err //nolint:wrapcheck
}
ehm := mapElementHandle(vu, eh)
return rt.ToValue(ehm).ToObject(rt)
return ehm, nil
}
maps["$$"] = func(selector string) *goja.Object {
var (
mehs []mapping
ehs = f.QueryAll(selector)
)
maps["$$"] = func(selector string) ([]mapping, error) {
ehs, err := f.QueryAll(selector)
if err != nil {
return nil, err //nolint:wrapcheck
}
var mehs []mapping
for _, eh := range ehs {
ehm := mapElementHandle(vu, eh)
mehs = append(mehs, ehm)
}
return rt.ToValue(mehs).ToObject(rt)
return mehs, nil
}

return maps
Expand Down Expand Up @@ -540,21 +548,25 @@ func mapPage(vu moduleVU, p api.Page) mapping {
return rt.ToValue(mws).ToObject(rt)
},
}
maps["$"] = func(selector string) *goja.Object {
eh := p.Query(selector)
maps["$"] = func(selector string) (mapping, error) {
eh, err := p.Query(selector)
if err != nil {
return nil, err //nolint:wrapcheck
}
ehm := mapElementHandle(vu, eh)
return rt.ToValue(ehm).ToObject(rt)
return ehm, nil
}
maps["$$"] = func(selector string) *goja.Object {
var (
mehs []mapping
ehs = p.QueryAll(selector)
)
maps["$$"] = func(selector string) ([]mapping, error) {
ehs, err := p.QueryAll(selector)
if err != nil {
return nil, err //nolint:wrapcheck
}
var mehs []mapping
for _, eh := range ehs {
ehm := mapElementHandle(vu, eh)
mehs = append(mehs, ehm)
}
return rt.ToValue(mehs).ToObject(rt)
return mehs, nil
}

return maps
Expand Down
32 changes: 16 additions & 16 deletions common/element_handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -1023,7 +1023,7 @@ func (h *ElementHandle) Press(key string, opts goja.Value) {

// Query runs "element.querySelector" within the page. If no element matches the selector,
// the return value resolves to "null".
func (h *ElementHandle) Query(selector string) api.ElementHandle {
func (h *ElementHandle) Query(selector string) (api.ElementHandle, error) {
parsedSelector, err := NewSelector(selector)
if err != nil {
k6ext.Panic(h.ctx, "parsing selector %q: %w", selector, err)
Expand All @@ -1039,35 +1039,35 @@ func (h *ElementHandle) Query(selector string) api.ElementHandle {
}
result, err := h.evalWithScript(h.ctx, opts, fn, parsedSelector)
if err != nil {
k6ext.Panic(h.ctx, "querying selector %q: %w", selector, err)
return nil, fmt.Errorf("querying selector %q: %w", selector, err)
}
if result == nil {
return nil
return nil, fmt.Errorf("querying selector %q", selector)
}

var (
handle = result.(api.JSHandle)
element = handle.AsElement()
)
applySlowMo(h.ctx)
if element != nil {
return element
handle, ok := result.(api.JSHandle)
if !ok {
return nil, fmt.Errorf("querying selector %q, wrong type %T", selector, result)
}
handle.Dispose()
return nil
element := handle.AsElement()
if element == nil {
handle.Dispose()
return nil, fmt.Errorf("querying selector %q", selector)
}

return element, nil
}

// QueryAll queries element subtree for matching elements.
// If no element matches the selector, the return value resolves to "null".
func (h *ElementHandle) QueryAll(selector string) []api.ElementHandle {
func (h *ElementHandle) QueryAll(selector string) ([]api.ElementHandle, error) {
defer applySlowMo(h.ctx)

handles, err := h.queryAll(selector, h.evalWithScript)
if err != nil {
k6ext.Panic(h.ctx, "querying all selector %q: %w", selector, err)
return nil, fmt.Errorf("querying all selector %q: %w", selector, err)
}

return handles
return handles, err
}

func (h *ElementHandle) queryAll(selector string, eval evalFunc) ([]api.ElementHandle, error) {
Expand Down
17 changes: 5 additions & 12 deletions common/frame.go
Original file line number Diff line number Diff line change
Expand Up @@ -1304,32 +1304,25 @@ func (f *Frame) Name() string {

// Query runs a selector query against the document tree, returning the first matching element or
// "null" if no match is found.
func (f *Frame) Query(selector string) api.ElementHandle {
func (f *Frame) Query(selector string) (api.ElementHandle, error) {
f.log.Debugf("Frame:Query", "fid:%s furl:%q sel:%q", f.ID(), f.URL(), selector)

document, err := f.document()
if err != nil {
k6ext.Panic(f.ctx, "getting document: %w", err)
}
value := document.Query(selector)
if value != nil {
return value
}
return nil
return document.Query(selector)
}

func (f *Frame) QueryAll(selector string) []api.ElementHandle {
// QueryAll runs a selector query against the document tree, returning all matching elements.
func (f *Frame) QueryAll(selector string) ([]api.ElementHandle, error) {
f.log.Debugf("Frame:QueryAll", "fid:%s furl:%q sel:%q", f.ID(), f.URL(), selector)

document, err := f.document()
if err != nil {
k6ext.Panic(f.ctx, "getting document: %w", err)
}
value := document.QueryAll(selector)
if value != nil {
return value
}
return nil
return document.QueryAll(selector)
}

// Page returns page that owns frame.
Expand Down
6 changes: 4 additions & 2 deletions common/page.go
Original file line number Diff line number Diff line change
Expand Up @@ -675,13 +675,15 @@ func (p *Page) Press(selector string, key string, opts goja.Value) {
p.MainFrame().Press(selector, key, opts)
}

func (p *Page) Query(selector string) api.ElementHandle {
// Query returns the first element matching the specified selector.
func (p *Page) Query(selector string) (api.ElementHandle, error) {
p.logger.Debugf("Page:Query", "sid:%v selector:%s", p.sessionID(), selector)

return p.frameManager.MainFrame().Query(selector)
}

func (p *Page) QueryAll(selector string) []api.ElementHandle {
// QueryAll returns all elements matching the specified selector.
func (p *Page) QueryAll(selector string) ([]api.ElementHandle, error) {
p.logger.Debugf("Page:QueryAll", "sid:%v selector:%s", p.sessionID(), selector)

return p.frameManager.MainFrame().QueryAll(selector)
Expand Down
Loading

0 comments on commit 7b5f51f

Please sign in to comment.