Skip to content
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

Fix goja escape from DispatchEvents #1193

Merged
merged 3 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
110 changes: 65 additions & 45 deletions browser/mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,29 +62,35 @@ func mapLocator(vu moduleVU, lo *common.Locator) mapping {
return nil, lo.Click(popts) //nolint:wrapcheck
}), nil
},
"dblclick": lo.Dblclick,
"check": lo.Check,
"uncheck": lo.Uncheck,
"isChecked": lo.IsChecked,
"isEditable": lo.IsEditable,
"isEnabled": lo.IsEnabled,
"isDisabled": lo.IsDisabled,
"isVisible": lo.IsVisible,
"isHidden": lo.IsHidden,
"fill": lo.Fill,
"focus": lo.Focus,
"getAttribute": lo.GetAttribute,
"innerHTML": lo.InnerHTML,
"innerText": lo.InnerText,
"textContent": lo.TextContent,
"inputValue": lo.InputValue,
"selectOption": lo.SelectOption,
"press": lo.Press,
"type": lo.Type,
"hover": lo.Hover,
"tap": lo.Tap,
"dispatchEvent": lo.DispatchEvent,
"waitFor": lo.WaitFor,
"dblclick": lo.Dblclick,
"check": lo.Check,
"uncheck": lo.Uncheck,
"isChecked": lo.IsChecked,
"isEditable": lo.IsEditable,
"isEnabled": lo.IsEnabled,
"isDisabled": lo.IsDisabled,
"isVisible": lo.IsVisible,
"isHidden": lo.IsHidden,
"fill": lo.Fill,
"focus": lo.Focus,
"getAttribute": lo.GetAttribute,
"innerHTML": lo.InnerHTML,
"innerText": lo.InnerText,
"textContent": lo.TextContent,
"inputValue": lo.InputValue,
"selectOption": lo.SelectOption,
"press": lo.Press,
"type": lo.Type,
"hover": lo.Hover,
"tap": lo.Tap,
"dispatchEvent": func(typ string, eventInit, opts goja.Value) error {
popts := common.NewFrameDispatchEventOptions(lo.DefaultTimeout())
if err := popts.Parse(vu.Context(), opts); err != nil {
return fmt.Errorf("parsing locator dispatch event options: %w", err)
}
return lo.DispatchEvent(typ, eventInit.Export(), popts) //nolint:wrapcheck
},
"waitFor": lo.WaitFor,
}
}

