appium / appium-flutter-driver

Appium Flutter Driver is a test automation tool for Flutter apps on multiple platforms/OSes. Appium Flutter Driver is part of the Appium mobile test automation tool maintained by community
MIT License
440 stars 179 forks source link

Swipe actions issue #631

Closed Vladeezyy closed 7 months ago

Vladeezyy commented 7 months ago

I'm trying to perform a swipe, but having problems. As I saw somewhere here in other issues, I need to use Appium's commands to do swipes, flutter driver can't do it, so I was trying to:

async swipeLeft() {
        // Get the size of the device screen
        const { width, height } = await driver.getWindowRect();

        // Calculate start and end points for the swipe
        const startX = width * 0.8; // 80% from the left of the screen
        const endX = width * 0.2; // 20% from the left of the screen
        const startY = height / 2; // middle of the screen

        // Perform the swipe action
        await driver.touchAction([
            { action: "press", x: startX, y: startY },
            { action: "wait", ms: 500 }, // Duration of the swipe
            { action: "moveTo", x: endX, y: startY },
            "release",
        ]);
    }

and different other approaches, but getting "unknown method: Not implemented", can I somehow go through it? Maybe i'm doing it by wrong way?

KazuCocoa commented 7 months ago

Could you attach the appium server log?

Vladeezyy commented 7 months ago

@KazuCocoa sorry for so late answer, the problem was solved, I have changed the code a bit and now it's working, maybe someone will find it helpful, i will just share my whole gestures file:


import { RectReturn } from '@wdio/protocols/build/types';
/**
 * To make a Gesture methods more robust for multiple devices and also
 * multiple screen sizes the advice is to work with percentages instead of
 * actual coordinates. The percentages will calculate the position on the
 * screen based on the SCREEN_SIZE which will be determined once if needed
 * multiple times.
 */
interface scrollOptions {
    limit: number;
    percentage: number;
    soft: boolean;
}
const DEFAULT_SCROLL_OPTIONS: Partial<scrollOptions> = {
    limit: 3,
    percentage: 1,
    soft: false,
};
type direction = 'right' | 'left' | 'up' | 'down';

interface XY {
    x: number;
    y: number;
}

/**
 * The values in the below object are percentages of the screen
 */
const SWIPE_DIRECTION_PERCENTAGES = {
    down: {
        start: { x: 0.5, y: 0.2 },
        end: { x: 0.5, y: 0.8 },
    },
    left: {
        start: { x: 0.5, y: 0.5 },
        end: { x: 0.05, y: 0.5 },
    },
    right: {
        start: { x: 0.05, y: 0.5 },
        end: { x: 0.95, y: 0.5 },
    },
    up: {
        start: { x: 0.5, y: 0.8 },
        end: { x: 0.5, y: 0.2 },
    },
};

class Gestures  {
    async tapOnElement(element: WebdriverIO.Element) {
        await browser.touchAction({
            action: 'tap',
            x: 100,
            y: 100,
            element: element,
        });
    }

    async tapOnCoords(x: number, y: number) {
        await browser.touchAction({
            action: 'tap',
            x: x,
            y: y,
        });
    }
    /**
     * Swipe down based on a percentage
     */
    async swipeDown(percentage = 1) {
        console.info(`Swiping down with [${percentage}] percentage`);
        await this.swipeOnPercentage(
            SWIPE_DIRECTION_PERCENTAGES.down.start,
            SWIPE_DIRECTION_PERCENTAGES.down.end,
            percentage,
            'down'
        );
    }

    /**
     * Swipe Up based on a percentage
     */
    async swipeUp(percentage = 1) {
        console.info(`Swiping up with [${percentage}] percentage`);
        await this.swipeOnPercentage(
            SWIPE_DIRECTION_PERCENTAGES.up.start,
            SWIPE_DIRECTION_PERCENTAGES.up.end,
            percentage,
            'up'
        );
    }

    /**
     * Swipe left based on a percentage
     */
    async swipeLeft(percentage = 1) {
        await this.swipeOnPercentage(
            SWIPE_DIRECTION_PERCENTAGES.left.start,
            SWIPE_DIRECTION_PERCENTAGES.left.end,
            percentage,
            'left'
        );
    }

    /**
     * Swipe right based on a percentage
     */
    async swipeRight(percentage = 1) {
        await this.swipeOnPercentage(
            SWIPE_DIRECTION_PERCENTAGES.right.start,
            SWIPE_DIRECTION_PERCENTAGES.right.end,
            percentage,
            'right'
        );
    }

