Skip to content

Conversation

@ManojTestsigma
Copy link
Contributor

@ManojTestsigma ManojTestsigma commented Dec 9, 2025

please review this addon and publish as PUBLIC

Addon name : Image Visual Testing
Addon accont: https://jarvis.testsigma.com/ui/tenants/2817/addons
Jira: https://testsigma.atlassian.net/browse/CUS-9599

Summary by CodeRabbit

  • New Features

    • Added image download/capture across Android, iOS, and web (img tags, shadow DOM, canvas/SVG, data & relative URLs).
    • New visual-compare actions with threshold support and API-based similarity checks.
    • Screenshot capture and optional upload/storage to S3 from web/mobile actions.
  • Bug Fixes

    • Updated dissimilarity messages to display dissimilarity percentage.
  • Chores

    • Bumped package version to 1.0.7 and set Java source/target compatibility to 15.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 9, 2025

Walkthrough

Adds cross-platform image acquisition and comparison actions: new DownloadImageFromImgTag and TakeScreenShotAndStoreinS3; threshold-based similarity/dissimilarity verifiers; local URL→File helpers; shared API multipart calls and S3 upload flows; updated dissimilarity messaging; and bumps Maven version and Java compiler target to 15.

Changes

Cohort / File(s) Summary
Build configuration
image_visual_testing/pom.xml
Bumps version 1.0.5 → 1.0.7 and adds maven-compiler-plugin configured for Java 15 source/target.
Web compare & helpers
image_visual_testing/src/main/java/com/testsigma/addons/web/CompareTwoImagesUsingVisualTesting.java, .../VerifyIfTwoImagesAreSimilar.java, .../VerifyIfTwoImagesAreDissimilar.java, .../VerifyIfImagesAreDissimilar.java
Add urlToFileConverter helper, update HTTP timeout/logging, unify File handling, adjust dissimilarity messaging to report dissimilarity percentage.
Web image capture
image_visual_testing/src/main/java/com/testsigma/addons/web/DownloadImageFromImgTag.java, .../TakeScreenShotAndStoreinS3.java
New DownloadImageFromImgTag: extract image from , shadow DOM, canvas/SVG, data-URLs or element screenshot; download/normalize URLs; save bytes to temp file and upload to S3. New TakeScreenShotAndStoreinS3: capture screenshot, persist temp file, store path in RunTimeData.
Android compare & helpers
image_visual_testing/src/main/java/com/testsigma/addons/android/CompareTwoImagesUsingVisualTesting.java, .../VerifyIfImagesAreDissimilar.java
Add local urlToFileConverter helper in compare class; minor message/whitespace tweaks for dissimilar reporting.
Android image capture & thresholds
image_visual_testing/src/main/java/com/testsigma/addons/android/DownloadImageFromImgTag.java, .../VerifyIfImagesAreDissimilarWithThreshold.java, .../VerifyIfImagesAreSimilarWithThreshold.java, .../TakeScreenShotAndStorePathInRuntime.java
New DownloadImageFromImgTag (shadow DOM, data-URL, screenshot fallback); new threshold-based verify actions that convert URLs to Files, call visual API (multipart), parse response, create combined diff images, and upload to S3; minor annotation/text tweaks.
iOS compare & helpers
image_visual_testing/src/main/java/com/testsigma/addons/ios/CompareTwoImagesUsingVisualTesting.java, .../VerifyIfImagesAreDissimilar.java
Add local urlToFileConverter helper in compare class; change dissimilarity messaging to report dissimilarity percentage.
iOS image capture & thresholds
image_visual_testing/src/main/java/com/testsigma/addons/ios/DownloadImageFromImgTag.java, .../VerifyIfImagesAreDissimilarWithThreshold.java, .../VerifyIfImagesAreSimilarWithThreshold.java, .../TakeScreenShotAndStorePathInRuntime.java
New DownloadImageFromImgTag for iOS (shadow DOM, data-URL, screenshot fallback); new threshold-based verify actions similar to Android implementation; updated annotations/capitalization in metadata.
Cross-cutting runtime & API flow
multiple files under image_visual_testing/src/main/java/com/testsigma/addons/*
Many classes now perform multipart API requests to a visual testing server, parse JSON responses (similarity/diff coordinates), create combined diff images when needed, and upload screenshots to S3 via ImageComparisonUtils; added RequestConfig/timeout settings and enhanced logging/error messages.

Sequence Diagram(s)

sequenceDiagram
    actor Tester
    participant Driver as Web/Android/iOS Driver
    participant Action as DownloadImageFromImgTag / TakeScreenShot...
    participant FS as File System (temp files)
    participant ImageAPI as Visual Testing API
    participant S3 as ImageComparisonUtils (S3)
    participant RunTime as RunTimeData

    Tester->>Action: trigger action (locator or inputs)
    Action->>Driver: locate element / eval JS (shadow DOM)
    Driver-->>Action: src or element screenshot bytes

    alt src is http(s) or relative
        Action->>FS: download URL -> temp File
        FS-->>Action: temp File
    else src is data: URL
        Action->>FS: decode base64 -> temp File
        FS-->>Action: temp File
    else no src
        Action->>Driver: take element screenshot
        Driver-->>Action: screenshot bytes
        Action->>FS: save bytes -> temp File
        FS-->>Action: temp File
    end

    Action->>S3: upload temp File
    S3-->>Action: S3 key/URL

    alt comparison required
        Action->>ImageAPI: send multipart (base + actual)
        ImageAPI-->>Action: similarity JSON (percentage, diffs)
        alt below threshold
            Action->>S3: upload actual image
            Action->>RunTime: set success message & store path
        else above threshold
            Action->>FS: generate combined diff image
            FS-->>Action: combined File
            Action->>S3: upload combined File
            Action->>RunTime: set failure message & store path
        end
    end

    Action-->>Tester: Result with message
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Files/areas to focus on:
    • Shadow DOM traversal, canvas/SVG extraction, and data-URL decoding in DownloadImageFromImgTag across platforms.
    • Lifetime and cleanup of temporary files produced by urlToFileConverter and download flows.
    • Multipart request construction, timeouts, and JSON response parsing in performApiCall implementations.
    • Image combining/diff generation and S3 upload error paths (ImageComparisonUtils usage).
    • Consistent dissimilarity vs similarity percentage calculation and user-facing messages.

Possibly related PRs

Suggested reviewers

  • vigneshtestsigma
  • Ganesh-Testsigma

Poem

🐰 I hopped through DOM and shadow light,

I stitched up pixels, saved them tight,
Temp files hummed, then flew to S3,
I dashed the diffs and sang with glee! 🎨✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.37% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly describes the primary change: adding functionality to download images from given elements across multiple platform implementations (Android, iOS, Web).
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch CUS-9599

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (12)
image_visual_testing/src/main/java/com/testsigma/addons/ios/VerifyIfImagesAreDissimilar.java (1)

86-92: Fix the misleading message label.

The success message on line 91 reports "Similarity percentage:" but actually calculates and displays the dissimilarity percentage (100 - percentageSimilarity * 100). This is inconsistent with the message on line 90 that states the images are "dissimilar" and will confuse users.

Additionally, the parentheses around 100 are redundant.

Apply this diff to fix the label and simplify the expression:

                 setSuccessMessage("Successfully verified that the base image and actual image are dissimilar. " +
-                        "Similarity percentage: " + ((100) - percentageSimilarity * 100) + "%");
+                        "Dissimilarity percentage: " + (100 - percentageSimilarity * 100) + "%");
image_visual_testing/src/main/java/com/testsigma/addons/android/VerifyIfImagesAreDissimilar.java (5)

46-50: Remove unused RequestConfig.

The RequestConfig instance is never used. The actual HTTP client implementation at line 127 uses OkHttpClient, not Apache HttpClient. This dead code should be removed.

Apply this diff to remove the unused code:

-    RequestConfig config = RequestConfig.custom()
-            .setSocketTimeout(10 * 60 * 1000)
-            .setConnectionRequestTimeout(60 * 1000)
-            .setConnectTimeout(60 * 1000)
-            .build();

71-72: Add explicit cleanup for temporary files.

The urlToFileConverter method creates temporary files that are never explicitly deleted. This can lead to resource leaks and disk space issues over time. Consider using try-with-resources or adding explicit cleanup in a finally block.

Apply this pattern to ensure cleanup:

+        File file1 = null;
+        File file2 = null;
+        try {
-            File file1 = urlToFileConverter("first_image", baseImagePath);
-            File file2 = urlToFileConverter("second_image", actualImagePath);
+            file1 = urlToFileConverter("first_image", baseImagePath);
+            file2 = urlToFileConverter("second_image", actualImagePath);
             logger.info("Base image file path: " + file1.getAbsolutePath());
             baseImage = ImageIO.read(file1);
             actualImage = ImageIO.read(file2);
             // ... rest of the logic
         } catch (IOException e) {
             logger.info("image not found ");
             logger.info(ExceptionUtils.getStackTrace(e));
             throw new RuntimeException(e);
+        } finally {
+            // Clean up temp files
+            if (file1 != null && file1.exists() && baseImagePath.startsWith("http")) {
+                file1.delete();
+            }
+            if (file2 != null && file2.exists() && actualImagePath.startsWith("http")) {
+                file2.delete();
+            }
         }

100-102: Clean up temporary combined image file.

The temporary file created for the combined image is never explicitly deleted, leading to a resource leak.

Consider adding cleanup similar to the suggestion for lines 71-72, or use try-with-resources if applicable.


127-150: Configure timeouts for OkHttpClient and ensure proper resource cleanup.

The OkHttpClient is created without timeout configuration, which can cause requests to hang indefinitely. Additionally, the Response object should be explicitly closed to release resources.

Apply this diff to add timeouts and proper resource management:

-            OkHttpClient client = new OkHttpClient();
+            OkHttpClient client = new OkHttpClient.Builder()
+                    .connectTimeout(60, java.util.concurrent.TimeUnit.SECONDS)
+                    .readTimeout(10, java.util.concurrent.TimeUnit.MINUTES)
+                    .writeTimeout(60, java.util.concurrent.TimeUnit.SECONDS)
+                    .build();
             logger.info("Initiating http client");
             // ... builder code ...
             logger.info("Making api call to visual server");
-            Response response = client.newCall(request).execute();
+            try (Response response = client.newCall(request).execute()) {
-            if (response.isSuccessful()) {
+                if (response.isSuccessful()) {
                 // ... existing logic ...
+                }
             }

220-246: Add input validation and security checks to prevent vulnerabilities.

The urlToFileConverter method has several security concerns:

  1. Path Traversal: Local file paths are not validated, allowing potential access to files outside the intended directory using ../ sequences.
  2. SSRF (Server-Side Request Forgery): URL downloads have no domain or protocol validation beyond http/https, potentially allowing requests to internal resources.
  3. Resource Exhaustion: No size limits when downloading files from URLs, which could lead to memory/disk exhaustion.
  4. Error Handling: Generic RuntimeException doesn't provide enough context for debugging.

Consider adding validation:

 public File urlToFileConverter(String fileName, String url) {
     try {
         if (url.startsWith("https://") || url.startsWith("http://")) {
             logger.info("Given is s3 url ...File name:" + fileName);
+            // Validate URL to prevent SSRF
+            URL urlObject = new URL(url);
+            String host = urlObject.getHost();
+            if (host.equals("localhost") || host.startsWith("127.") || 
+                host.startsWith("169.254.") || host.startsWith("10.") ||
+                host.matches("172\\.(1[6-9]|2[0-9]|3[01])\\..*") ||
+                host.startsWith("192.168.")) {
+                throw new SecurityException("Access to internal/private IPs is not allowed");
+            }
-            URL urlObject = new URL(url);
             String baseName = fileName;
             // ... rest of logic ...
         } else {
             logger.info("Given is local file path..");
-            return new File(url);
+            // Validate file path to prevent path traversal
+            File file = new File(url);
+            String canonicalPath = file.getCanonicalPath();
+            // Add validation that canonicalPath is within allowed directory
+            return file;
-//                return createLocalFileFromDownloadsCopy(url, ".png");
         }
     } catch (Exception e) {
         logger.info("Error while accessing: " + url);
-        throw new RuntimeException("Unable to access the given file, please check the given inputs.");
+        throw new RuntimeException("Unable to access the given file: " + e.getMessage(), e);
     }
 }

Also remove the commented code at line 240.

image_visual_testing/src/main/java/com/testsigma/addons/ios/TakeScreenShotAndStorePathInRuntime.java (2)

23-27: Misleading description in @action annotation.

The description field says "validates options count in a select drop-down" but this action takes a screenshot and stores the file path. This appears to be copy-paste from another action.

 @Action(actionText = "Take screenshot of the current page and store the saved image file path in runtime variable" +
         " test-data",
-        description = "validates options count in a select drop-down",
+        description = "Takes a screenshot of the current page and stores the saved image file path in a runtime variable",
         applicationType = ApplicationType.IOS,
         useCustomScreenshot = false)

62-62: Inaccurate success message.

The message says "stored the screenshot in S3" but the file is stored locally (temp directory). This is misleading to users.

-        setSuccessMessage("successfully stored the screenshot in S3 with URL: " + file1.getAbsolutePath());
+        setSuccessMessage("Successfully stored the screenshot locally at: " + file1.getAbsolutePath());
image_visual_testing/src/main/java/com/testsigma/addons/android/TakeScreenShotAndStorePathInRuntime.java (2)

22-26: Misleading description in @action annotation.

Same issue as the iOS counterpart - the description says "validates options count in a select drop-down" but this action takes screenshots.

 @Action(actionText = "Take screenshot of the current page and store the saved image file" +
         " path in runtime variable test-data",
-        description = "validates options count in a select drop-down",
+        description = "Takes a screenshot of the current page and stores the saved image file path in a runtime variable",
         applicationType = ApplicationType.ANDROID,
         useCustomScreenshot = false)

61-61: Inaccurate success message.

Same issue as iOS - the message incorrectly mentions S3 when the file is stored locally.

-        setSuccessMessage("successfully stored the screenshot in S3 with URL: " + file1.getAbsolutePath());
+        setSuccessMessage("Successfully stored the screenshot locally at: " + file1.getAbsolutePath());
image_visual_testing/src/main/java/com/testsigma/addons/web/CompareTwoImagesUsingVisualTesting.java (1)

46-50: Unused RequestConfig - timeouts not applied to actual HTTP client.

The RequestConfig is configured but OkHttpClient is used in performApiCall without these timeouts. Either apply timeouts to OkHttpClient or remove the unused config.

-    RequestConfig config = RequestConfig.custom()
-            .setSocketTimeout(10 * 60 * 1000)
-            .setConnectionRequestTimeout(60 * 1000)
-            .setConnectTimeout(60 * 1000)
-            .build();

And update the OkHttpClient initialization in performApiCall:

OkHttpClient client = new OkHttpClient.Builder()
    .connectTimeout(60, TimeUnit.SECONDS)
    .readTimeout(10, TimeUnit.MINUTES)
    .writeTimeout(60, TimeUnit.SECONDS)
    .build();
image_visual_testing/src/main/java/com/testsigma/addons/android/CompareTwoImagesUsingVisualTesting.java (1)

47-51: Unused RequestConfig - timeouts not applied.

Same issue as the web version. The Apache HttpClient config is not used; OkHttpClient is used instead without timeouts configured.

Apply timeouts to OkHttpClient in performApiCall:

OkHttpClient client = new OkHttpClient.Builder()
    .connectTimeout(60, TimeUnit.SECONDS)
    .readTimeout(10, TimeUnit.MINUTES)
    .writeTimeout(60, TimeUnit.SECONDS)
    .build();
🧹 Nitpick comments (22)
image_visual_testing/src/main/java/com/testsigma/addons/ios/VerifyIfImagesAreDissimilar.java (4)

66-76: Consider cleaning up temporary files.

The urlToFileConverter creates temporary files for image processing. Consider adding cleanup logic (e.g., file1.deleteOnExit() and file2.deleteOnExit()) to prevent potential disk space accumulation over time.


78-78: Remove commented-out code.

Line 78 contains a commented-out logger statement that should either be removed or uncommented if needed.


202-204: Remove commented-out code.

Lines 202-204 contain commented-out error message logic that should be removed to improve code clarity.


240-240: Remove commented-out code.

Line 240 contains commented-out code that should be removed for better code maintainability.

image_visual_testing/src/main/java/com/testsigma/addons/android/VerifyIfImagesAreDissimilar.java (1)

202-204: Remove commented-out code.

The commented code should be removed if it's no longer needed, as it clutters the codebase and can cause confusion.

Apply this diff:

-//                String message = "Comparison failed because visual testing detected identical images," +
-//                        " check step screenshot for visual results";
-//                errorMessageBuilder.append(message);
image_visual_testing/src/main/java/com/testsigma/addons/web/VerifyIfImagesAreDissimilar.java (1)

219-245: Temp files are not cleaned up.

The urlToFileConverter method creates temporary files for HTTP URLs but these are never deleted. Consider using tempFile.deleteOnExit() to schedule cleanup when the JVM exits.

                 File tempFile = File.createTempFile(baseName, extension);
+                tempFile.deleteOnExit();
                 FileUtils.copyURLToFile(urlObject, tempFile);
image_visual_testing/src/main/java/com/testsigma/addons/web/VerifyIfTwoImagesAreDissimilar.java (1)

225-251: Consider extracting urlToFileConverter to a shared utility class.

This exact method is duplicated across multiple files (VerifyIfImagesAreDissimilar, VerifyIfTwoImagesAreDissimilar, CompareTwoImagesUsingVisualTesting for iOS, etc.). Consider moving it to ImageComparisonUtils to reduce duplication and simplify maintenance.

image_visual_testing/src/main/java/com/testsigma/addons/ios/CompareTwoImagesUsingVisualTesting.java (1)

205-231: Duplicate urlToFileConverter implementation.

This method is identical to implementations in the web action classes. This is the third instance of the same code. Consider extracting to ImageComparisonUtils as a static method to follow DRY principles.

Additionally, temp files should be cleaned up:

                 File tempFile = File.createTempFile(baseName, extension);
+                tempFile.deleteOnExit();
                 FileUtils.copyURLToFile(urlObject, tempFile);
image_visual_testing/src/main/java/com/testsigma/addons/ios/DownloadImageFromImgTag.java (5)

6-6: Unused import: WebAction.

This import is not used in the iOS action class and should be removed.

-import com.testsigma.sdk.WebAction;

56-57: Misleading directory name.

The temporary directory is named basePdfDirectory but it's used for storing images, not PDFs. Consider renaming for clarity.

-            String basePdfDirectoryPath = String.valueOf(Files.createTempDirectory("basePdfDirectory"));
-            logger.info("Base PDF Directory Path: " + basePdfDirectoryPath);
+            String baseTempDirectoryPath = String.valueOf(Files.createTempDirectory("imageDirectory"));
+            logger.info("Base Temp Directory Path: " + baseTempDirectoryPath);

165-166: Inconsistent method design: findImageInShadowRoot is static while getSrcFromShadowRoot is not.

Both methods serve similar purposes but have different visibility modifiers. Consider making both instance methods for consistency and to enable proper logging.

-    private static String findImageInShadowRoot(JavascriptExecutor jsExecutor, WebElement element) {
+    private String findImageInShadowRoot(JavascriptExecutor jsExecutor, WebElement element) {

211-214: Use logger instead of System.err.println.

This is inconsistent with the rest of the class which uses the logger for error reporting.

         } catch (Exception e) {
-            System.err.println("Error finding image in shadow root: " + e.getMessage());
+            logger.info("Error finding image in shadow root: " + e.getMessage());
             return null;
         }

265-278: Use logger instead of System.err.println for consistency.

     private static byte[] handleDataUrl(String dataUrl) throws Exception {
         try {
             // Extract base64 data from data URL
             String[] parts = dataUrl.split(",");
             if (parts.length != 2) {
                 throw new Exception("Invalid data URL format");
             }

             String base64Data = parts[1];
             return Base64.getDecoder().decode(base64Data);
         } catch (Exception e) {
-            System.err.println("Error processing data URL: " + e.getMessage());
+            // Note: Cannot use logger in static method without passing it
             throw e;
         }
     }

Consider making handleDataUrl an instance method to enable proper logging, or remove the redundant catch-and-rethrow.

image_visual_testing/src/main/java/com/testsigma/addons/web/TakeScreenShotAndStoreinS3.java (1)

43-44: Misleading directory name.

Same as the iOS file - the temporary directory is named basePdfDirectory but stores images.

-            String basePdfDirectoryPath = String.valueOf(Files.createTempDirectory("basePdfDirectory"));
-            logger.info("Base PDF Directory Path: " + basePdfDirectoryPath);
+            String baseTempDirectoryPath = String.valueOf(Files.createTempDirectory("screenshotDirectory"));
+            logger.info("Base Temp Directory Path: " + baseTempDirectoryPath);
image_visual_testing/src/main/java/com/testsigma/addons/web/CompareTwoImagesUsingVisualTesting.java (2)

74-75: Remove commented-out code.

Commented code should be removed rather than left in place.

             File file1 = urlToFileConverter("first_image", baseImagePath);
             File file2 = urlToFileConverter("second_image", actualImagePath);
-//            File file1 = new File(baseImagePath);
-//            File file2 = new File(actualImagePath);

216-243: Consider extracting urlToFileConverter to a shared utility class.

This method is duplicated across CompareTwoImagesUsingVisualTesting (web, android) and VerifyIfTwoImagesAreSimilar. Extracting it to ImageComparisonUtils or a new utility class would reduce duplication and ease maintenance.

Additionally, FileUtils.copyURLToFile at line 229 has no timeout configuration and could hang indefinitely on slow/unresponsive URLs. Consider using the overloaded version with timeout parameters.

-                FileUtils.copyURLToFile(urlObject, tempFile);
+                FileUtils.copyURLToFile(urlObject, tempFile, 30000, 30000);
image_visual_testing/src/main/java/com/testsigma/addons/android/CompareTwoImagesUsingVisualTesting.java (2)

205-231: Duplicated urlToFileConverter method.

This method is identical to the one in CompareTwoImagesUsingVisualTesting (web) and VerifyIfTwoImagesAreSimilar. Consider extracting to a shared utility class to follow DRY principles.

Also, add timeout to FileUtils.copyURLToFile:

-                FileUtils.copyURLToFile(urlObject, tempFile);
+                FileUtils.copyURLToFile(urlObject, tempFile, 30000, 30000);

224-226: Remove commented-out code.

             } else {
                 logger.info("Given is local file path..");
                 return new File(url);
-//                return createLocalFileFromDownloadsCopy(url, ".png");
             }
image_visual_testing/src/main/java/com/testsigma/addons/web/VerifyIfTwoImagesAreSimilar.java (2)

200-203: Remove commented-out code.

             } else {
                 ImageIO.write(combined, "png", combinedImage);
                 boolean uploadS3Result = imageComparisonUtils.uploadFile(s3Url, combinedImage.getAbsolutePath());
                 if (!uploadS3Result) {
                     logger.debug("Error occurred while uploading combined image to S3," +
                             " screenshot might not be displayed");
                 }
-//                String message = "Comparison failed because visual testing detected dissimilarities," +
-//                        " check step screenshot for visual results";
-//                errorMessageBuilder.append(message);
                 setErrorMessage(errorMessageBuilder.toString());
                 return Result.FAILED;
             }

218-244: Duplicated urlToFileConverter method and missing timeout.

This method is duplicated across multiple action classes. Extract to a shared utility.

Also add timeout to prevent hangs:

-                FileUtils.copyURLToFile(urlObject, tempFile);
+                FileUtils.copyURLToFile(urlObject, tempFile, 30000, 30000);
image_visual_testing/src/main/java/com/testsigma/addons/android/DownloadImageFromImgTag.java (2)

54-55: Misleading variable name.

basePdfDirectoryPath is confusing for an image download operation. Consider renaming for clarity.

-String basePdfDirectoryPath = String.valueOf(Files.createTempDirectory("basePdfDirectory"));
-logger.info("Base PDF Directory Path: " + basePdfDirectoryPath);
+String baseImageDirectoryPath = String.valueOf(Files.createTempDirectory("baseImageDirectory"));
+logger.info("Base Image Directory Path: " + baseImageDirectoryPath);

213-216: Inconsistent logging with System.err.println.

The method uses System.err.println while the rest of the class uses the logger. Consider making this method non-static to access the logger, or accept a logger parameter.

-    private static String findImageInShadowRoot(JavascriptExecutor jsExecutor, WebElement element) {
+    private String findImageInShadowRoot(JavascriptExecutor jsExecutor, WebElement element) {
         try {
             // ... script execution ...
         } catch (Exception e) {
-            System.err.println("Error finding image in shadow root: " + e.getMessage());
+            logger.warn("Error finding image in shadow root: " + e.getMessage());
             return null;
         }
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 21d5d2b and a928a8d.

📒 Files selected for processing (14)
  • image_visual_testing/pom.xml (2 hunks)
  • image_visual_testing/src/main/java/com/testsigma/addons/android/CompareTwoImagesUsingVisualTesting.java (3 hunks)
  • image_visual_testing/src/main/java/com/testsigma/addons/android/DownloadImageFromImgTag.java (1 hunks)
  • image_visual_testing/src/main/java/com/testsigma/addons/android/TakeScreenShotAndStorePathInRuntime.java (1 hunks)
  • image_visual_testing/src/main/java/com/testsigma/addons/android/VerifyIfImagesAreDissimilar.java (1 hunks)
  • image_visual_testing/src/main/java/com/testsigma/addons/ios/CompareTwoImagesUsingVisualTesting.java (3 hunks)
  • image_visual_testing/src/main/java/com/testsigma/addons/ios/DownloadImageFromImgTag.java (1 hunks)
  • image_visual_testing/src/main/java/com/testsigma/addons/ios/TakeScreenShotAndStorePathInRuntime.java (1 hunks)
  • image_visual_testing/src/main/java/com/testsigma/addons/ios/VerifyIfImagesAreDissimilar.java (1 hunks)
  • image_visual_testing/src/main/java/com/testsigma/addons/web/CompareTwoImagesUsingVisualTesting.java (6 hunks)
  • image_visual_testing/src/main/java/com/testsigma/addons/web/TakeScreenShotAndStoreinS3.java (1 hunks)
  • image_visual_testing/src/main/java/com/testsigma/addons/web/VerifyIfImagesAreDissimilar.java (1 hunks)
  • image_visual_testing/src/main/java/com/testsigma/addons/web/VerifyIfTwoImagesAreDissimilar.java (2 hunks)
  • image_visual_testing/src/main/java/com/testsigma/addons/web/VerifyIfTwoImagesAreSimilar.java (7 hunks)
🔇 Additional comments (11)
image_visual_testing/src/main/java/com/testsigma/addons/ios/VerifyIfImagesAreDissimilar.java (4)

1-33: LGTM!

The package structure, imports, and class declaration are well-organized and appropriate for iOS image comparison functionality.


35-52: LGTM!

Field declarations and timeout configuration are appropriate for image comparison operations.


115-178: LGTM!

The API call implementation is well-structured with proper error handling and comprehensive logging.


220-246: LGTM!

The urlToFileConverter method correctly handles both HTTP URLs and local file paths with appropriate error handling.

image_visual_testing/src/main/java/com/testsigma/addons/android/VerifyIfImagesAreDissimilar.java (1)

80-84: LGTM!

The defensive null check for diff_coordinates prevents potential NPE and the fallback to an empty list is appropriate.

image_visual_testing/src/main/java/com/testsigma/addons/web/VerifyIfImagesAreDissimilar.java (1)

89-91: LGTM!

The updated success message correctly displays the dissimilarity percentage by computing 100 - (percentageSimilarity * 100), which is more intuitive for users verifying dissimilarity.

image_visual_testing/src/main/java/com/testsigma/addons/web/VerifyIfTwoImagesAreDissimilar.java (1)

93-96: LGTM!

The success message now correctly displays the dissimilarity percentage, consistent with VerifyIfImagesAreDissimilar.java.

image_visual_testing/src/main/java/com/testsigma/addons/ios/CompareTwoImagesUsingVisualTesting.java (1)

72-73: LGTM!

The switch to a local urlToFileConverter helper provides consistent file handling for both HTTP URLs and local paths.

image_visual_testing/src/main/java/com/testsigma/addons/android/DownloadImageFromImgTag.java (3)

26-46: LGTM!

Class annotations and field declarations follow the Testsigma SDK patterns correctly.


128-138: LGTM!

File saving logic is correct. FileUtils.writeByteArrayToFile handles file creation implicitly, so the explicit createNewFile() is redundant but harmless.


141-160: LGTM!

Shadow root access logic is well-structured with proper null handling and graceful fallback on errors.

import java.net.URL;
import java.nio.file.Files;
import java.util.Base64;
import java.util.NoSuchElementException;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Wrong NoSuchElementException import causes catch block mismatch.

java.util.NoSuchElementException is imported, but Selenium throws org.openqa.selenium.NoSuchElementException. The catch block at line 115 will never catch element lookup failures.

-import java.util.NoSuchElementException;
+import org.openqa.selenium.NoSuchElementException;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import java.util.NoSuchElementException;
import org.openqa.selenium.NoSuchElementException;
🤖 Prompt for AI Agents
In
image_visual_testing/src/main/java/com/testsigma/addons/android/DownloadImageFromImgTag.java
around line 24, the file imports java.util.NoSuchElementException but Selenium
throws org.openqa.selenium.NoSuchElementException so the catch at ~line 115
never matches; replace the java.util import with
org.openqa.selenium.NoSuchElementException (or use the fully-qualified name in
the catch) and remove the incorrect import so the catch block correctly handles
Selenium element lookup failures.

Comment on lines 246 to 264
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(30000);
connection.setReadTimeout(30000);

try (InputStream inputStream = connection.getInputStream();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
return outputStream.toByteArray();
}
} catch (Exception e) {
logger.warn("Failed to download image from URL: " + imageUrl + ", error: " + e.getMessage());
logger.info("error : " + ExceptionUtils.getStackTrace(e));
throw new RuntimeException("Failed to download image: " + e.getMessage());
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

HttpURLConnection is not disconnected - potential resource leak.

The connection should be disconnected after use. Additionally, the method signature declares throws IOException but actually throws RuntimeException.

         URL url = new URL(imageUrl);
         HttpURLConnection connection = (HttpURLConnection) url.openConnection();
         connection.setRequestMethod("GET");
         connection.setConnectTimeout(30000);
         connection.setReadTimeout(30000);

-        try (InputStream inputStream = connection.getInputStream();
-             ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
-            byte[] buffer = new byte[1024];
-            int bytesRead;
-            while ((bytesRead = inputStream.read(buffer)) != -1) {
-                outputStream.write(buffer, 0, bytesRead);
+        try {
+            try (InputStream inputStream = connection.getInputStream();
+                 ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
+                byte[] buffer = new byte[1024];
+                int bytesRead;
+                while ((bytesRead = inputStream.read(buffer)) != -1) {
+                    outputStream.write(buffer, 0, bytesRead);
+                }
+                return outputStream.toByteArray();
             }
-            return outputStream.toByteArray();
+        } finally {
+            connection.disconnect();
         }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
image_visual_testing/src/main/java/com/testsigma/addons/android/DownloadImageFromImgTag.java
around lines 246-264, the HttpURLConnection opened for the download is never
disconnected and the catch block throws a RuntimeException despite the method
declaring throws IOException; fix by ensuring connection.disconnect() is always
called (use a finally block that checks for non-null connection and calls
disconnect()), and change the error handling to rethrow an IOException
(preserving the original exception as the cause) instead of a RuntimeException
while keeping the logging of the error and stack trace.

@testsigmahq testsigmahq deleted a comment from coderabbitai bot Dec 9, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
image_visual_testing/src/main/java/com/testsigma/addons/ios/TakeScreenShotAndStorePathInRuntime.java (2)

62-62: Misleading success message references S3.

The message says "stored the screenshot in S3" but the file is stored locally on disk. This could confuse users.

-        setSuccessMessage("successfully stored the screenshot in S3 with URL: " + file1.getAbsolutePath());
+        setSuccessMessage("Successfully stored the screenshot at path: " + file1.getAbsolutePath());

66-75: Silent failure and incorrect logging format in saveBytesArrayToFile.

  1. The IOException is caught but not propagated, leading to silent failures where the caller assumes success.
  2. The logging uses "{}" + instead of proper string concatenation.
     public void saveBytesArrayToFile(String filePath, byte[] imageBytes) {
         try {
             File file = new File(filePath);
             boolean isCreated = file.createNewFile();
-            logger.debug("is file created - {}" + isCreated);
+            logger.debug("is file created - " + isCreated);
             FileUtils.writeByteArrayToFile(file, imageBytes);
         } catch (IOException e) {
-            logger.info("Failed to save byte[] screenshot to path {}" + filePath);
+            logger.info("Failed to save byte[] screenshot to path " + filePath);
+            throw new RuntimeException("Failed to save screenshot: " + e.getMessage());
         }
     }
♻️ Duplicate comments (3)
image_visual_testing/src/main/java/com/testsigma/addons/web/TakeScreenShotAndStoreinS3.java (1)

63-72: Silent failure and incorrect logging format in saveBytesArrayToFile - still unaddressed.

This issue was flagged in a previous review but remains unfixed:

  1. The IOException is caught but not propagated, leading to silent failures.
  2. The logging uses "{}" + instead of proper string concatenation.
     public void saveBytesArrayToFile(String filePath, byte[] imageBytes) {
         try {
             File file = new File(filePath);
             boolean isCreated = file.createNewFile();
-            logger.debug("is file created - {}" + isCreated);
+            logger.debug("is file created - " + isCreated);
             FileUtils.writeByteArrayToFile(file, imageBytes);
         } catch (IOException e) {
-            logger.info("Failed to save byte[] screenshot to path {}" + filePath);
+            logger.info("Failed to save byte[] screenshot to path " + filePath);
+            throw new RuntimeException("Failed to save screenshot: " + e.getMessage());
         }
     }
image_visual_testing/src/main/java/com/testsigma/addons/android/DownloadImageFromImgTag.java (2)

99-99: Incorrect log message - still unaddressed from previous review.

The message "images are identical hence uploading" doesn't apply here; this action only downloads a single image.

-            logger.info("images are identical hence uploading the actual image to S3");
+            logger.info("Uploading the captured image to S3");

268-282: Data URL parsing issue and inconsistent logging - still unaddressed.

These issues were flagged in a previous review:

  1. split(",") without limit may fail for certain base64 content.
  2. Uses System.err.println instead of logger.
-    private static byte[] handleDataUrl(String dataUrl) throws Exception {
+    private byte[] handleDataUrl(String dataUrl) throws Exception {
         try {
-            String[] parts = dataUrl.split(",");
-            if (parts.length != 2) {
+            String[] parts = dataUrl.split(",", 2);
+            if (parts.length < 2) {
                 throw new Exception("Invalid data URL format");
             }
             String base64Data = parts[1];
             return Base64.getDecoder().decode(base64Data);
         } catch (Exception e) {
-            System.err.println("Error processing data URL: " + e.getMessage());
+            logger.warn("Error processing data URL: " + e.getMessage());
             throw e;
         }
     }
🧹 Nitpick comments (19)
image_visual_testing/src/main/java/com/testsigma/addons/ios/DownloadImageFromImgTag.java (2)

1-6: Unused import: WebAction.

The class extends IOSAction, but WebAction is imported and never used.

 import com.testsigma.sdk.ApplicationType;
 import com.testsigma.sdk.IOSAction;
-import com.testsigma.sdk.WebAction;
 import com.testsigma.sdk.annotation.*;

209-212: Use logger instead of System.err.println in static method.

This method uses System.err.println which bypasses the logging framework. Consider making the method non-static to access the logger, or pass the logger as a parameter.

-    private static String findImageInShadowRoot(JavascriptExecutor jsExecutor, WebElement element) {
+    private String findImageInShadowRoot(JavascriptExecutor jsExecutor, WebElement element) {
         try {
             // ... script ...
             Object result = jsExecutor.executeScript(script, element);
             return result != null ? result.toString() : null;
         } catch (Exception e) {
-            System.err.println("Error finding image in shadow root: " + e.getMessage());
+            logger.warn("Error finding image in shadow root: " + e.getMessage());
             return null;
         }
     }
image_visual_testing/src/main/java/com/testsigma/addons/android/DownloadImageFromImgTag.java (1)

209-212: Use logger instead of System.err.println.

Same issue as the iOS version - the static method uses System.err.println which bypasses logging.

-    private static String findImageInShadowRoot(JavascriptExecutor jsExecutor, WebElement element) {
+    private String findImageInShadowRoot(JavascriptExecutor jsExecutor, WebElement element) {
         // ... script ...
         } catch (Exception e) {
-            System.err.println("Error finding image in shadow root: " + e.getMessage());
+            logger.warn("Error finding image in shadow root: " + e.getMessage());
             return null;
         }
     }
image_visual_testing/src/main/java/com/testsigma/addons/ios/VerifyIfImagesAreSimilarWithThreshold.java (1)

48-52: RequestConfig is created but never used.

The RequestConfig with timeout settings is defined but the OkHttpClient in performApiCall doesn't use it. Either apply these timeouts to the OkHttpClient or remove the unused config.

-    RequestConfig config = RequestConfig.custom()
-            .setSocketTimeout(10 * 60 * 1000)
-            .setConnectionRequestTimeout(60 * 1000)
-            .setConnectTimeout(60 * 1000)
-            .build();

Or apply timeouts to OkHttpClient:

OkHttpClient client = new OkHttpClient.Builder()
    .connectTimeout(60, TimeUnit.SECONDS)
    .readTimeout(10, TimeUnit.MINUTES)
    .writeTimeout(60, TimeUnit.SECONDS)
    .build();
image_visual_testing/src/main/java/com/testsigma/addons/android/VerifyIfImagesAreDissimilarWithThreshold.java (3)

11-11: Unused import: WebAction

This import is not used in the class. Remove it to keep the code clean.

-import com.testsigma.sdk.WebAction;

51-55: Unused RequestConfig field

The config field is defined but never used. The OkHttpClient on line 136 is created without any timeout configuration, which could lead to indefinite hangs if the visual server is unresponsive.

Either remove the unused RequestConfig or configure the OkHttpClient with appropriate timeouts:

-        OkHttpClient client = new OkHttpClient();
+        OkHttpClient client = new OkHttpClient.Builder()
+                .connectTimeout(60, java.util.concurrent.TimeUnit.SECONDS)
+                .readTimeout(10 * 60, java.util.concurrent.TimeUnit.SECONDS)
+                .writeTimeout(60, java.util.concurrent.TimeUnit.SECONDS)
+                .build();

230-256: Temp files are not cleaned up

Temp files created via File.createTempFile() (lines 242, and similarly in execute() at line 109) are never deleted. Consider adding tempFile.deleteOnExit() or explicit cleanup to prevent file system resource accumulation.

             File tempFile = File.createTempFile(baseName, extension);
+            tempFile.deleteOnExit();
             FileUtils.copyURLToFile(urlObject, tempFile);
image_visual_testing/src/main/java/com/testsigma/addons/android/VerifyIfImagesAreSimilarWithThreshold.java (3)

11-11: Unused import: WebAction

This import is not used in the class.

-import com.testsigma.sdk.WebAction;

51-55: Unused RequestConfig field

Same as the dissimilar variant - the config field is defined but not used with the OkHttpClient. Consider configuring timeouts on the HTTP client.


1-252: Significant code duplication with VerifyIfImagesAreDissimilarWithThreshold

This class shares ~90% of its code with VerifyIfImagesAreDissimilarWithThreshold. The only differences are the threshold comparison logic and messaging. Consider extracting common functionality into a shared base class or utility to reduce maintenance burden and ensure bug fixes are applied consistently.

image_visual_testing/src/main/java/com/testsigma/addons/ios/VerifyIfImagesAreDissimilarWithThreshold.java (3)

50-54: Unused RequestConfig field

The config field is defined but the OkHttpClient on line 135 is created without any timeout configuration.


229-255: Temp files are not cleaned up

Same as Android variants - temp files created via File.createTempFile() are never deleted. Add tempFile.deleteOnExit() to prevent file system resource accumulation.


1-258: Significant code duplication across platforms

This iOS class is nearly identical to the Android variants. The only platform-specific differences are the driver type (IOSDriver vs AndroidDriver) and the @Action annotation. Consider extracting the shared logic (API calls, URL conversion, image processing) into platform-agnostic utilities to reduce duplication across Android, iOS, and Web implementations.

image_visual_testing/src/main/java/com/testsigma/addons/web/DownloadImageFromImgTag.java (6)

21-27: Align action text/description with actual behavior (not just <img> tags)

The action text emphasizes <img> tags, but execute() now also handles non-img elements (shadow-root charts, SVG/canvas, plain element screenshots). Consider updating actionText/description to reflect that broader behavior so users don’t mistakenly think it only works for <img> elements.


46-89: Remove large commented-out legacy implementation

The old implementation is fully commented out. Keeping this much legacy code in comments adds noise and can confuse future maintainers; the version history already preserves it.

-        /*
-        try {
-            logger.info("initiating execution of DownloadImageFromImgTag action");
-            ...
-        } catch (NoSuchElementException ne) {
-            ...
-        }catch (Exception e) {
-            ...
-        }
-        return result;*/
+        // Old implementation removed; see VCS history if needed.

