CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-wd

WebDriver/Selenium 2 Node.js client for browser automation and testing

Pending
Overview
Eval results
Files

touch-actions.mddocs/

Touch Actions & Gestures

Advanced touch gesture support using TouchAction, MultiAction, and W3C Actions builders for mobile and touch-enabled devices.

Capabilities

TouchAction Class

Build and execute single touch gesture sequences.

/**
 * TouchAction constructor
 * @param driver - WebDriver instance
 */
class TouchAction {
  constructor(driver: Webdriver);
  
  /**
   * Add tap gesture
   * @param opts - Tap options
   */
  tap(opts?: {element?: Element, x?: number, y?: number, count?: number}): TouchAction;
  
  /**
   * Add press gesture
   * @param opts - Press options
   */
  press(opts?: {element?: Element, x?: number, y?: number}): TouchAction;
  
  /**
   * Add long press gesture
   * @param opts - Long press options
   */
  longPress(opts?: {element?: Element, x?: number, y?: number}): TouchAction;
  
  /**
   * Add move gesture
   * @param opts - Move options
   */
  moveTo(opts?: {element?: Element, x?: number, y?: number}): TouchAction;
  
  /**
   * Add release gesture
   */
  release(): TouchAction;
  
  /**
   * Add wait/pause
   * @param opts - Wait options or duration in milliseconds
   */
  wait(opts: {ms: number} | number): TouchAction;
  
  /**
   * Cancel all gestures
   */
  cancel(): TouchAction;
  
  /**
   * Execute the touch action sequence
   * @param cb - Callback receiving (err)
   */
  perform(cb?: callback): void;
}

Usage Examples:

const wd = require('wd');

// Simple tap gesture
const touchAction = new wd.TouchAction(browser);
touchAction
  .tap({element: targetElement})
  .perform(function(err) {
    console.log('Tap gesture completed');
  });

// Tap at coordinates
touchAction
  .tap({x: 100, y: 200})
  .perform();

// Long press gesture
touchAction
  .longPress({element: menuButton})
  .wait(1000)
  .release()
  .perform(function(err) {
    console.log('Long press menu opened');
  });

// Drag and drop gesture
touchAction
  .press({element: draggableItem})
  .wait(500)
  .moveTo({element: dropZone})
  .release()
  .perform(function(err) {
    console.log('Item dragged and dropped');
  });

// Swipe gesture
touchAction
  .press({x: 300, y: 400})
  .wait(100)
  .moveTo({x: 300, y: 100})  // Swipe up
  .release()
  .perform(function(err) {
    console.log('Swipe up completed');
  });

MultiAction Class

Execute multiple TouchAction sequences simultaneously.

/**
 * MultiAction constructor
 * @param browserOrElement - WebDriver instance or Element
 */
class MultiAction {
  constructor(browserOrElement: Webdriver | Element);
  
  /**
   * Add TouchAction to the multi-action
   * @param touchActions - One or more TouchAction instances
   */
  add(...touchActions: TouchAction[]): MultiAction;
  
  /**
   * Cancel all actions
   */
  cancel(): MultiAction;
  
  /**
   * Execute all touch actions simultaneously
   * @param cb - Callback receiving (err)
   */
  perform(cb?: callback): void;
}

Usage Examples:

// Two-finger pinch gesture
const finger1 = new wd.TouchAction(browser);
finger1.press({x: 200, y: 200}).wait(100).moveTo({x: 150, y: 150}).release();

const finger2 = new wd.TouchAction(browser);
finger2.press({x: 300, y: 300}).wait(100).moveTo({x: 350, y: 350}).release();

const pinchOut = new wd.MultiAction(browser);
pinchOut.add(finger1, finger2).perform(function(err) {
  console.log('Pinch out gesture completed');
});

// Two-finger zoom in
const zoom1 = new wd.TouchAction(browser);
zoom1.press({x: 150, y: 150}).wait(100).moveTo({x: 100, y: 100}).release();

const zoom2 = new wd.TouchAction(browser);
zoom2.press({x: 350, y: 350}).wait(100).moveTo({x: 400, y: 400}).release();

const zoomIn = new wd.MultiAction(browser);
zoomIn.add(zoom1, zoom2).perform(function(err) {
  console.log('Zoom in gesture completed');
});

// Multi-finger tap
const tap1 = new wd.TouchAction(browser).tap({x: 100, y: 200});
const tap2 = new wd.TouchAction(browser).tap({x: 200, y: 200});
const tap3 = new wd.TouchAction(browser).tap({x: 300, y: 200});

const multiTap = new wd.MultiAction(browser);
multiTap.add(tap1, tap2, tap3).perform(function(err) {
  console.log('Multi-finger tap completed');
});

W3C Actions

Modern W3C Actions API for complex input sequences.

/**
 * W3C Actions constructor
 * @param driver - WebDriver instance
 */
class W3CActions {
  constructor(driver: Webdriver);
  
