Skip to content
Open
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
30 changes: 30 additions & 0 deletions internal/js/modules/k6/browser/common/frame.go
Original file line number Diff line number Diff line change
Expand Up @@ -1573,6 +1573,36 @@ func (f *Frame) isVisible(selector string, opts *FrameIsVisibleOptions) (bool, e
return v, nil
}


// isInViewport finds the element specified by the selector and checks if it's in the viewport.
func (f *Frame) isInViewport(selector string, strict bool) (bool, error) {
isInViewportAction := func(ctx context.Context, handle *ElementHandle) (any, error) {
script := `(function() {
if (!this) return false;
const rect = this.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
})()`

opts := evalOptions{
forceCallable: true,
returnByValue: true,
}
return handle.eval(ctx, opts, script)
}

v, err := f.runActionOnSelector(f.ctx, selector, strict, isInViewportAction, func() bool { return false })
if err != nil {
return false, err
}

return v, nil
}

// ID returns the frame id.
func (f *Frame) ID() string {
f.propertiesMu.RLock()
Expand Down
20 changes: 19 additions & 1 deletion internal/js/modules/k6/browser/common/locator.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
"fmt"
"strconv"
"time"
"strings"
"github.com/grafana/sobek"

Check failure on line 9 in internal/js/modules/k6/browser/common/locator.go

View workflow job for this annotation

GitHub Actions / test-latest (1.25.x, ubuntu-24.04-arm)

"github.com/grafana/sobek" imported and not used

Check failure on line 9 in internal/js/modules/k6/browser/common/locator.go

View workflow job for this annotation

GitHub Actions / test-latest (1.25.x, ubuntu-22.04)

"github.com/grafana/sobek" imported and not used

Check failure on line 9 in internal/js/modules/k6/browser/common/locator.go

View workflow job for this annotation

GitHub Actions / test-latest (1.25.x, windows-latest)

"github.com/grafana/sobek" imported and not used

Check failure on line 9 in internal/js/modules/k6/browser/common/locator.go

View workflow job for this annotation

GitHub Actions / test (stable, windows-latest)

"github.com/grafana/sobek" imported and not used

Check failure on line 9 in internal/js/modules/k6/browser/common/locator.go

View workflow job for this annotation

GitHub Actions / test (stable, ubuntu-latest)

"github.com/grafana/sobek" imported and not used

Check failure on line 9 in internal/js/modules/k6/browser/common/locator.go

View workflow job for this annotation

GitHub Actions / test (tip, macos-latest)

"github.com/grafana/sobek" imported and not used

Check failure on line 9 in internal/js/modules/k6/browser/common/locator.go

View workflow job for this annotation

GitHub Actions / test (stable, macos-latest)

"github.com/grafana/sobek" imported and not used

Check failure on line 9 in internal/js/modules/k6/browser/common/locator.go

View workflow job for this annotation

GitHub Actions / test (tip, ubuntu-24.04-arm)

"github.com/grafana/sobek" imported and not used

Check failure on line 9 in internal/js/modules/k6/browser/common/locator.go

View workflow job for this annotation

GitHub Actions / test (stable, ubuntu-24.04-arm)

"github.com/grafana/sobek" imported and not used

Check failure on line 9 in internal/js/modules/k6/browser/common/locator.go

View workflow job for this annotation

GitHub Actions / test (tip, ubuntu-latest)

"github.com/grafana/sobek" imported and not used

Check failure on line 9 in internal/js/modules/k6/browser/common/locator.go

View workflow job for this annotation

GitHub Actions / test (tip, windows-latest)

"github.com/grafana/sobek" imported and not used

Check failure on line 9 in internal/js/modules/k6/browser/common/locator.go

View workflow job for this annotation

GitHub Actions / lint

"github.com/grafana/sobek" imported and not used) (typecheck)

Check failure on line 9 in internal/js/modules/k6/browser/common/locator.go

View workflow job for this annotation

GitHub Actions / build

"github.com/grafana/sobek" imported and not used

"go.k6.io/k6/internal/js/modules/k6/browser/log"
)
Expand Down Expand Up @@ -273,7 +275,23 @@
return visible, nil
}

// IsHidden returns true if the element matches the locator's



func (l *Locator) IsInViewport() (bool, error) {
l.log.Debugf("Locator:IsInViewport", "fid:%s furl:%q sel:%q", l.frame.ID(), l.frame.URL(), l.selector)

visible, err := l.frame.isInViewport(l.selector, true)
if err != nil {
if strings.Contains(err.Error(), "failed to find element") || strings.Contains(err.Error(), "strict mode violation") {
return false, nil
}
return false, fmt.Errorf("checking is %q in viewport: %w", l.selector, err)
}

return visible, nil
}

// selector and is hidden. Otherwise, returns false.
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)
Expand Down
37 changes: 37 additions & 0 deletions internal/js/modules/k6/browser/tests/frame_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,3 +394,40 @@ func TestFrameWaitForURLFailure(t *testing.T) {
})
}
}



Comment on lines +397 to +399
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove these extra lines.

func TestFrameElementIsInViewport(t *testing.T) {
t.Parallel()

tb := newTestBrowser(t)
p := tb.NewPage(nil)

err := p.SetContent(`
<a id="top-link" href="#bottom-div">Go to Bottom</a>
<div id="bottom-div" style="margin-top: 2000px;">I am at the bottom</div>
`, nil)
require.NoError(t, err)

mainFrame := p.MainFrame()

bottomLocator := mainFrame.Locator("#bottom-div")

inViewport, err := bottomLocator.IsInViewport()
require.NoError(t, err)
require.False(t, inViewport, "the bottom element should not be in the viewport initially")

topLocator := mainFrame.Locator("#top-link")

clickOpts := common.NewFrameClickOptions(mainFrame.Timeout())
err = topLocator.Click(clickOpts)
require.NoError(t, err)

waitOpts := common.NewFrameWaitForSelectorOptions(mainFrame.Timeout(), common.DOMElementStateVisible)
_, err = mainFrame.WaitForSelector("#bottom-div", waitOpts)
require.NoError(t, err, "waiting for #bottom-div to become visible after scroll")

inViewport, err = bottomLocator.IsInViewport()
require.NoError(t, err)
require.True(t, inViewport, "the bottom element should be in the viewport after clicking the anchor link")
}
Loading