Skip to content

Conversation

@akhil-testsigma
Copy link
Contributor

@akhil-testsigma akhil-testsigma commented Dec 17, 2025

Publish this addon as public

Addon Name: Run Lighthouse Audit and Upload Report to Testsigma Uploads
Jarvis Link: https://jarvis.testsigma.com/ui/tenants/3072/addons
Jira : https://testsigma.atlassian.net/browse/CUS-9392
Added class Lighthouse Audit and Report Upload to Testsigma Upload Section

Summary by CodeRabbit

  • New Features
    • Lighthouse audit functionality now available with automatic performance and accessibility scoring
    • Generated HTML reports are uploaded to Testsigma
    • Audit scores stored as runtime data for use in subsequent test steps

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

@coderabbitai
Copy link

coderabbitai bot commented Dec 17, 2025

Walkthrough

This PR introduces a new Testsigma addon project that integrates Google Lighthouse audits with Testsigma. The addon orchestrates a Lighthouse audit via PageSpeed API, extracts performance metrics, generates an HTML report through Lighthouse Viewer, and uploads the report to Testsigma.

Changes

Cohort / File(s) Summary
Maven Project Configuration
pom.xml
Defines new addon project with coordinates, properties for compiler/SDK versions, and dependencies including Testsigma SDK, Selenium, Appium, OkHttp, Jackson, and test frameworks. Configures maven-shade-plugin and maven-source-plugin.
Core Addon Implementation
src/main/java/com/testsigma/addons/web/RunLighthouseAuditAndUploadReport.java
Introduces WebAction class that executes Lighthouse audits: builds PageSpeed API URL, calls Google API, parses audit scores, persists results to runtime data, generates HTML report via Lighthouse Viewer, uploads to Testsigma with multipart request, and handles cleanup.
Runtime Configuration
src/main/resources/testsigma-sdk.properties
Adds Testsigma SDK API key for authentication.

Sequence Diagram(s)

sequenceDiagram
    participant User as Testsigma Test
    participant Addon as RunLighthouseAuditAndUploadReport
    participant PageSpeed as Google PageSpeed API
    participant Viewer as Lighthouse Viewer
    participant Upload as Testsigma Upload
    participant Runtime as Runtime Data
    participant FileSystem as File System

    User->>Addon: execute()
    Addon->>PageSpeed: POST audit request<br/>(target URL + strategy)
    activate PageSpeed
    PageSpeed-->>Addon: Lighthouse JSON result
    deactivate PageSpeed
    
    Addon->>Addon: Parse scores<br/>(performance, accessibility, best-practices)
    Addon->>Runtime: Store audit scores
    
    Addon->>FileSystem: Write JSON to temp file
    Addon->>Viewer: POST JSON to generate<br/>HTML report
    activate Viewer
    Viewer-->>Addon: HTML page source
    deactivate Viewer
    Addon->>FileSystem: Write HTML to temp file
    
    Addon->>Upload: Multipart POST<br/>(HTML report + metadata)
    activate Upload
    alt Upload Successful
        Upload-->>Addon: Success response
        Addon-->>User: Result.SUCCESS
    else Upload Failed
        Upload-->>Addon: Error response
        Addon-->>User: Result.FAILED
    end
    deactivate Upload
    
    Addon->>FileSystem: Cleanup temp files
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Areas requiring extra attention:

  • External API integration logic: verify correct handling of Google PageSpeed API responses and error scenarios
  • Multipart request construction for Testsigma upload: ensure proper serialization of report data and metadata
  • Temporary file handling and cleanup: confirm files are properly created, used, and cleaned up even on exception paths
  • Runtime data persistence: validate correct binding and storage of audit scores
  • Error handling propagation: ensure all failure paths return appropriate Result states with logging

Suggested reviewers

  • Ganesh-Testsigma
  • vigneshtestsigma

Poem

🐰 A lighthouse shines through the digital night,
Auditing pages with metrics so bright,
Scores bundled up in reports that gleam,
Uploaded to Testsigma—a quality dream! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 clearly summarizes the main change: adding a Lighthouse Audit and Report Upload class to the Testsigma platform.
✨ 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 feat/CUS-9392-Added-class-Lighthouse-Audit-and-Report-Upload-to-Testsigma-Upload-Section

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: 6

