NỘI DUNG BÀI HỌC

✅Cách xử lý Radio, Checkbox, Switch
✅Cách xử lý Tap, Swipe, Zoom

✅Cách xử lý Radio, Checkbox, Switch

Hình dạng của Radio, CheckboxSwitch tuy khác nhau nhưng cách xử lý thì giống nhau.






- Để tích chọn hoặc bật tắt chúng ta dùng hàm click()
- Để kiểm tra trạng thái thì dùng hàm isSelected()hoặc getAttribute("checked")


Ví dụ xử lý RadioCheckbox:

@Test
public void testCheckbox() {
    WebElement checkbox = driver.findElement(AppiumBy.id("checkbox_id"));
    if (!checkbox.isSelected()) {
        checkbox.click();
    }
    System.out.println(checkbox.isSelected());
}

@Test
public void testRadioButton() {
    WebElement radio = driver.findElement(AppiumBy.xpath("//android.widget.RadioButton[@text='Option 1']"));
    radio.click();
    System.out.println(radio.isSelected());
}


Ví dụ xử lý Switch trên Taurus App:

package com.anhtester.Bao10_Radio_Checkbox;

import com.anhtester.common.BaseTestTaurusApp;
import com.anhtester.drivers.DriverManager;
import com.anhtester.keywords.MobileUI;
import io.appium.java_client.AppiumBy;
import org.openqa.selenium.WebElement;
import org.testng.annotations.Test;

public class DemoRadioCheckboxSwitch extends BaseTestTaurusApp {

    @Test(priority = 1)
    public void testAddTable() {
        loginTaurusApp();

        //Navigate to config
        DriverManager.getDriver().findElement(AppiumBy.accessibilityId("Config")).click();

        //Add table
        DriverManager.getDriver().findElement(AppiumBy.xpath("//android.widget.Button[contains(@content-desc,'Tables management')]")).click();
        DriverManager.getDriver().findElement(AppiumBy.accessibilityId("Add Table")).click();

        //Check status
        String checkBeforeClick = DriverManager.getDriver().findElement(AppiumBy.xpath("//android.widget.Switch")).getAttribute("checked");
        System.out.println(checkBeforeClick);
        MobileUI.sleep(1);
        //Click to turn on
        DriverManager.getDriver().findElement(AppiumBy.xpath("//android.widget.Switch")).click();
        MobileUI.sleep(1);
        //Check status
        String checkAfterClick = DriverManager.getDriver().findElement(AppiumBy.xpath("//android.widget.Switch")).getAttribute("checked");
        System.out.println(checkAfterClick);
    }
}


Class BaseTestTaurusApp có chứa 2 hàm sau:

public void loginTaurusApp() {
    MobileUI.sleep(2);
    WebElement inputUsername = DriverManager.getDriver().findElement(AppiumBy.xpath("//android.view.View[@content-desc=\"Mobile App Flutter Beta\"]/following-sibling::android.widget.EditText[1]"));
    inputUsername.click();
    inputUsername.sendKeys("admin");
    MobileUI.sleep(1);
    WebElement inputPassword = DriverManager.getDriver().findElement(AppiumBy.xpath("//android.view.View[@content-desc=\"Mobile App Flutter Beta\"]/following-sibling::android.widget.EditText[2]"));
    inputPassword.click();
    inputPassword.sendKeys("admin");

    DriverManager.getDriver().findElement(AppiumBy.xpath("//android.widget.Button[@content-desc=\"Sign in\"]")).click();

    MobileUI.sleep(2);
    WebElement menuMenu = DriverManager.getDriver().findElement(AppiumBy.accessibilityId("Menu"));
    if (menuMenu.isDisplayed()) {
        System.out.println("Login success.");
    } else {
        System.out.println("Login failed.");
    }
}

public void downloadDataFromServer(int dataNumber) {
    //Navigate to config to download database demo
    DriverManager.getDriver().findElement(AppiumBy.accessibilityId("Config")).click();
    DriverManager.getDriver().findElement(AppiumBy.accessibilityId("Server database")).click();
    MobileUI.sleep(2);
    DriverManager.getDriver().findElement(AppiumBy.xpath("//android.view.View[contains(@content-desc,'Data " + dataNumber + "')]/android.widget.Button")).click();
    DriverManager.getDriver().findElement(AppiumBy.accessibilityId("Replace")).click();
    MobileUI.sleep(1);

    //Handle Alert Message, check displayed hoặc getText/getAttribute để kiểm tra nội dung message
    if (DriverManager.getDriver().findElement(AppiumBy.accessibilityId("Downloaded")).isDisplayed()) {
        System.out.println("Database demo downloaded.");
    } else {
        System.out.println("Warning!! Can not download Database demo.");
    }
    MobileUI.sleep(2);
}


