Skip to content

Commit

Permalink
fixes panic for the selectOption
Browse files Browse the repository at this point in the history
  • Loading branch information
olegbespalov committed Nov 28, 2024
1 parent 0fbb4c7 commit cdc2413
Show file tree
Hide file tree
Showing 4 changed files with 320 additions and 31 deletions.
105 changes: 74 additions & 31 deletions common/element_handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import (
"github.com/chromedp/cdproto/dom"
cdppage "github.com/chromedp/cdproto/page"
"github.com/grafana/sobek"
"go.opentelemetry.io/otel/attribute"

"github.com/grafana/xk6-browser/common/js"
"github.com/grafana/xk6-browser/k6ext"
k6common "go.k6.io/k6/js/common"
"go.opentelemetry.io/otel/attribute"
)

const (
Expand Down Expand Up @@ -479,7 +479,7 @@ func (h *ElementHandle) press(apiCtx context.Context, key string, opts KeyboardO
//nolint:funlen,gocognit,cyclop
func (h *ElementHandle) selectOption(apiCtx context.Context, values sobek.Value) (any, error) {
convertSelectOptionValues := func(values sobek.Value) ([]any, error) {
if sobek.IsNull(values) || sobek.IsUndefined(values) {
if k6common.IsNullish(values) {
return nil, nil
}

Expand All @@ -489,38 +489,41 @@ func (h *ElementHandle) selectOption(apiCtx context.Context, values sobek.Value)
rt = h.execCtx.vu.Runtime()
)
switch values.ExportType().Kind() {
case reflect.Map:
s := reflect.ValueOf(t)
for i := 0; i < s.Len(); i++ {
item := s.Index(i)
switch item.Kind() {
case reflect.TypeOf(nil).Kind():
return nil, fmt.Errorf("options[%d]: expected object, got null", i)
case reflect.TypeOf(&ElementHandle{}).Kind():
opts = append(opts, t.(*ElementHandle))
case reflect.TypeOf(sobek.Object{}).Kind():
obj := values.ToObject(rt)
opt := SelectOption{}
for _, k := range obj.Keys() {
switch k {
case "value":
opt.Value = new(string)
*opt.Value = obj.Get(k).String()
case "label":
opt.Label = new(string)
*opt.Label = obj.Get(k).String()
case "index":
opt.Index = new(int64)
*opt.Index = obj.Get(k).ToInteger()
}
}
opts = append(opts, &opt)
case reflect.String:
case reflect.Slice:
var sl []interface{}
if err := rt.ExportTo(values, &sl); err != nil {
return nil, fmt.Errorf("options: expected array, got %T", values)
}

for _, item := range sl {
switch item := item.(type) {
case string:
opt := SelectOption{Value: new(string)}
*opt.Value = item.String()
*opt.Value = item
opts = append(opts, &opt)
case map[string]interface{}:
opt, err := extractSelectOptionFromMap(item)
if err != nil {
return nil, err
}

opts = append(opts, opt)
default:
return nil, fmt.Errorf("options: expected string or object, got %T", item)
}
}
case reflect.Map:
var raw map[string]interface{}
if err := rt.ExportTo(values, &raw); err != nil {
return nil, fmt.Errorf("options: expected object, got %T", values)
}

opt, err := extractSelectOptionFromMap(raw)
if err != nil {
return nil, err
}

opts = append(opts, opt)
case reflect.TypeOf(&ElementHandle{}).Kind():
opts = append(opts, t.(*ElementHandle))
case reflect.TypeOf(sobek.Object{}).Kind():
Expand All @@ -544,6 +547,8 @@ func (h *ElementHandle) selectOption(apiCtx context.Context, values sobek.Value)
opt := SelectOption{Value: new(string)}
*opt.Value = t.(string)
opts = append(opts, &opt)
default:
return nil, fmt.Errorf("options: unsupported type %T", values)
}

return opts, nil
Expand Down Expand Up @@ -575,6 +580,44 @@ func (h *ElementHandle) selectOption(apiCtx context.Context, values sobek.Value)
return result, nil
}

func extractSelectOptionFromMap(v map[string]interface{}) (*SelectOption, error) {
opt := &SelectOption{}
for k, raw := range v {
switch k {
case "value":
opt.Value = new(string)

v, ok := raw.(string)
if !ok {
return nil, fmt.Errorf("options[%v]: expected string, got %T", k, raw)
}

*opt.Value = v
case "label":
opt.Label = new(string)

v, ok := raw.(string)
if !ok {
return nil, fmt.Errorf("options[%v]: expected string, got %T", k, raw)
}
*opt.Label = v
case "index":
opt.Index = new(int64)

switch raw := raw.(type) {
case int:
*opt.Index = int64(raw)
case int64:
*opt.Index = raw
default:
return nil, fmt.Errorf("options[%v]: expected int, got %T", k, raw)
}
}
}

return opt, nil
}

func (h *ElementHandle) selectText(apiCtx context.Context) error {
fn := `
(node, injected) => {
Expand Down
56 changes: 56 additions & 0 deletions common/tests/cmd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package tests

import (
"bytes"
"testing"

"github.com/stretchr/testify/assert"

"go.k6.io/k6/cmd"
k6tests "go.k6.io/k6/cmd/tests"
)

func TestCmd(t *testing.T) {
t.Skip("data race")

t.Parallel()

ts := k6tests.NewGlobalTestState(t)

ts.CmdArgs = []string{
"k6", "run", "-",
}
ts.Stdin = bytes.NewBufferString(`
import { browser } from 'k6/browser';
export const options = {
scenarios: {
browser: {
executor: 'shared-iterations',
options: {
browser: {
type: 'chromium',
},
},
},
},
};
export default async function () {
const page = await browser.newPage();
await page.goto('https://test.k6.io/browser.php');
const options = page.locator('#numbers-options');
await options.selectOption({label:'Five'});
await options.selectOption({index:5});
await options.selectOption({value:'five'});
await options.selectOption({label:'Five'});
await options.selectOption('Five'); // Value or label
await options.selectOption([{label:'Five'}]);
await options.selectOption(['Five']); // Value or label
}
`)
cmd.ExecuteWithGlobalState(ts.GlobalState)

assert.Empty(t, ts.Stderr.String())
}
35 changes: 35 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -20,49 +20,84 @@ require (
)

require (
buf.build/gen/go/gogo/protobuf/protocolbuffers/go v1.31.0-20210810001428-4df00b267f94.1 // indirect
buf.build/gen/go/prometheus/prometheus/protocolbuffers/go v1.31.0-20230627135113-9a12bc2590d2.1 // indirect
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
github.com/PuerkitoBio/goquery v1.9.2 // indirect
github.com/Soontao/goHttpDigestClient v0.0.0-20170320082612-6d28bb1415c5 // indirect
github.com/andybalholm/brotli v1.1.1 // indirect
github.com/andybalholm/cascadia v1.3.2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bufbuild/protocompile v0.14.1 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/chromedp/sysutil v1.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dlclark/regexp2 v1.11.4 // indirect
github.com/evanw/esbuild v0.21.2 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/pprof v0.0.0-20230728192033-2ba5b33183c6 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grafana/xk6-dashboard v0.7.5 // indirect
github.com/grafana/xk6-output-opentelemetry v0.3.0 // indirect
github.com/grafana/xk6-output-prometheus-remote v0.5.0 // indirect
github.com/grafana/xk6-redis v0.3.1 // indirect
github.com/grafana/xk6-webcrypto v0.5.0 // indirect
github.com/grafana/xk6-websockets v0.7.2 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/influxdata/influxdb1-client v0.0.0-20190402204710-8ff2fc3824fc // indirect
github.com/jhump/protoreflect v1.17.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mstoykov/atlas v0.0.0-20220811071828-388f114305dd // indirect
github.com/mstoykov/envconfig v1.5.0 // indirect
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.16.0 // indirect
github.com/prometheus/client_model v0.4.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.10.1 // indirect
github.com/r3labs/sse/v2 v2.10.0 // indirect
github.com/redis/go-redis/v9 v9.0.5 // indirect
github.com/serenize/snaker v0.0.0-20201027110005-a7ad2135616e // indirect
github.com/spf13/afero v1.1.2 // indirect
github.com/spf13/cobra v1.4.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/tidwall/gjson v1.18.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0 // indirect
go.opentelemetry.io/otel/metric v1.29.0 // indirect
go.opentelemetry.io/otel/sdk v1.29.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.28.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
go.uber.org/goleak v1.3.0 // indirect
golang.org/x/crypto v0.28.0 // indirect
golang.org/x/crypto/x509roots/fallback v0.0.0-20240806160748-b2d3a6a4b4d3 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/term v0.25.0 // indirect
golang.org/x/text v0.19.0 // indirect
golang.org/x/time v0.7.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect
google.golang.org/grpc v1.67.1 // indirect
google.golang.org/protobuf v1.35.1 // indirect
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading

0 comments on commit cdc2413

Please sign in to comment.