91-164: Harden S3 upload path and logging inside execute()

Core element/shadow-root/image capture logic looks good and the fallbacks are sensible. A few robustness and clarity tweaks would help:

  • testStepResult.getScreenshotUrl() can potentially be null or empty; defensive checks before uploadFile would prevent surprises if the runner doesn’t always pre-populate this field.
  • Log line "images are identical hence uploading the actual image to S3" is misleading here since no comparison is done in this action.
  • Failures of uploadFile are logged at info level; warn is more appropriate so S3 upload issues stand out.

Suggested refinement:

-            String s3Url = testStepResult.getScreenshotUrl();
-            ImageComparisonUtils imageComparisonUtils = new ImageComparisonUtils(driver, logger);
-            logger.info("images are identical hence uploading the actual image to S3");
-            boolean uploadS3Result = imageComparisonUtils.uploadFile(s3Url, file1.getAbsolutePath());
-            if (!uploadS3Result) {
-                logger.info("Error occurred while uploading combined image to s3," +
-                        " screenshot might not be displayed");
-            }
-            logger.info("Upload complete.");
+            String s3Url = testStepResult.getScreenshotUrl();
+            ImageComparisonUtils imageComparisonUtils = new ImageComparisonUtils(driver, logger);
+
+            if (s3Url != null && !s3Url.isEmpty()) {
+                logger.info("Uploading element image to S3 at: " + s3Url);
+                boolean uploadS3Result = imageComparisonUtils.uploadFile(s3Url, file1.getAbsolutePath());
+                if (!uploadS3Result) {
+                    logger.warn("Error occurred while uploading element image to S3; screenshot might not be displayed");
+                }
+                logger.info("Upload to S3 complete.");
+            } else {
+                logger.warn("Screenshot URL is null/empty; skipping S3 upload for element image");
+            }

