Skip to content

Commit

Permalink
Adding support for Appium Client v8 and v9 (#141)
Browse files Browse the repository at this point in the history
* adding support for v8 and v9

* adding backward compatibility for Mobile Element
  • Loading branch information
prklm10 authored Oct 31, 2023
1 parent 4553bc0 commit c3f6c2f
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 53 deletions.
28 changes: 19 additions & 9 deletions src/main/java/io/percy/appium/lib/ScreenshotOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import io.appium.java_client.MobileElement;
import org.openqa.selenium.WebElement;

public class ScreenshotOptions {
private String deviceName = null;
Expand All @@ -15,11 +16,11 @@ public class ScreenshotOptions {
private Integer screenLengths = 4;
private List<String> ignoreRegionXpaths = new ArrayList<String>();
private List<String> ignoreRegionAccessibilityIds = new ArrayList<String>();
private List<MobileElement> ignoreRegionAppiumElements = new ArrayList<MobileElement>();
private List<WebElement> ignoreRegionAppiumElements = new ArrayList<WebElement>();
private List<Region> customIgnoreRegions = new ArrayList<Region>();
private List<String> considerRegionXpaths = new ArrayList<String>();
private List<String> considerRegionAccessibilityIds = new ArrayList<String>();
private List<MobileElement> considerRegionAppiumElements = new ArrayList<MobileElement>();
private List<WebElement> considerRegionAppiumElements = new ArrayList<WebElement>();
private List<Region> customConsiderRegions = new ArrayList<Region>();
private String scrollableXpath = null;
private String scrollableId = null;
Expand Down Expand Up @@ -114,12 +115,12 @@ public void setIgnoreRegionAccessibilityIds(List<String> ignoreRegionAccessibili
this.ignoreRegionAccessibilityIds = ignoreRegionAccessibilityIds;
}

public List<MobileElement> getIgnoreRegionAppiumElements() {
public List<WebElement> getIgnoreRegionAppiumElements() {
return ignoreRegionAppiumElements;
}

public void setIgnoreRegionAppiumElements(List<MobileElement> ignoreRegionAppiumElements) {
this.ignoreRegionAppiumElements = ignoreRegionAppiumElements;
public void setIgnoreRegionAppiumElements(List<Object> ignoreRegionAppiumElements) {
this.ignoreRegionAppiumElements = castMobileElementsToWebElements(ignoreRegionAppiumElements);
}

public List<Region> getCustomIgnoreRegions() {
Expand All @@ -146,12 +147,12 @@ public void setConsiderRegionAccessibilityIds(List<String> considerRegionAccessi
this.considerRegionAccessibilityIds = considerRegionAccessibilityIds;
}

public List<MobileElement> getConsiderRegionAppiumElements() {
public List<WebElement> getConsiderRegionAppiumElements() {
return considerRegionAppiumElements;
}

public void setConsiderRegionAppiumElements(List<MobileElement> considerRegionAppiumElements) {
this.considerRegionAppiumElements = considerRegionAppiumElements;
public void setConsiderRegionAppiumElements(List<Object> considerRegionAppiumElements) {
this.considerRegionAppiumElements = castMobileElementsToWebElements(considerRegionAppiumElements);
}

public List<Region> getCustomConsiderRegions() {
Expand All @@ -177,4 +178,13 @@ public String getScrollableId() {
public void setScrollableId(String scrollableId) {
this.scrollableId = scrollableId;
}

public List<WebElement> castMobileElementsToWebElements(List<Object> mobileElements) {
List<WebElement> webElements = mobileElements.stream()
.filter(obj -> WebElement.class.isAssignableFrom(obj.getClass())) // Check if the object is a WebElement
.map(obj -> (WebElement) obj) // Cast the object to WebElement
.collect(Collectors.toList());

return webElements;
}
}
15 changes: 1 addition & 14 deletions src/main/java/io/percy/appium/metadata/AndroidMetadata.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@

import java.util.Map;

import org.openqa.selenium.remote.Response;
import org.openqa.selenium.remote.http.HttpMethod;

import io.appium.java_client.AppiumDriver;
import io.appium.java_client.android.AndroidDriver;
import io.percy.appium.lib.Cache;
Expand Down Expand Up @@ -63,21 +60,11 @@ public Integer navBarHeight() {

private Map getViewportRect() {
if (Cache.CACHE_MAP.get("viewportRect_" + sessionId) == null) {
try {
Cache.CACHE_MAP.put("viewportRect_" + sessionId, getSession().get("viewportRect"));
} catch (java.lang.NoSuchMethodError e) {
Cache.CACHE_MAP.put("viewportRect_" + sessionId, driver.getSessionDetails().get("viewportRect"));
}
Cache.CACHE_MAP.put("viewportRect_" + sessionId, getSession().get("viewportRect"));
}
return (Map) Cache.CACHE_MAP.get("viewportRect_" + sessionId);
}

private Map getSession() {
driver.addCommand(HttpMethod.GET, "/session/" + driver.getSessionId(), "getSession");
Response session = driver.execute("getSession");
return (Map) session.getValue();
}

public Integer scaleFactor() {
return 1;
}
Expand Down
17 changes: 2 additions & 15 deletions src/main/java/io/percy/appium/metadata/IosMetadata.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@

import java.util.Map;

import org.openqa.selenium.remote.Response;
import org.openqa.selenium.remote.http.HttpMethod;

import io.appium.java_client.AppiumDriver;
import io.appium.java_client.ios.IOSDriver;
import io.percy.appium.lib.Cache;
Expand Down Expand Up @@ -68,21 +65,11 @@ public Integer statBarHeight() {

private Map getViewportRect() {
if (Cache.CACHE_MAP.get("viewportRect_" + sessionId) == null) {
try {
Cache.CACHE_MAP.put("viewportRect_" + sessionId, getSession().get("viewportRect"));
} catch (java.lang.NoSuchMethodError e) {
Cache.CACHE_MAP.put("viewportRect_" + sessionId, driver.getSessionDetails().get("viewportRect"));
}
Cache.CACHE_MAP.put("viewportRect_" + sessionId, getSession().get("viewportRect"));
}
return (Map) Cache.CACHE_MAP.get("viewportRect_" + sessionId);
}

private Map getSession() {
driver.addCommand(HttpMethod.GET, "/session/" + driver.getSessionId(), "getSession");
Response session = driver.execute("getSession");
return (Map) session.getValue();
}

public Integer navBarHeight() {
Integer navBar = getNavBar();
if (navBar != null) {
Expand All @@ -92,7 +79,7 @@ public Integer navBarHeight() {
}

public Integer scaleFactor() {
return Integer.valueOf(driver.getSessionDetails().get("pixelRatio").toString());
return Integer.valueOf(getSession().get("pixelRatio").toString());
}

}
17 changes: 17 additions & 0 deletions src/main/java/io/percy/appium/metadata/Metadata.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package io.percy.appium.metadata;

import java.util.Map;

import org.openqa.selenium.remote.Response;
import org.openqa.selenium.remote.http.HttpMethod;

import io.appium.java_client.AppiumDriver;
import io.percy.appium.lib.Cache;

public abstract class Metadata {
private static AppiumDriver driver;
Expand All @@ -9,6 +15,7 @@ public abstract class Metadata {
private Integer statusBar;
private Integer navBar;
private String deviceName;
private String sessionId;

public Metadata(AppiumDriver driver, String deviceName, Integer statusBar, Integer navBar, String orientation,
String platformVersion) {
Expand All @@ -18,6 +25,7 @@ public Metadata(AppiumDriver driver, String deviceName, Integer statusBar, Integ
this.statusBar = statusBar;
this.navBar = navBar;
this.deviceName = deviceName;
this.sessionId = driver.getSessionId().toString();
}

public String osName() {
Expand Down Expand Up @@ -74,6 +82,15 @@ public Integer getStatusBar() {
return statusBar;
}

public Map getSession() {
if (Cache.CACHE_MAP.get("getSession_" + sessionId) == null) {
driver.addCommand(HttpMethod.GET, "/session/" + driver.getSessionId(), "getSession");
Response session = driver.execute("getSession");
Cache.CACHE_MAP.put("getSession_" + sessionId, session.getValue());
}
return (Map) Cache.CACHE_MAP.get("getSession_" + sessionId);
}

public abstract Integer deviceScreenWidth();

public abstract String deviceName();
Expand Down
13 changes: 7 additions & 6 deletions src/main/java/io/percy/appium/providers/GenericProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@
import org.apache.commons.codec.binary.Base64;
import org.json.JSONArray;
import org.json.JSONObject;
import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.Point;
import org.openqa.selenium.WebElement;

import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileElement;
import io.percy.appium.AppPercy;
import io.percy.appium.lib.CliWrapper;
import io.percy.appium.lib.Region;
Expand Down Expand Up @@ -153,7 +154,7 @@ public void setDebugUrl(String debugUrl) {
public JSONArray findRegions(
List<String> xpaths,
List<String> accessibilityIds,
List<MobileElement> elements,
List<WebElement> elements,
List<Region> locations
) {
JSONArray elementsArray = new JSONArray();
Expand All @@ -165,7 +166,7 @@ public JSONArray findRegions(
return elementsArray;
}

public JSONObject getRegionObject(String selector, MobileElement element) {
public JSONObject getRegionObject(String selector, WebElement element) {
Point location = element.getLocation();
Dimension size = element.getSize();
double scaleFactor = metadata.scaleFactor();
Expand All @@ -185,7 +186,7 @@ public JSONObject getRegionObject(String selector, MobileElement element) {
public void getRegionsByXpath(JSONArray elementsArray, List<String> xpaths) {
for (String xpath : xpaths) {
try {
MobileElement element = (MobileElement) driver.findElementByXPath(xpath);
WebElement element = (WebElement) driver.findElement(By.xpath(xpath));
String selector = String.format("xpath: %s", xpath);
JSONObject region = getRegionObject(selector, element);
elementsArray.put(region);
Expand All @@ -199,7 +200,7 @@ public void getRegionsByXpath(JSONArray elementsArray, List<String> xpaths) {
public void getRegionsByIds(JSONArray elementsArray, List<String> ids) {
for (String id : ids) {
try {
MobileElement element = (MobileElement) driver.findElementByAccessibilityId(id);
WebElement element = (WebElement) driver.findElement(By.id(id));
String selector = String.format("id: %s", id);
JSONObject region = getRegionObject(selector, element);
elementsArray.put(region);
Expand All @@ -211,7 +212,7 @@ public void getRegionsByIds(JSONArray elementsArray, List<String> ids) {
}
}

public void getRegionsByElements(JSONArray elementsArray, List<MobileElement> elements) {
public void getRegionsByElements(JSONArray elementsArray, List<WebElement> elements) {
for (int index = 0; index < elements.size(); index++) {
try {
String type = elements.get(index).getAttribute("class");
Expand Down
40 changes: 40 additions & 0 deletions src/test/java/io/percy/appium/lib/ScreenshotOptionsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package io.percy.appium.lib;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.List;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebElement;

import io.appium.java_client.MobileElement;

@RunWith(org.mockito.junit.MockitoJUnitRunner.class)
public class ScreenshotOptionsTest {
@Test
public void testCastMobileElementsToWebElements() {
ScreenshotOptions casting = new ScreenshotOptions();

// Create a list of MobileElements
List<Object> mobileElements = new ArrayList<>();
mobileElements.add(new MobileElement() {});
mobileElements.add(new Object());
mobileElements.add(new Object());
mobileElements.add(new MobileElement() {});
mobileElements.add(new MobileElement() {});

// Call the function to cast them to WebElements
List<WebElement> webElements = casting.castMobileElementsToWebElements(mobileElements);

// Check if the sizes of the original and converted lists are the same
assertEquals(webElements.size(), 3);

// Check that each element in the converted list is an instance of WebElement
for (WebElement element : webElements) {
assertTrue(element instanceof WebElement);
}
}
}
8 changes: 5 additions & 3 deletions src/test/java/io/percy/appium/metadata/IosMetadataTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,22 @@ public class IosMetadataTest {
Capabilities capabilities;

HashMap<String, Long> viewportRect = new HashMap<String, Long>();
HashMap<String, HashMap<String, Long>> sessionValue = new HashMap<String, HashMap<String, Long>>();
HashMap<String, Object> sessionValue = new HashMap<>();
Response session = new Response(new SessionId("abc"));

Faker faker = new Faker();
Long width = faker.number().randomNumber(3, false);
Long top = faker.number().randomNumber(3, false);
Long height = faker.number().randomNumber(3, false);
Long pixelRatio = faker.number().randomNumber(1, false);

@Before
public void setup() {
viewportRect.put("width", width);
viewportRect.put("top", top);
viewportRect.put("height", height);
sessionValue.put("viewportRect", viewportRect);
sessionValue.put("pixelRatio", pixelRatio);
session.setValue(sessionValue);
when(driver.execute("getSession")).thenReturn(session);
when(driver.getCapabilities()).thenReturn(capabilities);
Expand Down Expand Up @@ -170,9 +172,9 @@ public void testOrientatioAuto() {

@Test
public void testScaleFactor() {
Cache.CACHE_MAP.clear();
Map details = new HashMap<>();
details.put("pixelRatio", 2);
when(driver.getSessionDetails()).thenReturn(details);
Assert.assertEquals(metadata.scaleFactor().intValue(), 2);
Assert.assertEquals(metadata.scaleFactor().intValue(), pixelRatio.intValue());
}
}
14 changes: 8 additions & 6 deletions src/test/java/io/percy/appium/providers/GenericProviderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@
import org.junit.runner.RunWith;

import org.mockito.Mock;
import org.openqa.selenium.By;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.Point;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.Response;
import org.openqa.selenium.remote.SessionId;

Expand All @@ -42,7 +44,7 @@ public class GenericProviderTest {
Capabilities capabilities;

@Mock
MobileElement mockElement;
WebElement mockElement;

Faker faker = new Faker();
Long top = faker.number().randomNumber(3, false);
Expand Down Expand Up @@ -146,7 +148,7 @@ public void testGetRegionsByXpath() {
Point location = new Point(10, 20);
Dimension size = new Dimension(100, 200);

when(androidDriver.findElementByXPath("//div[@class='example']")).thenReturn(mockElement);
when(androidDriver.findElement(By.xpath("//div[@class='example']"))).thenReturn(mockElement);
when(mockElement.getLocation()).thenReturn(location);
when(mockElement.getSize()).thenReturn(size);

Expand All @@ -156,7 +158,7 @@ public void testGetRegionsByXpath() {

genericProvider.getRegionsByXpath(elementsArray, xpaths);

verify(androidDriver).findElementByXPath("//div[@class='example']");
verify(androidDriver).findElement(By.xpath("//div[@class='example']"));
JSONObject region = elementsArray.getJSONObject(0);
Assert.assertEquals("xpath: //div[@class='example']", region.get("selector"));
JSONObject coOrdinates = region.getJSONObject("co_ordinates");
Expand All @@ -175,7 +177,7 @@ public void testGetRegionsByIds() {
Point location = new Point(10, 20);
Dimension size = new Dimension(100, 200);

when(androidDriver.findElementByAccessibilityId("some id")).thenReturn(mockElement);
when(androidDriver.findElement(By.id("some id"))).thenReturn(mockElement);
when(mockElement.getLocation()).thenReturn(location);
when(mockElement.getSize()).thenReturn(size);

Expand All @@ -185,7 +187,7 @@ public void testGetRegionsByIds() {

genericProvider.getRegionsByIds(elementsArray, ids);

verify(androidDriver).findElementByAccessibilityId("some id");
verify(androidDriver).findElement(By.id("some id"));
JSONObject region = elementsArray.getJSONObject(0);
Assert.assertEquals("id: some id", region.get("selector"));
JSONObject coOrdinates = region.getJSONObject("co_ordinates");
Expand All @@ -200,7 +202,7 @@ public void testGetRegionsByElement() {
JSONArray elementsArray = new JSONArray();
Point location = new Point(10, 20);
Dimension size = new Dimension(100, 200);
List<MobileElement> elements = new ArrayList<>();
List<WebElement> elements = new ArrayList<>();
when(mockElement.getLocation()).thenReturn(location);
when(mockElement.getSize()).thenReturn(size);
when(mockElement.getAttribute("class")).thenReturn("Button");
Expand Down

0 comments on commit c3f6c2f

Please sign in to comment.