grafana/k6 · error

clicking on %q: %w

Error message

clicking on %q: %w

What it means

Frame.Click() runs a pointer action that first waits for an element matching the selector to be attached, visible, stable and enabled (per injected_script.js checks) within opts.Timeout, then dispatches mouse events. This error wraps any failure of that pipeline — most commonly a wait timeout ('timed out after Nms' from the injected script) or a DOM error surfaced by errorFromDOMError.

Source

Thrown at internal/js/modules/k6/browser/common/frame.go:609

// ChildFrames returns a list of child frames.
func (f *Frame) ChildFrames() []*Frame {
	f.childFramesMu.RLock()
	defer f.childFramesMu.RUnlock()

	l := make([]*Frame, 0, len(f.childFrames))
	for child := range f.childFrames {
		l = append(l, child)
	}
	return l
}

// Click clicks the first element found that matches selector.
func (f *Frame) Click(selector string, opts *FrameClickOptions) error {
	f.log.Debugf("Frame:Click", "fid:%s furl:%q sel:%q", f.ID(), f.URL(), selector)

	if err := f.click(selector, opts); err != nil {
		return fmt.Errorf("clicking on %q: %w", selector, err)
	}

	applySlowMo(f.ctx)

	return nil
}

func (f *Frame) click(selector string, opts *FrameClickOptions) error {
	click := func(apiCtx context.Context, handle *ElementHandle, p *Position) (any, error) {
		return nil, handle.click(p, opts.ToMouseClickOptions())
	}
	act := f.newPointerAction(
		selector, DOMElementStateAttached, opts.Strict, click, &opts.ElementHandleBasePointerOptions,
	)
	if _, err := call(f.ctx, act, opts.Timeout); err != nil {
		return errorFromDOMError(err)
	}

View on GitHub (pinned to 93accf6570)

Solutions

  1. Wait first: await page.waitForSelector(sel, { state: 'visible', timeout: 30000 }) then click, or pass a larger { timeout: ... } to click itself.
  2. Make the selector unique (data-testid) to avoid strict-mode ambiguity.
  3. Handle overlays: close/dismiss the overlay, or scroll the element into view before clicking.
  4. If the element is intentionally non-actionable in tests, assert with try-catch instead of letting the iteration abort.

Example fix

// before
page.click('#submit'); // fails: button under cookie banner

// after
await page.waitForSelector('#submit', { state: 'visible', timeout: 30000 });
page.click('#submit', { timeout: 30000 });
Defensive patterns

Strategy: validation

Validate before calling

await page.waitForSelector(sel, { state: 'visible', timeout: 30000 });
// optionally verify uniqueness for strict mode:
const n = page.evaluate('(s) => document.querySelectorAll(s).length', sel);

Try / catch

try {
  page.click(sel, { timeout: 30000 });
} catch (e) {
  if (/timed out/.test(e.message)) { /* retry or mark element-not-ready */ }
  throw e;
}

Prevention

When it happens

Trigger: Selector matches nothing, matches multiple elements with strict:true, or the element stays hidden/covered by an overlay (cookie banner, spinner) so actionability checks time out; opts.Timeout set lower than render time; navigation destroys the execution context mid-action.

Common situations: SPA renders the target late (client-side hydration); a modal or toast overlays the button; default action timeout lowered via options (timeout in browser options); strict-mode selectors that match a list (e.g. '.btn' with several buttons); iframe content while the caller used the main frame.

Related errors


AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15). Data as JSON: /api/errors/fcdf4561542f638d. Report an issue: GitHub.