webdriverio icon indicating copy to clipboard operation
webdriverio copied to clipboard

Implement `swipe` command

Open christian-bromann opened this issue 4 years ago • 5 comments

Implement swipe commands from wdio-mobile-utils. I suggest the following commands:

  • swipe(from: Coordinate, to: Coordinate, opts: SwipeOpts)
    • where Coordinate = { x: number; y: number }
    • where SwipeOpts = { unit: 'px' | 'percentage' }
    • I would like to combine swipe and swipeOnPercentage from the original project to not overwhelm users with a variation of swipe commands
    • the command should implement a browser compatible execution using performAction for browser environments
  • swipe[Up|Right|Down|Left](target: Target)
    • where Target = WebdriverIO.Element | number
    • also here I would like to combine the methods for swiping on an element or by percentage
    • this time we can differentiate by parameter type

christian-bromann avatar Mar 03 '21 08:03 christian-bromann

@christian-bromann For Appium there are 2 ways of swiping

  • with actions
  • with native swipe functions for iOS and specific ones for Android.

The first one is cross-platform, but slower due to multiple commands for retrieving data, the second one is more efficient and less complex per command, but depends on specific versions of Appium (for example, Android support is only available since version 1.19.0)

I can put a pseudo code draft in here in the coming days with all the data that is needed to make both work

wswebcreation avatar Mar 03 '21 09:03 wswebcreation

I suggest to make a good guess if native swiping is supported. If necessary we can make a PR to Appium to expose its version as part of the session response.

christian-bromann avatar Mar 03 '21 09:03 christian-bromann

I just came across this issue and want to give some input as I kind of struggled with this recently.

A native implementation for swiping for a text could look like this:

async checkIfDisplayedWithSwipeUp(text: string, maxScrolls: number): Promise<WebdriverIO.Element> {
  if (driver.isAndroid) {
    return swipeIntoViewAndroid(text, maxScrolls)
  }
  return swipeIntoViewIOS(text, maxScrolls)
}

async swipeIntoViewAndroid(text: string, maxScrolls: number, amount = 0): Promise<WebdriverIO.Element> {
  const scrollForward = `android=new UiScrollable(new UiSelector().scrollable(true)).scrollForward()`
  const search = new Selector().ByText(text).build()
  const element = $(search)
  if (!(await element.isDisplayed()) && amount <= maxScrolls) {
    await $(scrollForward)
    await driver.pause(WAIT_FOR_SWIPE_FINISHED)
    await this.swipeIntoViewAndroid(text, maxScrolls, amount + 1)
  } else if (amount > maxScrolls) {
    // If the element is still not visible after the max amount of scroll let it fail
    throw new Error(`The element '${text}' could not be found or is not visible.`)
  }
  return element
}

async swipeIntoViewIOS(text: string, maxScrolls: number, amount = 0): Promise<WebdriverIO.Element> {
  // If the element is not displayed and we haven't scrolled the max amount of scrolls
  // then scroll and execute the method again
  const element = $(`-ios predicate string:label LIKE + ${text}`)
  if (!(await element.isDisplayed()) && amount <= maxScrolls) {
    await driver.execute('mobile:swipe', { direction: 'up' })
    await driver.pause(WAIT_FOR_SWIPE_FINISHED)
    await this.swipeIntoViewIOS(text, maxScrolls, amount + 1)
  } else if (amount > maxScrolls) {
    // If the element is still not visible after the max amount of scroll let it fail
    throw new Error(`The element '${text}' could not be found or is not visible.`)
  }
  return element
}

This can be made generic (not only for text) very easily by replacing the element with a passed target. Further information can be found here

This definitely would also resolve https://github.com/webdriverio/webdriverio/issues/6537

sarahsporck avatar Jan 31 '23 15:01 sarahsporck

The above code is working on iOS. Thank you @sarahsporck

purushotham64 avatar Sep 17 '23 02:09 purushotham64

@sarahsporck Hi Sarah, the documentation you shared seems to be inaccessible right now but I am trying the horizontal scroll on a container. So far no success but your code is working on vertical. Do you have any solutions for horizontal as well? :D

dalkilicdeniz avatar May 24 '24 13:05 dalkilicdeniz