  /**
   * Add input device to the action sequence
   * @param inputSource - InputDevice instance
   */
  addInputDevice(inputSource: InputDevice): W3CActions;
  
  /**
   * Add touch input device
   */
  addTouchInput(): InputDevice;
  
  /**
   * Add mouse input device
   */
  addMouseInput(): InputDevice;
  
  /**
   * Add pen input device
   */
  addPenInput(): InputDevice;
  
  /**
   * Add keyboard input device
   */
  addKeyInput(): InputDevice;
  
  /**
   * Execute the W3C actions
   * @param cb - Callback receiving (err)
   */
  perform(cb?: callback): void;
}

/**
 * InputDevice for W3C Actions
 */
class InputDevice {
  constructor(opts?: {type?: string, id?: string, pointerType?: string, parameters?: object});
  
  /**
   * Pause input source
   * @param opts - Pause options or duration
   */
  pause(opts: {duration: number} | number): InputDevice;
  
  // Key input methods (for type='key')
  keyDown(opts: {value: string} | string): InputDevice;
  keyUp(opts: {value: string} | string): InputDevice;
  
  // Pointer input methods (for type='pointer')
  pointerDown(opts?: {button?: number}): InputDevice;
  pointerUp(opts?: {button?: number}): InputDevice;
  pointerMove(opts: {element?: Element, duration?: number, origin?: string, x?: number, y?: number}): InputDevice;
  pointerCancel(opts?: {button?: number}): InputDevice;
}

Usage Examples:

// Basic W3C touch gesture
const w3cActions = new wd.W3CActions(browser);
const finger = w3cActions.addTouchInput();

finger
  .pointerMove({x: 100, y: 200})
  .pointerDown()
  .pause(100)
  .pointerMove({x: 300, y: 200})
  .pointerUp();

w3cActions.perform(function(err) {
  console.log('W3C touch gesture completed');
});

// Multi-touch W3C gesture
const w3cMultiTouch = new wd.W3CActions(browser);
const finger1 = w3cMultiTouch.addTouchInput();
const finger2 = w3cMultiTouch.addTouchInput();

// Pinch gesture
finger1
  .pointerMove({x: 200, y: 200})
  .pointerDown()
  .pause(100)
  .pointerMove({x: 150, y: 150})
  .pointerUp();

finger2
  .pointerMove({x: 300, y: 300})
  .pointerDown()
  .pause(100)
  .pointerMove({x: 350, y: 350})
  .pointerUp();

w3cMultiTouch.perform(function(err) {
  console.log('W3C pinch gesture completed');
});

// Combined input types
const mixedActions = new wd.W3CActions(browser);
const touch = mixedActions.addTouchInput();
const keyboard = mixedActions.addKeyInput();

// Touch and type simultaneously
touch.pointerMove({x: 100, y: 100}).pointerDown();
keyboard.keyDown('a').keyUp('a');
touch.pointerUp();

mixedActions.perform(function(err) {
  console.log('Mixed input actions completed');
});

Gesture Helpers

Common gesture patterns and helper functions.

Usage Examples:

// Swipe helper functions
function swipeUp(element, distance = 100) {
  const touchAction = new wd.TouchAction(browser);
  return touchAction
    .press({element: element})
    .wait(100)
    .moveTo({element: element, x: 0, y: -distance})
    .release()
    .perform();
}

function swipeDown(element, distance = 100) {
  const touchAction = new wd.TouchAction(browser);
  return touchAction
    .press({element: element})
    .wait(100)
    .moveTo({element: element, x: 0, y: distance})
    .release()
    .perform();
}

function swipeLeft(element, distance = 100) {
  const touchAction = new wd.TouchAction(browser);
  return touchAction
    .press({element: element})
    .wait(100)
    .moveTo({element: element, x: -distance, y: 0})
    .release()
    .perform();
}

function swipeRight(element, distance = 100) {
  const touchAction = new wd.TouchAction(browser);
  return touchAction
    .press({element: element})
    .wait(100)
    .moveTo({element: element, x: distance, y: 0})
    .release()
    .perform();
}

// Usage of swipe helpers
browser.elementByCss('.swipeable-area', function(err, area) {
  swipeUp(area, 200);  // Swipe up 200 pixels
});

// Pinch zoom helper
function pinchZoom(centerX, centerY, scale = 1.5) {
  const distance = 100;
  const scaledDistance = distance * scale;
  
  const finger1 = new wd.TouchAction(browser);
  finger1
    .press({x: centerX - distance/2, y: centerY})
    .wait(100)
    .moveTo({x: centerX - scaledDistance/2, y: centerY})
    .release();
    
  const finger2 = new wd.TouchAction(browser);
  finger2
    .press({x: centerX + distance/2, y: centerY})
    .wait(100)
    .moveTo({x: centerX + scaledDistance/2, y: centerY})
    .release();
    
  const multiAction = new wd.MultiAction(browser);
  return multiAction.add(finger1, finger2).perform();
}

