diff --git a/api/element_handle.go b/api/element_handle.go index 0b2640c6c..9b6d48a7f 100644 --- a/api/element_handle.go +++ b/api/element_handle.go @@ -39,5 +39,5 @@ type ElementHandle interface { Type(text string, opts goja.Value) Uncheck(opts goja.Value) WaitForElementState(state string, opts goja.Value) - WaitForSelector(selector string, opts goja.Value) ElementHandle + WaitForSelector(selector string, opts goja.Value) (ElementHandle, error) } diff --git a/api/frame.go b/api/frame.go index 9d508407b..f24a394bb 100644 --- a/api/frame.go +++ b/api/frame.go @@ -52,6 +52,6 @@ type Frame interface { WaitForFunction(pageFunc, opts goja.Value, args ...goja.Value) (any, error) WaitForLoadState(state string, opts goja.Value) WaitForNavigation(opts goja.Value) (Response, error) - WaitForSelector(selector string, opts goja.Value) ElementHandle + WaitForSelector(selector string, opts goja.Value) (ElementHandle, error) WaitForTimeout(timeout int64) } diff --git a/api/page.go b/api/page.go index 5938597ae..90d3dcea3 100644 --- a/api/page.go +++ b/api/page.go @@ -78,7 +78,7 @@ type Page interface { WaitForNavigation(opts goja.Value) (Response, error) WaitForRequest(urlOrPredicate, opts goja.Value) Request WaitForResponse(urlOrPredicate, opts goja.Value) Response - WaitForSelector(selector string, opts goja.Value) ElementHandle + WaitForSelector(selector string, opts goja.Value) (ElementHandle, error) WaitForTimeout(timeout int64) Workers() []Worker } diff --git a/browser/mapping.go b/browser/mapping.go index c600ffde6..b25df0d8e 100644 --- a/browser/mapping.go +++ b/browser/mapping.go @@ -198,7 +198,6 @@ func mapJSHandle(vu moduleVU, jsh api.JSHandle) mapping { // //nolint:funlen func mapElementHandle(vu moduleVU, eh api.ElementHandle) mapping { - rt := vu.Runtime() maps := mapping{ "boundingBox": eh.BoundingBox, "check": eh.Check, @@ -248,10 +247,12 @@ func mapElementHandle(vu moduleVU, eh api.ElementHandle) mapping { "type": eh.Type, "uncheck": eh.Uncheck, "waitForElementState": eh.WaitForElementState, - "waitForSelector": func(selector string, opts goja.Value) *goja.Object { - eh := eh.WaitForSelector(selector, opts) - ehm := mapElementHandle(vu, eh) - return rt.ToValue(ehm).ToObject(rt) + "waitForSelector": func(selector string, opts goja.Value) (mapping, error) { + eh, err := eh.WaitForSelector(selector, opts) + if err != nil { + return nil, err //nolint:wrapcheck + } + return mapElementHandle(vu, eh), nil }, } maps["$"] = func(selector string) (mapping, error) { @@ -385,10 +386,12 @@ func mapFrame(vu moduleVU, f api.Frame) mapping { return mapResponse(vu, resp), nil }) }, - "waitForSelector": func(selector string, opts goja.Value) *goja.Object { - eh := f.WaitForSelector(selector, opts) - ehm := mapElementHandle(vu, eh) - return rt.ToValue(ehm).ToObject(rt) + "waitForSelector": func(selector string, opts goja.Value) (mapping, error) { + eh, err := f.WaitForSelector(selector, opts) + if err != nil { + return nil, err //nolint:wrapcheck + } + return mapElementHandle(vu, eh), nil }, "waitForTimeout": f.WaitForTimeout, } @@ -548,8 +551,14 @@ func mapPage(vu moduleVU, p api.Page) mapping { }, "waitForRequest": p.WaitForRequest, "waitForResponse": p.WaitForResponse, - "waitForSelector": p.WaitForSelector, - "waitForTimeout": p.WaitForTimeout, + "waitForSelector": func(selector string, opts goja.Value) (mapping, error) { + eh, err := p.WaitForSelector(selector, opts) + if err != nil { + return nil, err //nolint:wrapcheck + } + return mapElementHandle(vu, eh), nil + }, + "waitForTimeout": p.WaitForTimeout, "workers": func() *goja.Object { var mws []mapping for _, w := range p.Workers() { diff --git a/common/element_handle.go b/common/element_handle.go index 8d9e48fcd..922ba1ad5 100644 --- a/common/element_handle.go +++ b/common/element_handle.go @@ -1308,18 +1308,19 @@ func (h *ElementHandle) WaitForElementState(state string, opts goja.Value) { } } -func (h *ElementHandle) WaitForSelector(selector string, opts goja.Value) api.ElementHandle { +// WaitForSelector waits for the selector to appear in the DOM. +func (h *ElementHandle) WaitForSelector(selector string, opts goja.Value) (api.ElementHandle, error) { parsedOpts := NewFrameWaitForSelectorOptions(h.defaultTimeout()) if err := parsedOpts.Parse(h.ctx, opts); err != nil { - k6ext.Panic(h.ctx, "parsing waitForSelector %q options: %w", selector, err) + return nil, fmt.Errorf("parsing waitForSelector %q options: %w", selector, err) } handle, err := h.waitForSelector(h.ctx, selector, parsedOpts) if err != nil { - k6ext.Panic(h.ctx, "waiting for selector %q: %w", selector, err) + return nil, fmt.Errorf("waiting for selector %q: %w", selector, err) } - return handle + return handle, nil } // evalWithScript evaluates the given js code in the scope of this ElementHandle and returns the result. diff --git a/common/frame.go b/common/frame.go index 226588da0..76a7ace6c 100644 --- a/common/frame.go +++ b/common/frame.go @@ -1820,16 +1820,17 @@ func (f *Frame) WaitForNavigation(opts goja.Value) (api.Response, error) { } // WaitForSelector waits for the given selector to match the waiting criteria. -func (f *Frame) WaitForSelector(selector string, opts goja.Value) api.ElementHandle { +func (f *Frame) WaitForSelector(selector string, opts goja.Value) (api.ElementHandle, error) { parsedOpts := NewFrameWaitForSelectorOptions(f.defaultTimeout()) if err := parsedOpts.Parse(f.ctx, opts); err != nil { - k6ext.Panic(f.ctx, "parsing wait for selector %q options: %w", selector, err) + return nil, fmt.Errorf("parsing wait for selector %q options: %w", selector, err) } handle, err := f.waitForSelectorRetry(selector, parsedOpts, maxRetry) if err != nil { - k6ext.Panic(f.ctx, "waiting for selector %q: %w", selector, err) + return nil, fmt.Errorf("waiting for selector %q: %w", selector, err) } - return handle + + return handle, nil } // WaitForTimeout waits the specified amount of milliseconds. diff --git a/common/page.go b/common/page.go index 6de21da5f..5e5366c70 100644 --- a/common/page.go +++ b/common/page.go @@ -935,7 +935,7 @@ func (p *Page) WaitForResponse(urlOrPredicate, opts goja.Value) api.Response { } // WaitForSelector waits for the given selector to match the waiting criteria. -func (p *Page) WaitForSelector(selector string, opts goja.Value) api.ElementHandle { +func (p *Page) WaitForSelector(selector string, opts goja.Value) (api.ElementHandle, error) { p.logger.Debugf("Page:WaitForSelector", "sid:%v stid:%v ptid:%v selector:%s", p.sessionID(), p.session.TargetID(), p.targetID, selector) diff --git a/tests/element_handle_test.go b/tests/element_handle_test.go index 7e12a1355..62910c2d2 100644 --- a/tests/element_handle_test.go +++ b/tests/element_handle_test.go @@ -375,10 +375,10 @@ func TestElementHandleWaitForSelector(t *testing.T) { }, 100); } `)) - element := root.WaitForSelector(".element-to-appear", tb.toGojaValue(struct { + element, err := root.WaitForSelector(".element-to-appear", tb.toGojaValue(struct { Timeout int64 `js:"timeout"` }{Timeout: 1000})) - + require.NoError(t, err) require.NotNil(t, element, "expected element to have been found after wait") element.Dispose()