grafana/k6 · error
tapping on %q: %w
Error message
tapping on %q: %w
What it means
Frame.Tap() wraps the internal pointer action as 'tapping on "<selector>": <cause>'. The cause is the real signal: wait-for-element timeout, actionability failure (not visible, not stable, hit-target check fails because something else covers the point), or context cancellation.
Source
Thrown at internal/js/modules/k6/browser/common/frame.go:1801
// SetInputFiles sets input files for the selected element.
func (f *Frame) SetInputFiles(selector string, pfiles *Files, popts *FrameSetInputFilesOptions) error {
f.log.Debugf("Frame:SetInputFiles", "fid:%s furl:%q sel:%q", f.ID(), f.URL(), selector)
if err := f.setInputFiles(selector, pfiles, popts); err != nil {
return fmt.Errorf("setting input files on %q: %w", selector, err)
}
applySlowMo(f.ctx)
return nil
}
// Tap the first element that matches the selector.
func (f *Frame) Tap(selector string, opts *FrameTapOptions) error {
f.log.Debugf("Frame:Tap", "fid:%s furl:%q sel:%q", f.ID(), f.URL(), selector)
if err := f.tap(selector, opts); err != nil {
return fmt.Errorf("tapping on %q: %w", selector, err)
}
applySlowMo(f.ctx)
return nil
}
func (f *Frame) tap(selector string, opts *FrameTapOptions) error {
tap := func(apiCtx context.Context, handle *ElementHandle, p *Position) (any, error) {
return nil, handle.tap(apiCtx, p)
}
act := f.newPointerAction(
selector, DOMElementStateAttached, opts.Strict, tap, &opts.ElementHandleBasePointerOptions,
)
if _, err := call(f.ctx, act, opts.Timeout); err != nil {
return errorFromDOMError(err)
}
View on GitHub (pinned to 93accf6570)
Solutions
- Wait for visibility and stability: await frame.waitForSelector(sel, { state: 'visible' }) and let animations finish before tapping.
- Scroll the element into view (locator.scrollIntoViewIfNeeded or evaluate scrollIntoView) first.
- Pass { force: true } to bypass hit-target/actionability checks when the overlay is intentional.
- Use a unique selector or { strict: false } to avoid ambiguity.
Example fix
// before
await frame.tap('#checkout'); // sticky header covers it
// after
await frame.waitForSelector('#checkout', { state: 'visible' });
await frame.tap('#checkout', { force: true }); Defensive patterns
Strategy: validation
Validate before calling
await frame.waitForSelector(sel, { state: 'visible' });
await frame.evaluate(s => document.querySelector(s)?.scrollIntoView({ block: 'center' }), sel); Try / catch
try { await frame.tap(sel); }
catch (e) { if (/tapping on/.test(e.message) && /timeout|not visible|hit target/i.test(e.message)) { /* retry after scroll or force */ } throw e; } Prevention
- Scroll targets into view and let animations settle before tapping
- Use unique selectors with strict mode
- Reserve force:true for verified overlays
When it happens
Trigger: frame.tap(sel) with no touch emulation metadata is fine, but fails when the element is off-viewport or covered; selector matches multiple elements with strict:true; element detaches between resolution and the tap; page/frame closed.
Common situations: Mobile-emulation tests tapping buttons under sticky headers/cookie banners; elements that animate (hit-target check sees them moving); tapping elements that only appear after async load without waiting.
Related errors
- clicking on element: %w
- double clicking on element: %w
- filling element: %w
- pressing %q on element: %w
- selecting text: %w
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/92ea96b790058523.
Report an issue: GitHub.