grafana/k6 · error
finding clickable point
Error message
finding clickable point: %w
What it means
clickablePoint() computes the center of the element from its bounding box before a pointer action; this error means BoundingBox() failed for the element. The wrapped cause is typically ErrElementNotVisible (box model not computable), ErrElementNotAttachedToDOM, or a CDP/session error.
Solutions
- Wait for the element to be actionable before clicking: await el.waitFor({ state: 'visible' }) or use locators, which auto-wait
- Scroll into view first with el.scrollIntoViewIfNeeded()
- If the element is animated, wait for it to finish (wait for opacity/size via el.waitFor() or a custom wait)
- Re-query the element fresh after any navigation instead of reusing an old handle
Example fix
// before
const el = page.locator('.hidden-tab >> text=Save');
await el.click();
// after
await page.locator('.tab-handle').click(); // reveal the tab first
const el = page.locator('.hidden-tab >> text=Save');
await el.waitFor({ state: 'visible' });
await el.click(); Defensive patterns
Strategy: validation
Validate before calling
if (!(await el.isVisible())) {
await el.waitFor({ state: 'visible', timeout: 10_000 });
}
const box = await el.boundingBox();
if (!box || box.width === 0 || box.height === 0) {
throw new Error('element has no clickable area');
} Prevention
- Always waitFor visible before click/hover on lazily shown elements
- Check for zero-size bounding boxes before pointer actions on animated elements
- Re-query elements after navigations; never reuse stale handles
When it happens
Trigger: Calling click/dblclick/hover/check on an element with display:none or visibility:hidden, a zero-size element, an element detached from the DOM between resolution and action, or after the page/target has crashed or navigated away.
Common situations: Clicking buttons in hidden tabs, accordions, or carousel slides; elements behind 'display:none until animation completes'; acting on stale handles grabbed before a navigation; headless environments where fonts/layout differ and the element collapses to 0x0.
Related errors
- finding offset position
- %w: %w
- another element is intercepting with pointer action
- clicking on element
- converting result ( of type %t) to border
AI-assisted analysis of grafana/k6@3fcf5388d7 (2026-08-18).
Data as JSON: /api/errors/987534ecb30297cd.
Report an issue: GitHub.
Appendix: source
Thrown at internal/js/modules/k6/browser/common/element_handle.go:219
case bool:
return &v, nil
}
return nil, fmt.Errorf(
"checking state %q of element %q", state, reflect.TypeOf(result))
}
func (h *ElementHandle) click(p *Position, opts *MouseClickOptions) error {
return h.frame.page.Mouse.click(p.X, p.Y, opts)
}
// This will get the clickable point of the element relative to the page even
// when the element is in an iframe. In some cases this isn't the case and we
// need to translate the point to the page.
func (h *ElementHandle) clickablePoint() (*Position, error) {
r, err := h.BoundingBox()
if err != nil {
return nil, fmt.Errorf("finding clickable point: %w", err)
}
return &Position{X: r.X + r.Width/2, Y: r.Y + r.Height/2}, nil
}
func (h *ElementHandle) dblclick(p *Position, opts *MouseClickOptions) error {
return h.frame.page.Mouse.click(p.X, p.Y, opts)
}
// DefaultTimeout returns the default timeout for this element handle.
// If the receiver or any of the chained fields are nil (which can happen
// when the element handle is no longer attached to a live frame), the
// package-level DefaultTimeout constant is returned instead of panicking.
func (h *ElementHandle) DefaultTimeout() time.Duration {
if h == nil || h.frame == nil || h.frame.manager == nil || h.frame.manager.timeoutSettings == nil {
return DefaultTimeout
}
return h.frame.manager.timeoutSettings.timeout()
}View on GitHub (pinned to 3fcf5388d7)