🧹 Nitpick comments (6)
run_lighthouse_audit_and_upload_report_to_testsigma_uploads/src/main/java/com/testsigma/addons/web/RunLighthouseAuditAndUploadReport.java (4)

74-77: Consider sharing the OkHttpClient instance.

Creating a new OkHttpClient per action instance is wasteful since OkHttp is designed for connection pooling and reuse. For an addon that may be called multiple times, consider making this static or using a singleton pattern.

-    private final OkHttpClient client = new OkHttpClient.Builder()
+    private static final OkHttpClient client = new OkHttpClient.Builder()
             .connectTimeout(Duration.ofSeconds(60))
             .readTimeout(Duration.ofSeconds(60))
             .build();

122-132: Consider truncating error response body.

If the Google API returns a large error response, including the entire body in the exception message could clutter logs. Consider truncating it.

         try (Response response = client.newCall(request).execute()) {
             String body = response.body() != null ? response.body().string() : "";
             if (!response.isSuccessful()) {
-                throw new RuntimeException("Google API error (" + response.code() + "): " + body);
+                String truncatedBody = body.length() > 500 ? body.substring(0, 500) + "..." : body;
+                throw new RuntimeException("Google API error (" + response.code() + "): " + truncatedBody);
             }
             return new JSONObject(body);
         }

207-211: Include response body in upload error for debugging.

When the upload fails, only the status code is reported. Including the response body would help diagnose issues like authentication failures or validation errors.

         try (Response response = client.newCall(request).execute()) {
             if (!response.isSuccessful()) {
-                throw new RuntimeException("Upload failed: " + response.code());
+                String errorBody = response.body() != null ? response.body().string() : "";
+                throw new RuntimeException("Upload failed (" + response.code() + "): " + errorBody);
             }
         }

214-220: Specify explicit charset for file writing.

