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

Prepare Mouse for async migration #1322

Merged
merged 7 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions browser/mapping_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,12 @@ func TestMappings(t *testing.T) {
return mapKeyboard(moduleVU{VU: vu}, &common.Keyboard{})
},
},
"mapMouse": {
apiInterface: (*mouseAPI)(nil),
mapp: func() mapping {
return mapMouse(moduleVU{VU: vu}, &common.Mouse{})
},
},
} {
tt := tt
t.Run(name, func(t *testing.T) {
Expand Down Expand Up @@ -534,16 +540,12 @@ type touchscreenAPI interface {
}

// mouseAPI is the interface of a mouse input device.
// TODO: map this to page.GetMouse(). Currently, the common.Mouse type
// mapping is not tested using this interface. We use the concrete type
// without testing its exported methods.
type mouseAPI interface { //nolint: unused
Click(x float64, y float64, opts goja.Value)
DblClick(x float64, y float64, opts goja.Value)
Down(x float64, y float64, opts goja.Value)
Move(x float64, y float64, opts goja.Value)
Up(x float64, y float64, opts goja.Value)
// Wheel(opts goja.Value)
type mouseAPI interface {
Click(x float64, y float64, opts goja.Value) error
DblClick(x float64, y float64, opts goja.Value) error
Down(opts goja.Value) error
Up(opts goja.Value) error
Move(x float64, y float64, opts goja.Value) error
}

// workerAPI is the interface of a web worker.
Expand Down
15 changes: 15 additions & 0 deletions browser/mouse_mapping.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package browser

import (
"github.com/grafana/xk6-browser/common"
)

func mapMouse(_ moduleVU, m *common.Mouse) mapping {
return mapping{
"click": m.Click,
"dblClick": m.DblClick,
"down": m.Down,
"up": m.Up,
"move": m.Move,
}
}
2 changes: 1 addition & 1 deletion browser/page_mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func mapPage(vu moduleVU, p *common.Page) mapping { //nolint:gocognit,cyclop
mf := mapFrame(vu, p.MainFrame())
return rt.ToValue(mf).ToObject(rt)
},
"mouse": rt.ToValue(p.GetMouse()).ToObject(rt),
"mouse": mapMouse(vu, p.GetMouse()),
"on": func(event string, handler goja.Callable) error {
tq := vu.taskQueueRegistry.get(p.TargetID())

Expand Down
149 changes: 63 additions & 86 deletions common/mouse.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import (
"github.com/chromedp/cdproto/cdp"
"github.com/chromedp/cdproto/input"
"github.com/dop251/goja"

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

// Mouse represents a mouse input device.
Expand All @@ -36,6 +34,18 @@ func NewMouse(ctx context.Context, s session, f *Frame, ts *TimeoutSettings, k *
}
}

// Click will trigger a series of MouseMove, MouseDown and MouseUp events in the browser.
func (m *Mouse) Click(x float64, y float64, opts goja.Value) error {
mouseOpts := NewMouseClickOptions()
if err := mouseOpts.Parse(m.ctx, opts); err != nil {
return fmt.Errorf("parsing mouse click options: %w", err)
}
if err := m.click(x, y, mouseOpts); err != nil {
return fmt.Errorf("clicking on x:%f y:%f: %w", x, y, err)
}
return nil
}

func (m *Mouse) click(x float64, y float64, opts *MouseClickOptions) error {
mouseDownUpOpts := opts.ToMouseDownUpOptions()
if err := m.move(x, y, NewMouseMoveOptions()); err != nil {
Expand All @@ -61,6 +71,30 @@ func (m *Mouse) click(x float64, y float64, opts *MouseClickOptions) error {
return nil
}

// DblClick will trigger Click twice in quick succession.
func (m *Mouse) DblClick(x float64, y float64, opts goja.Value) error {
mouseOpts := NewMouseDblClickOptions()
if err := mouseOpts.Parse(m.ctx, opts); err != nil {
return fmt.Errorf("parsing double click options: %w", err)
}
if err := m.click(x, y, mouseOpts.ToMouseClickOptions()); err != nil {
return fmt.Errorf("double clicking on x:%f y:%f: %w", x, y, err)
}
return nil
}

// Down will trigger a MouseDown event in the browser.
func (m *Mouse) Down(opts goja.Value) error {
mouseOpts := NewMouseDownUpOptions()
if err := mouseOpts.Parse(m.ctx, opts); err != nil {
return fmt.Errorf("parsing mouse down options: %w", err)
}
if err := m.down(mouseOpts); err != nil {
return fmt.Errorf("pressing the mouse button on x:%f y:%f: %w", m.x, m.y, err)
}
return nil
}

func (m *Mouse) down(opts *MouseDownUpOptions) error {
m.button = input.MouseButton(opts.Button)
action := input.DispatchMouseEvent(input.MousePressed, m.x, m.y).
Expand All @@ -73,22 +107,15 @@ func (m *Mouse) down(opts *MouseDownUpOptions) error {
return nil
}

func (m *Mouse) move(x float64, y float64, opts *MouseMoveOptions) error {
fromX := m.x
fromY := m.y
m.x = x
m.y = y
for i := int64(1); i <= opts.Steps; i++ {
x := fromX + (m.x-fromX)*float64(i/opts.Steps)
y := fromY + (m.y-fromY)*float64(i/opts.Steps)
action := input.DispatchMouseEvent(input.MouseMoved, x, y).
WithButton(m.button).
WithModifiers(input.Modifier(m.keyboard.modifiers))
if err := action.Do(cdp.WithExecutor(m.ctx, m.session)); err != nil {
return fmt.Errorf("mouse move: %w", err)
}
// Up will trigger a MouseUp event in the browser.
func (m *Mouse) Up(opts goja.Value) error {
mouseOpts := NewMouseDownUpOptions()
if err := mouseOpts.Parse(m.ctx, opts); err != nil {
return fmt.Errorf("parsing mouse up options: %w", err)
}
if err := m.up(mouseOpts); err != nil {
return fmt.Errorf("releasing the mouse button on x:%f y:%f: %w", m.x, m.y, err)
}

return nil
}

Expand All @@ -105,83 +132,33 @@ func (m *Mouse) up(opts *MouseDownUpOptions) error {
return nil
}

// Click will trigger a series of MouseMove, MouseDown and MouseUp events in the browser.
func (m *Mouse) Click(x float64, y float64, opts goja.Value) {
mouseOpts := NewMouseClickOptions()
if err := mouseOpts.Parse(m.ctx, opts); err != nil {
k6ext.Panic(m.ctx, "parsing mouse click options: %w", err)
}
if err := m.click(x, y, mouseOpts); err != nil {
k6ext.Panic(m.ctx, "clicking on x:%f y:%f: %w", x, y, err)
}
}

// DblClick will trigger Click twice in quick succession.
func (m *Mouse) DblClick(x float64, y float64, opts goja.Value) {
mouseOpts := NewMouseDblClickOptions()
if err := mouseOpts.Parse(m.ctx, opts); err != nil {
k6ext.Panic(m.ctx, "parsing double click options: %w", err)
}
if err := m.click(x, y, mouseOpts.ToMouseClickOptions()); err != nil {
k6ext.Panic(m.ctx, "double clicking on x:%f y:%f: %w", x, y, err)
}
}

// Down will trigger a MouseDown event in the browser.
func (m *Mouse) Down(opts goja.Value) {
mouseOpts := NewMouseDownUpOptions()
if err := mouseOpts.Parse(m.ctx, opts); err != nil {
k6ext.Panic(m.ctx, "parsing mouse down options: %w", err)
}
if err := m.down(mouseOpts); err != nil {
k6ext.Panic(m.ctx, "pressing the mouse button on x:%f y:%f: %w", m.x, m.y, err)
}
}

// Move will trigger a MouseMoved event in the browser.
func (m *Mouse) Move(x float64, y float64, opts goja.Value) {
func (m *Mouse) Move(x float64, y float64, opts goja.Value) error {
mouseOpts := NewMouseMoveOptions()
if err := mouseOpts.Parse(m.ctx, opts); err != nil {
k6ext.Panic(m.ctx, "parsing mouse move options: %w", err)
return fmt.Errorf("parsing mouse move options: %w", err)
}
if err := m.move(x, y, mouseOpts); err != nil {
k6ext.Panic(m.ctx, "moving the mouse pointer to x:%f y:%f: %w", x, y, err)
}
}

// Up will trigger a MouseUp event in the browser.
func (m *Mouse) Up(opts goja.Value) {
mouseOpts := NewMouseDownUpOptions()
if err := mouseOpts.Parse(m.ctx, opts); err != nil {
k6ext.Panic(m.ctx, "parsing mouse up options: %w", err)
}
if err := m.up(mouseOpts); err != nil {
k6ext.Panic(m.ctx, "releasing the mouse button on x:%f y:%f: %w", m.x, m.y, err)
return fmt.Errorf("moving the mouse pointer to x:%f y:%f: %w", x, y, err)
}
return nil
}

// Wheel will trigger a MouseWheel event in the browser
/*func (m *Mouse) Wheel(opts goja.Value) {
var deltaX float64 = 0.0
var deltaY float64 = 0.0

if opts != nil && !goja.IsUndefined(opts) && !goja.IsNull(opts) {
opts := opts.ToObject(rt)
for _, k := range opts.Keys() {
switch k {
case "deltaX":
deltaX = opts.Get(k).ToFloat()
case "deltaY":
deltaY = opts.Get(k).ToFloat()
}
func (m *Mouse) move(x float64, y float64, opts *MouseMoveOptions) error {
fromX := m.x
fromY := m.y
m.x = x
m.y = y
for i := int64(1); i <= opts.Steps; i++ {
x := fromX + (m.x-fromX)*float64(i/opts.Steps)
y := fromY + (m.y-fromY)*float64(i/opts.Steps)
action := input.DispatchMouseEvent(input.MouseMoved, x, y).
WithButton(m.button).
WithModifiers(input.Modifier(m.keyboard.modifiers))
if err := action.Do(cdp.WithExecutor(m.ctx, m.session)); err != nil {
return fmt.Errorf("mouse move: %w", err)
}
}

action := input.DispatchMouseEvent(input.MouseWheel, m.x, m.y).
WithModifiers(input.Modifier(m.keyboard.modifiers)).
WithDeltaX(deltaX).
WithDeltaY(deltaY)
if err := action.Do(cdp.WithExecutor(m.ctx, m.session)); err != nil {
k6Throw(m.ctx, "mouse down: %w", err)
}
}*/
return nil
}
12 changes: 6 additions & 6 deletions tests/mouse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func TestMouseActions(t *testing.T) {

// Simulate a click at the button coordinates
box := button.BoundingBox()
m.Click(box.X, box.Y, nil)
require.NoError(t, m.Click(box.X, box.Y, nil))

// Verify the button's text changed
assert.Equal(t, "Clicked!", button.TextContent())
Expand Down Expand Up @@ -56,7 +56,7 @@ func TestMouseActions(t *testing.T) {
box := button.BoundingBox()

// Simulate a double click at the button coordinates
m.DblClick(box.X, box.Y, nil)
require.NoError(t, m.DblClick(box.X, box.Y, nil))

// Verify the button's text changed
assert.Equal(t, "Double Clicked!", button.TextContent())
Expand Down Expand Up @@ -87,7 +87,7 @@ func TestMouseActions(t *testing.T) {

// Simulate mouse move within the div
box := area.BoundingBox()
m.Move(box.X+50, box.Y+50, nil) // Move to the center of the div
require.NoError(t, m.Move(box.X+50, box.Y+50, nil)) // Move to the center of the div
assert.Equal(t, "Mouse Moved", area.TextContent())
})

Expand All @@ -110,10 +110,10 @@ func TestMouseActions(t *testing.T) {
require.NoError(t, err)

box := button.BoundingBox()
m.Move(box.X, box.Y, nil)
m.Down(nil)
require.NoError(t, m.Move(box.X, box.Y, nil))
require.NoError(t, m.Down(nil))
assert.Equal(t, "Mouse Down", button.TextContent())
m.Up(nil)
require.NoError(t, m.Up(nil))
assert.Equal(t, "Mouse Up", button.TextContent())
})
}
Loading