cypress-io / cypress

Fast, easy and reliable testing for anything that runs in a browser.
https://cypress.io
MIT License
46.67k stars 3.16k forks source link

Simulate swipe action #1418

Open vpivet opened 6 years ago

vpivet commented 6 years ago

Desired behavior:

I use Cypress with Ionic 3 and I want to test my side-menu opening/closing, tabs change and pull to refresh with a swipe action. It is possible to simulate a swipe action with Cypress ? I tried to get inspired by the drag and drop example but it doesn't works. Maybe I'm doing something wrong.

Test code:

it('should close menu', () => {
  // This open my side menu by click on a button (OK)
  cy.get('button').click();

  // This should close menu by swipe (DO NOTHING)
  // I selected content of my menu.
  cy.get('content of my menu').trigger('mousedown', { which: 1 })
    .trigger('mousemove', { clientX: 120, clientY: 300 })
    .trigger('mouseup', {force: true})
});
lakiefer commented 5 years ago

I've got he same problem with

Cypress version 3.1.0 Chrome Version 68.0.3440.106 trying to test the swipe function in angular with hammerjs.

Is there a way to do this?

jennifer-shehane commented 5 years ago

We are unaware of a current workaround for simulating swipe. Keeping issue open as a feature request for the future.

blumk commented 5 years ago

@jennifer-shehane Adding support for touch gestures would be a tremendous improvement to Cypress.

Quite a lot of use-cases require touch gestures, especially when doing mobile development / PWAs. E.g.:

nomadigital commented 5 years ago

I had the same problem trying to swipe an element using vuetify-swipeout with cypress.

After a couple hours searching, I end up looking which event is really triggered when swiping my element in chrome using the developer tools:

TomdeHaan commented 5 years ago

I had the same problem trying to swipe an element using vuetify-swipeout with cypress.

After a couple hours searching, I end up looking which event is really triggered when swiping my element in chrome using the developer tools:

  • Ctrl + Shift + I (Developer Tools) > Sources> Event Listener Breakpoints (on the right)
  • I found out that the event triggered was not mousedown but pointerdown so I simply replaced it doing something like:
cy.get('[data-cy=my-element]')
   .trigger('pointerdown', { which: 1 })
   .trigger('pointermove', 'right')
   .trigger('pointerup', { force: true })

Hope it can help ;-)

I'm going to try this, thanks!

nshoes commented 5 years ago

I got this to work with the popular react-easy-swipe:

cy.get('[data-cy=week-picker-swipe-container]')
  .trigger('touchstart', {
    touches: [{ pageY: 0, pageX: 0 }]
  })
  .trigger('touchmove', {
    touches: [{ pageY: 0, pageX: -30 }]
  })
Tobska commented 4 years ago

I had the same problem trying to swipe an element using vuetify-swipeout with cypress.

After a couple hours searching, I end up looking which event is really triggered when swiping my element in chrome using the developer tools:

  • Ctrl + Shift + I (Developer Tools) > Sources> Event Listener Breakpoints (on the right)
  • I found out that the event triggered was not mousedown but pointerdown so I simply replaced it doing something like:
cy.get('[data-cy=my-element]')
   .trigger('pointerdown', { which: 1 })
   .trigger('pointermove', 'right')
   .trigger('pointerup', { force: true })

Hope it can help ;-)

This also works with Ionic's Slides Component.

aurium commented 4 years ago

Hi, i have the same problem to test my Vue application. So i wrote a commands module to do this. https://www.npmjs.com/package/cy-mobile-commands

I did it today and i have implemented only the swipe command. This is my first command to cypress, so i will be glad to receive some review feedback about my implementation. https://gitlab.com/nTopus/cy-mobile-commands/issues

mvindahl commented 4 years ago

Failing to get any of the above solutions to work with ionic, I went down the rabbit hole of sprinkling their code with logpoints to figure out what it was doing. FWIW, the following has the official Works On My Machine Seal of Approval.

  cy.get('[data-cy=my-element]')
    // simulate swipe right
    .trigger('mousedown', { which: 1 }) // start capture
    .trigger('mousemove', 'left') // register start position
    .trigger('mousemove', 'right') // register end position
    .wait(0) // wait for requestAnimationFrame to invoke fireOnMove 
    .trigger('mouseup'); // end capture
jennifer-shehane commented 4 years ago

@aurium Could you open a pull request to add this plugin to our documentation? Thanks! Instructions here.

intellix commented 4 years ago

cy-mobile-commands looks really good. I could ask it to swipe left to right etc on an element that explicitly listens to touchstart/move/end events but unfortunately it's not sufficient for testing scrolling as I believe that requires the browser to have touch emulation?

We recently had a regression updating from Angular 8 to 9 due to a Hammer change which killed scrolling due to elements listening to panleft/right gaining a touch-action: none property. Was hoping that I could add a couple of basic swipe up/down/up/down e2e tests to ensure scrolling still works but it doesn't work within Cypress.

It seems the only way to ensure it still works before deployment is to manually get your phone out and scroll up/down

mesqueeb commented 3 years ago

for me cy-mobile-commands was the only working solution. 😅 VERY GOOD JOB.

For anyone here, just don't forget to use cy.visitMobile('/') instead of cy.visit('/') for the swipes to work!!

MurhafSousli commented 3 years ago

I had the same problem trying to swipe an element using vuetify-swipeout with cypress.

After a couple hours searching, I end up looking which event is really triggered when swiping my element in chrome using the developer tools:

  • Ctrl + Shift + I (Developer Tools) > Sources> Event Listener Breakpoints (on the right)
  • I found out that the event triggered was not mousedown but pointerdown so I simply replaced it doing something like:
cy.get('[data-cy=my-element]')
   .trigger('pointerdown', { which: 1 })
   .trigger('pointermove', 'right')
   .trigger('pointerup', { force: true })

@nomadigital Is it possible to animate panning speed? I want to write e2e for sliding items in a carousel which depends on the speed of sliding!

TobiWeiss commented 2 years ago

If anyone has problems getting this to work in combination with Angular and hammerJS: cypress-real-events did the trick for me .

skurgansky-sugarcrm commented 2 months ago

We recently had a regression updating from Angular 8 to 9 due to a Hammer change which killed scrolling due to elements listening to panleft/right gaining a touch-action: none property. Was hoping that I could add a couple of basic swipe up/down/up/down e2e tests to ensure scrolling still works but it doesn't work within Cypress.

any progress on your problem? i got same issue with touch-action css prop and cy-mobile-commands doesn't work with it either

skurgansky-sugarcrm commented 2 months ago

this worked for me

Cypress.Commands.add('swipeOver', { prevSubject: 'element' }, (subject, direction, distance) => {
    const rect = subject[0].getBoundingClientRect();
    const start = {
        x: (direction === 'left' ? rect.width - 10 : 10) + rect.x,
        y: Math.round(rect.height / 2) + rect.y,
    };
    let end;

    switch (direction) {
      case 'left':
        end = { x: start.x - distance, y: start.y };
        break;
      case 'right':
        end = { x: start.x + distance, y: start.y };
        break;
      default:
        throw new Error(`Unknown direction: ${direction}`);
    }

    const opts = {
        which: 1,
        force: true,
        pointerId: 1,
        bubbles: true,
        pointerType: "mouse"
    };

    cy.wrap(subject).trigger('pointerover', {
        ...opts,
        clientX: start.x,
        clientY: start.y,
    });
    cy.wrap(subject).trigger('pointerdown', {
        ...opts,
        clientX: start.x,
        clientY: start.y,
    });

    cy.wrap(subject).trigger('pointermove', {
        ...opts,
        clientX: start.x,
        clientY: start.y,
    });
    cy.wrap(subject).trigger('pointermove', {
        ...opts,
        clientX: (start.x + end.x) / 2,
        clientY: start.y,
    });

    cy.wrap(subject).trigger('pointermove', {
        ...opts,
        clientX: end.x,
        clientY: end.y,
    });

    cy.wait(400);
    cy.wrap(subject).trigger('pointerup', {
        ...opts,
        clientX: end.x,
        clientY: end.y,
    });
});