Skip to content

Release 1.0.13 #31

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 28 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
afde02a
Added crop snapshot for SmartUIAppSnapshot
greydaemon Mar 28, 2025
835dd89
sdk changes for crop status and navigation bar
greydaemon Apr 3, 2025
8933261
Merge pull request #27 from greydaemon/DOT-4926
sushobhit-lt Apr 4, 2025
18546da
added null check for safety
greydaemon Apr 4, 2025
ca8c3b7
Merge pull request #28 from greydaemon/DOT-4926
sushobhit-lt Apr 4, 2025
9211130
DOT-4925 : Changes for full page ss in app sdk
greydaemon Apr 7, 2025
4996dc5
minor refactor
greydaemon Apr 7, 2025
4ce5324
[DOT-4925] Changes and refactoring for supporting full page screensho…
greydaemon Apr 8, 2025
f29d8ea
[DOT-4925] Added support for exporting host url and support for Uploa…
greydaemon Apr 9, 2025
84ffa5f
changed scrolling logic to scroll by 20%
greydaemon Apr 9, 2025
77e13de
Refactored changes as per testing
greydaemon Apr 10, 2025
fada3e7
minor refactor
greydaemon Apr 10, 2025
2552de7
Changes as per requirement changes for custom cropping and QA testing
greydaemon Apr 14, 2025
eabd753
changes in stop build and http client
greydaemon Apr 14, 2025
c417003
removed unused imports and minor refactoring in http client util
greydaemon Apr 15, 2025
c1e35f8
removed logs for debugging and handled edge case in pageCount
greydaemon Apr 15, 2025
3483e7e
Merge pull request #29 from greydaemon/DOT-4925
sushobhit-lt Apr 17, 2025
c9c2ae8
bump version
sushobhit-lt Apr 18, 2025
e2e4581
Merge pull request #32 from sushobhit-lt/stage
sushobhit-lt Apr 18, 2025
0aff2b2
downgraded appium version to support GS dependency conflict
greydaemon Apr 21, 2025
38950cf
Merge remote-tracking branch 'upstream/stage' into DOT-4925
greydaemon Apr 21, 2025
8a35bb2
Added beta version for testing conflicting dependencies for GS test s…
greydaemon Apr 21, 2025
67eed71
bumped sdk version to 13.1 beta
greydaemon Apr 21, 2025
37ee7b1
Merge pull request #33 from greydaemon/DOT-4925
sushobhit-lt Apr 21, 2025
823378c
made changes in scrolling logic to support appium version downgrade f…
greydaemon Apr 22, 2025
6a4c6f8
introduced some delay in swipe for IOS devices
greydaemon Apr 22, 2025
ace5e35
changes in sdk version to beta 1
greydaemon Apr 22, 2025
6e39895
Merge pull request #34 from greydaemon/DOT-4925
sushobhit-lt Apr 22, 2025
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
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ plugins {
}

group = 'io.github.lambdatest'
version = '1.0.12'
version = '1.0.13-beta.1'
description = 'lambdatest-java-sdk'

