Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions swipe_actions/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.testsigma.addons</groupId>
<artifactId>swipe_actions</artifactId>
<version>1.0.1</version>
<packaging>jar</packaging>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<testsigma.sdk.version>1.2.24_cloud</testsigma.sdk.version>
<junit.jupiter.version>5.8.0-M1</junit.jupiter.version>
<testsigma.addon.maven.plugin>1.0.0</testsigma.addon.maven.plugin>
<maven.source.plugin.version>3.2.1</maven.source.plugin.version>
<lombok.version>1.18.30</lombok.version>

</properties>

<dependencies>
<dependency>
<groupId>com.testsigma</groupId>
<artifactId>testsigma-java-sdk</artifactId>
<version>${testsigma.sdk.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.33.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.appium/java-client -->
<dependency>
<groupId>io.appium</groupId>
<artifactId>java-client</artifactId>
<version>9.4.0</version>
</dependency>
Comment on lines +47 to +58
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

latest Selenium Java version April 2026

💡 Result:

The latest version of Selenium Java as of April 30, 2026, is 4.43.0, released on April 10, 2026. This is confirmed by the official Selenium downloads page listing it as the stable version and the GitHub release page providing the selenium-java-4.43.0.zip asset with significant downloads.

Citations:


🌐 Web query:

Appium java-client latest version 9.4.0 April 2026

💡 Result:

As of 2026-04-30, the latest released version of the Appium Java client (artifact io.appium:java-client) is 10.1.1 (with 10.1.0 released 2026-03-11).

Citations:


Update to latest Selenium and Appium versions in use.

Selenium 4.33.0 is outdated; the latest stable version as of April 2026 is 4.43.0 (released April 10, 2026). Similarly, Appium java-client 9.4.0 is significantly behind the latest version 10.1.1 (released March 11, 2026). Update both dependencies to their latest versions and verify compatibility with the Testsigma SDK.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@swipe_actions/pom.xml` around lines 47 - 58, Update the Selenium and Appium
dependency versions in the POM: change org.seleniumhq.selenium:selenium-java
from 4.33.0 to 4.43.0 and io.appium:java-client from 9.4.0 to 10.1.1, then run a
build and smoke tests to ensure these updated artifacts (selenium-java and
java-client) remain compatible with the Testsigma SDK and adjust any
import/usage changes surfaced by the newer APIs.

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.13.0</version>
</dependency>

</dependencies>
<build>
<finalName>swipe_actions</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>${maven.source.plugin.version}</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package com.testsigma.addons.android;

import com.testsigma.sdk.AndroidAction;
import com.testsigma.sdk.ApplicationType;
import com.testsigma.sdk.Element;
import com.testsigma.sdk.Result;
import com.testsigma.sdk.annotation.Action;
import com.testsigma.sdk.annotation.TestData;
import io.appium.java_client.AppiumDriver;
import lombok.Data;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.interactions.PointerInput;
import org.openqa.selenium.interactions.Sequence;

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

import static org.openqa.selenium.interactions.PointerInput.Kind.TOUCH;
import static org.openqa.selenium.interactions.PointerInput.MouseButton.LEFT;
import static org.openqa.selenium.interactions.PointerInput.Origin.viewport;

@Data
@Action(actionText = "Swipe inside the element element-name in direction direction for duration seconds",
description = "Scrolls inside the given element in the specified direction. The swipe gesture takes the" +
" given number of seconds to complete. Use longer durations for slower, more deliberate scrolls.",
applicationType = ApplicationType.ANDROID,
displayName = "Scroll inside element with direction and duration",
useCustomScreenshot = false)
public class ScrollInsideElementWithDuration extends AndroidAction {

@com.testsigma.sdk.annotation.Element(reference = "element-name")
private Element elementName;

@TestData(reference = "direction",
allowedValues = {
"LEFT TO RIGHT",
"RIGHT TO LEFT",
"MIDDLE TO LEFT",
"MIDDLE TO RIGHT",
"LEFT TO MIDDLE",
"RIGHT TO MIDDLE",
"TOP TO BOTTOM",
"BOTTOM TO TOP",
"TOP TO MIDDLE",
"MIDDLE TO TOP",
"BOTTOM TO MIDDLE",
"MIDDLE TO BOTTOM"
})
private com.testsigma.sdk.TestData direction;

@TestData(reference = "duration")
private com.testsigma.sdk.TestData duration;

@Override
protected Result execute() throws NoSuchElementException {
logger.info("Starting scroll inside element with direction and duration");

int durationSeconds;
try {
durationSeconds = Integer.parseInt(duration.getValue().toString().trim());
} catch (NumberFormatException e) {
setErrorMessage("Invalid duration: '" + duration.getValue() + "'. Please provide a whole number of seconds.");
return Result.FAILED;
}

if (durationSeconds <= 0) {
setErrorMessage("Duration must be greater than 0, but got: " + durationSeconds);
return Result.FAILED;
}

String swipeDirection = direction.getValue().toString().trim().toUpperCase();

try {
org.openqa.selenium.WebElement webElement = elementName.getElement();
Rectangle rect = webElement.getRect();

int centerX = rect.x + rect.width / 2;
int centerY = rect.y + rect.height / 2;
int left = rect.x;
int right = rect.x + rect.width;
int top = rect.y;
int bottom = rect.y + rect.height;

logger.info(String.format("Element rect: x=%d y=%d w=%d h=%d", rect.x, rect.y, rect.width, rect.height));

int[] coords = resolveCoordinates(swipeDirection, left, right, top, bottom, centerX, centerY);
if (coords == null) {
setErrorMessage("Unsupported direction: " + swipeDirection);
return Result.FAILED;
}

int startX = coords[0];
int startY = coords[1];
int endX = coords[2];
int endY = coords[3];

logger.info(String.format("Swipe [%s]: (%d,%d) -> (%d,%d) over %ds",
swipeDirection, startX, startY, endX, endY, durationSeconds));

AppiumDriver appiumDriver = (AppiumDriver) this.driver;
PointerInput finger = new PointerInput(TOUCH, "finger");
Sequence swipe = new Sequence(finger, 1)
.addAction(finger.createPointerMove(Duration.ofMillis(0), viewport(), startX, startY))
.addAction(finger.createPointerDown(LEFT.asArg()))
.addAction(finger.createPointerMove(Duration.ofSeconds(durationSeconds), viewport(), endX, endY))
.addAction(finger.createPointerUp(LEFT.asArg()));

appiumDriver.perform(Collections.singletonList(swipe));

setSuccessMessage(String.format(
"Successfully scrolled inside the element [%s] over %d second(s)", swipeDirection, durationSeconds));
return Result.SUCCESS;

} catch (NoSuchElementException e) {
logger.debug("Element not found: " + e.getMessage());
setErrorMessage("Element not found: " + e.getMessage());
return Result.FAILED;
} catch (Exception e) {
logger.debug("Scroll failed: " + e.getMessage());
setErrorMessage("Scroll failed: " + e.getMessage());
return Result.FAILED;
}
}

private int[] resolveCoordinates(String dir, int left, int right, int top, int bottom, int cx, int cy) {
switch (dir) {
// ── Horizontal ──────────────────────────────────────────────────────────
case "LEFT TO RIGHT": return new int[]{left, cy, right, cy};
case "RIGHT TO LEFT": return new int[]{right, cy, left, cy};
case "MIDDLE TO LEFT": return new int[]{cx, cy, left, cy};
case "MIDDLE TO RIGHT": return new int[]{cx, cy, right, cy};
case "LEFT TO MIDDLE": return new int[]{left, cy, cx, cy};
case "RIGHT TO MIDDLE": return new int[]{right, cy, cx, cy};
// ── Vertical ────────────────────────────────────────────────────────────
case "TOP TO BOTTOM": return new int[]{cx, top, cx, bottom};
case "BOTTOM TO TOP": return new int[]{cx, bottom, cx, top};
case "TOP TO MIDDLE": return new int[]{cx, top, cx, cy};
case "MIDDLE TO TOP": return new int[]{cx, cy, cx, top};
case "BOTTOM TO MIDDLE":return new int[]{cx, bottom, cx, cy};
case "MIDDLE TO BOTTOM":return new int[]{cx, cy, cx, bottom};
default: return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.testsigma.addons.ios;

import com.testsigma.sdk.ApplicationType;
import com.testsigma.sdk.Element;
import com.testsigma.sdk.IOSAction;
import com.testsigma.sdk.Result;
import com.testsigma.sdk.annotation.Action;
import io.appium.java_client.AppiumDriver;
import lombok.Data;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.interactions.PointerInput;
import org.openqa.selenium.interactions.Sequence;

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

import static org.openqa.selenium.interactions.PointerInput.Kind.TOUCH;
import static org.openqa.selenium.interactions.PointerInput.MouseButton.LEFT;
import static org.openqa.selenium.interactions.PointerInput.Origin.viewport;

@Data
@Action(actionText = "Swipe inside the element element-name from middle to bottom",
description = "Scrolls inside the given element starting from its vertical midpoint down to its bottom edge." +
" Useful for revealing content below the centre of the element.",
applicationType = ApplicationType.IOS,
displayName = "Scroll inside element from middle to bottom",
useCustomScreenshot = false)
public class ScrollInsideElementFromMiddleToBottom extends IOSAction {

@com.testsigma.sdk.annotation.Element(reference = "element-name")
private Element elementName;

@Override
protected Result execute() throws NoSuchElementException {
logger.info("Starting scroll inside element from middle to bottom");

try {
org.openqa.selenium.WebElement webElement = elementName.getElement();
Rectangle rect = webElement.getRect();

int startX = rect.x + rect.width / 2;
int startY = rect.y + rect.height / 2;
int endX = startX;
int endY = rect.y + rect.height;

logger.info(String.format("Element rect: x=%d y=%d w=%d h=%d", rect.x, rect.y, rect.width, rect.height));
logger.info(String.format("Swipe: (%d,%d) -> (%d,%d)", startX, startY, endX, endY));

AppiumDriver appiumDriver = (AppiumDriver) this.driver;
PointerInput finger = new PointerInput(TOUCH, "finger");
Sequence swipe = new Sequence(finger, 1)
.addAction(finger.createPointerMove(Duration.ofMillis(0), viewport(), startX, startY))
.addAction(finger.createPointerDown(LEFT.asArg()))
.addAction(finger.createPointerMove(Duration.ofSeconds(2), viewport(), endX, endY))
.addAction(finger.createPointerUp(LEFT.asArg()));

appiumDriver.perform(Collections.singletonList(swipe));

setSuccessMessage("Successfully scrolled inside the element from middle to bottom");
return Result.SUCCESS;

} catch (NoSuchElementException e) {
logger.debug("Element not found: " + e.getMessage());
setErrorMessage("Element not found: " + e.getMessage());
return Result.FAILED;
} catch (Exception e) {
logger.debug("Failed to scroll inside element from middle to bottom: " + e.getMessage());
setErrorMessage("Failed to scroll: " + e.getMessage());
return Result.FAILED;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.testsigma.addons.ios;

import com.testsigma.sdk.ApplicationType;
import com.testsigma.sdk.Element;
import com.testsigma.sdk.IOSAction;
import com.testsigma.sdk.Result;
import com.testsigma.sdk.annotation.Action;
import io.appium.java_client.AppiumDriver;
import lombok.Data;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.interactions.PointerInput;
import org.openqa.selenium.interactions.Sequence;

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

import static org.openqa.selenium.interactions.PointerInput.Kind.TOUCH;
import static org.openqa.selenium.interactions.PointerInput.MouseButton.LEFT;
import static org.openqa.selenium.interactions.PointerInput.Origin.viewport;

@Data
@Action(actionText = "Swipe inside the element element-name from middle to top",
description = "Scrolls inside the given element starting from its vertical midpoint up to its top edge." +
" Useful for revealing content above the centre of the element.",
applicationType = ApplicationType.IOS,
displayName = "Scroll inside element from middle to top",
useCustomScreenshot = false)
public class ScrollInsideElementFromMiddleToTop extends IOSAction {

@com.testsigma.sdk.annotation.Element(reference = "element-name")
private Element elementName;

@Override
protected Result execute() throws NoSuchElementException {
logger.info("Starting scroll inside element from middle to top");

try {
org.openqa.selenium.WebElement webElement = elementName.getElement();
Rectangle rect = webElement.getRect();

int startX = rect.x + rect.width / 2;
int startY = rect.y + rect.height / 2;
int endX = startX;
int endY = rect.y;

logger.info(String.format("Element rect: x=%d y=%d w=%d h=%d", rect.x, rect.y, rect.width, rect.height));
logger.info(String.format("Swipe: (%d,%d) -> (%d,%d)", startX, startY, endX, endY));

AppiumDriver appiumDriver = (AppiumDriver) this.driver;
PointerInput finger = new PointerInput(TOUCH, "finger");
Sequence swipe = new Sequence(finger, 1)
.addAction(finger.createPointerMove(Duration.ofMillis(0), viewport(), startX, startY))
.addAction(finger.createPointerDown(LEFT.asArg()))
.addAction(finger.createPointerMove(Duration.ofSeconds(2), viewport(), endX, endY))
.addAction(finger.createPointerUp(LEFT.asArg()));

appiumDriver.perform(Collections.singletonList(swipe));

setSuccessMessage("Successfully scrolled inside the element from middle to top");
return Result.SUCCESS;

} catch (NoSuchElementException e) {
logger.debug("Element not found: " + e.getMessage());
setErrorMessage("Element not found: " + e.getMessage());
return Result.FAILED;
} catch (Exception e) {
logger.debug("Failed to scroll inside element from middle to top: " + e.getMessage());
setErrorMessage("Failed to scroll: " + e.getMessage());
return Result.FAILED;
}
}
}
Loading