Input steps are the pointer and touch toolkit: hover variants, double / right / middle clicks, modifier-key clicks, drag-and-drop, touch taps, and viewport resizing. They pick up where the core click and press steps stop - the gestures behind mega-menus, tooltips, context menus, kanban boards, spreadsheet-style editing, and multi-row selection.
Every step in this group addresses its target with a CSS selector (#id, .class, [data-testid=...], or any compound selector) and operates on the first match. Under the hood each gesture is a Playwright locator action, so the usual auto-waiting applies: the element must be attached, visible, and stable before the pointer moves. Like all state-changing steps, each gesture is followed by a silent BBR smart-settle pass so menus, drop targets, and context menus opened by the gesture are ready for the next step.
When a gesture cannot be performed, the step throws a friendly error naming the action and selector plus a hint - usually that the element must exist, be visible, and not be covered by an overlay. That last case (an interception overlay) is the most common real-world cause of pointer failures.
Quick reference
| Step | What it does |
|---|---|
When I hover over "#nav-products" | Hover the mouse pointer over an element. |
When I move the pointer to "#cta" | Alias for hover, phrased as pointer movement. |
When I double-click on "#row-1" | Double-click an element (also double click). |
When I right-click on "#row-1" | Right-click (context menu) an element (also right click). |
When I middle-click on "a.external" | Middle-click an element (also middle click). |
When I click on "#row-1" while holding "Shift" | Click while holding Shift, Control, Alt, or Meta. |
When I drag "#card-1" to "#column-done" | Drag a source element onto a target element. |
When I set the viewport size to 1280x720 | Resize the browser viewport to WxH pixels. |
When I tap on "#cta" | Touch-tap an element, falling back to click without touch support. |
Steps in detail
When I hover over "..." / When I move the pointer to "..."
Two phrasings for the same Playwright hover() action. Use them to open hover-triggered menus, reveal tooltips, or fire mouseenter handlers before asserting the revealed content. The pointer stays where you left it, so a hover followed by a click on the revealed item works naturally.
When I hover over "#nav-products"
Then I should see "All products"
When I move the pointer to ".tooltip-trigger"
Then ".tooltip" should be visible
When I double-click on "..."
Playwright dblclick(). Both double-click and double click spellings match. Typical uses: entering edit mode on a grid cell or opening an item from a file-tile view.
When I double-click on "td.editable-cell"
When I double click on ".file-tile"
When I right-click on "..." / When I middle-click on "..."
Non-primary button clicks (button: 'right' / button: 'middle'), with hyphenated and spaced spellings. Right-click is the way to open custom context menus; note it triggers the page's contextmenu handler, not the browser's native menu. Middle-click fires the click with the auxiliary button - it will not open a new tab in the automated browser.
When I right-click on ".tree-node"
Then I should see "Rename"
When I middle click on "a.external"
When I click on "..." while holding "..."
Clicks with a modifier key held. The modifier must be one of Playwright's names - Shift, Control, Alt, Meta (the error hint lists them if you pass anything else). This is the step for range-select and multi-select interactions in lists and tables.
When I click on "#row-1" while holding "Shift"
And I click on ".checkbox" while holding "Control"
When I drag "..." to "..."
Wraps Playwright's dragTo(): both elements are resolved first, then a full HTML5 drag sequence runs from source to target. Both must exist and the target must accept drops - libraries that only react to raw mouse events may need a page-specific step instead.
When I drag "#card-1" to "#column-done"
Then I should see "Done (1)"
When I drag ".file-tile" to "#trash"
When I set the viewport size to WxH
Resizes the viewport to exact pixel dimensions, e.g. 1280x720 or 375x667, for responsive checks mid-scenario. If the browser was launched in fluid-viewport mode the step fails with a hint to set a fixed contextOptions.viewport in the Playwright config. For named breakpoints (mobile, tablet, desktop) prefer the responsive steps group.
When I set the viewport size to 375x667
Then I should see an "button.menu" element
When I set the viewport size to 1920x1080
When I tap on "..."
Touch-taps the element. If the browser context was not created with hasTouch: true, the step transparently falls back to a regular click, so the same scenario runs in desktop and mobile-emulation profiles without edits.
When I set the viewport size to 375x667
And I tap on ".bottom-nav-item"
Then I should see "Menu"
Complete example
Feature: Kanban board pointer interactions
Scenario: Move a card with drag-and-drop and manage it via the context menu
Given I am on "/board"
When I hover over "#card-1"
Then I should see "Drag to move"
When I drag "#card-1" to "#column-done"
Then I should see "Done (1)"
When I right-click on "#card-1"
Then I should see "Archive"
When I click on "#row-1" while holding "Shift"
And I double-click on "td.editable-cell"
Scenario: The board works on a phone-sized viewport
Given I am on "/board"
When I set the viewport size to 375x667
And I tap on ".bottom-nav-item"
Then I should see "Menu"
Tips
- If a gesture fails with an interception error, something is covering the target - dismiss overlays and cookie banners first, or wait for animations to finish.
- Modifier-click on macOS conventions: use
Metafor Cmd-click behavior andControlfor Ctrl-click; scenarios stay portable if the app treats both as multi-select. - These steps take CSS selectors only. To keep feature files readable, register long selectors once with the selector registry and reference short names.