repositories {
Expand All @@ -21,7 +21,7 @@ dependencies {
implementation 'com.google.code.gson:gson:2.10.1'
implementation 'io.netty:netty-transport-native-epoll:4.1.104.Final'
implementation 'io.netty:netty-transport-native-kqueue:4.1.104.Final'

implementation 'io.appium:java-client:7.6.0'
// New dependencies from POM file
implementation 'org.apache.httpcomponents:httpmime:4.5.13'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.16.1'
Expand Down Expand Up @@ -83,7 +83,7 @@ afterEvaluate {
mavenJava(MavenPublication) {
groupId = 'io.github.lambdatest'
artifactId = 'lambdatest-java-sdk'
version = '1.0.12'
version = '1.0.13-beta.1'

pom {
name.set('LambdaTest Java SDK')
Expand Down
7 changes: 6 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.lambdatest</groupId>
<artifactId>lambdatest-java-sdk</artifactId>
<version>1.0.12</version>
<version>1.0.13-beta.1</version>
<name>lambdatest-java-sdk</name>
<description>LambdaTest SDK in Java</description>
<url>https://www.lambdatest.com</url>
Expand Down Expand Up @@ -58,6 +58,11 @@
<artifactId>selenium-java</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>io.appium</groupId>
<artifactId>java-client</artifactId>
<version>8.0.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
Expand Down
163 changes: 108 additions & 55 deletions src/main/java/io/github/lambdatest/SmartUIAppSnapshot.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,13 @@
import com.google.gson.Gson;
import io.github.lambdatest.constants.Constants;
import io.github.lambdatest.models.*;
import io.github.lambdatest.utils.FullPageScreenshotUtil;
import io.github.lambdatest.utils.GitUtils;
import io.github.lambdatest.utils.SmartUIUtil;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.*;

import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.*;
import java.util.logging.Logger;
import io.github.lambdatest.utils.LoggerUtil;

Expand Down Expand Up @@ -81,67 +77,124 @@ private String getProjectToken(Map<String, String> options) {
}
throw new IllegalArgumentException(Constants.Errors.PROJECT_TOKEN_UNSET);
}
private void validateMandatoryParams(WebDriver driver, String screenshotName, String deviceName) {
if (driver == null) {
log.severe(Constants.Errors.SELENIUM_DRIVER_NULL + " during take snapshot");
throw new IllegalArgumentException(Constants.Errors.SELENIUM_DRIVER_NULL);
}
if (screenshotName == null || screenshotName.isEmpty()) {
log.info(Constants.Errors.SNAPSHOT_NAME_NULL);
throw new IllegalArgumentException(Constants.Errors.SNAPSHOT_NAME_NULL);
}
if (deviceName == null || deviceName.isEmpty()) {
throw new IllegalArgumentException(Constants.Errors.DEVICE_NAME_NULL);
}
}

private String getOptionValue(Map<String, String> options, String key) {
if (options != null && options.containsKey(key)) {
String value = options.get(key);
return value != null ? value.trim() : "";
}
return "";
}

private UploadSnapshotRequest initializeUploadRequest(String screenshotName, String viewport) {
UploadSnapshotRequest request = new UploadSnapshotRequest();
request.setScreenshotName(screenshotName);
request.setProjectToken(projectToken);
request.setViewport(viewport);
log.info("Viewport set to :" + viewport);
if (Objects.nonNull(buildData)) {
request.setBuildId(buildData.getBuildId());
request.setBuildName(buildData.getName());
}
return request;
}

private UploadSnapshotRequest configureDeviceNameAndPlatform(UploadSnapshotRequest request, String deviceName, String platform) {
String browserName = deviceName.toLowerCase().startsWith("i") ? "iOS" : "Android";
String platformName = (platform == null || platform.isEmpty()) ? browserName : platform;
request.setOs(platformName);
request.setDeviceName(deviceName + " " + platformName);
assert platform != null;
request.setBrowserName(platform.toLowerCase().contains("ios") ? "safari" : "chrome");
return request;
}

public void smartuiAppSnapshot(WebDriver appiumDriver, String screenshotName, Map<String, String> options)
public void smartuiAppSnapshot(WebDriver driver, String screenshotName, Map<String, String> options)
throws Exception {
try {
if (appiumDriver == null) {
log.severe(Constants.Errors.SELENIUM_DRIVER_NULL + " during take snapshot");
throw new IllegalArgumentException(Constants.Errors.SELENIUM_DRIVER_NULL);
String deviceName = getOptionValue(options, "deviceName");
String platform = getOptionValue(options, "platform");
validateMandatoryParams(driver, screenshotName, deviceName);
Dimension d = driver.manage().window().getSize();
int width = d.getWidth(), height = d.getHeight();
UploadSnapshotRequest initReq = initializeUploadRequest(screenshotName, width + "x" + height);
UploadSnapshotRequest uploadSnapshotRequest = configureDeviceNameAndPlatform(initReq, deviceName, platform);
String screenshotHash = UUID.randomUUID().toString();
uploadSnapshotRequest.setScreenshotHash(screenshotHash);
String uploadChunk = getOptionValue(options, "uploadChunk");
String pageCount = getOptionValue(options, "pageCount"); int userInputtedPageCount=0;
if(!pageCount.isEmpty()) {
userInputtedPageCount = Integer.parseInt(pageCount);
}
if (screenshotName == null || screenshotName.isEmpty()) {
log.info(Constants.Errors.SNAPSHOT_NAME_NULL);
throw new IllegalArgumentException(Constants.Errors.SNAPSHOT_NAME_NULL);
if(!uploadChunk.isEmpty() && uploadChunk.toLowerCase().contains("true")) {
uploadSnapshotRequest.setUploadChunk("true");
} else {
uploadSnapshotRequest.setUploadChunk("false");
}
String navBarHeight = getOptionValue(options, "navigationBarHeight");
String statusBarHeight = getOptionValue(options, "statusBarHeight");

TakesScreenshot takesScreenshot = (TakesScreenshot) appiumDriver;
File screenshot = takesScreenshot.getScreenshotAs(OutputType.FILE);
log.info("Screenshot captured: " + screenshotName);

UploadSnapshotRequest uploadSnapshotRequest = new UploadSnapshotRequest();
uploadSnapshotRequest.setScreenshotName(screenshotName);
uploadSnapshotRequest.setProjectToken(projectToken);
Dimension d = appiumDriver.manage().window().getSize();
int w = d.getWidth(), h = d.getHeight();
uploadSnapshotRequest.setViewport(w + "x" + h);
log.info("Device viewport set to: " + uploadSnapshotRequest.getViewport());
String platform = "", deviceName = "", browserName = "";
if (options != null && options.containsKey("platform")) {
platform = options.get("platform").trim();
}
if (options != null && options.containsKey("deviceName")) {
deviceName = options.get("deviceName").trim();
if(!navBarHeight.isEmpty()) {
uploadSnapshotRequest.setNavigationBarHeight(navBarHeight);
}
if (deviceName == null || deviceName.isEmpty()) {
throw new IllegalArgumentException(Constants.Errors.DEVICE_NAME_NULL);
if(!statusBarHeight.isEmpty()) {
uploadSnapshotRequest.setStatusBarHeight(statusBarHeight);
}
if (platform == null || platform.isEmpty()) {
if (deviceName.toLowerCase().startsWith("i")) {
browserName = "iOS";
} else {
browserName = "Android";
}
String cropFooter = getOptionValue(options, "cropFooter");
if (!cropFooter.isEmpty()) {
uploadSnapshotRequest.setCropFooter(cropFooter.toLowerCase());
}
uploadSnapshotRequest.setOs(platform != null && !platform.isEmpty() ? platform : browserName);
if (platform != null && !platform.isEmpty()) {
uploadSnapshotRequest.setDeviceName(deviceName + " " + platform);
} else {
uploadSnapshotRequest.setDeviceName(deviceName + " " + browserName);
String cropStatusBar = getOptionValue(options, "cropStatusBar");
if (!cropStatusBar.isEmpty()) {
uploadSnapshotRequest.setCropStatusBar(cropStatusBar.toLowerCase());
}

if (platform.toLowerCase().contains("ios")) {
uploadSnapshotRequest.setBrowserName("safari");
String fullPage = getOptionValue(options, "fullPage").toLowerCase();
if(!Boolean.parseBoolean(fullPage)){
if(!pageCount.isEmpty()){
throw new IllegalArgumentException(Constants.Errors.PAGE_COUNT_ERROR);
}
TakesScreenshot takesScreenshot = (TakesScreenshot) driver;
File screenshot = takesScreenshot.getScreenshotAs(OutputType.FILE);
log.info("Screenshot captured: " + screenshotName);
uploadSnapshotRequest.setFullPage("false");
util.uploadScreenshot(screenshot, uploadSnapshotRequest, this.buildData);

} else {
uploadSnapshotRequest.setBrowserName("chrome");
}
if (Objects.nonNull(buildData)) {
uploadSnapshotRequest.setBuildId(buildData.getBuildId());
uploadSnapshotRequest.setBuildName(buildData.getName());
uploadSnapshotRequest.setFullPage("true");
FullPageScreenshotUtil fullPageCapture = new FullPageScreenshotUtil(driver, screenshotName);
List<File> ssDir = fullPageCapture.captureFullPage(userInputtedPageCount);
if(ssDir.isEmpty()){
throw new RuntimeException(Constants.Errors.SMARTUI_SNAPSHOT_FAILED);
}
int pageCountInSsDir = ssDir.size(); int i;
if(pageCountInSsDir == 1) { //when page count is set to 1 as user for fullPage
uploadSnapshotRequest.setFullPage("false");
util.uploadScreenshot(ssDir.get(0), uploadSnapshotRequest, this.buildData);
return;
}
for( i = 0; i < pageCountInSsDir -1; ++i){
uploadSnapshotRequest.setIsLastChunk("false");
uploadSnapshotRequest.setChunkCount(i);
util.uploadScreenshot(ssDir.get(i), uploadSnapshotRequest, this.buildData);
}
uploadSnapshotRequest.setIsLastChunk("true");
uploadSnapshotRequest.setChunkCount(i);
util.uploadScreenshot(ssDir.get(pageCountInSsDir-1), uploadSnapshotRequest, this.buildData);
}
UploadSnapshotResponse uploadSnapshotResponse = util.uploadScreenshot(screenshot, uploadSnapshotRequest,
this.buildData);
log.info("For uploading: " + uploadSnapshotRequest.toString() + " received response: "
+ uploadSnapshotResponse.getData());
} catch (Exception e) {
log.severe(Constants.Errors.UPLOAD_SNAPSHOT_FAILED + " due to: " + e.getMessage());
throw new Exception("Couldnt upload image to Smart UI due to: " + e.getMessage());
Expand Down
12 changes: 11 additions & 1 deletion src/main/java/io/github/lambdatest/constants/Constants.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
package io.github.lambdatest.constants;

import static io.github.lambdatest.constants.Constants.SmartUIRoutes.SMARTUI_CLIENT_API_URL;

public interface Constants {

String SMARTUI_SERVER_ADDRESS = "SMARTUI_SERVER_ADDRESS";
public static final String PROJECT_TOKEN = "projectToken";
public final String TEST_TYPE = "lambdatest-java-app-sdk";
String LOCAL_SERVER_HOST = "http://localhost:8080";

public static String getHostUrlFromEnvOrDefault() {
String envUrl = System.getenv("SMARTUI_CLIENT_API_URL");
return (envUrl != null && !envUrl.isEmpty()) ? envUrl : SMARTUI_CLIENT_API_URL;
}

//SmartUI API routes
interface SmartUIRoutes {
public static final String HOST_URL = "https://api.lambdatest.com/visualui/1.0";
public static final String SMARTUI_CLIENT_API_URL = "https://api.lambdatest.com/visualui/1.0";
public static final String SMARTUI_HEALTHCHECK_ROUTE = "/healthcheck";
public static final String SMARTUI_DOMSERIALIZER_ROUTE = "/domserializer";
public static final String SMARTUI_SNAPSHOT_ROUTE = "/snapshot";
Expand Down Expand Up @@ -44,6 +52,7 @@ interface LogEnvVars {
interface Errors {
public static final String SELENIUM_DRIVER_NULL = "An instance of the selenium driver object is required.";
public static final String SNAPSHOT_NAME_NULL = "The `snapshotName` argument is required.";
public static final String SNAPSHOT_NOT_FOUND = "Screenshot not found.";
public static final String SMARTUI_NOT_RUNNING = "SmartUI server is not running.";
public static final String JAVA_SCRIPT_NOT_SUPPORTED = "The driver does not support JavaScript execution.";
public static final String EMPTY_RESPONSE_DOMSERIALIZER = "Response from fetchDOMSerializer is null or empty.";
Expand All @@ -60,6 +69,7 @@ interface Errors {
public static final String PROJECT_TOKEN_UNSET = "projectToken cant be empty";
public static final String USER_AUTH_ERROR = "User authentication failed";
public static final String STOP_BUILD_FAILED = "Failed to stop build";
public static final String PAGE_COUNT_ERROR = "Page Count Value is invalid";
public static final String NULL_OPTIONS_OBJECT = "Options object is null or missing in request.";
public static final String DEVICE_NAME_NULL = "Device name is a mandatory parameter.";
}
Expand Down
Loading