Appium - How to scroll down using UiAutomator2 and WebdriverIO with React Native (Android) and JavaScript
Asked Answered
J

3

7

No matter what I try, I am unable to get my React Native (Android) app to scroll down using Appium.

I am using UiAutomator2 and WebdriverIO.

My code looks like this:

scrollUntilDisplayed(element: WebdriverIO.Element) {
    const dimensions = driver.getWindowSize();
    touchScroll(10, 100);
}

In place of touchScroll, I have tried the following calls:

  • driver.touchScroll(offsetX, offsetY) - throws an error (invalid argument: java.lang.IllegalArgumentException: ScrollToModel: The mandatory field 'params' is not present in JSON)
  • driver.touchScroll(offsetX, offsetY, element) - throws an error (invalid argument: java.lang.IllegalArgumentException: ScrollToModel: The mandatory field 'params' is not present in JSON)
  • browser.execute("mobile: scroll", {direction: 'down'}); - throws an error (unknown error: An unknown server-side error occurred while processing the command. Original error: Both strategy and selector arguments must be provided)
  • driver.touchFlick(0, dimensions.height, undefined, 10000, 10000, 10000); - does nothing; sits until Appium times out
  • element.scrollIntoView(); - does nothing
Jorin answered 3/8, 2020 at 23:18 Comment(0)
J
9

Since ReactNative has a NATIVE_APP context (as a regular Android app) you can use uiautomator selector:

const bottomElementSelector = `new UiScrollable(new UiSelector().scrollable(true)).scrollIntoView(new UiSelector().text("Element label text"))`
const bottomEl = $(`android=${bottomElementSelector}`)

Search for an element with srollable selector should move focus down to that element

Note: Make sure you are using UiAutomator2 in Appium capabilities

January answered 4/8, 2020 at 13:8 Comment(4)
I ended up querying by description, as I'd rather gear towards querying Accessibility Labels than inner text. But both work exactly as intended :)Jorin
You are right, using text is a bad way to go in terms of maintaince. I just wanted to make the simplest example :)January
I'm not sure it works with latest versions, appium/wdio jsut report an error on the execution of the code ` error: 'no such element',` and proceed to the next line... Maybe due to the FlatList as the element cannot be detect (not yet rendered). Any solution for this case?Bayreuth
Im using driver.find_element(by=AppiumBy.ANDROID_UIAUTOMATOR,value='new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(text("Desired Text"))') the problem is the scroll is scrolling up, not scroll down.Aphasic
U
3

More optimal, convenient and readable is to use the touchPerform of Appium. At the very least, it returns Promise and you can wait for this action to complete:

const startPercentage = 10;
const endPercentage = 90;
const anchorPercentage = 50;

const { width, height } = driver.getWindowSize();
const anchor = height * anchorPercentage / 100;
const startPoint = width * startPercentage / 100;
const endPoint = width * endPercentage / 100;
driver.touchPerform([
  {
    action: 'press',
    options: {
      x: startPoint,
      y: anchor,
    },
  },
  {
    action: 'wait',
    options: {
      ms: 100,
    },
  },
  {
    action: 'moveTo',
    options: {
      x: endPoint,
      y: anchor,
    },
  },
  {
    action: 'release',
    options: {},
  },
]);
Uncharitable answered 26/4, 2023 at 12:41 Comment(0)
B
1

Another solution is to use the performActions of Appium:

/**
 * Scroll down by simulating a swipe down gesture.
 *
 * @param driver
 * @param scrollDuration a lower scroll duration add more fling speed.
 */
export const scrollDown = async (driver, scrollDuration = 300) => {
    const startPercentage = 90
    const endPercentage = 10
    const anchorPercentage = 50

    const { width, height } = await driver.getWindowSize()
    const density = (await driver.getDisplayDensity()) / 100
    const anchor = (width * anchorPercentage) / 100
    const startPoint = (height * startPercentage) / 100
    const endPoint = (height * endPercentage) / 100

    await driver.performActions([
        {
            type: 'pointer',
            id: 'finger1',
            parameters: { pointerType: 'touch' },
            actions: [
                { type: 'pointerMove', duration: 0, x: anchor, y: startPoint },
                { type: 'pointerDown', button: 0 },
                { type: 'pause', duration: 100 },
                { type: 'pointerMove', duration: scrollDuration, origin: 'pointer', x: 0, y: -endPoint * density },
                { type: 'pointerUp', button: 0 },
                { type: 'pause', duration: scrollDuration },
            ],
        },
    ])
}
Bayreuth answered 6/7, 2022 at 15:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.