grafana/k6 · error

tapping element

Error message

tapping element: %w

What it means

Thrown by the k6 browser module's ElementHandle.tap(). It wraps the whole pointer-action pipeline: scrolling the element into view, actionability checks (visible/stable/enabled), computing the tap point, hit-target verification, and finally Touchscreen.tap at the page level. Any stage failure — timeout, detached element, or 'another element is intercepting pointer action' (error:intercept) — surfaces wrapped in this message.

Solutions

  1. Launch the browser with touch enabled: const context = await browser.newContext({ hasTouch: true, viewport: { width: 390, height: 844 } }) and prefer page.tap or locator-based tap.
  2. Dismiss blocking overlays first (cookie banner, modal) or wait for them to disappear before tapping.
  3. Increase the timeout: el.tap({ timeout: '60s' }).
  4. Use { position: { x, y } } to tap a part of the element not covered by the overlay, or { force: true } as a last resort.
  5. Re-query the element to get a fresh attached handle.

Example fix

// before
const el = await page.$('#menu-item');
await el.tap(); // intercepting overlay or no touch emulation

// after
const context = await browser.newContext({ hasTouch: true, viewport: { width: 390, height: 844 } });
const page = await context.newPage();
await page.click('#cookie-accept', { timeout: '5s' }).catch(() => {});
const el = await page.waitForSelector('#menu-item', { state: 'visible' });
await el.tap({ timeout: '30s' });
Defensive patterns

Strategy: try-catch

Validate before calling

const context = await browser.newContext({ hasTouch: true, viewport: { width: 390, height: 844 } });
const visible = await el.isVisible().catch(() => false);
if (visible) { await el.tap({ timeout: '30s' }); }

Try / catch

try {
  await el.tap({ timeout: '30s' });
} catch (e) {
  if (String(e).includes('intercept')) {
    await page.click('#cookie-accept').catch(() => {});
    await el.tap({ timeout: '30s' });
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling el.tap() when the browser context was launched without touch support enabled (hasTouch not set), so tap events misbehave; an overlay (cookie banner, modal backdrop) covering the element; element hidden/animating past the timeout; element detached by rerender.

Common situations: Testing mobile flows on a desktop-launched context without the hasTouch browser option; cookie-consent or chat-widget overlays intercepting the tap point; sticky headers covering the target after scroll.

Related errors


AI-assisted analysis of grafana/k6@3fcf5388d7 (2026-08-18). Data as JSON: /api/errors/5b1b1ac1f1ee4842. Report an issue: GitHub.

Appendix: source

Thrown at internal/js/modules/k6/browser/common/element_handle.go:1509

	if !ok {
		return fmt.Errorf("unexpected type %T", result)
	}
	if v != "done" {
		return errorFromDOMError(v)
	}

	return nil
}

// Tap scrolls element into view and taps in the center of the element.
func (h *ElementHandle) Tap(opts *ElementHandleTapOptions) error {
	tap := func(apiCtx context.Context, handle *ElementHandle, p *Position) (any, error) {
		return nil, handle.tap(apiCtx, p)
	}
	tapAction := h.newPointerAction(tap, &opts.ElementHandleBasePointerOptions)

	if _, err := call(h.ctx, tapAction, opts.Timeout); err != nil {
		return fmt.Errorf("tapping element: %w", err)
	}

	applySlowMo(h.ctx)

	return nil
}

func (h *ElementHandle) tap(_ context.Context, p *Position) error {
	return h.frame.page.Touchscreen.tap(p.X, p.Y)
}

// TextContent returns the text content of the element.
// The second return value is true if the text content exists, and false otherwise.
func (h *ElementHandle) TextContent() (string, bool, error) {
	textContent := func(apiCtx context.Context, handle *ElementHandle) (any, error) {
		return handle.textContent(apiCtx)
	}
	opts := NewElementHandleBaseOptions(h.DefaultTimeout())

View on GitHub (pinned to 3fcf5388d7)