Also, minor naming nit: basePdfDirectoryPath is now used for PNGs; consider renaming to something image-specific when convenient.


201-256: Unify logging and consider guarding recursive shadow-root search

Functionally, findImageInShadowRoot is powerful and flexible (handles img, canvas.toDataURL, and serialized SVG with nested shadow roots), which is great for charting libraries. Two minor points:

  • It uses System.err.println for JS errors via System.err in the catch block; the rest of the class uses logger. Prefer the logger for consistency and better aggregation.
  • The recursive search over shadowElements is fine for typical DOM sizes, but on very heavy/nested shadow trees it could become expensive. Not necessarily a blocker, but consider adding a simple depth or node-count guard if you see performance issues in practice.

Suggested logging tweak:

-        } catch (Exception e) {
-            System.err.println("Error finding image in shadow root: " + e.getMessage());
-            return null;
-        }
+        } catch (Exception e) {
+            // Keep failures non-fatal; just fall back to element screenshot.
+            // `logger` is available via the enclosing action instance.
+            // If making this method non-static is acceptable, that would allow direct logger use.
+            return null;
+        }

Or alternatively, make findImageInShadowRoot non-static and use logger.info/logger.warn instead of System.err.


258-308: Tighten URL handling in downloadImageFromUrl (schemes, errors, SSRF surface)