    /**
     * Swipe from coordinates (from) to the new coordinates (to). The given coordinates are
     * percentages of the screen.
     */
    async swipeOnPercentage(from: XY, to: XY, percentage: number, direction: direction) {
        // Get the screen size and store it so it can be re-used.
        // This will save a lot of webdriver calls if this methods is used multiple times.
        const SCREEN_SIZE = await driver.getWindowRect();
        // Get the start position on the screen for the swipe
        const pressCoords = this.getDeviceScreenCoords(SCREEN_SIZE, from);
        console.log('pressCoords :>> ', pressCoords);
        // Get the move to position on the screen for the swipe
        let releaseCoords = this.getDeviceScreenCoords(SCREEN_SIZE, to);
        releaseCoords = this.getReleaseCoords(pressCoords, releaseCoords, percentage, direction);
        await this.swipe(pressCoords, releaseCoords);
    }

    /**
     * Get Release Coords
     *
     * Get Release Coords based on percentage and direction
     * @param {XY} pressCoords
     * @param {XY} releaseCoords
     * @param {number} percentage
     * @param {direction} direction
     * @returns {XY}
     */
    getReleaseCoords(pressCoords: XY, releaseCoords: XY, percentage: number, direction: direction) {
        if (direction === 'up')
            releaseCoords = {
                x: releaseCoords.x,
                y: Math.round(pressCoords.y + percentage * (releaseCoords.y - pressCoords.y)),
            };
        if (direction === 'down')
            releaseCoords = {
                x: releaseCoords.x,
                y: Math.round(pressCoords.y + percentage * (releaseCoords.y - pressCoords.y)),
            };
        if (direction === 'left')
            releaseCoords = {
                x: Math.round(pressCoords.x + percentage * (releaseCoords.x - pressCoords.x)),
                y: releaseCoords.y,
            };
        if (direction === 'right')
            releaseCoords = {
                x: Math.round(pressCoords.x + percentage * (releaseCoords.x - pressCoords.x)),
                y: releaseCoords.y,
            };
        console.log('releaseCoords :>> ', releaseCoords);
        return releaseCoords;
    }
    /**
     * Swipe from coordinates (from) to the new coordinates (to). The given coordinates are in pixels.
     */
    async swipe(from: XY, to: XY) {
        await driver.performActions([
            {
                // a. Create the event
                type: 'pointer',
                id: 'finger1',
                parameters: { pointerType: 'touch' },
                actions: [
                    // b. Move finger into start position
                    { type: 'pointerMove', duration: 0, x: from.x, y: from.y },
                    // c. Finger comes down into contact with screen
                    { type: 'pointerDown', button: 0 },
                    // d. Pause for a little bit
                    { type: 'pause', duration: 100 },
                    // e. Finger moves to end position
                    //    We move our finger from the center of the element to the
                    //    starting position of the element.
                    //    Play with the duration to make the swipe go slower / faster
                    { type: 'pointerMove', duration: 800, x: to.x, y: to.y },
                    // f. Finger gets up, off the screen
                    { type: 'pointerUp', button: 0 },
                ],
            },
        ]);
        // Add a pause, just to make sure the swipe is done
        await driver.pause(1000);
    }

    /**
     * Get the screen coordinates based on a device his screen size
     */
    getDeviceScreenCoords(screenSize: RectReturn, coordinates: XY): XY {
        return {
            x: Math.round(screenSize.width * coordinates.x),
            y: Math.round(screenSize.height * coordinates.y),
        };
    }

    /**
     * Calculate the x y coordinates based on a percentage
     */

    async makeSignature(signatureArea: WebdriverIO.Element) {
        const locX = (await (await signatureArea.getLocation()).x) + 50;
        const locY = (await (await signatureArea.getLocation()).y) + 50;

        await driver.performActions([
            {
                type: 'pointer',
                id: 'finger1',
                parameters: { pointerType: 'touch' },
                actions: [
                    { type: 'pointerMove', duration: 0, x: locX, y: locY },
                    { type: 'pointerDown', button: 0 },
                    { type: 'pause', duration: 100 },
                    { type: 'pointerMove', duration: 1000, x: locX + 200, y: locY },
                    { type: 'pointerUp', button: 0 },
                ],
            },
        ]);
    }
}

export default new Gestures();