diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b165439..29151f3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,7 +32,7 @@ jobs: - name: Get yarn cache directory path id: yarn-cache-dir-path run: echo "::set-output name=dir::$(yarn cache dir)" - - uses: actions/cache@v2 + - uses: actions/cache@v3 with: path: ${{ steps.yarn-cache-dir-path.outputs.dir }} key: v1/${{ runner.os }}/java-${{ matrix.java }}/${{ hashFiles('**/yarn.lock') }} diff --git a/README.md b/README.md index d36d74b..e2eca62 100644 --- a/README.md +++ b/README.md @@ -220,6 +220,49 @@ public class Example { - `bottom` (int): Bottom coordinate of the consider region. - `left` (int): Left coordinate of the consider region. - `right` (int): Right coordinate of the consider region. + - `regions` parameter that allows users to apply snapshot options to specific areas of the page. This parameter is an array where each object defines a custom region with configurations. + - Parameters: + - `elementSelector` (optional, only one of the following must be provided, if this is not provided then full page will be considered as region) + - `boundingBox` (object): Defines the coordinates and size of the region. + - `x` (number): X-coordinate of the region. + - `y` (number): Y-coordinate of the region. + - `width` (number): Width of the region. + - `height` (number): Height of the region. + - `elementXpath` (string): The XPath selector for the element. + - `elementCSS` (string): The CSS selector for the element. + - `algorithm` (mandatory) + - Specifies the snapshot comparison algorithm. + - Allowed values: `standard`, `layout`, `ignore`, `intelliignore`. + - `configuration` (required for `standard` and `intelliignore` algorithms, ignored otherwise) + - `diffSensitivity` (number): Sensitivity level for detecting differences. + - `imageIgnoreThreshold` (number): Threshold for ignoring minor image differences. + - `carouselsEnabled` (boolean): Whether to enable carousel detection. + - `bannersEnabled` (boolean): Whether to enable banner detection. + - `adsEnabled` (boolean): Whether to enable ad detection. + - `assertion` (optional) + - Defines assertions to apply to the region. + - `diffIgnoreThreshold` (number): The threshold for ignoring minor differences. +### Example Usage for regions +``` + Map params = new HashMap<>(); + params.put("elementXpath", "//div[@id='test']"); + params.put("algorithm", "standard"); + params.put("diffSensitivity", 3); + params.put("imageIgnoreThreshold", 0.2); + params.put("carouselsEnabled", true); + params.put("bannersEnabled", false); + params.put("adsEnabled", true); + params.put("diffIgnoreThreshold", 0.1); + + // Call the method to create the region + Map regions2 = percy.createRegion(params); + List> regions = Collections.singletonList(obj1); + Map options = new HashMap<>(); + options.put("regions", regions); + + percy.snapshot("Homepage", options); + +``` ### Creating Percy on automate build Note: Automate Percy Token starts with `auto` keyword. The command can be triggered using `exec` keyword. diff --git a/package.json b/package.json index f33e97a..4711c51 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,6 @@ "test": "npx percy exec --testing -- mvn test" }, "devDependencies": { - "@percy/cli": "1.29.5-beta.0" + "@percy/cli": "1.30.9" } } diff --git a/src/main/java/io/percy/selenium/Percy.java b/src/main/java/io/percy/selenium/Percy.java index 7fe919b..0cf20f0 100644 --- a/src/main/java/io/percy/selenium/Percy.java +++ b/src/main/java/io/percy/selenium/Percy.java @@ -28,6 +28,9 @@ import java.util.stream.Collectors; +import javax.swing.text.html.CSS; +import javax.xml.xpath.XPath; + /** * Percy client for visual testing. */ @@ -75,6 +78,80 @@ public Percy(WebDriver driver) { this.env = new Environment(driver); } + /** + * Creates a region configuration based on the provided parameters. + * + * @param params A map containing the region configuration options. Expected keys: + *
    + *
  • boundingBox - The bounding box of the region, or null.
  • + *
  • elementXpath - The XPath of the element, or null.
  • + *
  • elementCSS - The CSS selector of the element, or null.
  • + *
  • padding - The padding around the region, or null.
  • + *
  • algorithm - The algorithm to be used (default: 'ignore').
  • + *
  • diffSensitivity - The sensitivity for diffing, or null.
  • + *
  • imageIgnoreThreshold - The image ignore threshold, or null.
  • + *
  • carouselsEnabled - Flag for enabling carousels, or null.
  • + *
  • bannersEnabled - Flag for enabling banners, or null.
  • + *
  • adsEnabled - Flag for enabling ads, or null.
  • + *
  • diffIgnoreThreshold - The diff ignore threshold, or null.
  • + *
+ * @return A map representing the region configuration. + */ + + public Map createRegion(Map params) { + Map elementSelector = new HashMap<>(); + if (params.containsKey("boundingBox")) { + elementSelector.put("boundingBox", params.get("boundingBox")); + } + if (params.containsKey("elementXpath")) { + elementSelector.put("elementXpath", params.get("elementXpath")); + } + if (params.containsKey("elementCSS")) { + elementSelector.put("elementCSS", params.get("elementCSS")); + } + + Map region = new HashMap<>(); + region.put("algorithm", params.getOrDefault("algorithm", "ignore")); + region.put("elementSelector", elementSelector); + + if (params.containsKey("padding")) { + region.put("padding", params.get("padding")); + } + + Map configuration = new HashMap<>(); + String algorithm = (String) params.getOrDefault("algorithm", "ignore"); + if (algorithm.equals("standard") || algorithm.equals("intelliignore")) { + List keys = Arrays.asList( + "diffSensitivity", + "imageIgnoreThreshold", + "carouselsEnabled", + "bannersEnabled", + "adsEnabled" + ); + + for (String key : keys) { + if (params.containsKey(key)) { + configuration.put(key, params.get(key)); + } + } + } + + if (!configuration.isEmpty()) { + region.put("configuration", configuration); + } + + Map assertion = new HashMap<>(); + if (params.containsKey("diffIgnoreThreshold")) { + assertion.put("diffIgnoreThreshold", params.get("diffIgnoreThreshold")); + } + + if (!assertion.isEmpty()) { + region.put("assertion", assertion); + } + + return region; + } + /** * Take a snapshot and upload it to Percy. * diff --git a/src/test/java/io/percy/selenium/SdkTest.java b/src/test/java/io/percy/selenium/SdkTest.java index 9619c8d..d7c6b6f 100644 --- a/src/test/java/io/percy/selenium/SdkTest.java +++ b/src/test/java/io/percy/selenium/SdkTest.java @@ -7,6 +7,7 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Order; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -207,4 +208,50 @@ public void takeScreenshotThrowErrorForWeb() { Throwable exception = assertThrows(RuntimeException.class, () -> mockedPercy.screenshot("Test")); assertEquals("Invalid function call - screenshot(). Please use snapshot() function for taking screenshot. screenshot() should be used only while using Percy with Automate. For more information on usage of snapshot(), refer doc for your language https://www.browserstack.com/docs/percy/integrate/overview", exception.getMessage()); } + + @Test + public void createRegionTest() { + // Setup the parameters for the region + Map params = new HashMap<>(); + params.put("boundingBox", "100,100,200,200"); + params.put("elementXpath", "//div[@id='test']"); + params.put("elementCSS", ".test-class"); + params.put("padding", 10); + params.put("algorithm", "standard"); + params.put("diffSensitivity", 0.5); + params.put("imageIgnoreThreshold", 0.2); + params.put("carouselsEnabled", true); + params.put("bannersEnabled", false); + params.put("adsEnabled", true); + params.put("diffIgnoreThreshold", 0.1); + + // Call the method to create the region + Map region = percy.createRegion(params); + + // Validate the returned region + assertNotNull(region); + + // Check if elementSelector was added correctly + Map elementSelector = (Map) region.get("elementSelector"); + assertNotNull(elementSelector); + assertEquals("100,100,200,200", elementSelector.get("boundingBox")); + assertEquals("//div[@id='test']", elementSelector.get("elementXpath")); + assertEquals(".test-class", elementSelector.get("elementCSS")); + + // Validate algorithm and configuration + assertEquals("standard", region.get("algorithm")); + + Map configuration = (Map) region.get("configuration"); + assertNotNull(configuration); + assertEquals(0.5, configuration.get("diffSensitivity")); + assertEquals(0.2, configuration.get("imageIgnoreThreshold")); + assertTrue((Boolean) configuration.get("carouselsEnabled")); + assertFalse((Boolean) configuration.get("bannersEnabled")); + assertTrue((Boolean) configuration.get("adsEnabled")); + + // Validate assertion + Map assertion = (Map) region.get("assertion"); + assertNotNull(assertion); + assertEquals(0.1, assertion.get("diffIgnoreThreshold")); + } }