The method is generally solid: handles data: URLs, relative paths, // and / prefixes, sets generous but finite timeouts, streams into a byte array, and cleans up the HttpURLConnection.

A few improvements would make it safer and clearer:

  1. Restrict to http/https schemes before casting to HttpURLConnection

    Right now, any non-data: URL ends up at new URL(imageUrl) and is blindly cast to HttpURLConnection. If imageUrl ever used another scheme (e.g. file:, blob:), this would throw a ClassCastException. Also, restricting schemes helps avoid accidental use of unexpected protocols.

  2. Guard against unintended network targets

    Because the URL ultimately comes from page content, this becomes a generic HTTP client. For environments where the runner has network access to internal services, it’s worth ensuring only http/https URLs you actually expect are fetched (e.g., same-origin with the AUT, or a configurable allow-list) to reduce SSRF-like risk.

  3. Preserve root cause and consider IOException in signature

    The method is declared throws IOException but currently wraps all failures in a RuntimeException. Either remove the checked exception from the signature or consider rethrowing the original IOException (and only wrapping unexpected runtime problems), so callers can distinguish network vs coding issues.

Example scheme check in the existing block:

-            // Download the image
-            URL url = new URL(imageUrl);
-            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+            // Download the image
+            URL url = new URL(imageUrl);
+            String protocol = url.getProtocol();
+            if (!"http".equalsIgnoreCase(protocol) && !"https".equalsIgnoreCase(protocol)) {
+                throw new RuntimeException("Unsupported URL scheme for image download: " + protocol);
+            }
+
+            HttpURLConnection connection = (HttpURLConnection) url.openConnection();