// Usage of pinch zoom
pinchZoom(200, 300, 2.0);  // Zoom 2x at coordinates (200, 300)

// Scroll helper using touch
function touchScroll(element, direction, distance) {
  const directions = {
    up: {x: 0, y: -distance},
    down: {x: 0, y: distance},
    left: {x: -distance, y: 0},
    right: {x: distance, y: 0}
  };
  
  const offset = directions[direction] || directions.down;
  
  const touchAction = new wd.TouchAction(browser);
  return touchAction
    .press({element: element})
    .wait(200)
    .moveTo({element: element, x: offset.x, y: offset.y})
    .release()
    .perform();
}

// Usage of touch scroll
browser.elementByCss('.scrollable-list', function(err, list) {
  touchScroll(list, 'down', 300);  // Scroll down 300 pixels
});

// Double tap helper
function doubleTap(element, delay = 100) {
  const touchAction = new wd.TouchAction(browser);
  return touchAction
    .tap({element: element})
    .wait(delay)
    .tap({element: element})
    .perform();
}

// Custom gesture builder
class GestureBuilder {
  constructor(browser) {
    this.browser = browser;
  }
  
  createSwipe(startX, startY, endX, endY, duration = 1000) {
    const touchAction = new wd.TouchAction(this.browser);
    return touchAction
      .press({x: startX, y: startY})
      .wait(100)
      .moveTo({x: endX, y: endY})
      .release();
  }
  
  createTap(x, y, count = 1) {
    const touchAction = new wd.TouchAction(this.browser);
    let action = touchAction;
    
    for (let i = 0; i < count; i++) {
      action = action.tap({x: x, y: y});
      if (i < count - 1) {
        action = action.wait(100);
      }
    }
    
    return action;
  }
  
  createPinch(centerX, centerY, startDistance, endDistance) {
    const finger1 = new wd.TouchAction(this.browser);
    finger1
      .press({x: centerX - startDistance/2, y: centerY})
      .wait(100)
      .moveTo({x: centerX - endDistance/2, y: centerY})
      .release();
      
    const finger2 = new wd.TouchAction(this.browser);
    finger2
      .press({x: centerX + startDistance/2, y: centerY})
      .wait(100)
      .moveTo({x: centerX + endDistance/2, y: centerY})
      .release();
      
    return new wd.MultiAction(this.browser).add(finger1, finger2);
  }
}

// Usage of gesture builder
const gestureBuilder = new GestureBuilder(browser);

// Create and execute custom gestures
gestureBuilder.createSwipe(100, 300, 400, 300).perform();  // Horizontal swipe
gestureBuilder.createTap(200, 200, 3).perform();           // Triple tap
gestureBuilder.createPinch(250, 400, 50, 150).perform();   // Pinch out

Performance and Optimization

Best practices for efficient touch gesture automation.

Usage Examples:

// Batch gestures for better performance
const gestures = [];

// Create multiple gestures
for (let i = 0; i < 5; i++) {
  const touchAction = new wd.TouchAction(browser);
  touchAction.tap({x: 100 + i * 50, y: 200});
  gestures.push(touchAction);
}

// Execute gestures in sequence
async function executeGestures(gestures) {
  for (const gesture of gestures) {
    await new Promise((resolve, reject) => {
      gesture.perform(function(err) {
        if (err) reject(err);
        else resolve();
      });
    });
  }
}

executeGestures(gestures).then(() => {
  console.log('All gestures completed');
});

// Optimize gesture timing
function createOptimizedSwipe(element, direction) {
  const touchAction = new wd.TouchAction(browser);
  
  // Shorter waits for faster execution
  return touchAction
    .press({element: element})
    .wait(50)  // Reduced from 100ms
    .moveTo({element: element, x: direction.x, y: direction.y})
    .release();
}

// Error handling for gestures
function safeGesture(gestureFunction, retries = 3) {
  return new Promise((resolve, reject) => {
    let attempt = 0;
    
    function tryGesture() {
      attempt++;
      gestureFunction().perform(function(err) {
        if (err && attempt < retries) {
          console.log(`Gesture attempt ${attempt} failed, retrying...`);
          setTimeout(tryGesture, 1000);
        } else if (err) {
          reject(err);
        } else {
          resolve();
        }
      });
    }
    
    tryGesture();
  });
}

// Usage of safe gesture
const swipeGesture = () => new wd.TouchAction(browser)
  .press({x: 100, y: 200})
  .moveTo({x: 300, y: 200})
  .release();

safeGesture(swipeGesture, 3).then(() => {
  console.log('Gesture completed successfully');
}).catch(err => {
  console.error('Gesture failed after retries:', err);
});

Install with Tessl CLI

npx tessl i tessl/npm-wd

docs

browser-sessions.md

configuration.md

element-location.md

index.md

javascript-execution.md

mobile-testing.md

navigation.md

touch-actions.md

user-input.md

waiting.md

window-management.md

tile.json