Skip to content

Keyboard and Mouse Actions in Cypress

Beyond basic clicking and typing, real applications often need keyboard shortcuts, hover states, drag-and-drop, and scroll-triggered behavior tested. This lesson covers those advanced interaction patterns.

Beyond Basic Click and Type

Many UI patterns depend on interactions Cypress supports but that are used less often: modifier-key combinations, focus/blur transitions, mouse-hover-triggered menus, and drag-and-drop reordering.

Some of these, particularly native drag-and-drop and true hover-only CSS states, need a bit more care than a single command, since Cypress simulates events rather than literal OS-level mouse movement.

cy.get('[data-cy="search"]').type('{ctrl}a{del}');
cy.get('[data-cy="menu-trigger"]').trigger('mouseover');
cy.get('[data-cy="dropdown-menu"]').should('be.visible');

{ctrl}a{del} selects all text and deletes it; .trigger('mouseover') simulates a hover to reveal a menu.

Common Interaction Patterns

.type('{ctrl}{shift}z')   // modifier-key combination
.focus()                  // focus an element directly
.blur()                   // remove focus
.trigger('mouseover')     // simulate hover-related events
.scrollIntoView()         // scroll an element into the viewport
  • Modifier keys in .type() use curly braces: {ctrl}, {shift}, {alt}, {meta}.
  • .trigger(eventName) fires an arbitrary DOM event, useful for hover-based and custom-event interactions.
  • .scrollIntoView() scrolls an element into the visible viewport before interacting with it.
  • .focus()/.blur() directly manage focus state without needing a click.

Keyboard and Mouse Cheat Sheet

Advanced interaction commands beyond basic click and type.

Goal Command
Select all text .type('{selectall}')
Copy shortcut .type('{ctrl}c')
Simulate hover .trigger('mouseover')
Simulate mouse leave .trigger('mouseout')
Focus an input .focus()
Remove focus .blur()
Scroll into view .scrollIntoView()
Simulate drag start .trigger('dragstart')

Simulating Hover States

Cypress does not move a real mouse cursor, so pure CSS :hover states cannot be triggered by moving anything. Instead, use .trigger('mouseover') (and .trigger('mouseout') to leave) to fire the underlying events that JavaScript-driven hover menus typically listen for.

If a hover effect is implemented purely in CSS with no JavaScript listener, testing its exact visual appearance is better suited to visual regression testing than functional Cypress assertions.

cy.get('[data-cy="nav-item"]').trigger('mouseover');
cy.get('[data-cy="submenu"]').should('be.visible');
cy.get('[data-cy="nav-item"]').trigger('mouseout');
cy.get('[data-cy="submenu"]').should('not.be.visible');

Testing Drag-and-Drop

Drag-and-drop interactions typically rely on a sequence of low-level events: mousedown, mousemove, and mouseup (or their touch/pointer equivalents). Cypress can simulate this sequence with .trigger(), though the exact events needed depend on the drag-and-drop library your application uses.

cy.get('[data-cy="drag-item-1"]')
  .trigger('dragstart');
cy.get('[data-cy="drop-zone"]')
  .trigger('drop');
cy.get('[data-cy="drag-item-1"]')
  .trigger('dragend');

Many teams use the community cypress-drag-drop plugin, which wraps this event sequence in a single reusable command.

Scrolling Elements Into View

Cypress automatically scrolls an element into view before most actions, but .scrollIntoView() is useful when you need to assert on visibility explicitly, or when testing scroll-triggered behavior like lazy-loaded content or sticky headers.

  • Cypress scrolls automatically before clicking or typing into an element.
  • Use .scrollIntoView() explicitly when testing scroll-triggered UI, like infinite scroll or lazy loading.
  • Combine with .should('be.visible') to assert the scroll actually revealed the target element.

Common Mistakes

  • Expecting .trigger('mouseover') alone to reproduce a pure CSS :hover effect with no JavaScript listener behind it.
  • Trying to simulate drag-and-drop with only .click() and .type() instead of the correct low-level event sequence.
  • Forgetting that Cypress does not move a literal cursor, so "hover" tests must target the actual events your code listens for.
  • Overusing .trigger() for interactions that a standard action command like .click() already handles correctly.

Key Takeaways

  • Modifier-key combinations and special keys are typed using curly-brace syntax inside .type().
  • .trigger() fires arbitrary DOM events, essential for hover and drag-and-drop simulation.
  • Cypress does not move a real cursor, so pure CSS-only hover effects may need visual regression testing instead.
  • .scrollIntoView() is useful for testing scroll-triggered behavior explicitly.

Pro Tip

Before writing custom .trigger() sequences for drag-and-drop, check whether your drag-and-drop library already has a maintained Cypress testing plugin, reimplementing the correct event sequence by hand is a common source of flaky, hard-to-maintain tests.