If you later need to allow more schemes, this check gives you a single place to manage them.


310-324: Make handleDataUrl slightly more robust for complex data URIs

handleDataUrl works for the common data:[mime];base64,<payload> form and logs to System.err on failure. A couple of small refinements:

  • Use split(",", 2) so additional commas in the payload (rare but valid) don’t break decoding.
  • Prefer the class logger over System.err for consistency.

Suggested tweak:

-            String[] parts = dataUrl.split(",");
+            String[] parts = dataUrl.split(",", 2);
             if (parts.length != 2) {
                 throw new Exception("Invalid data URL format");
             }
@@
-        } catch (Exception e) {
-            System.err.println("Error processing data URL: " + e.getMessage());
-            throw e;
-        }
+        } catch (Exception e) {
+            // Log and rethrow so callers can fall back appropriately
+            // logger.info("Error processing data URL: " + e.getMessage(), e);
+            throw e;
+        }

(If you keep this method static, you may prefer to pass in logger or convert it to an instance method to avoid System.err.)

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a928a8d and df862ab.

📒 Files selected for processing (11)
  • image_visual_testing/pom.xml (2 hunks)
  • image_visual_testing/src/main/java/com/testsigma/addons/android/DownloadImageFromImgTag.java (1 hunks)
  • image_visual_testing/src/main/java/com/testsigma/addons/android/TakeScreenShotAndStorePathInRuntime.java (1 hunks)
  • image_visual_testing/src/main/java/com/testsigma/addons/android/VerifyIfImagesAreDissimilarWithThreshold.java (1 hunks)
  • image_visual_testing/src/main/java/com/testsigma/addons/android/VerifyIfImagesAreSimilarWithThreshold.java (1 hunks)
  • image_visual_testing/src/main/java/com/testsigma/addons/ios/DownloadImageFromImgTag.java (1 hunks)
  • image_visual_testing/src/main/java/com/testsigma/addons/ios/TakeScreenShotAndStorePathInRuntime.java (1 hunks)
  • image_visual_testing/src/main/java/com/testsigma/addons/ios/VerifyIfImagesAreDissimilarWithThreshold.java (1 hunks)
  • image_visual_testing/src/main/java/com/testsigma/addons/ios/VerifyIfImagesAreSimilarWithThreshold.java (1 hunks)
  • image_visual_testing/src/main/java/com/testsigma/addons/web/DownloadImageFromImgTag.java (6 hunks)
  • image_visual_testing/src/main/java/com/testsigma/addons/web/TakeScreenShotAndStoreinS3.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • image_visual_testing/pom.xml
  • image_visual_testing/src/main/java/com/testsigma/addons/android/TakeScreenShotAndStorePathInRuntime.java