Class MobileUI:

package com.anhtester.keywords;

public class MobileUI {
    public static void sleep(double second){
        try {
            Thread.sleep((long) (1000*second));
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

 

✅Cách xử lý Tap, Swipe, Zoom

3 cái tên nói trên là 3 thao tác hành động:
- Tap là chạm một ngón tay vào một vị trí cụ thể, có thể đè giữ một thời gian (long tap)
- Swipe là hành động vuốt màn hình từ dưới lên hoặc trên xuống hoặc trái phải.
- Zoom là dùng 2 ngón tay thu hẹp hoặc phóng rộng ra (để xem hình chẳng hạn)

Tất cả 3 hành động trên đều dùng chung các class hỗ trợ xử lý từ SeleniumAppium: PointerInput Sequence


🔆Xử lý Tap (chạm)

package com.anhtester.Bao10_Radio_Checkbox;

import com.anhtester.common.BaseTestTaurusApp;
import com.anhtester.drivers.DriverManager;
import com.anhtester.keywords.MobileUI;
import io.appium.java_client.AppiumBy;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.Point;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Pause;
import org.openqa.selenium.interactions.PointerInput;
import org.openqa.selenium.interactions.Sequence;
import org.testng.annotations.Test;

import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;

public class DemoTap extends BaseTestTaurusApp {

    private Point getCenterOfElement(Point location, Dimension size) {
        return new Point(location.getX() + size.getWidth() / 2,
                location.getY() + size.getHeight() / 2);
    }

    public void tap(WebElement element) {
        Point location = element.getLocation();
        Dimension size = element.getSize();
        Point centerOfElement = getCenterOfElement(location, size);
        PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger");
        Sequence sequence = new Sequence(finger, 1)
                .addAction(finger.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), centerOfElement))
                .addAction(finger.createPointerDown(PointerInput.MouseButton.LEFT.asArg()))
                .addAction(new Pause(finger, Duration.ofMillis(500)))
                .addAction(finger.createPointerUp(PointerInput.MouseButton.LEFT.asArg()));

        DriverManager.getDriver().perform(Collections.singletonList(sequence));
    }

    public void tap(int x, int y) {
        PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger");
        Sequence tap = new Sequence(finger, 1);
        tap.addAction(finger.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), x, y));
        tap.addAction(finger.createPointerDown(PointerInput.MouseButton.LEFT.asArg()));
        tap.addAction(new Pause(finger, Duration.ofMillis(200))); //Chạm nhẹ nhanh
        tap.addAction(finger.createPointerUp(PointerInput.MouseButton.LEFT.asArg()));
        DriverManager.getDriver().perform(Arrays.asList(tap));
    }

    public void tap(int x, int y, int second) {
        PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger");
        Sequence tap = new Sequence(finger, 1);
        tap.addAction(finger.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), x, y));
        tap.addAction(finger.createPointerDown(PointerInput.MouseButton.LEFT.asArg()));
        tap.addAction(new Pause(finger, Duration.ofMillis(second))); //Chạm vào với thời gian chỉ định
        tap.addAction(finger.createPointerUp(PointerInput.MouseButton.LEFT.asArg()));
        DriverManager.getDriver().perform(Arrays.asList(tap));
    }

    @Test(priority = 1)
    public void demoTap1() {
        loginTaurusApp();

        //Navigate to config
        WebElement menuConfig = DriverManager.getDriver().findElement(AppiumBy.accessibilityId("Config"));
        tap(menuConfig);

        MobileUI.sleep(3);
    }
}

 

Giải thích chi tiết

  • element.getLocation(): Lấy tọa độ của phần tử trên màn hình.
  • getCenterOfElement(): Lấy vị trí chính giữa của element từ hàm getLocation() trên
  • PointerInput: Đại diện cho một thiết bị đầu vào, trong trường hợp này là ngón tay (PointerInput.Kind.TOUCH).
  • Sequence: Tập hợp các hành động được thực hiện bởi một PointerInput.
  • createPointerMove(): Di chuyển con trỏ đến vị trí của phần tử. PointerInput.Origin.viewport() xác định hệ tọa độ dựa trên viewport (khung nhìn) của ứng dụng.
  • createPointerDown(): Mô phỏng việc chạm vào màn hình. Tham số 0 chỉ định ngón tay đầu tiên (thường là ngón tay duy nhất được sử dụng).
  • createPointerUp(): Mô phỏng việc nhấc ngón tay khỏi màn hình.
  • driver.perform(): Thực hiện chuỗi hành động được định nghĩa trong Sequence.

