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

Refactor parseBrowserContextOptions to Sobek #1526

Merged
merged 6 commits into from
Nov 7, 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
26 changes: 24 additions & 2 deletions browser/browser_context_options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"testing"

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

"github.com/grafana/xk6-browser/common"
"github.com/grafana/xk6-browser/k6ext/k6test"
Expand All @@ -12,7 +13,7 @@ import (
func TestBrowserContextOptionsPermissions(t *testing.T) {
vu := k6test.NewVU(t)

opts, err := parseBrowserContextOptions(vu.Context(), vu.ToSobekValue((struct {
opts, err := parseBrowserContextOptions(vu.Runtime(), vu.ToSobekValue((struct {
Permissions []any `js:"permissions"`
}{
Permissions: []any{"camera", "microphone"},
Expand All @@ -25,7 +26,7 @@ func TestBrowserContextOptionsPermissions(t *testing.T) {
func TestBrowserContextSetGeolocation(t *testing.T) {
vu := k6test.NewVU(t)

opts, err := parseBrowserContextOptions(vu.Context(), vu.ToSobekValue((struct {
opts, err := parseBrowserContextOptions(vu.Runtime(), vu.ToSobekValue((struct {
GeoLocation *common.Geolocation `js:"geolocation"`
}{
GeoLocation: &common.Geolocation{
Expand All @@ -40,3 +41,24 @@ func TestBrowserContextSetGeolocation(t *testing.T) {
assert.Equal(t, 2.0, opts.Geolocation.Longitude)
assert.Equal(t, 3.0, opts.Geolocation.Accuracy)
}

func TestBrowserContextDefaultOptions(t *testing.T) {
inancgumus marked this conversation as resolved.
Show resolved Hide resolved
vu := k6test.NewVU(t)

defaults := common.DefaultBrowserContextOptions()

// gets the default options by default
opts, err := parseBrowserContextOptions(vu.Runtime(), nil)
require.NoError(t, err)
assert.Equal(t, defaults, opts)

// merges with the default options
opts, err = parseBrowserContextOptions(vu.Runtime(), vu.ToSobekValue((struct {
DeviceScaleFactor float64 `js:"deviceScaleFactor"` // just to test a different field
}{
DeviceScaleFactor: defaults.DeviceScaleFactor + 1,
})))
require.NoError(t, err)
assert.NotEqual(t, defaults.DeviceScaleFactor, opts.DeviceScaleFactor)
assert.Equal(t, defaults.Locale, opts.Locale) // should remain as default
}
97 changes: 6 additions & 91 deletions browser/browser_mapping.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package browser

import (
"context"
"fmt"

"github.com/grafana/sobek"
Expand Down Expand Up @@ -37,7 +36,7 @@ func mapBrowser(vu moduleVU) mapping { //nolint:funlen,cyclop,gocognit
return b.IsConnected(), nil
},
"newContext": func(opts sobek.Value) (*sobek.Promise, error) {
popts, err := parseBrowserContextOptions(vu.Context(), opts)
popts, err := parseBrowserContextOptions(vu.Runtime(), opts)
if err != nil {
return nil, fmt.Errorf("parsing browser.newContext options: %w", err)
}
Expand Down Expand Up @@ -72,7 +71,7 @@ func mapBrowser(vu moduleVU) mapping { //nolint:funlen,cyclop,gocognit
return b.Version(), nil
},
"newPage": func(opts sobek.Value) (*sobek.Promise, error) {
popts, err := parseBrowserContextOptions(vu.Context(), opts)
popts, err := parseBrowserContextOptions(vu.Runtime(), opts)
if err != nil {
return nil, fmt.Errorf("parsing browser.newPage options: %w", err)
}
Expand Down Expand Up @@ -110,94 +109,10 @@ func initBrowserContext(bctx *common.BrowserContext, testRunID string) error {
}

// parseBrowserContextOptions parses the [common.BrowserContext] options from a Sobek value.
func parseBrowserContextOptions(ctx context.Context, opts sobek.Value) (*common.BrowserContextOptions, error) { //nolint:cyclop,funlen,gocognit,lll
if !sobekValueExists(opts) {
return nil, nil //nolint:nilnil
func parseBrowserContextOptions(rt *sobek.Runtime, opts sobek.Value) (*common.BrowserContextOptions, error) {
b := common.DefaultBrowserContextOptions()
if err := mergeWith(rt, b, opts); err != nil {
return nil, err
}

b := common.NewBrowserContextOptions()

rt := k6ext.Runtime(ctx)
o := opts.ToObject(rt)
for _, k := range o.Keys() {
switch k {
case "acceptDownloads":
b.AcceptDownloads = o.Get(k).ToBoolean()
case "downloadsPath":
b.DownloadsPath = o.Get(k).String()
case "bypassCSP":
b.BypassCSP = o.Get(k).ToBoolean()
case "colorScheme":
switch common.ColorScheme(o.Get(k).String()) { //nolint:exhaustive
case "light":
b.ColorScheme = common.ColorSchemeLight
case "dark":
b.ColorScheme = common.ColorSchemeDark
default:
b.ColorScheme = common.ColorSchemeNoPreference
}
case "deviceScaleFactor":
b.DeviceScaleFactor = o.Get(k).ToFloat()
case "extraHTTPHeaders":
headers := o.Get(k).ToObject(rt)
for _, k := range headers.Keys() {
b.ExtraHTTPHeaders[k] = headers.Get(k).String()
}
case "geolocation":
gl, err := exportTo[*common.Geolocation](rt, o.Get(k))
if err != nil {
return nil, fmt.Errorf("parsing geolocation options: %w", err)
}
b.Geolocation = gl
case "hasTouch":
b.HasTouch = o.Get(k).ToBoolean()
case "httpCredentials":
var err error
b.HTTPCredentials, err = exportTo[common.Credentials](rt, o.Get(k))
if err != nil {
return nil, fmt.Errorf("parsing HTTP credential options: %w", err)
}
case "ignoreHTTPSErrors":
b.IgnoreHTTPSErrors = o.Get(k).ToBoolean()
case "isMobile":
b.IsMobile = o.Get(k).ToBoolean()
case "javaScriptEnabled":
b.JavaScriptEnabled = o.Get(k).ToBoolean()
case "locale":
b.Locale = o.Get(k).String()
case "offline":
b.Offline = o.Get(k).ToBoolean()
case "permissions":
var err error
b.Permissions, err = exportTo[[]string](rt, o.Get(k))
if err != nil {
return nil, fmt.Errorf("parsing permissions options: %w", err)
}
case "reducedMotion":
switch common.ReducedMotion(o.Get(k).String()) { //nolint:exhaustive
case "reduce":
b.ReducedMotion = common.ReducedMotionReduce
default:
b.ReducedMotion = common.ReducedMotionNoPreference
}
case "screen":
var err error
b.Screen, err = exportTo[common.Screen](rt, o.Get(k))
if err != nil {
return nil, fmt.Errorf("parsing screen options: %w", err)
}
case "timezoneID":
b.TimezoneID = o.Get(k).String()
case "userAgent":
b.UserAgent = o.Get(k).String()
case "viewport":
var err error
b.Viewport, err = exportTo[common.Viewport](rt, o.Get(k))
if err != nil {
return nil, fmt.Errorf("parsing viewport options: %w", err)
}
}
}

return b, nil
}
8 changes: 8 additions & 0 deletions browser/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ func panicIfFatalError(ctx context.Context, err error) {
}
}

// mergeWith merges the Sobek value with the existing Go value.
func mergeWith[T any](rt *sobek.Runtime, src T, v sobek.Value) error {
if !sobekValueExists(v) {
return nil
}
return rt.ExportTo(v, &src) //nolint:wrapcheck
}

// exportTo exports the Sobek value to a Go value.
// It returns the zero value of T if obj does not exist in the Sobek runtime.
// It's caller's responsibility to check for nilness.
Expand Down
4 changes: 2 additions & 2 deletions browser/sync_browser_mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func syncMapBrowser(vu moduleVU) mapping { //nolint:funlen,cyclop
return b.IsConnected(), nil
},
"newContext": func(opts sobek.Value) (*sobek.Object, error) {
popts, err := parseBrowserContextOptions(vu.Context(), opts)
popts, err := parseBrowserContextOptions(vu.Runtime(), opts)
if err != nil {
return nil, fmt.Errorf("parsing browser.newContext options: %w", err)
}
Expand Down Expand Up @@ -69,7 +69,7 @@ func syncMapBrowser(vu moduleVU) mapping { //nolint:funlen,cyclop
return b.Version(), nil
},
"newPage": func(opts sobek.Value) (mapping, error) {
popts, err := parseBrowserContextOptions(vu.Context(), opts)
popts, err := parseBrowserContextOptions(vu.Runtime(), opts)
if err != nil {
return nil, fmt.Errorf("parsing browser.newPage options: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion common/browser.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ func (b *Browser) connect() error {
}

// We don't need to lock this because `connect()` is called only in NewBrowser
b.defaultContext, err = NewBrowserContext(b.vuCtx, b, "", NewBrowserContextOptions(), b.logger)
b.defaultContext, err = NewBrowserContext(b.vuCtx, b, "", DefaultBrowserContextOptions(), b.logger)
if err != nil {
return fmt.Errorf("browser connect: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion common/browser_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func NewBrowserContext(
) (*BrowserContext, error) {
// set the default options if none provided.
if opts == nil {
opts = NewBrowserContextOptions()
opts = DefaultBrowserContextOptions()
}

b := BrowserContext{
Expand Down
4 changes: 2 additions & 2 deletions common/browser_context_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ type BrowserContextOptions struct {
Viewport Viewport `js:"viewport"`
}

// NewBrowserContextOptions creates a default set of browser context options.
func NewBrowserContextOptions() *BrowserContextOptions {
// DefaultBrowserContextOptions returns the default browser context options.
func DefaultBrowserContextOptions() *BrowserContextOptions {
return &BrowserContextOptions{
ColorScheme: ColorSchemeLight,
DeviceScaleFactor: 1.0,
Expand Down
6 changes: 3 additions & 3 deletions tests/browser_context_options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
func TestBrowserContextOptionsDefaultValues(t *testing.T) {
t.Parallel()

opts := common.NewBrowserContextOptions()
opts := common.DefaultBrowserContextOptions()
assert.False(t, opts.AcceptDownloads)
assert.Empty(t, opts.DownloadsPath)
assert.False(t, opts.BypassCSP)
Expand Down Expand Up @@ -52,7 +52,7 @@ func TestBrowserContextOptionsSetViewport(t *testing.T) {
t.Parallel()

tb := newTestBrowser(t)
opts := common.NewBrowserContextOptions()
opts := common.DefaultBrowserContextOptions()
opts.Viewport = common.Viewport{
Width: 800,
Height: 600,
Expand All @@ -77,7 +77,7 @@ func TestBrowserContextOptionsExtraHTTPHeaders(t *testing.T) {

tb := newTestBrowser(t, withHTTPServer())

opts := common.NewBrowserContextOptions()
opts := common.DefaultBrowserContextOptions()
opts.ExtraHTTPHeaders = map[string]string{
"Some-Header": "Some-Value",
}
Expand Down
2 changes: 1 addition & 1 deletion tests/element_handle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ func TestElementHandleClickConcealedLink(t *testing.T) {

tb := newTestBrowser(t, withFileServer())

bcopts := common.NewBrowserContextOptions()
bcopts := common.DefaultBrowserContextOptions()
bcopts.Viewport = common.Viewport{
Width: 500,
Height: 240,
Expand Down
2 changes: 1 addition & 1 deletion tests/network_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ func TestBasicAuth(t *testing.T) {

browser := newTestBrowser(t, withHTTPServer())

bcopts := common.NewBrowserContextOptions()
bcopts := common.DefaultBrowserContextOptions()
bcopts.HTTPCredentials = common.Credentials{
Username: validUser,
Password: validPassword,
Expand Down
Loading