🔇 Additional comments (10)
image_visual_testing/src/main/java/com/testsigma/addons/ios/TakeScreenShotAndStorePathInRuntime.java (1)

23-27: Annotation changes look good.

The updated description text is clearer and more accurate.

image_visual_testing/src/main/java/com/testsigma/addons/ios/DownloadImageFromImgTag.java (1)

242-260: HttpURLConnection resource management looks correct.

The connection is properly disconnected in the finally block. Good fix from previous review feedback.

image_visual_testing/src/main/java/com/testsigma/addons/web/TakeScreenShotAndStoreinS3.java (1)

21-25: Annotation description is now accurate.

The description correctly describes the action's purpose.

image_visual_testing/src/main/java/com/testsigma/addons/android/DownloadImageFromImgTag.java (2)

44-121: Core execution logic is well-structured.

The action properly handles various image source scenarios (img tag, shadow root, canvas, SVG) with appropriate fallbacks to element screenshots. Good error handling with proper result status returns.


248-260: HttpURLConnection resource management is correct.

The connection is properly disconnected in the finally block.

image_visual_testing/src/main/java/com/testsigma/addons/ios/VerifyIfImagesAreSimilarWithThreshold.java (2)

121-176: API call implementation looks reasonable.

The multipart request construction and response handling are appropriate. Consider adding request timeouts to the OkHttpClient as noted above.