Lưu ý

  • Bạn cần import các lớp PointerInput, Sequence, PointDuration từ org.openqa.selenium.java.time.



Chúng ta có thể Tap theo tạo độ khi không có cách nào xác định được element.

Trên Appium Inspector các bạn chuyển sang tuỳ chọn Tap/Swipe By Coordinates để hiển thị toạ độ của vị trí chuột.

Lưu ý: muốn chính xác toạ độ thì phải dùng cùng 1 thiết bị để bắt toạ độ và chạy automation.




Ví dụ option Table management (12) có toạ độ là (460, 954) trên device Pixel 9 Pro XL 34 có độ phân giải là 1344x2992

package com.anhtester.Bao10_Radio_Checkbox;

import com.anhtester.common.BaseTestTaurusApp;
import com.anhtester.drivers.DriverManager;
import com.anhtester.keywords.MobileUI;
import io.appium.java_client.AppiumBy;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.Point;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Pause;
import org.openqa.selenium.interactions.PointerInput;
import org.openqa.selenium.interactions.Sequence;
import org.testng.annotations.Test;

import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;

public class DemoTap extends BaseTestTaurusApp {

    private Point getCenterOfElement(Point location, Dimension size) {
        return new Point(location.getX() + size.getWidth() / 2,
                location.getY() + size.getHeight() / 2);
    }

    public void tap(WebElement element) {
        Point location = element.getLocation();
        Dimension size = element.getSize();
        Point centerOfElement = getCenterOfElement(location, size);
        PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger");
        Sequence sequence = new Sequence(finger, 1)
                .addAction(finger.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), centerOfElement))
                .addAction(finger.createPointerDown(PointerInput.MouseButton.LEFT.asArg()))
                .addAction(new Pause(finger, Duration.ofMillis(500)))
                .addAction(finger.createPointerUp(PointerInput.MouseButton.LEFT.asArg()));

        DriverManager.getDriver().perform(Collections.singletonList(sequence));
    }

    public void tap(int x, int y) {
        PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger");
        Sequence tap = new Sequence(finger, 1);
        tap.addAction(finger.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), x, y));
        tap.addAction(finger.createPointerDown(PointerInput.MouseButton.LEFT.asArg()));
        tap.addAction(new Pause(finger, Duration.ofMillis(200))); //Chạm nhẹ nhanh
        tap.addAction(finger.createPointerUp(PointerInput.MouseButton.LEFT.asArg()));
        DriverManager.getDriver().perform(Arrays.asList(tap));
    }

    public void tap(int x, int y, int second) {
        PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger");
        Sequence tap = new Sequence(finger, 1);
        tap.addAction(finger.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), x, y));
        tap.addAction(finger.createPointerDown(PointerInput.MouseButton.LEFT.asArg()));
        tap.addAction(new Pause(finger, Duration.ofMillis(second))); //Chạm vào với thời gian chỉ định
        tap.addAction(finger.createPointerUp(PointerInput.MouseButton.LEFT.asArg()));
        DriverManager.getDriver().perform(Arrays.asList(tap));
    }

    @Test(priority = 2)
    public void demoTap2() {
        loginTaurusApp();

        //Navigate to config
        WebElement menuConfig = DriverManager.getDriver().findElement(AppiumBy.accessibilityId("Config"));
        tap(menuConfig);

        MobileUI.sleep(3);

        //Click option Table management
        tap(456, 954);
        MobileUI.sleep(2);
        //Click Back
        tap(82, 155);
        MobileUI.sleep(2);
        //Click menu Profile
        tap(924, 2777);
        MobileUI.sleep(2);
        //Click Edit button
        tap(297, 1199);

        MobileUI.sleep(3);
    }
}

 

🔆Xử lý Swipe (vuốt)

Ví dụ vào app Taurus, vào trang Menu hiện danh sách Tables.

- Thực hiện vuốt từ dưới lên để hiện phần table ẩn bên dưới:

package com.anhtester.Bao10_Radio_Checkbox;

import com.anhtester.common.BaseTestTaurusApp;
import com.anhtester.drivers.DriverManager;
import com.anhtester.keywords.MobileUI;
import io.appium.java_client.AppiumBy;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.Point;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Pause;
import org.openqa.selenium.interactions.PointerInput;
import org.openqa.selenium.interactions.Sequence;
import org.testng.annotations.Test;

import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;

public class DemoSwipe extends BaseTestTaurusApp {

