Implement `swipe` command
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
swipeandswipeOnPercentagefrom the original project to not overwhelm users with a variation of swipe commands - the command should implement a browser compatible execution using
performActionfor browser environments
- where
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
- where
@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
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.
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
The above code is working on iOS. Thank you @sarahsporck
@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