Skip to content

Commit

Permalink
Merge pull request #715 from grafana/add/707-map-click
Browse files Browse the repository at this point in the history
Map [Page|ElementHandle|Frame|Locator].Click promises and fix tests
  • Loading branch information
inancgumus authored Jan 17, 2023
2 parents 2aa3ad1 + 0f65c79 commit 575b975
Show file tree
Hide file tree
Showing 12 changed files with 109 additions and 139 deletions.
2 changes: 1 addition & 1 deletion api/element_handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ type ElementHandle interface {

BoundingBox() *Rect
Check(opts goja.Value)
Click(opts goja.Value) *goja.Promise
Click(opts goja.Value) error
ContentFrame() Frame
Dblclick(opts goja.Value)
DispatchEvent(typ string, props goja.Value)
Expand Down
2 changes: 1 addition & 1 deletion api/frame.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ type Frame interface {
AddStyleTag(opts goja.Value) *goja.Promise
Check(selector string, opts goja.Value)
ChildFrames() []Frame
Click(selector string, opts goja.Value) *goja.Promise
Click(selector string, opts goja.Value) error
Content() string
Dblclick(selector string, opts goja.Value)
DispatchEvent(selector string, typ string, eventInit goja.Value, opts goja.Value)
Expand Down
2 changes: 1 addition & 1 deletion api/page.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type Page interface {
AddStyleTag(opts goja.Value) *goja.Promise
BringToFront()
Check(selector string, opts goja.Value)
Click(selector string, opts goja.Value) *goja.Promise
Click(selector string, opts goja.Value) error
Close(opts goja.Value)
Content() string
Context() BrowserContext
Expand Down
31 changes: 23 additions & 8 deletions browser/mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,12 @@ func mapElementHandle(ctx context.Context, vu k6modules.VU, eh api.ElementHandle
"objectID": eh.ObjectID,
"boundingBox": eh.BoundingBox,
"check": eh.Check,
"click": eh.Click,
"click": func(opts goja.Value) *goja.Promise {
return k6ext.Promise(ctx, func() (any, error) {
err := eh.Click(opts)
return nil, err //nolint:wrapcheck
})
},
"contentFrame": func() *goja.Object {
f := eh.ContentFrame()
mf := mapFrame(ctx, vu, f)
Expand Down Expand Up @@ -231,7 +236,12 @@ func mapFrame(ctx context.Context, vu k6modules.VU, f api.Frame) mapping {
}
return rt.ToValue(mcfs).ToObject(rt)
},
"click": f.Click,
"click": func(selector string, opts goja.Value) *goja.Promise {
return k6ext.Promise(ctx, func() (any, error) {
err := f.Click(selector, opts)
return nil, err //nolint:wrapcheck
})
},
"content": f.Content,
"dblclick": f.Dblclick,
"dispatchEvent": f.DispatchEvent,
Expand Down Expand Up @@ -323,12 +333,17 @@ func mapFrame(ctx context.Context, vu k6modules.VU, f api.Frame) mapping {
func mapPage(ctx context.Context, vu k6modules.VU, p api.Page) mapping {
rt := vu.Runtime()
maps := mapping{
"addInitScript": p.AddInitScript,
"addScriptTag": p.AddScriptTag,
"addStyleTag": p.AddStyleTag,
"bringToFront": p.BringToFront,
"check": p.Check,
"click": p.Click,
"addInitScript": p.AddInitScript,
"addScriptTag": p.AddScriptTag,
"addStyleTag": p.AddStyleTag,
"bringToFront": p.BringToFront,
"check": p.Check,
"click": func(selector string, opts goja.Value) *goja.Promise {
return k6ext.Promise(ctx, func() (any, error) {
err := p.Click(selector, opts)
return nil, err //nolint:wrapcheck
})
},
"close": p.Close,
"content": p.Content,
"context": p.Context,
Expand Down
26 changes: 12 additions & 14 deletions common/element_handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -736,25 +736,23 @@ func (h *ElementHandle) BoundingBox() *api.Rect {
// Click scrolls element into view and clicks in the center of the element
// TODO: look into making more robust using retries
// (see: https://github.com/microsoft/playwright/blob/master/src/server/dom.ts#L298)
func (h *ElementHandle) Click(opts goja.Value) *goja.Promise {
func (h *ElementHandle) Click(opts goja.Value) error {
actionOpts := NewElementHandleClickOptions(h.defaultTimeout())
if err := actionOpts.Parse(h.ctx, opts); err != nil {
k6ext.Panic(h.ctx, "parsing element click options: %v", err)
}
return k6ext.Promise(h.ctx, func() (any, error) {
click := h.newPointerAction(
func(apiCtx context.Context, handle *ElementHandle, p *Position) (any, error) {
return nil, handle.click(p, actionOpts.ToMouseClickOptions())
},
&actionOpts.ElementHandleBasePointerOptions,
)
if _, err := call(h.ctx, click, actionOpts.Timeout); err != nil {
return nil, fmt.Errorf("clicking on element: %w", err)
}
applySlowMo(h.ctx)
click := h.newPointerAction(
func(apiCtx context.Context, handle *ElementHandle, p *Position) (any, error) {
return nil, handle.click(p, actionOpts.ToMouseClickOptions())
},
&actionOpts.ElementHandleBasePointerOptions,
)
if _, err := call(h.ctx, click, actionOpts.Timeout); err != nil {
return fmt.Errorf("clicking on element: %w", err)
}
applySlowMo(h.ctx)

return nil, nil
})
return nil
}

func (h *ElementHandle) ContentFrame() api.Frame {
Expand Down
16 changes: 8 additions & 8 deletions common/frame.go
Original file line number Diff line number Diff line change
Expand Up @@ -583,20 +583,20 @@ func (f *Frame) ChildFrames() []api.Frame {
}

// Click clicks the first element found that matches selector.
func (f *Frame) Click(selector string, opts goja.Value) *goja.Promise {
func (f *Frame) Click(selector string, opts goja.Value) error {
f.log.Debugf("Frame:Click", "fid:%s furl:%q sel:%q", f.ID(), f.URL(), selector)

popts := NewFrameClickOptions(f.defaultTimeout())
if err := popts.Parse(f.ctx, opts); err != nil {
k6ext.Panic(f.ctx, "parsing click options %q: %w", selector, err)
}
return k6ext.Promise(f.ctx, func() (any, error) {
if err := f.click(selector, popts); err != nil {
return nil, fmt.Errorf("clicking on %q: %w", selector, err)
}
applySlowMo(f.ctx)
return nil, nil
})
if err := f.click(selector, popts); err != nil {
return fmt.Errorf("clicking on %q: %w", selector, err)
}

applySlowMo(f.ctx)

return nil
}

func (f *Frame) click(selector string, opts *FrameClickOptions) error {
Expand Down
4 changes: 2 additions & 2 deletions common/page.go
Original file line number Diff line number Diff line change
Expand Up @@ -395,10 +395,10 @@ func (p *Page) IsChecked(selector string, opts goja.Value) bool {
}

// Click clicks an element matching provided selector.
func (p *Page) Click(selector string, opts goja.Value) *goja.Promise {
func (p *Page) Click(selector string, opts goja.Value) error {
p.logger.Debugf("Page:Click", "sid:%v selector:%s", p.sessionID(), selector)

return p.MainFrame().Click(selector, opts)
return p.MainFrame().Click(selector, opts) //nolint:wrapcheck
}

// Close closes the page.
Expand Down
74 changes: 25 additions & 49 deletions tests/element_handle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,16 +94,13 @@ func TestElementHandleClick(t *testing.T) {
p.SetContent(htmlInputButton, nil)

button := p.Query("button")
err := tb.await(func() error {
_ = button.Click(tb.toGojaValue(struct {
NoWaitAfter bool `js:"noWaitAfter"`
}{
// FIX: this is just a workaround because navigation is never triggered
// and we'd be waiting for it to happen otherwise!
NoWaitAfter: true,
}))
return nil
})
err := button.Click(tb.toGojaValue(struct {
NoWaitAfter bool `js:"noWaitAfter"`
}{
// FIX: this is just a workaround because navigation is never triggered
// and we'd be waiting for it to happen otherwise!
NoWaitAfter: true,
}))
require.NoError(t, err)

res := tb.asGojaValue(p.Evaluate(tb.toGojaValue("() => window['result']")))
Expand All @@ -120,16 +117,13 @@ func TestElementHandleClickWithNodeRemoved(t *testing.T) {
p.Evaluate(tb.toGojaValue("() => delete window['Node']"))

button := p.Query("button")
err := tb.await(func() error {
_ = button.Click(tb.toGojaValue(struct {
NoWaitAfter bool `js:"noWaitAfter"`
}{
// FIX: this is just a workaround because navigation is never triggered
// and we'd be waiting for it to happen otherwise!
NoWaitAfter: true,
}))
return nil
})
err := button.Click(tb.toGojaValue(struct {
NoWaitAfter bool `js:"noWaitAfter"`
}{
// FIX: this is just a workaround because navigation is never triggered
// and we'd be waiting for it to happen otherwise!
NoWaitAfter: true,
}))
require.NoError(t, err)

res := tb.asGojaValue(p.Evaluate(tb.toGojaValue("() => window['result']")))
Expand All @@ -146,16 +140,13 @@ func TestElementHandleClickWithDetachedNode(t *testing.T) {
// Detach node to panic when clicked
p.Evaluate(tb.toGojaValue("button => button.remove()"), tb.toGojaValue(button))

err := tb.await(func() error {
_ = button.Click(tb.toGojaValue(struct {
NoWaitAfter bool `js:"noWaitAfter"`
}{
// FIX: this is just a workaround because navigation is never triggered and we'd be waiting for
// it to happen otherwise!
NoWaitAfter: true,
}))
return nil
})
err := button.Click(tb.toGojaValue(struct {
NoWaitAfter bool `js:"noWaitAfter"`
}{
// FIX: this is just a workaround because navigation is never triggered and we'd be waiting for
// it to happen otherwise!
NoWaitAfter: true,
}))
assert.ErrorContains(
t, err,
"element is not attached to the DOM",
Expand Down Expand Up @@ -193,14 +184,9 @@ func TestElementHandleClickConcealedLink(t *testing.T) {
require.NoError(t, err)
require.Equal(t, wantBefore, clickResult())

err = tb.await(func() error {
tb.promise(p.Click("#concealed", nil)).
then(func() {
require.Equal(t, wantAfter, clickResult())
})
return nil
})
err = p.Click("#concealed", nil)
require.NoError(t, err)
require.Equal(t, wantAfter, clickResult())
}

func TestElementHandleNonClickable(t *testing.T) {
Expand All @@ -211,18 +197,8 @@ func TestElementHandleNonClickable(t *testing.T) {
require.NotNil(t, resp)
require.NoError(t, err)

var notClickable bool
err = tb.await(func() error {
tb.promise(p.Click("#non-clickable", nil)).
then(
func() { t.Fatal("element should not be clickable") },
func() { notClickable = true },
)

return nil
})
require.NoError(t, err)
require.True(t, notClickable, "element should not be clickable")
err = p.Click("#non-clickable", nil)
require.Errorf(t, err, "element should not be clickable")
}

func TestElementHandleGetAttribute(t *testing.T) {
Expand Down
35 changes: 19 additions & 16 deletions tests/frame_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,18 @@ func TestWaitForFrameNavigationWithinDocument(t *testing.T) {
fakePromise := k6ext.Promise(tb.vu.Context(), func() (result any, reason error) {
return nil, nil
})
tb.promise(fakePromise).
then(func() testPromise {
waitForNav := p.WaitForNavigation(tb.toGojaValue(&common.FrameWaitForNavigationOptions{
Timeout: time.Duration(timeout.Milliseconds()), // interpreted as ms
}))
click := p.Click(tc.selector, nil)
return tb.promiseAll(waitForNav, click)
}).
then(func() {
done = true
tb.promise(fakePromise).then(func() testPromise {
opts := tb.toGojaValue(&common.FrameWaitForNavigationOptions{
Timeout: time.Duration(timeout.Milliseconds()), // interpreted as ms
})
waitForNav := p.WaitForNavigation(opts)
click := k6ext.Promise(tb.vu.Context(), func() (result any, reason error) {
return nil, p.Click(tc.selector, nil)
})
return tb.promiseAll(waitForNav, click)
}).then(func() {
done = true
})

return nil
})
Expand Down Expand Up @@ -120,12 +121,14 @@ func TestWaitForFrameNavigation(t *testing.T) {
})
tb.promise(fakePromise).
then(func() testPromise {
var timeout time.Duration = 5000 // interpreted as ms
wfnPromise := p.WaitForNavigation(tb.toGojaValue(&common.FrameWaitForNavigationOptions{
Timeout: timeout, // interpreted as ms
}))
cPromise := p.Click(`a`, nil)
return tb.promiseAll(wfnPromise, cPromise)
opts := tb.toGojaValue(&common.FrameWaitForNavigationOptions{
Timeout: 5000, // interpreted as ms
})
waitForNav := p.WaitForNavigation(opts)
click := k6ext.Promise(tb.vu.Context(), func() (result any, reason error) {
return nil, p.Click(`a`, nil)
})
return tb.promiseAll(waitForNav, click)
}).
then(func() {
assert.Equal(t, "Second page", p.Title())
Expand Down
33 changes: 7 additions & 26 deletions tests/frame_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,8 @@ import (
"strconv"
"testing"

"github.com/dop251/goja"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/grafana/xk6-browser/k6ext"
)

func TestFramePress(t *testing.T) {
Expand Down Expand Up @@ -57,29 +54,13 @@ func TestFrameDismissDialogBox(t *testing.T) {
)
require.NoError(t, err)

err = tb.await(func() error {
// TODO
// remove this once we have finished our work on the mapping layer.
// for now: provide a fake promise
fakePromise := k6ext.Promise(tb.vu.Context(), func() (result any, reason error) {
return nil, nil
})
tb.promise(fakePromise).then(func() *goja.Promise {
if tt == "beforeunload" {
return p.Click("#clickHere", nil)
}
result := p.TextContent("#textField", nil)
assert.EqualValues(t, tt+" dismissed", result)

return nil
}).then(func() {
result := p.TextContent("#textField", nil)
assert.EqualValues(t, tt+" dismissed", result)
})

return nil
})
require.NoError(t, err)
if tt == "beforeunload" {
err = p.Click("#clickHere", nil)
require.NoError(t, err)
}

result := p.TextContent("#textField", nil)
assert.EqualValues(t, tt+" dismissed", result)
})
}
}
Expand Down
Loading

0 comments on commit 575b975

Please sign in to comment.