FileWriter uses the platform's default charset, which may vary. Since the content includes JSON and HTML that may contain special characters, explicitly use UTF-8 for consistency.

     private File writeTempFile(String name, String ext, String content) throws IOException {
         File file = File.createTempFile(name, ext);
-        try (FileWriter writer = new FileWriter(file)) {
+        try (FileWriter writer = new FileWriter(file, StandardCharsets.UTF_8)) {
             writer.write(content);
         }
         return file;
     }
run_lighthouse_audit_and_upload_report_to_testsigma_uploads/pom.xml (2)

18-18: Unused property: remove or utilize.

The testsigma.addon.maven.plugin property is defined but never referenced in the build configuration.

Apply this diff to remove the unused property:

     <maven.source.plugin.version>3.2.1</maven.source.plugin.version>
     <lombok.version>1.18.30</lombok.version>
-
-    <testsigma.addon.maven.plugin>1.0.0</testsigma.addon.maven.plugin>
 </properties>

84-96: Consider configuring the Maven Shade Plugin for better dependency management.

The Maven Shade Plugin is configured with minimal settings. For production addons, consider adding transformers to merge service files and filters to exclude unnecessary dependencies, which can reduce JAR size and prevent classpath conflicts.

Example configuration:

<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>
            <configuration>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"/>
                </transformers>
                <filters>
                    <filter>
                        <artifact>*:*</artifact>
                        <excludes>
                            <exclude>META-INF/*.SF</exclude>
                            <exclude>META-INF/*.DSA</exclude>
                            <exclude>META-INF/*.RSA</exclude>
                        </excludes>
                    </filter>
                </filters>
            </configuration>
        </execution>
    </executions>
</plugin>
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d22206f and a388c3d.

📒 Files selected for processing (3)
  • run_lighthouse_audit_and_upload_report_to_testsigma_uploads/pom.xml (1 hunks)
  • run_lighthouse_audit_and_upload_report_to_testsigma_uploads/src/main/java/com/testsigma/addons/web/RunLighthouseAuditAndUploadReport.java (1 hunks)
  • run_lighthouse_audit_and_upload_report_to_testsigma_uploads/src/main/resources/testsigma-sdk.properties (1 hunks)
🧰 Additional context used
🪛 Gitleaks (8.30.0)
run_lighthouse_audit_and_upload_report_to_testsigma_uploads/src/main/resources/testsigma-sdk.properties

[high] 1-1: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.

(jwt)

🪛 OSV Scanner (2.3.0)
run_lighthouse_audit_and_upload_report_to_testsigma_uploads/pom.xml

[HIGH] 1-1: org.json:json 20230227: Java: DoS Vulnerability in JSON-JAVA

(GHSA-4jq9-2xhw-jpx7)


[HIGH] 1-1: org.testng:testng 6.14.3: TestNG is vulnerable to Path Traversal

(GHSA-rc2q-x9mf-w3vf)

🔇 Additional comments (5)
run_lighthouse_audit_and_upload_report_to_testsigma_uploads/src/main/java/com/testsigma/addons/web/RunLighthouseAuditAndUploadReport.java (3)

23-30: LGTM!

The class declaration with @Data and @Action annotations is properly configured. The action text is descriptive and the application type correctly identifies this as a web action.


79-109: LGTM!

The execute() method is well-structured with proper try-catch-finally pattern. Temporary file cleanup in the finally block ensures resources are released even on failure.


151-155: LGTM!

Score storage with null-safe runtime data handling is properly implemented.

run_lighthouse_audit_and_upload_report_to_testsigma_uploads/pom.xml (1)

42-46: Security vulnerability: TestNG 6.14.3 has a Path Traversal flaw.

TestNG 6.14.3 is over six years old and likely contains known security vulnerabilities. The specific vulnerability referenced (GHSA-rc2q-x9mf-w3vf) requires verification, but upgrading to a more recent TestNG version is strongly recommended.

Upgrade to TestNG 7.5.1 or later to address known security issues.

run_lighthouse_audit_and_upload_report_to_testsigma_uploads/src/main/resources/testsigma-sdk.properties (1)

1-1: Hardcoded JWT in properties file is part of a repository-wide pattern across 180+ addons—requires clarification on credential policy.

This JWT token is hardcoded in the properties file, which is packaged into distributions and already visible in the public GitHub repository. However, this is not an isolated issue: every addon in this repository (~180+) follows the identical pattern with different JWT tokens per addon (each with different uniqueIds), suggesting this may be an intentional test credential design rather than accidental exposure.

Before taking action:

  • Clarify whether these are intentional test/dummy credentials or production secrets
  • Determine if Testsigma has an established credential management policy for community addons
  • Decide whether to address this as a repository-wide issue rather than per-addon fixes

If these are test credentials and the pattern is intentional, document that explicitly. If they are real credentials, this requires coordinated remediation across all addons and a policy change for credential handling in future addon development.

Comment on lines +36 to +41
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
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

Milestone version of JUnit may cause stability issues.

The junit-jupiter-api dependency uses version 5.8.0-M1, which is a milestone (pre-release) version and may not be suitable for production use.

Apply this diff to use a stable release:

-        <junit.jupiter.version>5.8.0-M1</junit.jupiter.version>
+        <junit.jupiter.version>5.10.5</junit.jupiter.version>

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

🤖 Prompt for AI Agents
In run_lighthouse_audit_and_upload_report_to_testsigma_uploads/pom.xml around
lines 36 to 41, the junit-jupiter-api dependency is using a milestone
pre-release version (5.8.0-M1); change it to a stable release by updating the
version reference (replace the milestone with a stable version such as 5.8.2 or
another current stable release) and, if the version comes from a property (e.g.
${junit.jupiter.version}), update that property accordingly so the pom
references a non-milestone, supported JUnit 5 release.

Comment on lines +48 to +51
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.33.0</version>
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

Update dependencies to latest secure versions.

The project is using significantly outdated dependencies. Selenium should be upgraded from 4.33.0 to at least 4.38.0 (latest as of October 2025). Jackson-annotations 2.13.0 should be upgraded to 2.20 or migrate to Jackson 3.0.0. OkHttp 4.12.0 should be upgraded to address known security patterns in newer versions, with 5.3.0 being the current stable release.

Comment on lines +69 to +73
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20230227</version>
</dependency>
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

🧩 Analysis chain

🏁 Script executed:

find . -name "pom.xml" -type f -exec grep -l "org.json" {} \;

Repository: testsigmahq/testsigma-addons

Length of output: 311


Update org.json dependency due to DoS vulnerability

org.json:json version 20230227 contains CVE-2023-5072 (GHSA-rm7j-f5g5-27vv). This vulnerability was fixed in version 20231013. Update to 20250517 or a later stable release.

🤖 Prompt for AI Agents
In run_lighthouse_audit_and_upload_report_to_testsigma_uploads/pom.xml around
lines 69 to 73, the org.json:json dependency is pinned to 20230227 which
contains CVE-2023-5072; update the <version> element to a patched release (at
least 20231013, preferably 20250517 or later) to remediate the DoS
vulnerability, then run mvn -U clean install or update your dependency lock to
ensure the new version is resolved and rebuild to verify no dependency
conflicts.

Comment on lines +111 to +120
private String buildLighthouseApiUrl() {
String encodedUrl = URLEncoder.encode(targetUrl.getValue().toString(), StandardCharsets.UTF_8);
String strat = strategy.getValue().toString().toLowerCase();

return String.format(
"https://www.googleapis.com/pagespeedonline/v5/runPagespeed" +
"?url=%s&strategy=%s&category=performance&category=accessibility&category=best-practices&key=%s",
encodedUrl, strat, apiKey.getValue().toString()
);
}
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

API key may be exposed in logs or error messages.

The Google API key is embedded directly in the URL. If this URL is logged or included in an exception message, the API key could be leaked to logs, monitoring systems, or error reports.

Consider sanitizing the URL before including it in any error messages, or use a more secure method to pass the API key if the PageSpeed API supports it.

     private String buildLighthouseApiUrl() {
         String encodedUrl = URLEncoder.encode(targetUrl.getValue().toString(), StandardCharsets.UTF_8);
         String strat = strategy.getValue().toString().toLowerCase();
 
-        return String.format(
+        String apiKeyValue = apiKey.getValue().toString();
+        if (apiKeyValue == null || apiKeyValue.trim().isEmpty()) {
+            throw new IllegalArgumentException("Google API key is required");
+        }
+        return String.format(
             "https://www.googleapis.com/pagespeedonline/v5/runPagespeed" +
             "?url=%s&strategy=%s&category=performance&category=accessibility&category=best-practices&key=%s",
-            encodedUrl, strat, apiKey.getValue().toString()
+            encodedUrl, strat, apiKeyValue
         );
     }

Additionally, consider wrapping the callGoogleApi call to avoid leaking the key in exception messages:

try {
    JSONObject lighthouseJson = callGoogleApi(apiUrl);
} catch (Exception e) {
    // Re-throw with sanitized message (no URL containing API key)
    throw new RuntimeException("Failed to call Google PageSpeed API: " + e.getMessage());
}
🤖 Prompt for AI Agents
In
run_lighthouse_audit_and_upload_report_to_testsigma_uploads/src/main/java/com/testsigma/addons/web/RunLighthouseAuditAndUploadReport.java
around lines 111-120, the constructed URL contains the API key which may be
leaked via logs or exception messages; change the code to stop embedding the key
into any string that might be logged: keep a method that builds the base API URL
without the key for logging/exception contexts and append the key only at the
point of making the HTTP request (preferably passing the key in a non-logged
header or request body if the PageSpeed API supports it, otherwise append it
right before the request and avoid logging the full URL). Also wrap the
callGoogleApi invocation in a try/catch, and rethrow or log only a sanitized
error message that does not include the URL or apiKey value (e.g., "Failed to
call PageSpeed API" + e.getMessage()) so the key never appears in logs or
exception text.

Comment on lines +134 to +144
private Map<String, Integer> extractScores(JSONObject json) {
JSONObject categories = json
.getJSONObject("lighthouseResult")
.getJSONObject("categories");

Map<String, Integer> scores = new HashMap<>();
scores.put("performance", getScore(categories, "performance"));
scores.put("accessibility", getScore(categories, "accessibility"));
scores.put("best-practices", getScore(categories, "best-practices"));
return scores;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add defensive checks for JSON structure.

The method assumes lighthouseResult and categories keys exist. If the API response structure changes or contains an error object instead, this will throw an unhelpful JSONException.

     private Map<String, Integer> extractScores(JSONObject json) {
+        if (!json.has("lighthouseResult")) {
+            throw new RuntimeException("Invalid API response: missing 'lighthouseResult'");
+        }
+        JSONObject lighthouseResult = json.getJSONObject("lighthouseResult");
+        if (!lighthouseResult.has("categories")) {
+            throw new RuntimeException("Invalid API response: missing 'categories'");
+        }
-        JSONObject categories = json
-                .getJSONObject("lighthouseResult")
-                .getJSONObject("categories");
+        JSONObject categories = lighthouseResult.getJSONObject("categories");
 
         Map<String, Integer> scores = new HashMap<>();
         scores.put("performance", getScore(categories, "performance"));
         scores.put("accessibility", getScore(categories, "accessibility"));
         scores.put("best-practices", getScore(categories, "best-practices"));
         return scores;
     }
📝 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
private Map<String, Integer> extractScores(JSONObject json) {
JSONObject categories = json
.getJSONObject("lighthouseResult")
.getJSONObject("categories");
Map<String, Integer> scores = new HashMap<>();
scores.put("performance", getScore(categories, "performance"));
scores.put("accessibility", getScore(categories, "accessibility"));
scores.put("best-practices", getScore(categories, "best-practices"));
return scores;
}
private Map<String, Integer> extractScores(JSONObject json) {
if (!json.has("lighthouseResult")) {
throw new RuntimeException("Invalid API response: missing 'lighthouseResult'");
}
JSONObject lighthouseResult = json.getJSONObject("lighthouseResult");
if (!lighthouseResult.has("categories")) {
throw new RuntimeException("Invalid API response: missing 'categories'");
}
JSONObject categories = lighthouseResult.getJSONObject("categories");
Map<String, Integer> scores = new HashMap<>();
scores.put("performance", getScore(categories, "performance"));
scores.put("accessibility", getScore(categories, "accessibility"));
scores.put("best-practices", getScore(categories, "best-practices"));
return scores;
}
🤖 Prompt for AI Agents
In
run_lighthouse_audit_and_upload_report_to_testsigma_uploads/src/main/java/com/testsigma/addons/web/RunLighthouseAuditAndUploadReport.java
around lines 134 to 144, the method extractScores assumes the JSON contains
"lighthouseResult" and "categories" and will throw JSONException if those keys
are missing or not objects; update the method to defensively check for these
keys (use has/optJSONObject or check for null and instance types), return an
empty map or throw a clear, descriptive exception when the expected structure is
missing, and ensure downstream calls to getScore are only made when categories
is valid (or have getScore handle missing category gracefully); also consider
logging the unexpected JSON shape for debugging.

Comment on lines +170 to +174
new WebDriverWait(driver, Duration.ofSeconds(60))
.until(ExpectedConditions.presenceOfElementLocated(
By.xpath("//div[contains(@class,'lh-report')]")));

Thread.sleep(1500);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Replace Thread.sleep with explicit wait condition.

Using Thread.sleep(1500) after the WebDriverWait is a brittle approach. The WebDriverWait already confirms the report element is present. If additional stabilization is needed, use another explicit wait for a specific condition (e.g., waiting for JavaScript to finish or a specific element state).

             new WebDriverWait(driver, Duration.ofSeconds(60))
                     .until(ExpectedConditions.presenceOfElementLocated(
                             By.xpath("//div[contains(@class,'lh-report')]")));
 
-            Thread.sleep(1500);
+            // Wait for report to fully render
+            new WebDriverWait(driver, Duration.ofSeconds(10))
+                    .until(ExpectedConditions.visibilityOfElementLocated(
+                            By.xpath("//div[contains(@class,'lh-report')]")));
🤖 Prompt for AI Agents
In
run_lighthouse_audit_and_upload_report_to_testsigma_uploads/src/main/java/com/testsigma/addons/web/RunLighthouseAuditAndUploadReport.java
around lines 170-174, remove the Thread.sleep(1500) and replace it with an
explicit wait that ensures the page/report is stabilized (for example, wait
until the report element is visible/interactive or until document.readyState ==
"complete" or until a loading spinner disappears). Use WebDriverWait with an
appropriate ExpectedCondition such as visibilityOfElementLocated,
elementToBeClickable on the lh-report element, or a JavascriptExecutor check for
readyState, and then proceed; do not use Thread.sleep.

@akhil-testsigma akhil-testsigma merged commit 217e82d into dev Dec 19, 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.

3 participants