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

Remove the timeout option from isVisible and isHidden #1111

Merged
merged 9 commits into from
Nov 28, 2023
12 changes: 6 additions & 6 deletions common/element_handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -382,12 +382,12 @@ func (h *ElementHandle) isEnabled(apiCtx context.Context, timeout time.Duration)
return h.waitForElementState(apiCtx, []string{"enabled"}, timeout)
}

func (h *ElementHandle) isHidden(apiCtx context.Context, timeout time.Duration) (bool, error) {
return h.waitForElementState(apiCtx, []string{"hidden"}, timeout)
func (h *ElementHandle) isHidden(apiCtx context.Context) (bool, error) {
return h.waitForElementState(apiCtx, []string{"hidden"}, 0)
}

func (h *ElementHandle) isVisible(apiCtx context.Context, timeout time.Duration) (bool, error) {
return h.waitForElementState(apiCtx, []string{"visible"}, timeout)
func (h *ElementHandle) isVisible(apiCtx context.Context) (bool, error) {
return h.waitForElementState(apiCtx, []string{"visible"}, 0)
}

func (h *ElementHandle) offsetPosition(apiCtx context.Context, offset *Position) (*Position, error) {
Expand Down Expand Up @@ -949,7 +949,7 @@ func (h *ElementHandle) IsEnabled() bool {

// IsHidden checks if the element is hidden.
func (h *ElementHandle) IsHidden() bool {
result, err := h.isHidden(h.ctx, 0)
result, err := h.isHidden(h.ctx)
if err != nil && !errors.Is(err, ErrTimedOut) { // We don't care anout timeout errors here!
k6ext.Panic(h.ctx, "checking element is hidden: %w", err)
}
Expand All @@ -958,7 +958,7 @@ func (h *ElementHandle) IsHidden() bool {

// IsVisible checks if the element is visible.
func (h *ElementHandle) IsVisible() bool {
result, err := h.isVisible(h.ctx, 0)
result, err := h.isVisible(h.ctx)
if err != nil && !errors.Is(err, ErrTimedOut) { // We don't care anout timeout errors here!
k6ext.Panic(h.ctx, "checking element is visible: %w", err)
}
Expand Down
12 changes: 6 additions & 6 deletions common/frame.go
Original file line number Diff line number Diff line change
Expand Up @@ -1245,7 +1245,7 @@ func (f *Frame) isDisabled(selector string, opts *FrameIsDisabledOptions) (bool,
func (f *Frame) IsHidden(selector string, opts goja.Value) (bool, error) {
f.log.Debugf("Frame:IsHidden", "fid:%s furl:%q sel:%q", f.ID(), f.URL(), selector)

popts := NewFrameIsHiddenOptions(f.defaultTimeout())
popts := NewFrameIsHiddenOptions()
if err := popts.Parse(f.ctx, opts); err != nil {
return false, fmt.Errorf("parsing is hidden options: %w", err)
}
Expand All @@ -1259,8 +1259,8 @@ func (f *Frame) IsHidden(selector string, opts goja.Value) (bool, error) {

func (f *Frame) isHidden(selector string, opts *FrameIsHiddenOptions) (bool, error) {
isHidden := func(apiCtx context.Context, handle *ElementHandle) (any, error) {
v, err := handle.isHidden(apiCtx, 0) // Zero timeout when checking state
if errors.Is(err, ErrTimedOut) { // We don't care about timeout errors here!
v, err := handle.isHidden(apiCtx) // Zero timeout when checking state
if errors.Is(err, ErrTimedOut) { // We don't care about timeout errors here!
return v, nil
}
return v, err
Expand All @@ -1278,7 +1278,7 @@ func (f *Frame) isHidden(selector string, opts *FrameIsHiddenOptions) (bool, err
func (f *Frame) IsVisible(selector string, opts goja.Value) (bool, error) {
f.log.Debugf("Frame:IsVisible", "fid:%s furl:%q sel:%q", f.ID(), f.URL(), selector)

popts := NewFrameIsVisibleOptions(f.defaultTimeout())
popts := NewFrameIsVisibleOptions()
if err := popts.Parse(f.ctx, opts); err != nil {
return false, fmt.Errorf("parsing is visible options: %w", err)
}
Expand All @@ -1292,8 +1292,8 @@ func (f *Frame) IsVisible(selector string, opts goja.Value) (bool, error) {

func (f *Frame) isVisible(selector string, opts *FrameIsVisibleOptions) (bool, error) {
isVisible := func(apiCtx context.Context, handle *ElementHandle) (any, error) {
v, err := handle.isVisible(apiCtx, 0) // Zero timeout when checking state
if errors.Is(err, ErrTimedOut) { // We don't care about timeout errors here!
v, err := handle.isVisible(apiCtx) // Zero timeout when checking state
if errors.Is(err, ErrTimedOut) { // We don't care about timeout errors here!
return v, nil
}
return v, err
Expand Down
119 changes: 33 additions & 86 deletions common/frame_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,11 @@ type FrameIsEnabledOptions struct {
}

type FrameIsHiddenOptions struct {
FrameBaseOptions
Strict bool `json:"strict"`
}

type FrameIsVisibleOptions struct {
FrameBaseOptions
Strict bool `json:"strict"`
}

type FramePressOptions struct {
Expand Down Expand Up @@ -223,19 +223,10 @@ func NewFrameCheckOptions(defaultTimeout time.Duration) *FrameCheckOptions {
}

func (o *FrameCheckOptions) Parse(ctx context.Context, opts goja.Value) error {
rt := k6ext.Runtime(ctx)
if err := o.ElementHandleBasePointerOptions.Parse(ctx, opts); err != nil {
return err
}
if opts != nil && !goja.IsUndefined(opts) && !goja.IsNull(opts) {
opts := opts.ToObject(rt)
for _, k := range opts.Keys() {
switch k {
case "strict":
o.Strict = opts.Get(k).ToBoolean()
}
}
}
o.Strict = parseStrict(ctx, opts)
return nil
}

Expand All @@ -247,19 +238,10 @@ func NewFrameClickOptions(defaultTimeout time.Duration) *FrameClickOptions {
}

func (o *FrameClickOptions) Parse(ctx context.Context, opts goja.Value) error {
rt := k6ext.Runtime(ctx)
if err := o.ElementHandleClickOptions.Parse(ctx, opts); err != nil {
return err
}
if opts != nil && !goja.IsUndefined(opts) && !goja.IsNull(opts) {
opts := opts.ToObject(rt)
for _, k := range opts.Keys() {
switch k {
case "strict":
o.Strict = opts.Get(k).ToBoolean()
}
}
}
o.Strict = parseStrict(ctx, opts)
return nil
}

Expand All @@ -271,19 +253,10 @@ func NewFrameDblClickOptions(defaultTimeout time.Duration) *FrameDblclickOptions
}

func (o *FrameDblclickOptions) Parse(ctx context.Context, opts goja.Value) error {
rt := k6ext.Runtime(ctx)
if err := o.ElementHandleDblclickOptions.Parse(ctx, opts); err != nil {
return err
}
if opts != nil && !goja.IsUndefined(opts) && !goja.IsNull(opts) {
opts := opts.ToObject(rt)
for _, k := range opts.Keys() {
switch k {
case "strict":
o.Strict = opts.Get(k).ToBoolean()
}
}
}
o.Strict = parseStrict(ctx, opts)
return nil
}

Expand All @@ -295,19 +268,10 @@ func NewFrameFillOptions(defaultTimeout time.Duration) *FrameFillOptions {
}

func (o *FrameFillOptions) Parse(ctx context.Context, opts goja.Value) error {
rt := k6ext.Runtime(ctx)
if err := o.ElementHandleBaseOptions.Parse(ctx, opts); err != nil {
return err
}
if opts != nil && !goja.IsUndefined(opts) && !goja.IsNull(opts) {
opts := opts.ToObject(rt)
for _, k := range opts.Keys() {
switch k {
case "strict":
o.Strict = opts.Get(k).ToBoolean()
}
}
}
o.Strict = parseStrict(ctx, opts)
return nil
}

Expand Down Expand Up @@ -348,19 +312,10 @@ func NewFrameHoverOptions(defaultTimeout time.Duration) *FrameHoverOptions {
}

func (o *FrameHoverOptions) Parse(ctx context.Context, opts goja.Value) error {
rt := k6ext.Runtime(ctx)
if err := o.ElementHandleHoverOptions.Parse(ctx, opts); err != nil {
return err
}
if opts != nil && !goja.IsUndefined(opts) && !goja.IsNull(opts) {
opts := opts.ToObject(rt)
for _, k := range opts.Keys() {
switch k {
case "strict":
o.Strict = opts.Get(k).ToBoolean()
}
}
}
o.Strict = parseStrict(ctx, opts)
return nil
}

Expand Down Expand Up @@ -455,29 +410,23 @@ func (o *FrameIsEnabledOptions) Parse(ctx context.Context, opts goja.Value) erro
return nil
}

func NewFrameIsHiddenOptions(defaultTimeout time.Duration) *FrameIsHiddenOptions {
return &FrameIsHiddenOptions{
FrameBaseOptions: *NewFrameBaseOptions(defaultTimeout),
}
// NewFrameIsHiddenOptions creates and returns a new instance of FrameIsHiddenOptions.
func NewFrameIsHiddenOptions() *FrameIsHiddenOptions {
return &FrameIsHiddenOptions{}
}

func (o *FrameIsHiddenOptions) Parse(ctx context.Context, opts goja.Value) error {
if err := o.FrameBaseOptions.Parse(ctx, opts); err != nil {
return err
}
o.Strict = parseStrict(ctx, opts)
return nil
}

func NewFrameIsVisibleOptions(defaultTimeout time.Duration) *FrameIsVisibleOptions {
return &FrameIsVisibleOptions{
FrameBaseOptions: *NewFrameBaseOptions(defaultTimeout),
}
// NewFrameIsVisibleOptions creates and returns a new instance of FrameIsVisibleOptions.
func NewFrameIsVisibleOptions() *FrameIsVisibleOptions {
return &FrameIsVisibleOptions{}
}

func (o *FrameIsVisibleOptions) Parse(ctx context.Context, opts goja.Value) error {
if err := o.FrameBaseOptions.Parse(ctx, opts); err != nil {
return err
}
o.Strict = parseStrict(ctx, opts)
return nil
}

Expand All @@ -502,19 +451,10 @@ func NewFrameSelectOptionOptions(defaultTimeout time.Duration) *FrameSelectOptio
}

func (o *FrameSelectOptionOptions) Parse(ctx context.Context, opts goja.Value) error {
rt := k6ext.Runtime(ctx)
if err := o.ElementHandleBaseOptions.Parse(ctx, opts); err != nil {
return err
}
if opts != nil && !goja.IsUndefined(opts) && !goja.IsNull(opts) {
opts := opts.ToObject(rt)
for _, k := range opts.Keys() {
switch k {
case "strict":
o.Strict = opts.Get(k).ToBoolean()
}
}
}
o.Strict = parseStrict(ctx, opts)
return nil
}

Expand Down Expand Up @@ -611,19 +551,10 @@ func NewFrameUncheckOptions(defaultTimeout time.Duration) *FrameUncheckOptions {
}

func (o *FrameUncheckOptions) Parse(ctx context.Context, opts goja.Value) error {
rt := k6ext.Runtime(ctx)
if err := o.ElementHandleBasePointerOptions.Parse(ctx, opts); err != nil {
return err
}
if opts != nil && !goja.IsUndefined(opts) && !goja.IsNull(opts) {
opts := opts.ToObject(rt)
for _, k := range opts.Keys() {
switch k {
case "strict":
o.Strict = opts.Get(k).ToBoolean()
}
}
}
o.Strict = parseStrict(ctx, opts)
return nil
}

Expand Down Expand Up @@ -761,3 +692,19 @@ func NewFrameDispatchEventOptions(defaultTimeout time.Duration) *FrameDispatchEv
FrameBaseOptions: NewFrameBaseOptions(defaultTimeout),
}
}

func parseStrict(ctx context.Context, opts goja.Value) bool {
var strict bool

rt := k6ext.Runtime(ctx)
if opts != nil && !goja.IsUndefined(opts) && !goja.IsNull(opts) {
opts := opts.ToObject(rt)
for _, k := range opts.Keys() {
if k == "strict" {
strict = opts.Get(k).ToBoolean()
}
}
}

return strict
}
38 changes: 8 additions & 30 deletions common/locator.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,52 +233,30 @@ func (l *Locator) isDisabled(opts *FrameIsDisabledOptions) (bool, error) {

// IsVisible returns true if the element matches the locator's
// selector and is visible. Otherwise, returns false.
func (l *Locator) IsVisible(opts goja.Value) bool {
l.log.Debugf("Locator:IsVisible", "fid:%s furl:%q sel:%q opts:%+v", l.frame.ID(), l.frame.URL(), l.selector, opts)
func (l *Locator) IsVisible() (bool, error) {
l.log.Debugf("Locator:IsVisible", "fid:%s furl:%q sel:%q", l.frame.ID(), l.frame.URL(), l.selector)

copts := NewFrameIsVisibleOptions(l.frame.defaultTimeout())
if err := copts.Parse(l.ctx, opts); err != nil {
k6ext.Panic(l.ctx, "parsing is visible options: %w", err)
}
visible, err := l.isVisible(copts)
visible, err := l.frame.isVisible(l.selector, &FrameIsVisibleOptions{Strict: true})
if err != nil {
k6ext.Panic(l.ctx, "checking is %q visible: %w", l.selector, err)
return false, fmt.Errorf("checking is %q visible: %w", l.selector, err)
}

return visible
}

// isVisible is like IsVisible but takes parsed options and does not
// throw an error.
func (l *Locator) isVisible(opts *FrameIsVisibleOptions) (bool, error) {
opts.Strict = true
return l.frame.isVisible(l.selector, opts)
return visible, nil
}

// IsHidden returns true if the element matches the locator's
// selector and is hidden. Otherwise, returns false.
func (l *Locator) IsHidden(opts goja.Value) (bool, error) {
l.log.Debugf("Locator:IsHidden", "fid:%s furl:%q sel:%q opts:%+v", l.frame.ID(), l.frame.URL(), l.selector, opts)
func (l *Locator) IsHidden() (bool, error) {
l.log.Debugf("Locator:IsHidden", "fid:%s furl:%q sel:%q", l.frame.ID(), l.frame.URL(), l.selector)

copts := NewFrameIsHiddenOptions(l.frame.defaultTimeout())
if err := copts.Parse(l.ctx, opts); err != nil {
return false, fmt.Errorf("parsing is hidden options: %w", err)
}
hidden, err := l.isHidden(copts)
hidden, err := l.frame.isHidden(l.selector, &FrameIsHiddenOptions{Strict: true})
if err != nil {
return false, fmt.Errorf("checking is %q hidden: %w", l.selector, err)
}

return hidden, nil
}

// isHidden is like IsHidden but takes parsed options and does not
// throw an error.
func (l *Locator) isHidden(opts *FrameIsHiddenOptions) (bool, error) {
opts.Strict = true
return l.frame.isHidden(l.selector, opts)
}

// Fill out the element using locator's selector with strict mode on.
func (l *Locator) Fill(value string, opts goja.Value) {
l.log.Debugf(
Expand Down
4 changes: 2 additions & 2 deletions tests/locator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ func TestLocatorElementState(t *testing.T) {
{
"hidden",
`() => document.getElementById('inputText').style.visibility = 'hidden'`,
func(l *common.Locator) bool { resp, _ := l.IsHidden(nil); return !resp },
func(l *common.Locator) bool { resp, _ := l.IsHidden(); return !resp },
},
{
"readOnly",
Expand All @@ -354,7 +354,7 @@ func TestLocatorElementState(t *testing.T) {
{
"visible",
`() => document.getElementById('inputText').style.visibility = 'hidden'`,
func(l *common.Locator) bool { return l.IsVisible(nil) },
func(l *common.Locator) bool { resp, _ := l.IsVisible(); return resp },
},
}

Expand Down
8 changes: 2 additions & 6 deletions tests/page_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1270,9 +1270,7 @@ func TestPageIsVisible(t *testing.T) {
name: "first_div",
selector: "div",
options: common.FrameIsVisibleOptions{
FrameBaseOptions: common.FrameBaseOptions{
Strict: true,
},
Strict: true,
},
wantErr: "error:strictmodeviolation",
},
Expand Down Expand Up @@ -1337,9 +1335,7 @@ func TestPageIsHidden(t *testing.T) {
name: "first_div",
selector: "div",
options: common.FrameIsVisibleOptions{
FrameBaseOptions: common.FrameBaseOptions{
Strict: true,
},
Strict: true,
},
wantErr: "error:strictmodeviolation",
},
Expand Down