Expand Down Expand Up @@ -249,21 +255,23 @@ func mapElementHandle(vu moduleVU, eh *common.ElementHandle) mapping {
}
return mapFrame(vu, f), nil
},
"dblclick": eh.Dblclick,
"dispatchEvent": eh.DispatchEvent,
"fill": eh.Fill,
"focus": eh.Focus,
"getAttribute": eh.GetAttribute,
"hover": eh.Hover,
"innerHTML": eh.InnerHTML,
"innerText": eh.InnerText,
"inputValue": eh.InputValue,
"isChecked": eh.IsChecked,
"isDisabled": eh.IsDisabled,
"isEditable": eh.IsEditable,
"isEnabled": eh.IsEnabled,
"isHidden": eh.IsHidden,
"isVisible": eh.IsVisible,
"dblclick": eh.Dblclick,
"dispatchEvent": func(typ string, eventInit goja.Value) error {
return eh.DispatchEvent(typ, eventInit.Export()) //nolint:wrapcheck
},
"fill": eh.Fill,
"focus": eh.Focus,
"getAttribute": eh.GetAttribute,
"hover": eh.Hover,
"innerHTML": eh.InnerHTML,
"innerText": eh.InnerText,
"inputValue": eh.InputValue,
"isChecked": eh.IsChecked,
"isDisabled": eh.IsDisabled,
"isEditable": eh.IsEditable,
"isEnabled": eh.IsEnabled,
"isHidden": eh.IsHidden,
"isVisible": eh.IsVisible,
"ownerFrame": func() (mapping, error) {
f, err := eh.OwnerFrame()
if err != nil {
Expand Down Expand Up @@ -355,9 +363,15 @@ func mapFrame(vu moduleVU, f *common.Frame) mapping {
return nil, err //nolint:wrapcheck
}), nil
},
"content": f.Content,
"dblclick": f.Dblclick,
"dispatchEvent": f.DispatchEvent,
"content": f.Content,
"dblclick": f.Dblclick,
"dispatchEvent": func(selector, typ string, eventInit, opts goja.Value) error {
popts := common.NewFrameDispatchEventOptions(f.Timeout())
if err := popts.Parse(vu.Context(), opts); err != nil {
return fmt.Errorf("parsing frame dispatch event options: %w", err)
}
return f.DispatchEvent(selector, typ, eventInit.Export(), popts) //nolint:wrapcheck
},
"evaluate": func(pageFunction goja.Value, gargs ...goja.Value) any {
args := make([]any, 0, len(gargs))
for _, a := range gargs {
Expand Down Expand Up @@ -553,10 +567,16 @@ func mapPage(vu moduleVU, p *common.Page) mapping {

return p.Close(opts) //nolint:wrapcheck
},
"content": p.Content,
"context": p.Context,
"dblclick": p.Dblclick,
"dispatchEvent": p.DispatchEvent,
"content": p.Content,
"context": p.Context,
"dblclick": p.Dblclick,
"dispatchEvent": func(selector, typ string, eventInit, opts goja.Value) error {
popts := common.NewFrameDispatchEventOptions(p.Timeout())
if err := popts.Parse(vu.Context(), opts); err != nil {
return fmt.Errorf("parsing page dispatch event options: %w", err)
}
return p.DispatchEvent(selector, typ, eventInit.Export(), popts) //nolint:wrapcheck
},
"dragAndDrop": p.DragAndDrop,
"emulateMedia": p.EmulateMedia,
"emulateVisionDeficiency": p.EmulateVisionDeficiency,
Expand Down
10 changes: 7 additions & 3 deletions common/element_handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ func (h *ElementHandle) defaultTimeout() time.Duration {
return h.frame.manager.timeoutSettings.timeout()
}

func (h *ElementHandle) dispatchEvent(_ context.Context, typ string, eventInit goja.Value) (any, error) {
func (h *ElementHandle) dispatchEvent(_ context.Context, typ string, eventInit any) (any, error) {
fn := `
(node, injected, type, eventInit) => {
injected.dispatchEvent(node, type, eventInit);
Expand Down Expand Up @@ -774,17 +774,21 @@ func (h *ElementHandle) Dblclick(opts goja.Value) {
applySlowMo(h.ctx)
}

func (h *ElementHandle) DispatchEvent(typ string, eventInit goja.Value) {
// DispatchEvent dispatches a DOM event to the element.
func (h *ElementHandle) DispatchEvent(typ string, eventInit any) error {
fn := func(apiCtx context.Context, handle *ElementHandle) (any, error) {
return handle.dispatchEvent(apiCtx, typ, eventInit)
}
opts := NewElementHandleBaseOptions(h.defaultTimeout())
actFn := h.newAction([]string{}, fn, opts.Force, opts.NoWaitAfter, opts.Timeout)
_, err := call(h.ctx, actFn, opts.Timeout)
if err != nil {
k6ext.Panic(h.ctx, "dispatching element event: %w", err)
return fmt.Errorf("dispatching element event %q: %w", typ, err)
}

applySlowMo(h.ctx)

return nil
}

func (h *ElementHandle) Fill(value string, opts goja.Value) {
Expand Down
14 changes: 6 additions & 8 deletions common/frame.go
Original file line number Diff line number Diff line change
Expand Up @@ -719,22 +719,20 @@ func (f *Frame) dblclick(selector string, opts *FrameDblclickOptions) error {
}

// DispatchEvent dispatches an event for the first element matching the selector.
func (f *Frame) DispatchEvent(selector, typ string, eventInit, opts goja.Value) {
func (f *Frame) DispatchEvent(selector, typ string, eventInit any, opts *FrameDispatchEventOptions) error {
f.log.Debugf("Frame:DispatchEvent", "fid:%s furl:%q sel:%q typ:%q", f.ID(), f.URL(), selector, typ)

popts := NewFrameDispatchEventOptions(f.defaultTimeout())
if err := popts.Parse(f.ctx, opts); err != nil {
k6ext.Panic(f.ctx, "parsing dispatch event options: %w", err)
}
if err := f.dispatchEvent(selector, typ, eventInit, popts); err != nil {
k6ext.Panic(f.ctx, "dispatching event %q to %q: %w", typ, selector, err)
if err := f.dispatchEvent(selector, typ, eventInit, opts); err != nil {
return fmt.Errorf("dispatching frame event %q to %q: %w", typ, selector, err)
}
applySlowMo(f.ctx)

return nil
}

// dispatchEvent is like DispatchEvent but takes parsed options and neither throws
// an error, or applies slow motion.
func (f *Frame) dispatchEvent(selector, typ string, eventInit goja.Value, opts *FrameDispatchEventOptions) error {
func (f *Frame) dispatchEvent(selector, typ string, eventInit any, opts *FrameDispatchEventOptions) error {
dispatchEvent := func(apiCtx context.Context, handle *ElementHandle) (any, error) {
return handle.dispatchEvent(apiCtx, typ, eventInit)
}
Expand Down
22 changes: 12 additions & 10 deletions common/locator.go
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ func (l *Locator) tap(opts *FrameTapOptions) error {

// DispatchEvent dispatches an event for the element matching the
// locator's selector with strict mode on.
func (l *Locator) DispatchEvent(typ string, eventInit, opts goja.Value) {
func (l *Locator) DispatchEvent(typ string, eventInit any, opts *FrameDispatchEventOptions) error {
l.log.Debugf(
"Locator:DispatchEvent", "fid:%s furl:%q sel:%q typ:%q eventInit:%+v opts:%+v",
l.frame.ID(), l.frame.URL(), l.selector, typ, eventInit, opts,
Expand All @@ -594,18 +594,14 @@ func (l *Locator) DispatchEvent(typ string, eventInit, opts goja.Value) {
var err error
defer func() { panicOrSlowMo(l.ctx, err) }()

popts := NewFrameDispatchEventOptions(l.frame.defaultTimeout())
if err = popts.Parse(l.ctx, opts); err != nil {
err = fmt.Errorf("parsing dispatch event options: %w", err)
return
}
if err = l.dispatchEvent(typ, eventInit, popts); err != nil {
err = fmt.Errorf("dispatching event %q to %q: %w", typ, l.selector, err)
return
if err = l.dispatchEvent(typ, eventInit, opts); err != nil {
return fmt.Errorf("dispatching locator event %q to %q: %w", typ, l.selector, err)
}

return nil
}

func (l *Locator) dispatchEvent(typ string, eventInit goja.Value, opts *FrameDispatchEventOptions) error {
func (l *Locator) dispatchEvent(typ string, eventInit any, opts *FrameDispatchEventOptions) error {
opts.Strict = true
return l.frame.dispatchEvent(l.selector, typ, eventInit, opts)
}
Expand All @@ -627,3 +623,9 @@ func (l *Locator) waitFor(opts *FrameWaitForSelectorOptions) error {
opts.Strict = true
return l.frame.waitFor(l.selector, opts)
}

// DefaultTimeout returns the default timeout for the locator.
// This is an internal API and should not be used by users.
func (l *Locator) DefaultTimeout() time.Duration {
return l.frame.defaultTimeout()
}
5 changes: 3 additions & 2 deletions common/page.go
Original file line number Diff line number Diff line change
Expand Up @@ -716,10 +716,11 @@ func (p *Page) Dblclick(selector string, opts goja.Value) {
p.MainFrame().Dblclick(selector, opts)
}

func (p *Page) DispatchEvent(selector string, typ string, eventInit goja.Value, opts goja.Value) {
// DispatchEvent dispatches an event on the page to the element that matches the provided selector.
func (p *Page) DispatchEvent(selector string, typ string, eventInit any, opts *FrameDispatchEventOptions) error {
p.logger.Debugf("Page:DispatchEvent", "sid:%v selector:%s", p.sessionID(), selector)

p.MainFrame().DispatchEvent(selector, typ, eventInit, opts)
return p.MainFrame().DispatchEvent(selector, typ, eventInit, opts)
}

// DragAndDrop is not implemented.
Expand Down
8 changes: 4 additions & 4 deletions tests/launch_options_slowmo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"testing"

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

Expand All @@ -13,7 +12,6 @@ import (

func TestBrowserOptionsSlowMo(t *testing.T) {
t.Parallel()
t.Skip("TODO: fix goja escape")

if testing.Short() {
t.Skip()
Expand Down Expand Up @@ -47,7 +45,8 @@ func TestBrowserOptionsSlowMo(t *testing.T) {
t.Parallel()
tb := newTestBrowser(t, withFileServer())
testPageSlowMoImpl(t, tb, func(_ *testBrowser, p *common.Page) {
p.DispatchEvent("button", "click", goja.Null(), nil)
err := p.DispatchEvent("button", "click", nil, common.NewFrameDispatchEventOptions(p.Timeout()))
require.NoError(t, err)
})
})
t.Run("emulateMedia", func(t *testing.T) {
Expand Down Expand Up @@ -195,7 +194,8 @@ func TestBrowserOptionsSlowMo(t *testing.T) {
t.Parallel()
tb := newTestBrowser(t, withFileServer())
testFrameSlowMoImpl(t, tb, func(_ *testBrowser, f *common.Frame) {
f.DispatchEvent("button", "click", goja.Null(), nil)
err := f.DispatchEvent("button", "click", nil, common.NewFrameDispatchEventOptions(f.Timeout()))
require.NoError(t, err)
})
})
t.Run("evaluate", func(t *testing.T) {
Expand Down
13 changes: 10 additions & 3 deletions tests/locator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ type jsFrameWaitForSelectorOpts struct {

func TestLocator(t *testing.T) {
t.Parallel()
t.Skip("TODO: fix goja escape")

tests := []struct {
name string
Expand Down Expand Up @@ -91,7 +90,11 @@ func TestLocator(t *testing.T) {
return asBool(t, v)
}
require.False(t, result(), "should not be clicked first")
p.Locator("#link", nil).DispatchEvent("click", tb.toGojaValue("mouseevent"), nil)
opts := &common.FrameDispatchEventOptions{
inancgumus marked this conversation as resolved.
Show resolved Hide resolved
FrameBaseOptions: &common.FrameBaseOptions{},
}
err := p.Locator("#link", nil).DispatchEvent("click", "mouseevent", opts)
require.NoError(t, err)
require.True(t, result(), "cannot not dispatch event")
},
},
Expand Down Expand Up @@ -280,7 +283,11 @@ func TestLocator(t *testing.T) {
},
{
"DispatchEvent", func(l *common.Locator, tb *testBrowser) {
l.DispatchEvent("click", tb.toGojaValue("mouseevent"), timeout(tb))
err := l.DispatchEvent("click", "mouseevent", common.NewFrameDispatchEventOptions(100*time.Millisecond))
if err != nil {
// TODO: remove panic and update tests when all locator methods return error.
panic(err)
}
},
},
{
Expand Down