    public void swipe(int startX, int startY, int endX, int endY, int durationMillis) {
        PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger");
        Sequence swipe = new Sequence(finger, 1);
        swipe.addAction(finger.createPointerMove(Duration.ofMillis(0), PointerInput.Origin.viewport(), startX, startY));
        swipe.addAction(finger.createPointerDown(0));
        swipe.addAction(finger.createPointerMove(Duration.ofMillis(durationMillis), PointerInput.Origin.viewport(), endX, endY));
        swipe.addAction(finger.createPointerUp(0));
        DriverManager.getDriver().perform(Collections.singletonList(swipe));
    }

    @Test(priority = 1)
    public void demoSwipe1() {
        loginTaurusApp();
        downloadDataFromServer(1);

        DriverManager.getDriver().findElement(AppiumBy.accessibilityId("Back")).click();
        MobileUI.sleep(2);
        DriverManager.getDriver().findElement(AppiumBy.accessibilityId("Menu")).click();
        MobileUI.sleep(4);

        swipe(671, 1956, 671, 1229, 500);

        MobileUI.sleep(3);
    }

}


- Chuyển sang menu Date để thực hiện vuốt sang trái và phải:

package com.anhtester.Bao10_Radio_Checkbox;

import com.anhtester.common.BaseTestTaurusApp;
import com.anhtester.drivers.DriverManager;
import com.anhtester.keywords.MobileUI;
import io.appium.java_client.AppiumBy;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.Point;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Pause;
import org.openqa.selenium.interactions.PointerInput;
import org.openqa.selenium.interactions.Sequence;
import org.testng.annotations.Test;

import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;

public class DemoSwipe extends BaseTestTaurusApp {

    public void swipe(int startX, int startY, int endX, int endY, int durationMillis) {
        PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger");
        Sequence swipe = new Sequence(finger, 1);
        swipe.addAction(finger.createPointerMove(Duration.ofMillis(0), PointerInput.Origin.viewport(), startX, startY));
        swipe.addAction(finger.createPointerDown(0));
        swipe.addAction(finger.createPointerMove(Duration.ofMillis(durationMillis), PointerInput.Origin.viewport(), endX, endY));
        swipe.addAction(finger.createPointerUp(0));
        DriverManager.getDriver().perform(Collections.singletonList(swipe));
    }

    public void swipeLeft() {
        Dimension size = DriverManager.getDriver().manage().window().getSize();
        int startX = (int) (size.width * 0.8);
        //int startY = size.height / 2; // Ở chính giữa màn hình
        int startY = (int) (size.height * 0.3); // 1/3 bên trên màn hình
        int endX = (int) (size.width * 0.2);
        int endY = startY; // Giữ nguyên độ cao
        int duration = 200;

        swipe(startX, startY, endX, endY, duration);
    }

    public void swipeRight() {
        Dimension size = DriverManager.getDriver().manage().window().getSize();
        int startX = (int) (size.width * 0.2);
        //int startY = size.height / 2; // Ở chính giữa màn hình
        int startY = (int) (size.height * 0.3); // 1/3 bên trên màn hình
        int endX = (int) (size.width * 0.8);
        int endY = startY; // Giữ nguyên độ cao
        int duration = 200;

        swipe(startX, startY, endX, endY, duration);
    }

    @Test(priority = 2)
    public void demoSwipe2() {
        loginTaurusApp();

        DriverManager.getDriver().findElement(AppiumBy.accessibilityId("Date")).click();
        MobileUI.sleep(4);

        swipeLeft();
        MobileUI.sleep(2);
        swipeRight();
        MobileUI.sleep(2);

        //Nếu vị trí cố định ấy không dùng được thì chúng ta sẽ bắt toạ độ cụ thể

        //Từ trái qua phải
        swipe(95, 1032, 1255, 1032, 200);
        MobileUI.sleep(2);
        //Từ phải qua trái
        swipe(1255, 1032, 95, 1032, 200);

        MobileUI.sleep(3);
    }


}

 

🔆Xử lý ZOOM (phóng to, thu nhỏ)

package com.anhtester.Bao10_Radio_Checkbox;

import com.anhtester.common.BaseTestTaurusApp;
import com.anhtester.drivers.DriverManager;
import com.anhtester.keywords.MobileUI;
import io.appium.java_client.AppiumBy;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.PointerInput;
import org.openqa.selenium.interactions.Sequence;
import org.testng.annotations.Test;

import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;

public class DemoZoom extends BaseTestTaurusApp {