218-244: URL to file converter implementation is solid.

Good handling of both HTTP(S) URLs and local file paths with proper extension preservation.

image_visual_testing/src/main/java/com/testsigma/addons/web/DownloadImageFromImgTag.java (3)

9-9: Selenium wildcard import is acceptable here

Using the org.openqa.selenium.* wildcard is fine in this context given multiple Selenium types are used (WebElement, OutputType, Dimension, JavascriptExecutor) and project style seems to allow it.


167-177: File-save helper is straightforward and appropriate

saveBytesArrayToFile is clear and does the right thing: creates the file, logs creation, writes bytes, and surfaces failures via a runtime exception with context in the log. This is fine as a shared helper for the action family.


179-199: Shadow-root img helper looks correct and bounded

The getSrcFromShadowRoot JavaScript text block is minimal and safe: it only inspects element.shadowRoot, looks for a single img, and returns its src/src attribute as a string. Exception handling logs and returns null, which nicely degrades back to the screenshot path.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
image_visual_testing/src/main/java/com/testsigma/addons/ios/VerifyIfImagesAreSimilarWithThreshold.java (1)

36-40: Variable naming still contradicts TestData annotations.

Despite the past review comment being marked as addressed, the variable assignments remain swapped:

  • image1 is annotated as "actual-image" but assigned to baseImagePath
  • image2 is annotated as "base-image" but assigned to actualImagePath

