appium/java-client

Why does merging two sequences into a single androidDriver.perform() method result in an InvalidElementStateException in Appium/Selenide?

Deceptio opened this issue · 4 comments

I am working on automating tests for an Android application using Appium and Selenide. I have a scenario where I need to perform two separate actions on two different buttons. When I use a separate androidDriver.perform() method for each action, everything works fine. However, when I try to perform both actions within a single androidDriver.perform() method by passing both sequences to the method, I encounter an InvalidElementStateException.

if (isAndroid()) {

SelenideElement buttonsKeyBoard1 = $x("//android.widget.Button[contains(@resource-id, 'Keyboard_1Button')]").should(Condition.visible);
SelenideElement buttonsKeyBoard2 = $x("//android.widget.Button[contains(@resource-id, 'Keyboard_2Button')]");

List buttonsKeyBoard = new ArrayList<>();
buttonsKeyBoard.add(buttonsKeyBoard1);
buttonsKeyBoard.add(buttonsKeyBoard2);

// Create a list to hold the sequences
List sequences = new ArrayList<>();

// Process the first button
PointerInput finger1 = new PointerInput(PointerInput.Kind.TOUCH, "finger1");
PointerInput finger2 = new PointerInput(PointerInput.Kind.TOUCH, "finger2");

Sequence tap1 = new Sequence(finger1, 1);
Sequence tap2 = new Sequence(finger2, 1);

Point sourceLocation = buttonsKeyBoard1.getLocation();
Point sourceLocation2 = buttonsKeyBoard2.getLocation();

int centerX = sourceLocation.getX() + buttonsKeyBoard1.getSize().getWidth() / 2;
int centerY = sourceLocation.getY() + buttonsKeyBoard1.getSize().getHeight() / 2;
System.out.println("x1 and y1 " + centerX + " " + centerY);
int centerX2 = sourceLocation2.getX() + buttonsKeyBoard2.getSize().getWidth() / 2;
int centerY2= sourceLocation2.getY() + buttonsKeyBoard2.getSize().getHeight() / 2;

System.out.println("x2 and y2 " + centerX2 + " " + centerY2);
tap1.addAction(finger1.createPointerMove(Duration.ofMillis(10), PointerInput.Origin.viewport(), centerX, centerY));
tap1.addAction(finger1.createPointerDown(LEFT.asArg()));
tap1.addAction(finger1.createPointerUp(LEFT.asArg()));
sequences.add(tap1); // Add the sequence to the list of sequences

tap2.addAction(finger2.createPointerMove(Duration.ofMillis(10), PointerInput.Origin.viewport(), centerX2, centerY2));
tap2.addAction(finger2.createPointerDown(LEFT.asArg()));
tap2.addAction(finger2.createPointerUp(LEFT.asArg()));
sequences.add(tap2); // Add the sequence to the list of sequences

androidDriver.perform(sequences);
}

The error message that I receive is as follows:

Caused by: org.openqa.selenium.InvalidElementStateException: Unable to perform W3C actions. Check the logcat output for possible error reports and make sure your input actions chain is valid.

But when I change it to the follow, and create 2 seperate sequence and 2 different perform methods. the methode works. But I think that's not the idea, I want to execute as many sequences as possible with the same perform method.

    sequences.add(tap1);  
    tap2.addAction(finger2.createPointerMove(Duration.ofMillis(10), PointerInput.Origin.viewport(), centerX2, centerY2));
    tap2.addAction(finger2.createPointerDown(LEFT.asArg()));
    tap2.addAction(finger2.createPointerUp(LEFT.asArg()));
    sequences2.add(tap2); 
    androidDriver.perform(sequences);
    androidDriver.perform(sequences2);`

I can't believe it. I added the new Pause of 100ms after the createPointerDown and now it works.

But why not implement a default pause in the method createPointerDown()? So we don't need to remember to add a pause?

Here is my code snippet which i changed

` System.out.println("x2 and y2 " + centerX2 + " " + centerY2);
tap1.addAction(finger1.createPointerMove(ofMillis(0), PointerInput.Origin.viewport(), centerX, centerY));
tap1.addAction(finger1.createPointerDown(LEFT.asArg()));
tap1.addAction(new Pause(finger1, ofMillis(100)));
tap1.addAction(finger1.createPointerUp(LEFT.asArg()));
sequences.add(tap1); // Add the sequence to the list of sequences

        tap2.addAction(finger2.createPointerMove(ofMillis(0), PointerInput.Origin.viewport(), centerX2, centerY2));
        tap2.addAction(finger2.createPointerDown(LEFT.asArg()));
        tap2.addAction(new Pause(finger2, ofMillis(100)));
        tap2.addAction(finger2.createPointerUp(LEFT.asArg()));

        sequences.add(tap2);  // Add the sequence to the list of sequences

        androidDriver.perform(sequences);` 

But why not implement a default pause in the method createPointerDown()? So we don't need to remember to add a pause?

I assume because the implementation itself is platform-agnostic. Adding some preconditions there means it would probably stop working for some platforms while still works for others.

What is the message you get from logcat?