    public void zoom(WebElement element, double scale) {
        int centerX = element.getLocation().getX() + element.getSize().getWidth() / 2;
        int centerY = element.getLocation().getY() + element.getSize().getHeight() / 2;
        int distance = 100; // Khoảng cách giữa hai ngón tay

        PointerInput finger1 = new PointerInput(PointerInput.Kind.TOUCH, "finger1");
        PointerInput finger2 = new PointerInput(PointerInput.Kind.TOUCH, "finger2");

        Sequence zoom = new Sequence(finger1, 1);
        zoom.addAction(finger1.createPointerMove(Duration.ofMillis(0), PointerInput.Origin.viewport(), centerX - distance, centerY));
        zoom.addAction(finger1.createPointerDown(0));

        Sequence zoom2 = new Sequence(finger2, 1);
        zoom2.addAction(finger2.createPointerMove(Duration.ofMillis(0), PointerInput.Origin.viewport(), centerX + distance, centerY));
        zoom2.addAction(finger2.createPointerDown(0));

        if (scale > 1) { // Phóng to
            for (int i = 0; i < 10; i++) {
                zoom.addAction(finger1.createPointerMove(Duration.ofMillis(50), PointerInput.Origin.viewport(), centerX - distance / 2, centerY));
                zoom2.addAction(finger2.createPointerMove(Duration.ofMillis(50), PointerInput.Origin.viewport(), centerX + distance / 2, centerY));
            }
        } else { // Thu nhỏ
            for (int i = 0; i < 10; i++) {
                zoom.addAction(finger1.createPointerMove(Duration.ofMillis(50), PointerInput.Origin.viewport(), centerX - distance * 2, centerY));
                zoom2.addAction(finger2.createPointerMove(Duration.ofMillis(50), PointerInput.Origin.viewport(), centerX + distance * 2, centerY));
            }
        }

        zoom.addAction(finger1.createPointerUp(0));
        zoom2.addAction(finger2.createPointerUp(0));

        DriverManager.getDriver().perform(Arrays.asList(zoom, zoom2));
    }

    @Test(priority = 1)
    public void demoZoomIn() {
        loginTaurusApp();
        MobileUI.sleep(2);

        WebElement inputSearch = DriverManager.getDriver().findElement(AppiumBy.xpath("//android.widget.EditText"));
        zoom(inputSearch, 2); // Phóng to gấp 2 lần

        MobileUI.sleep(3);
    }

    @Test(priority = 2)
    public void demoZoomOut() {
        loginTaurusApp();
        MobileUI.sleep(2);

        WebElement inputSearch = DriverManager.getDriver().findElement(AppiumBy.xpath("//android.widget.EditText"));
        zoom(inputSearch, 0.5); // Thu nhỏ 2 lần

        MobileUI.sleep(3);
    }

}

 

Giải thích chi tiết

  • element.getLocation() element.getSize(): Lấy tọa độ và kích thước của phần tử để tính toán tâm của nó.
  • centerX centerY: Tọa độ tâm của phần tử.
  • distance: Khoảng cách ban đầu giữa hai ngón tay.
  • PointerInput: Đại diện cho hai thiết bị đầu vào, mỗi thiết bị đại diện cho một ngón tay (PointerInput.Kind.TOUCH).
  • Sequence: Tập hợp các hành động được thực hiện bởi mỗi PointerInput.
  • createPointerMove(): Di chuyển con trỏ đến vị trí tương ứng.
  • createPointerDown(): Mô phỏng việc chạm vào màn hình.
  • createPointerUp(): Mô phỏng việc nhấc ngón tay khỏi màn hình.
  • driver.perform(): Thực hiện chuỗi hành động được định nghĩa trong Sequence.
  • scale: Hệ số zoom. Nếu scale > 1, phóng to. Nếu scale < 1, thu nhỏ.

Chỗ này muốn nhìn rõ thì kiếm cái tấm hình, click vào xong thu phóng sẽ dễ nhìn hơn. Vì các element khác dạng cố định nên có thể không nhìn thấy sự thu phóng.

Teacher

Teacher

Anh Tester

Software Quality Engineer

Đường dẫu khó chân vẫn cần bước đi
Đời dẫu khổ tâm vẫn cần nghĩ thấu

Cộng đồng Automation Testing Việt Nam:

🌱 Telegram Automation Testing:   Cộng đồng Automation Testing
🌱 
Facebook Group Automation: Cộng đồng Automation Testing Việt Nam
🌱 
Facebook Fanpage: Cộng đồng Automation Testing Việt Nam - Selenium
🌱 Telegram
Manual Testing:   Cộng đồng Manual Testing
🌱 
Facebook Group Manual: Cộng đồng Manual Testing Việt Nam

Chia sẻ khóa học lên trang

Bạn có thể đăng khóa học của chính bạn lên trang Anh Tester để kiếm tiền

Danh sách bài học