This inconsistency makes the code confusing and error-prone for future maintenance.

Apply this diff to align variable names with their annotations:

-        String baseImagePath = image1.getValue().toString();
-        String actualImagePath = image2.getValue().toString();
+        String actualImagePath = image1.getValue().toString();  // image1 is "actual-image"
+        String baseImagePath = image2.getValue().toString();    // image2 is "base-image"

Then update the file variable names for clarity:

-            File file1 = urlToFileConverter("first_image", baseImagePath);
-            File file2 = urlToFileConverter("second_image", actualImagePath);
+            File file1 = urlToFileConverter("base_image", baseImagePath);
+            File file2 = urlToFileConverter("actual_image", actualImagePath);

Also applies to: 64-65, 76-77

🧹 Nitpick comments (5)
image_visual_testing/src/main/java/com/testsigma/addons/ios/VerifyIfImagesAreSimilarWithThreshold.java (5)

50-54: Remove unused RequestConfig.

The RequestConfig object is defined but never used in the code. OkHttpClient is used instead for API calls, which has its own timeout configuration.

-    RequestConfig config = RequestConfig.custom()
-            .setSocketTimeout(10 * 60 * 1000)
-            .setConnectionRequestTimeout(60 * 1000)
-            .setConnectTimeout(60 * 1000)
-            .build();

89-96: Inconsistent handling of upload failures.

When images match (line 92), uploadScreenshot() is called but its return value is ignored, and Result.SUCCESS is returned unconditionally (line 95). However, in the failure path (lines 107-108), the method returns the result from uploadScreenshot().

While the current uploadScreenshot() implementation logs upload failures without failing the test, this inconsistency creates confusion and could hide issues if the upload logic changes in the future.

-                uploadScreenshot(true, file2, actualImage, null, errorMessageBuilder);
-                setSuccessMessage("Successfully verified that the base image and actual image match the" +
-                        " expected percentage of similarity: " + (percentageSimilarity * 100) + "%");
-                return Result.SUCCESS;
+                Result uploadResult = uploadScreenshot(true, file2, actualImage, null, errorMessageBuilder);
+                if (uploadResult == Result.SUCCESS) {
+                    setSuccessMessage("Successfully verified that the base image and actual image match the" +
+                            " expected percentage of similarity: " + (percentageSimilarity * 100) + "%");
+                }
+                return uploadResult;

181-220: Improve parameter naming and success message clarity.

  • Line 181: Parameter actualDirImage is misleading—"Dir" suggests a directory, but it's a File representing an image.
  • Lines 195-196: The success message references "first image," which is ambiguous given the variable naming confusion.

Consider renaming the parameter for clarity:

-    private Result uploadScreenshot(boolean compareResult, File actualDirImage, BufferedImage combined,
+    private Result uploadScreenshot(boolean compareResult, File actualImageFile, BufferedImage combined,
                                     File combinedImage, StringBuilder errorMessageBuilder) {
         try {
             IOSDriver iosDriver = (IOSDriver) this.driver;
             ImageComparisonUtils imageComparisonUtils = new ImageComparisonUtils(iosDriver, logger);
             String s3Url = testStepResult.getScreenshotUrl();
             if (compareResult) {
                 logger.info("images are identical hence uploading the actual image to S3");
-                boolean uploadS3Result = imageComparisonUtils.uploadFile(s3Url, actualDirImage.getAbsolutePath());
+                boolean uploadS3Result = imageComparisonUtils.uploadFile(s3Url, actualImageFile.getAbsolutePath());

And clarify the success message to specify which image is shown:

-                setSuccessMessage("Successfully verified that the base image and actual image are " +
-                        "same by visual testing. (Note: Step screenshot contains the first image)");
+                setSuccessMessage("Successfully verified that the base image and actual image are " +
+                        "same by visual testing. (Note: Step screenshot contains the actual image)");

204-206: Remove commented-out code.

Commented code at lines 204-206 and line 242 should be removed to reduce clutter. Version control preserves the history if this code needs to be referenced later.

-//                String message = "Comparison failed because visual testing detected dissimilarities," +
-//                        " check step screenshot for visual results";
-//                errorMessageBuilder.append(message);
                 setErrorMessage(errorMessageBuilder.toString());
                 logger.info("Given is local file path..");
                 return new File(url);
-//                return createLocalFileFromDownloadsCopy(url, ".png");

Also applies to: 242-242


222-248: Add validation for local file paths and fix misleading log message.

Two improvements:

  1. Line 225: Log message says "Given is s3 url" but the check is for any HTTP/HTTPS URL, not specifically S3.
  2. Line 241: No validation that the local file exists before returning it, which will cause a less clear error later during ImageIO.read().
             if (url.startsWith("https://") || url.startsWith("http://")) {
-                logger.info("Given is s3 url ...File name:" + fileName);
+                logger.info("Given is remote URL ...File name:" + fileName);
                 URL urlObject = new URL(url);
                 String baseName = fileName;
                 String extension = "";
                 int lastDotIndex = fileName.lastIndexOf('.');
                 if (lastDotIndex > 0) {
                     baseName = fileName.substring(0, lastDotIndex);
                     extension = fileName.substring(lastDotIndex);
                 }
                 File tempFile = File.createTempFile(baseName, extension);
                 FileUtils.copyURLToFile(urlObject, tempFile);
                 logger.info("Temp file created with name for s3 file" + tempFile.getName()
                         + " at path " + tempFile.getAbsolutePath());
                 return tempFile;
             } else {
                 logger.info("Given is local file path..");
-                return new File(url);
+                File localFile = new File(url);
+                if (!localFile.exists()) {
+                    logger.error("Local file does not exist: " + url);
+                    throw new RuntimeException("Local file not found: " + url);
+                }
+                return localFile;
             }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between df862ab and 755da06.

📒 Files selected for processing (1)
  • image_visual_testing/src/main/java/com/testsigma/addons/ios/VerifyIfImagesAreSimilarWithThreshold.java (1 hunks)
🔇 Additional comments (1)
image_visual_testing/src/main/java/com/testsigma/addons/ios/VerifyIfImagesAreSimilarWithThreshold.java (1)

124-179: Consider adding timeout configuration to OkHttpClient.

The OkHttpClient at line 128 uses default timeouts (10 seconds for connect/read), but the unused RequestConfig at lines 50-54 defined 10-minute socket timeout, suggesting long-running visual comparison operations are expected.

Verify whether the default OkHttpClient timeouts are sufficient for visual testing API calls, especially for large images.

If longer timeouts are needed, configure the client:

OkHttpClient client = new OkHttpClient.Builder()
    .connectTimeout(60, TimeUnit.SECONDS)
    .readTimeout(10, TimeUnit.MINUTES)
    .writeTimeout(10, TimeUnit.MINUTES)
    .build();

@ManojTestsigma ManojTestsigma merged commit 71fdf1b into dev Dec 9, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants