title: Re-creating touch-based gestures with Playwright to test mobile viewports
body: <p>Can someone help me re-create touch-based gestures(swipe, zoom, pinch, etc.) in Playwright to test emulated mobile devices? It has only a tap method out of the box, which works perfectly, but I need a whole set of functionality to test the mobile viewports of our web application.</p>
  <p>I have tried so far a couple of scripts that I found online, which are not failing my tests but rather don't work for me for some reason:</p>
  <pre><code>await page.evaluate(() =&gt; {
    const target = document.querySelector(&quot;#abc&quot;);
    target.addEventListener('touchstart', (e) =&gt; {
        console.log('touch start');
    });
    
    function simulateTouchEvent(element, type, touches) {
      const touchEvents = [];
    
      touches.forEach((touch) =&gt; {
        touchEvents.push(new Touch({
          clientX: touch.x,
          clientY: touch.y,
          identifier: touch.id,
          target: element,
        }));
      });
    
      element.dispatchEvent(new TouchEvent(type, {
        touches: touchEvents,
        view: window,
        cancelable: true,
        bubbles: true,
      }));
    }
    
    simulateTouchEvent(target, 'touchstart', [{
      id: &quot;123&quot;,
      x: 10,
      y: 10,
    }]);
  
   simulateTouchEvent(target, 'touchend', [{
      id: &quot;123&quot;,
      x: 10,
      y: 10,
    }]);
  })
  </code></pre>
  <p>also this</p>
  <pre><code>const el = await page.locator(
                  &quot;.selector&quot;
              );
  const dataTransfer = await page.evaluateHandle(
                  () =&gt; new DataTransfer()
              );
  
  await el.dispatchEvent(&quot;touchstart&quot;, { dataTransfer, steps: 5 });
  await el.dispatchEvent(&quot;touchend&quot;, { dataTransfer, steps: 5 });
  </code></pre>
  <p>and</p>
  <pre><code>async function dispatchTouchEvent(
    playWright: Page,
    type: 'touchstart' | 'touchend' | 'touchcancel' | 'touchmove',
    selector: string,
    page?: Position,
    screen?: Position,
    client?: Position,
    options?: PageExtraTouchOptions,
  ) {
    await playWright.$eval(
      selector,
      (el, options) =&gt; {
        const rect = el.getBoundingClientRect();
  
        const {
          client = {},
          page = {},
          screen = {},
          type,
          options: touchOpt,
        } = options;
  
        const touchObj = new Touch({
          clientX: client.x,
          clientY: client.y,
          identifier: Date.now(),
          pageX:
            page.x || (client.x !== undefined ? rect.left + client.x : undefined),
          pageY:
            page.y || (client.y !== undefined ? rect.top + client.y : undefined),
          screenX: screen.x,
          screenY: screen.y,
          target: el,
        });
  
        const touchEvent = new TouchEvent(type, {
          bubbles: true,
          cancelable: true,
          ...touchOpt,
          changedTouches: [touchObj],
          targetTouches: [touchObj],
          touches: [touchObj],
        });
        return el.dispatchEvent(touchEvent);
      },
      { client, options, page, screen, type },
    );
  }
  
  await dispatchTouchEvent(
                  page,
                  &quot;touchstart&quot;,
                  &quot;.selector&quot;
              );
  await dispatchTouchEvent(
                  page,
                  &quot;touchend&quot;,
                  &quot;.selector&quot;
              );
  </code></pre>
  <p>I recently have been also looking into <a href="https://playwright.dev/docs/api/class-android" rel="nofollow noreferrer">Playwrights experimental android</a> emulation feature, in the hopes that it might help me to emulate at least an android device, but haven't even been able to even run it because of ECONNREFUSED error.</p>
  <p>Would appreciate any help, because I`m completely stuck in here.</p>
  <p>Playwright version: 1.23;
  OS: Ubuntu Neon KDE 20.04;</p>