From 0adcde335e933418e6d0fd8a00183cd1cde15e5f Mon Sep 17 00:00:00 2001 From: titusfortner Date: Sat, 4 Apr 2020 12:06:25 -0500 Subject: [PATCH 01/10] [java] move authentication handling into the Options class --- .../saucelabs/saucebindings/DataCenter.java | 6 +-- .../saucelabs/saucebindings/SauceOptions.java | 33 ++++++++++++++++- .../saucelabs/saucebindings/SauceSession.java | 31 +--------------- .../saucebindings/SauceOptionsTest.java | 37 +++++++++++++++---- .../saucebindings/SauceSessionTest.java | 32 ++++------------ 5 files changed, 72 insertions(+), 67 deletions(-) diff --git a/java/src/main/java/com/saucelabs/saucebindings/DataCenter.java b/java/src/main/java/com/saucelabs/saucebindings/DataCenter.java index 9c2615dd..0ead8da5 100644 --- a/java/src/main/java/com/saucelabs/saucebindings/DataCenter.java +++ b/java/src/main/java/com/saucelabs/saucebindings/DataCenter.java @@ -3,9 +3,9 @@ import lombok.Getter; public enum DataCenter { - US_WEST("ondemand.us-west-1.saucelabs.com"), - US_EAST("ondemand.us-east-1.saucelabs.com"), - EU_CENTRAL("ondemand.eu-central-1.saucelabs.com"); + US_WEST("https://ondemand.us-west-1.saucelabs.com/wd/hub"), + US_EAST("https://ondemand.us-east-1.saucelabs.com/wd/hub"), + EU_CENTRAL("https://ondemand.eu-central-1.saucelabs.com/wd/hub"); @Getter private final String value; diff --git a/java/src/main/java/com/saucelabs/saucebindings/SauceOptions.java b/java/src/main/java/com/saucelabs/saucebindings/SauceOptions.java index aedadd3a..a320c9d8 100644 --- a/java/src/main/java/com/saucelabs/saucebindings/SauceOptions.java +++ b/java/src/main/java/com/saucelabs/saucebindings/SauceOptions.java @@ -167,7 +167,7 @@ private SauceOptions(MutableCapabilities options) { } public MutableCapabilities toCapabilities() { - MutableCapabilities sauceCapabilities = new MutableCapabilities(); + MutableCapabilities sauceCapabilities = addAuthentication(); if (getCapability("jobVisibility") != null) { sauceCapabilities.setCapability("public", getCapability("jobVisibility")); @@ -326,6 +326,37 @@ private void setEnumCapability(String key, String value) { } } + private MutableCapabilities addAuthentication() { + MutableCapabilities caps = new MutableCapabilities(); + caps.setCapability("username", getSauceUsername()); + caps.setCapability("accessKey", getSauceAccessKey()); + return caps; + } + + protected String getSauceUsername() { + if (getSystemProperty("SAUCE_USERNAME") != null) { + return getSystemProperty("SAUCE_USERNAME"); + } else if (getEnvironmentVariable("SAUCE_USERNAME") != null) { + return getEnvironmentVariable("SAUCE_USERNAME"); + } else { + throw new SauceEnvironmentVariablesNotSetException("Sauce Username was not provided"); + } + } + + protected String getSauceAccessKey() { + if (getSystemProperty("SAUCE_ACCESS_KEY") != null) { + return getSystemProperty("SAUCE_ACCESS_KEY"); + } else if (getEnvironmentVariable("SAUCE_ACCESS_KEY") != null) { + return getEnvironmentVariable("SAUCE_ACCESS_KEY"); + } else { + throw new SauceEnvironmentVariablesNotSetException("Sauce Access Key was not provided"); + } + } + + protected String getSystemProperty(String key) { + return System.getProperty(key); + } + protected String getEnvironmentVariable(String key) { return System.getenv(key); } diff --git a/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java b/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java index 8c575c64..e571e1dc 100755 --- a/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java +++ b/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java @@ -34,9 +34,8 @@ public URL getSauceUrl() { if (sauceUrl != null) { return sauceUrl; } else { - String url = "https://" + getSauceUsername() + ":" + getSauceAccessKey() + "@" + dataCenter + "/wd/hub"; try { - return new URL(url); + return new URL(dataCenter.getValue()); } catch (MalformedURLException e) { throw new InvalidArgumentException("Invalid URL"); } @@ -70,32 +69,4 @@ private void stop() { driver.quit(); } } - - private String getSauceUsername() { - if (getSystemProperty("SAUCE_USERNAME") != null) { - return getSystemProperty("SAUCE_USERNAME"); - } else if (getEnvironmentVariable("SAUCE_USERNAME") != null) { - return getEnvironmentVariable("SAUCE_USERNAME"); - } else { - throw new SauceEnvironmentVariablesNotSetException("Sauce Username was not provided"); - } - } - - private String getSauceAccessKey() { - if (getSystemProperty("SAUCE_ACCESS_KEY") != null) { - return getSystemProperty("SAUCE_ACCESS_KEY"); - } else if (getEnvironmentVariable("SAUCE_ACCESS_KEY") != null) { - return getEnvironmentVariable("SAUCE_ACCESS_KEY"); - } else { - throw new SauceEnvironmentVariablesNotSetException("Sauce Access Key was not provided"); - } - } - - protected String getSystemProperty(String key) { - return System.getProperty(key); - } - - protected String getEnvironmentVariable(String key) { - return System.getenv(key); - } } diff --git a/java/src/test/java/com/saucelabs/saucebindings/SauceOptionsTest.java b/java/src/test/java/com/saucelabs/saucebindings/SauceOptionsTest.java index f8e8c839..f0852c4e 100644 --- a/java/src/test/java/com/saucelabs/saucebindings/SauceOptionsTest.java +++ b/java/src/test/java/com/saucelabs/saucebindings/SauceOptionsTest.java @@ -27,7 +27,7 @@ import static org.openqa.selenium.UnexpectedAlertBehaviour.DISMISS; public class SauceOptionsTest { - protected SauceOptions sauceOptions = new SauceOptions(); + private SauceOptions sauceOptions = spy(new SauceOptions()); @Rule public MockitoRule initRule = MockitoJUnit.rule(); @@ -222,7 +222,6 @@ public void acceptsSafariOptionsClass() { @Test public void createsDefaultBuildName() { - SauceOptions sauceOptions = spy(new SauceOptions()); doReturn("Not Empty").when(sauceOptions).getEnvironmentVariable("BUILD_TAG"); doReturn("TEMP BUILD").when(sauceOptions).getEnvironmentVariable("BUILD_NAME"); doReturn("11").when(sauceOptions).getEnvironmentVariable("BUILD_NUMBER"); @@ -301,6 +300,9 @@ public void setsCapabilitiesFromMap() throws FileNotFoundException { @Test public void parsesCapabilitiesFromW3CValues() { + doReturn("test-name").when(sauceOptions).getEnvironmentVariable("SAUCE_USERNAME"); + doReturn("test-accesskey").when(sauceOptions).getEnvironmentVariable("SAUCE_ACCESS_KEY"); + sauceOptions.setBrowserName(Browser.FIREFOX); sauceOptions.setPlatformName(SaucePlatform.MAC_HIGH_SIERRA); sauceOptions.setBrowserVersion("77"); @@ -316,8 +318,8 @@ public void parsesCapabilitiesFromW3CValues() { Map timeouts = new HashMap<>(); timeouts.put(Timeouts.IMPLICIT, 1); - timeouts.put(Timeouts.PAGE_LOAD, 100); timeouts.put(Timeouts.SCRIPT, 10); + timeouts.put(Timeouts.PAGE_LOAD, 100); MutableCapabilities expectedCapabilities = new MutableCapabilities(); expectedCapabilities.setCapability("browserName", "firefox"); @@ -332,6 +334,8 @@ public void parsesCapabilitiesFromW3CValues() { MutableCapabilities sauceCapabilities = new MutableCapabilities(); sauceCapabilities.setCapability("build", "Build Name"); + sauceCapabilities.setCapability("username", "test-name"); + sauceCapabilities.setCapability("accessKey", "test-accesskey"); expectedCapabilities.setCapability("sauce:options", sauceCapabilities); MutableCapabilities actualCapabilities = sauceOptions.toCapabilities(); @@ -340,6 +344,9 @@ public void parsesCapabilitiesFromW3CValues() { @Test public void parsesCapabilitiesFromSauceValues() { + doReturn("test-name").when(sauceOptions).getEnvironmentVariable("SAUCE_USERNAME"); + doReturn("test-accesskey").when(sauceOptions).getEnvironmentVariable("SAUCE_ACCESS_KEY"); + Map customData = new HashMap<>(); customData.put("foo", "foo"); customData.put("bar", "bar"); @@ -410,6 +417,8 @@ public void parsesCapabilitiesFromSauceValues() { sauceCapabilities.setCapability("timeZone", "San Francisco"); sauceCapabilities.setCapability("tunnelIdentifier", "tunnelname"); sauceCapabilities.setCapability("videoUploadOnPass", false); + sauceCapabilities.setCapability("username", "test-name"); + sauceCapabilities.setCapability("accessKey", "test-accesskey"); MutableCapabilities expectedCapabilities = new MutableCapabilities(); expectedCapabilities.setCapability("browserName", "chrome"); @@ -429,7 +438,11 @@ public void parsesCapabilitiesFromSeleniumValues() { firefoxOptions.addArguments("--foo"); firefoxOptions.addPreference("foo", "bar"); firefoxOptions.setUnhandledPromptBehaviour(DISMISS); - sauceOptions = new SauceOptions(firefoxOptions); + + sauceOptions = spy(new SauceOptions(firefoxOptions)); + doReturn("test-name").when(sauceOptions).getEnvironmentVariable("SAUCE_USERNAME"); + doReturn("test-accesskey").when(sauceOptions).getEnvironmentVariable("SAUCE_ACCESS_KEY"); + sauceOptions.setBuild("Build Name"); MutableCapabilities expectedCapabilities = new MutableCapabilities(); @@ -440,12 +453,15 @@ public void parsesCapabilitiesFromSeleniumValues() { MutableCapabilities sauceCapabilities = new MutableCapabilities(); sauceCapabilities.setCapability("build", "Build Name"); + sauceCapabilities.setCapability("username", "test-name"); + sauceCapabilities.setCapability("accessKey", "test-accesskey"); expectedCapabilities.setCapability("sauce:options", sauceCapabilities); MutableCapabilities actualCapabilities = sauceOptions.toCapabilities(); assertEquals(expectedCapabilities.asMap().toString(), actualCapabilities.asMap().toString()); } - @Test + + @Test public void parsesW3CAndSauceAndSeleniumSettings() { MutableCapabilities expectedCapabilities = new MutableCapabilities(); MutableCapabilities sauceCapabilities = new MutableCapabilities(); @@ -454,7 +470,10 @@ public void parsesW3CAndSauceAndSeleniumSettings() { firefoxOptions.addArguments("--foo"); firefoxOptions.setUnhandledPromptBehaviour(DISMISS); - sauceOptions = new SauceOptions(firefoxOptions); + sauceOptions = spy(new SauceOptions(firefoxOptions)); + + doReturn("test-name").when(sauceOptions).getEnvironmentVariable("SAUCE_USERNAME"); + doReturn("test-accesskey").when(sauceOptions).getEnvironmentVariable("SAUCE_ACCESS_KEY"); expectedCapabilities.merge(firefoxOptions); expectedCapabilities.setCapability("browserVersion", "latest"); @@ -473,8 +492,8 @@ public void parsesW3CAndSauceAndSeleniumSettings() { .setScript(10); Map timeouts = new HashMap<>(); timeouts.put(Timeouts.IMPLICIT, 1); - timeouts.put(Timeouts.PAGE_LOAD, 100); timeouts.put(Timeouts.SCRIPT, 10); + timeouts.put(Timeouts.PAGE_LOAD, 100); expectedCapabilities.setCapability("timeouts", timeouts); sauceOptions.setUnhandledPromptBehavior(UnhandledPromptBehavior.IGNORE); expectedCapabilities.setCapability("unhandledPromptBehavior", UnhandledPromptBehavior.IGNORE); @@ -488,10 +507,12 @@ public void parsesW3CAndSauceAndSeleniumSettings() { sauceOptions.setJobVisibility(JobVisibility.SHARE); sauceCapabilities.setCapability("public", JobVisibility.SHARE); + sauceCapabilities.setCapability("username", "test-name"); + sauceCapabilities.setCapability("accessKey", "test-accesskey"); expectedCapabilities.setCapability("sauce:options", sauceCapabilities); MutableCapabilities actualCapabilities = sauceOptions.toCapabilities(); assertEquals(expectedCapabilities.asMap().toString(), actualCapabilities.asMap().toString()); - } + } } diff --git a/java/src/test/java/com/saucelabs/saucebindings/SauceSessionTest.java b/java/src/test/java/com/saucelabs/saucebindings/SauceSessionTest.java index d51088e3..1453cf4e 100644 --- a/java/src/test/java/com/saucelabs/saucebindings/SauceSessionTest.java +++ b/java/src/test/java/com/saucelabs/saucebindings/SauceSessionTest.java @@ -23,6 +23,7 @@ public class SauceSessionTest { private SauceOptions sauceOptions = spy(new SauceOptions()); private SauceSession sauceSession = spy(new SauceSession()); + private SauceSession sauceOptsSession = spy(new SauceSession(sauceOptions)); private RemoteWebDriver dummyRemoteDriver = mock(RemoteWebDriver.class); private JavascriptExecutor dummyJSExecutor = mock(JavascriptExecutor.class); private MutableCapabilities dummyMutableCapabilities = mock(MutableCapabilities.class); @@ -48,11 +49,10 @@ public void sauceSessionDefaultsToLatestChromeOnWindows() { @Test public void sauceSessionUsesProvidedSauceOptions() { - sauceSession = spy(new SauceSession(sauceOptions)); doReturn(dummyMutableCapabilities).when(sauceOptions).toCapabilities(); - doReturn(dummyRemoteDriver).when(sauceSession).createRemoteWebDriver(any(URL.class), eq(dummyMutableCapabilities)); + doReturn(dummyRemoteDriver).when(sauceOptsSession).createRemoteWebDriver(any(URL.class), eq(dummyMutableCapabilities)); - sauceSession.start(); + sauceOptsSession.start(); verify(sauceOptions).toCapabilities(); } @@ -70,24 +70,6 @@ public void setsDataCenter() { assertEquals(expectedDataCenterEndpoint, sauceSession.getDataCenter().getValue()); } - @Test - public void defaultSauceURLUsesENVForUsernameAccessKey() { - doReturn("test-name").when(sauceSession).getEnvironmentVariable("SAUCE_USERNAME"); - doReturn("test-accesskey").when(sauceSession).getEnvironmentVariable("SAUCE_ACCESS_KEY"); - - String expetedSauceUrl = "https://test-name:test-accesskey@ondemand.us-west-1.saucelabs.com/wd/hub"; - assertEquals(expetedSauceUrl, sauceSession.getSauceUrl().toString()); - } - - @Test - public void setUserNameAndAccessKeyWithSystemProperties() { - doReturn("test-name").when(sauceSession).getSystemProperty("SAUCE_USERNAME"); - doReturn("test-accesskey").when(sauceSession).getSystemProperty("SAUCE_ACCESS_KEY"); - - String expetedSauceUrl = "https://test-name:test-accesskey@ondemand.us-west-1.saucelabs.com/wd/hub"; - assertEquals(expetedSauceUrl, sauceSession.getSauceUrl().toString()); - } - @Test public void setsSauceURLDirectly() throws MalformedURLException { sauceSession.setSauceUrl(new URL("http://example.com")); @@ -97,14 +79,14 @@ public void setsSauceURLDirectly() throws MalformedURLException { @Test(expected = SauceEnvironmentVariablesNotSetException.class) public void startThrowsErrorWithoutUsername() { - doReturn(null).when(sauceSession).getEnvironmentVariable("SAUCE_USERNAME"); - sauceSession.start(); + doReturn(null).when(sauceOptions).getEnvironmentVariable("SAUCE_USERNAME"); + sauceOptsSession.start(); } @Test(expected = SauceEnvironmentVariablesNotSetException.class) public void startThrowsErrorWithoutAccessKey() { - doReturn(null).when(sauceSession).getEnvironmentVariable("SAUCE_ACCESS_KEY"); - sauceSession.start(); + doReturn(null).when(sauceOptions).getEnvironmentVariable("SAUCE_ACCESS_KEY"); + sauceOptsSession.start(); } @Test From 2c4a69c42622c1eac3572b693f0da1672077d03b Mon Sep 17 00:00:00 2001 From: titusfortner Date: Sun, 12 Apr 2020 15:43:34 -0500 Subject: [PATCH 02/10] [java] add direct support for headless --- .../saucelabs/saucebindings/DataCenter.java | 2 + .../saucelabs/saucebindings/SauceOptions.java | 6 ++ .../saucebindings/SaucePlatform.java | 1 + .../saucelabs/saucebindings/SauceSession.java | 2 +- .../saucebindings/SauceSessionTest.java | 4 +- .../acceptance/SauceDesktopTest.java | 58 +++++++++++++++++++ .../SauceSessionAcceptanceTest.java | 39 ------------- 7 files changed, 70 insertions(+), 42 deletions(-) create mode 100644 java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceDesktopTest.java delete mode 100644 java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceSessionAcceptanceTest.java diff --git a/java/src/main/java/com/saucelabs/saucebindings/DataCenter.java b/java/src/main/java/com/saucelabs/saucebindings/DataCenter.java index 0ead8da5..444dec04 100644 --- a/java/src/main/java/com/saucelabs/saucebindings/DataCenter.java +++ b/java/src/main/java/com/saucelabs/saucebindings/DataCenter.java @@ -3,8 +3,10 @@ import lombok.Getter; public enum DataCenter { + US_LEGACY("https://ondemand.saucelabs.com/wd/hub"), US_WEST("https://ondemand.us-west-1.saucelabs.com/wd/hub"), US_EAST("https://ondemand.us-east-1.saucelabs.com/wd/hub"), + HEADLESS("https://ondemand.us-east-1.saucelabs.com/wd/hub"), EU_CENTRAL("https://ondemand.eu-central-1.saucelabs.com/wd/hub"); @Getter private final String value; diff --git a/java/src/main/java/com/saucelabs/saucebindings/SauceOptions.java b/java/src/main/java/com/saucelabs/saucebindings/SauceOptions.java index a320c9d8..95f42af2 100644 --- a/java/src/main/java/com/saucelabs/saucebindings/SauceOptions.java +++ b/java/src/main/java/com/saucelabs/saucebindings/SauceOptions.java @@ -128,6 +128,12 @@ public class SauceOptions { knownCITools.put("TeamCity", "TEAMCITY_PROJECT_NAME"); } + public static SauceOptions headless() { + SauceOptions headlessOptions = new SauceOptions(); + headlessOptions.setPlatformName(SaucePlatform.LINUX); + return headlessOptions; + } + public SauceOptions() { this(new MutableCapabilities()); } diff --git a/java/src/main/java/com/saucelabs/saucebindings/SaucePlatform.java b/java/src/main/java/com/saucelabs/saucebindings/SaucePlatform.java index 365279dc..0199c579 100644 --- a/java/src/main/java/com/saucelabs/saucebindings/SaucePlatform.java +++ b/java/src/main/java/com/saucelabs/saucebindings/SaucePlatform.java @@ -14,6 +14,7 @@ public enum SaucePlatform { MAC_HIGH_SIERRA("macOS 10.13"), MAC_SIERRA("macOS 10.12"), MAC_EL_CAPITAN("OS X 10.11"), + LINUX("Linux"), MAC_YOSEMITE("OS X 10.10"); @Getter diff --git a/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java b/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java index e571e1dc..75e6b344 100755 --- a/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java +++ b/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java @@ -11,7 +11,7 @@ import java.net.URL; public class SauceSession { - @Getter @Setter private DataCenter dataCenter = DataCenter.US_WEST; + @Getter @Setter private DataCenter dataCenter = DataCenter.US_LEGACY; @Getter private final SauceOptions sauceOptions; @Setter private URL sauceUrl; diff --git a/java/src/test/java/com/saucelabs/saucebindings/SauceSessionTest.java b/java/src/test/java/com/saucelabs/saucebindings/SauceSessionTest.java index 1453cf4e..38bc984d 100644 --- a/java/src/test/java/com/saucelabs/saucebindings/SauceSessionTest.java +++ b/java/src/test/java/com/saucelabs/saucebindings/SauceSessionTest.java @@ -58,8 +58,8 @@ public void sauceSessionUsesProvidedSauceOptions() { } @Test - public void defaultsToUSWestDataCenter() { - String expectedDataCenterEndpoint = DataCenter.US_WEST.getValue(); + public void defaultsToUSLegacyDataCenter() { + String expectedDataCenterEndpoint = DataCenter.US_LEGACY.getValue(); assertEquals(expectedDataCenterEndpoint, sauceSession.getDataCenter().getValue()); } diff --git a/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceDesktopTest.java b/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceDesktopTest.java new file mode 100644 index 00000000..55a88cda --- /dev/null +++ b/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceDesktopTest.java @@ -0,0 +1,58 @@ +package com.saucelabs.saucebindings.acceptance; + +import com.saucelabs.saucebindings.DataCenter; +import com.saucelabs.saucebindings.SauceOptions; +import com.saucelabs.saucebindings.SauceSession; +import org.junit.After; +import org.junit.Test; +import org.openqa.selenium.remote.RemoteWebDriver; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +public class SauceDesktopTest { + private SauceSession session = new SauceSession(); + private RemoteWebDriver webDriver; + + @After + public void cleanUp() { + session.stop(true); + } + + @Test + public void defaultsToLegacy() { + webDriver = session.start(); + assertNotNull(webDriver); + assertTrue(session.getSauceUrl().toString().contains("ondemand.saucelabs")); + } + + @Test + public void runsUSWest() { + session.setDataCenter(DataCenter.US_WEST); + webDriver = session.start(); + + assertNotNull(webDriver); + assertTrue(session.getSauceUrl().toString().contains("us-west-1")); + } + + @Test + public void runsEUCentral() { + session.setDataCenter(DataCenter.EU_CENTRAL); + webDriver = session.start(); + + assertNotNull(webDriver); + assertTrue(session.getSauceUrl().toString().contains("eu-central-1")); + } + + // Same as US_EAST just more descriptive + @Test + public void createsHeadlessDriver() { + SauceOptions sauceOptions = SauceOptions.headless(); + session = new SauceSession(sauceOptions); + session.setDataCenter(DataCenter.HEADLESS); + webDriver = session.start(); + + assertNotNull(webDriver); + assertTrue(session.getSauceUrl().toString().contains("us-east-1")); + } +} diff --git a/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceSessionAcceptanceTest.java b/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceSessionAcceptanceTest.java deleted file mode 100644 index aaa04e18..00000000 --- a/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceSessionAcceptanceTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.saucelabs.saucebindings.acceptance; - -import com.saucelabs.saucebindings.SauceOptions; -import com.saucelabs.saucebindings.SauceSession; -import org.junit.After; -import org.junit.Test; -import org.openqa.selenium.By; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.remote.RemoteWebDriver; - -import static org.junit.Assert.*; - -public class SauceSessionAcceptanceTest { - private WebDriver webDriver; - private SauceSession sauce; - - @After - public void cleanUp() { - sauce.stop(true); - } - - @Test - public void sauceSession_defaultSauceOptions_startsRealSession() { - SauceOptions options = new SauceOptions(); - sauce = new SauceSession(options); - webDriver = sauce.start(); - String sessionId = ((RemoteWebDriver) webDriver).getSessionId().toString(); - assertFalse(sessionId.isEmpty()); - } - - @Test - public void startSession_noSauceOptionsSet_returnsDriver() { - sauce = new SauceSession(); - webDriver = sauce.start(); - webDriver.get("https://www.saucedemo.com/"); - assertNotNull(webDriver); - webDriver.findElement(By.id("user-name")).sendKeys("test"); - } -} From d1c39cfd541aa339eaa78bbedcc9bb551e8159b4 Mon Sep 17 00:00:00 2001 From: titusfortner Date: Sun, 12 Apr 2020 15:52:38 -0500 Subject: [PATCH 03/10] [java] do not need JavaScript Executor --- .../saucelabs/saucebindings/SauceSession.java | 7 +------ .../saucebindings/SauceSessionTest.java | 20 +++++-------------- 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java b/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java index 75e6b344..f4ffcd50 100755 --- a/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java +++ b/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java @@ -1,7 +1,6 @@ package com.saucelabs.saucebindings; import lombok.Getter; -import org.openqa.selenium.JavascriptExecutor; import lombok.Setter; import org.openqa.selenium.InvalidArgumentException; import org.openqa.selenium.MutableCapabilities; @@ -46,10 +45,6 @@ protected RemoteWebDriver createRemoteWebDriver(URL url, MutableCapabilities cap return new RemoteWebDriver(url, capabilities); } - protected JavascriptExecutor getJSExecutor() { - return driver; - } - public void stop(Boolean passed) { String result = passed ? "passed" : "failed"; stop(result); @@ -61,7 +56,7 @@ public void stop(String result) { } private void updateResult(String result) { - getJSExecutor().executeScript("sauce:job-result=" + result); + getDriver().executeScript("sauce:job-result=" + result); } private void stop() { diff --git a/java/src/test/java/com/saucelabs/saucebindings/SauceSessionTest.java b/java/src/test/java/com/saucelabs/saucebindings/SauceSessionTest.java index 38bc984d..060d6dd6 100644 --- a/java/src/test/java/com/saucelabs/saucebindings/SauceSessionTest.java +++ b/java/src/test/java/com/saucelabs/saucebindings/SauceSessionTest.java @@ -5,7 +5,6 @@ import org.junit.Test; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; -import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.MutableCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; @@ -14,18 +13,13 @@ import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.*; public class SauceSessionTest { private SauceOptions sauceOptions = spy(new SauceOptions()); private SauceSession sauceSession = spy(new SauceSession()); private SauceSession sauceOptsSession = spy(new SauceSession(sauceOptions)); private RemoteWebDriver dummyRemoteDriver = mock(RemoteWebDriver.class); - private JavascriptExecutor dummyJSExecutor = mock(JavascriptExecutor.class); private MutableCapabilities dummyMutableCapabilities = mock(MutableCapabilities.class); @Rule @@ -99,33 +93,29 @@ public void stopCallsDriverQuitPassing() { @Test public void stopWithBooleanTrue() { - doReturn(dummyJSExecutor).when(sauceSession).getJSExecutor(); sauceSession.start(); sauceSession.stop(true); - verify(dummyJSExecutor).executeScript("sauce:job-result=passed"); + verify(dummyRemoteDriver).executeScript("sauce:job-result=passed"); } @Test public void stopWithBooleanFalse() { - doReturn(dummyJSExecutor).when(sauceSession).getJSExecutor(); sauceSession.start(); sauceSession.stop(false); - verify(dummyJSExecutor).executeScript("sauce:job-result=failed"); + verify(dummyRemoteDriver).executeScript("sauce:job-result=failed"); } @Test public void stopWithStringPassed() { - doReturn(dummyJSExecutor).when(sauceSession).getJSExecutor(); sauceSession.start(); sauceSession.stop("passed"); - verify(dummyJSExecutor).executeScript("sauce:job-result=passed"); + verify(dummyRemoteDriver).executeScript("sauce:job-result=passed"); } @Test public void stopWithStringFailed() { - doReturn(dummyJSExecutor).when(sauceSession).getJSExecutor(); sauceSession.start(); sauceSession.stop("failed"); - verify(dummyJSExecutor).executeScript("sauce:job-result=failed"); + verify(dummyRemoteDriver).executeScript("sauce:job-result=failed"); } } From 0a3c26ca66dff39c8d2434ff5c1638ecd4aff478 Mon Sep 17 00:00:00 2001 From: titusfortner Date: Sat, 4 Apr 2020 15:08:25 -0500 Subject: [PATCH 04/10] [java] add support for mobile browser on emusim with w3c + Appium --- java/pom.xml | 5 ++ .../saucebindings/SauceMobileOptions.java | 69 +++++++++++++++++++ .../saucebindings/SauceMobileSession.java | 30 ++++++++ .../saucelabs/saucebindings/SauceOptions.java | 10 +-- .../saucebindings/SaucePlatform.java | 1 + .../saucelabs/saucebindings/SauceSession.java | 4 +- .../saucebindings/SauceMobileSessionTest.java | 53 ++++++++++++++ .../acceptance/SauceEmuSimBrowserTest.java | 22 ++++++ 8 files changed, 187 insertions(+), 7 deletions(-) create mode 100644 java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java create mode 100644 java/src/main/java/com/saucelabs/saucebindings/SauceMobileSession.java create mode 100644 java/src/test/java/com/saucelabs/saucebindings/SauceMobileSessionTest.java create mode 100644 java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimBrowserTest.java diff --git a/java/pom.xml b/java/pom.xml index 1d4d8d78..5735ffdf 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -94,6 +94,11 @@ 1.25 test + + io.appium + java-client + 7.3.0 + diff --git a/java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java b/java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java new file mode 100644 index 00000000..06ae6dcb --- /dev/null +++ b/java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java @@ -0,0 +1,69 @@ +package com.saucelabs.saucebindings; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +import org.openqa.selenium.MutableCapabilities; + +import java.util.List; + +@Accessors(chain = true) +@Setter @Getter +public class SauceMobileOptions extends SauceOptions { + @Setter(AccessLevel.NONE) private MutableCapabilities appiumCapabilities; + + private Browser browserName = Browser.CHROME; + private String appiumVersion = "1.15.0"; + private String deviceName = "Android GoogleAPI Emulator"; + private String deviceOrientation = "portrait"; + private String platformVersion = "8.1"; + private SaucePlatform platformName = SaucePlatform.ANDROID; + + public static final List mobileW3COptions = List.of( + "browserName", + "platformName"); + + public static final List mobileSauceDefinedOptions = List.of( + "appiumVersion"); + + public static final List appiumDefinedOptions = List.of( + "deviceName", + "platformVersion", + "deviceOrientation"); + + public SauceMobileOptions() { + this(new MutableCapabilities()); + } + + private SauceMobileOptions(MutableCapabilities options) { + appiumCapabilities = new MutableCapabilities(options.asMap()); + } + + public MutableCapabilities toCapabilities() { + MutableCapabilities sauceCapabilities = addAuthentication(); + + mobileW3COptions.forEach((capability) -> { + addCapabilityIfDefined(appiumCapabilities, capability); + }); + + appiumDefinedOptions.forEach((capability) -> { + addAppiumCapabilityIfDefined(appiumCapabilities, capability); + }); + + mobileSauceDefinedOptions.forEach((capability) -> { + addCapabilityIfDefined(sauceCapabilities, capability); + }); + + appiumCapabilities.setCapability("sauce:options", sauceCapabilities); + + return appiumCapabilities; + } + + void addAppiumCapabilityIfDefined(MutableCapabilities capabilities, String capability) { + Object value = getCapability(capability); + if (value != null) { + capabilities.setCapability("appium:" + capability, value); + } + } +} diff --git a/java/src/main/java/com/saucelabs/saucebindings/SauceMobileSession.java b/java/src/main/java/com/saucelabs/saucebindings/SauceMobileSession.java new file mode 100644 index 00000000..951e1163 --- /dev/null +++ b/java/src/main/java/com/saucelabs/saucebindings/SauceMobileSession.java @@ -0,0 +1,30 @@ +package com.saucelabs.saucebindings; + +import io.appium.java_client.AppiumDriver; +import lombok.Getter; +import org.openqa.selenium.Capabilities; + +import java.net.URL; + +public class SauceMobileSession extends SauceSession { + @Getter private final SauceMobileOptions sauceOptions; + @Getter private AppiumDriver driver; + + public SauceMobileSession() { + this(new SauceMobileOptions()); + } + + public SauceMobileSession(SauceMobileOptions options) { + sauceOptions = options; + } + + public AppiumDriver start() { + AppiumDriver appiumDriver = createAppiumDriver(getSauceUrl(), sauceOptions.toCapabilities()); + this.driver = appiumDriver; + return appiumDriver; + } + + public AppiumDriver createAppiumDriver(URL url, Capabilities caps) { + return new AppiumDriver<>(url, caps); + } +} diff --git a/java/src/main/java/com/saucelabs/saucebindings/SauceOptions.java b/java/src/main/java/com/saucelabs/saucebindings/SauceOptions.java index 95f42af2..8b9b35d1 100644 --- a/java/src/main/java/com/saucelabs/saucebindings/SauceOptions.java +++ b/java/src/main/java/com/saucelabs/saucebindings/SauceOptions.java @@ -195,7 +195,7 @@ public MutableCapabilities toCapabilities() { return seleniumCapabilities; } - private void addCapabilityIfDefined(MutableCapabilities capabilities, String capability) { + protected void addCapabilityIfDefined(MutableCapabilities capabilities, String capability) { Object value = getCapability(capability); if (value != null) { capabilities.setCapability(capability, value); @@ -233,11 +233,11 @@ public void mergeCapabilities(Map capabilities) { } // This might be made public in future version; For now, no good reason to prefer it over direct accessor - private Object getCapability(String capability) { + protected Object getCapability(String capability) { try { String getter = "get" + capability.substring(0, 1).toUpperCase() + capability.substring(1); Method declaredMethod = null; - declaredMethod = SauceOptions.class.getDeclaredMethod(getter); + declaredMethod = this.getClass().getMethod(getter); return declaredMethod.invoke(this); } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); @@ -246,7 +246,7 @@ private Object getCapability(String capability) { } // This might be made public in future version; For now, no good reason to prefer it over direct accessor - public void setCapability(String key, Object value) { + protected void setCapability(String key, Object value) { if (primaryEnum.contains(key) && value.getClass().equals(String.class)) { setEnumCapability(key, (String) value); } else if (secondaryEnum.contains(key) && isKeyString((HashMap) value)) { @@ -332,7 +332,7 @@ private void setEnumCapability(String key, String value) { } } - private MutableCapabilities addAuthentication() { + protected MutableCapabilities addAuthentication() { MutableCapabilities caps = new MutableCapabilities(); caps.setCapability("username", getSauceUsername()); caps.setCapability("accessKey", getSauceAccessKey()); diff --git a/java/src/main/java/com/saucelabs/saucebindings/SaucePlatform.java b/java/src/main/java/com/saucelabs/saucebindings/SaucePlatform.java index 0199c579..3eadbf19 100644 --- a/java/src/main/java/com/saucelabs/saucebindings/SaucePlatform.java +++ b/java/src/main/java/com/saucelabs/saucebindings/SaucePlatform.java @@ -7,6 +7,7 @@ import java.util.Set; public enum SaucePlatform { + ANDROID("Android"), WINDOWS_10("Windows 10"), WINDOWS_8_1("Windows 8.1"), WINDOWS_8("Windows 8"), diff --git a/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java b/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java index f4ffcd50..e708bbc7 100755 --- a/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java +++ b/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java @@ -60,8 +60,8 @@ private void updateResult(String result) { } private void stop() { - if(driver !=null) { - driver.quit(); + if(getDriver() !=null) { + getDriver().quit(); } } } diff --git a/java/src/test/java/com/saucelabs/saucebindings/SauceMobileSessionTest.java b/java/src/test/java/com/saucelabs/saucebindings/SauceMobileSessionTest.java new file mode 100644 index 00000000..bbd811b4 --- /dev/null +++ b/java/src/test/java/com/saucelabs/saucebindings/SauceMobileSessionTest.java @@ -0,0 +1,53 @@ +package com.saucelabs.saucebindings; + +import io.appium.java_client.AppiumDriver; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.openqa.selenium.MutableCapabilities; + +import java.net.URL; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; + +public class SauceMobileSessionTest { + private SauceMobileSession sauceMobileSession = spy(new SauceMobileSession()); + private SauceMobileOptions sauceMobileOptions = spy(new SauceMobileOptions()); + private SauceMobileSession sauceMobileOptsSession = spy(new SauceMobileSession(sauceMobileOptions)); + private AppiumDriver dummyAppiumDriver = mock(AppiumDriver.class); + private MutableCapabilities dummyMutableCapabilities = mock(MutableCapabilities.class); + + @Rule + public MockitoRule initRule = MockitoJUnit.rule(); + + @Before + public void setUp() { + doReturn(dummyAppiumDriver).when(sauceMobileSession).createAppiumDriver(any(URL.class), any(MutableCapabilities.class)); + } + + @Test + public void sauceMObileSessionCreatesDefaultOptions() { + SauceMobileOptions sauceOptions = sauceMobileSession.getSauceOptions(); + + assertEquals(Browser.CHROME, sauceOptions.getBrowserName()); + assertEquals(SaucePlatform.ANDROID, sauceOptions.getPlatformName()); + assertEquals("1.15.0", sauceOptions.getAppiumVersion()); + assertEquals("Android GoogleAPI Emulator", sauceOptions.getDeviceName()); + assertEquals("portrait", sauceOptions.getDeviceOrientation()); + assertEquals("8.1", sauceOptions.getPlatformVersion()); + } + + @Test + public void sauceMobileSessionUsesProvidedSauceOptions() { + doReturn(dummyMutableCapabilities).when(sauceMobileOptions).toCapabilities(); + doReturn(dummyAppiumDriver).when(sauceMobileOptsSession).createAppiumDriver(any(URL.class), eq(dummyMutableCapabilities)); + + sauceMobileOptsSession.start(); + + verify(sauceMobileOptions).toCapabilities(); + } +} diff --git a/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimBrowserTest.java b/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimBrowserTest.java new file mode 100644 index 00000000..6508df94 --- /dev/null +++ b/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimBrowserTest.java @@ -0,0 +1,22 @@ +package com.saucelabs.saucebindings.acceptance; + +import com.saucelabs.saucebindings.SauceMobileSession; +import org.junit.Test; +import org.openqa.selenium.remote.RemoteWebDriver; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +public class SauceEmuSimBrowserTest { + private SauceMobileSession session = new SauceMobileSession(); + private RemoteWebDriver webDriver; + + @Test + public void defaultsToLegacy() { + webDriver = session.start(); + assertNotNull(webDriver); + assertTrue(session.getSauceUrl().toString().contains("ondemand.saucelabs")); + + session.stop(true); + } +} From 5fe6a3d8fe467c6d1ae29cc0de3e1c4b821b650b Mon Sep 17 00:00:00 2001 From: titusfortner Date: Sun, 12 Apr 2020 17:58:29 -0500 Subject: [PATCH 05/10] [java] add support for mobile browser on emusim with w3c toggle to support jwp-only endpoints --- java/pom.xml | 4 +- .../saucelabs/saucebindings/DataCenter.java | 4 ++ .../saucebindings/SauceMobileOptions.java | 39 +++++++++++++++---- .../saucebindings/SauceMobileSession.java | 29 ++++++++++++-- .../saucelabs/saucebindings/SauceOptions.java | 10 ++--- .../saucelabs/saucebindings/SauceSession.java | 2 +- .../saucebindings/SauceMobileSessionTest.java | 27 ++++++++++--- .../acceptance/SauceEmuSimBrowserTest.java | 26 ++++++++++++- 8 files changed, 115 insertions(+), 26 deletions(-) diff --git a/java/pom.xml b/java/pom.xml index 5735ffdf..5f6a51f5 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -57,8 +57,8 @@ org.mockito - mockito-all - 1.10.19 + mockito-core + 3.3.3 test diff --git a/java/src/main/java/com/saucelabs/saucebindings/DataCenter.java b/java/src/main/java/com/saucelabs/saucebindings/DataCenter.java index 444dec04..1fe924ba 100644 --- a/java/src/main/java/com/saucelabs/saucebindings/DataCenter.java +++ b/java/src/main/java/com/saucelabs/saucebindings/DataCenter.java @@ -15,6 +15,10 @@ public enum DataCenter { this.value = value; } + public boolean supportsW3C() { + return value.equals("https://ondemand.saucelabs.com/wd/hub"); + } + public String toString() { return value; } diff --git a/java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java b/java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java index 06ae6dcb..e851645e 100644 --- a/java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java +++ b/java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java @@ -13,12 +13,17 @@ public class SauceMobileOptions extends SauceOptions { @Setter(AccessLevel.NONE) private MutableCapabilities appiumCapabilities; + // Defined in W3C private Browser browserName = Browser.CHROME; - private String appiumVersion = "1.15.0"; + private SaucePlatform platformName = SaucePlatform.ANDROID; + + // Defined in Appium private String deviceName = "Android GoogleAPI Emulator"; private String deviceOrientation = "portrait"; private String platformVersion = "8.1"; - private SaucePlatform platformName = SaucePlatform.ANDROID; + + // Supported by Sauce + private String appiumVersion = "1.15.0"; public static final List mobileW3COptions = List.of( "browserName", @@ -40,13 +45,23 @@ private SauceMobileOptions(MutableCapabilities options) { appiumCapabilities = new MutableCapabilities(options.asMap()); } - public MutableCapabilities toCapabilities() { - MutableCapabilities sauceCapabilities = addAuthentication(); - + public MutableCapabilities toCapabilities(boolean w3c) { mobileW3COptions.forEach((capability) -> { addCapabilityIfDefined(appiumCapabilities, capability); }); + if (w3c) { + useW3cCapabilities(); + } else { + useJwpCapabilities(); + } + return appiumCapabilities; + } + + private void useW3cCapabilities() { + MutableCapabilities sauceCapabilities = new MutableCapabilities(); + addAuthentication(sauceCapabilities); + appiumDefinedOptions.forEach((capability) -> { addAppiumCapabilityIfDefined(appiumCapabilities, capability); }); @@ -56,11 +71,21 @@ public MutableCapabilities toCapabilities() { }); appiumCapabilities.setCapability("sauce:options", sauceCapabilities); + } - return appiumCapabilities; + private void useJwpCapabilities() { + addAuthentication(appiumCapabilities); + + appiumDefinedOptions.forEach((capability) -> { + addCapabilityIfDefined(appiumCapabilities, capability); + }); + + mobileSauceDefinedOptions.forEach((capability) -> { + addCapabilityIfDefined(appiumCapabilities, capability); + }); } - void addAppiumCapabilityIfDefined(MutableCapabilities capabilities, String capability) { + private void addAppiumCapabilityIfDefined(MutableCapabilities capabilities, String capability) { Object value = getCapability(capability); if (value != null) { capabilities.setCapability("appium:" + capability, value); diff --git a/java/src/main/java/com/saucelabs/saucebindings/SauceMobileSession.java b/java/src/main/java/com/saucelabs/saucebindings/SauceMobileSession.java index 951e1163..de79164d 100644 --- a/java/src/main/java/com/saucelabs/saucebindings/SauceMobileSession.java +++ b/java/src/main/java/com/saucelabs/saucebindings/SauceMobileSession.java @@ -3,7 +3,10 @@ import io.appium.java_client.AppiumDriver; import lombok.Getter; import org.openqa.selenium.Capabilities; +import org.openqa.selenium.InvalidArgumentException; +import org.openqa.selenium.MutableCapabilities; +import java.net.MalformedURLException; import java.net.URL; public class SauceMobileSession extends SauceSession { @@ -19,12 +22,32 @@ public SauceMobileSession(SauceMobileOptions options) { } public AppiumDriver start() { - AppiumDriver appiumDriver = createAppiumDriver(getSauceUrl(), sauceOptions.toCapabilities()); - this.driver = appiumDriver; - return appiumDriver; + MutableCapabilities capabilities; + URL url; + if (dataCenter.supportsW3C()) { + capabilities = sauceOptions.toCapabilities(true); + url = getSauceUrl(); + } else { + capabilities = sauceOptions.toCapabilities(false); + String username = (String) capabilities.getCapability("username"); + String key = (String) capabilities.getCapability("accessKey"); + url = getSauceUrl(username, key); + } + + driver = createAppiumDriver(url, capabilities); + return driver; } public AppiumDriver createAppiumDriver(URL url, Capabilities caps) { return new AppiumDriver<>(url, caps); } + + public URL getSauceUrl(String username, String key) { + String url = dataCenter.getValue().replace("://", "://" + username + ":" + key + "@"); + try { + return new URL(url); + } catch (MalformedURLException e) { + throw new InvalidArgumentException("Invalid URL"); + } + } } diff --git a/java/src/main/java/com/saucelabs/saucebindings/SauceOptions.java b/java/src/main/java/com/saucelabs/saucebindings/SauceOptions.java index 8b9b35d1..56417e9d 100644 --- a/java/src/main/java/com/saucelabs/saucebindings/SauceOptions.java +++ b/java/src/main/java/com/saucelabs/saucebindings/SauceOptions.java @@ -1,10 +1,9 @@ package com.saucelabs.saucebindings; +import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; -import lombok.AccessLevel; import lombok.experimental.Accessors; - import org.openqa.selenium.MutableCapabilities; import org.openqa.selenium.Proxy; import org.openqa.selenium.chrome.ChromeOptions; @@ -173,7 +172,8 @@ private SauceOptions(MutableCapabilities options) { } public MutableCapabilities toCapabilities() { - MutableCapabilities sauceCapabilities = addAuthentication(); + MutableCapabilities sauceCapabilities = new MutableCapabilities(); + addAuthentication(sauceCapabilities); if (getCapability("jobVisibility") != null) { sauceCapabilities.setCapability("public", getCapability("jobVisibility")); @@ -332,11 +332,9 @@ private void setEnumCapability(String key, String value) { } } - protected MutableCapabilities addAuthentication() { - MutableCapabilities caps = new MutableCapabilities(); + protected void addAuthentication(MutableCapabilities caps) { caps.setCapability("username", getSauceUsername()); caps.setCapability("accessKey", getSauceAccessKey()); - return caps; } protected String getSauceUsername() { diff --git a/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java b/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java index e708bbc7..4d28a7e3 100755 --- a/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java +++ b/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java @@ -10,7 +10,7 @@ import java.net.URL; public class SauceSession { - @Getter @Setter private DataCenter dataCenter = DataCenter.US_LEGACY; + @Getter @Setter protected DataCenter dataCenter = DataCenter.US_LEGACY; @Getter private final SauceOptions sauceOptions; @Setter private URL sauceUrl; diff --git a/java/src/test/java/com/saucelabs/saucebindings/SauceMobileSessionTest.java b/java/src/test/java/com/saucelabs/saucebindings/SauceMobileSessionTest.java index bbd811b4..3fbb811f 100644 --- a/java/src/test/java/com/saucelabs/saucebindings/SauceMobileSessionTest.java +++ b/java/src/test/java/com/saucelabs/saucebindings/SauceMobileSessionTest.java @@ -19,7 +19,7 @@ public class SauceMobileSessionTest { private SauceMobileOptions sauceMobileOptions = spy(new SauceMobileOptions()); private SauceMobileSession sauceMobileOptsSession = spy(new SauceMobileSession(sauceMobileOptions)); private AppiumDriver dummyAppiumDriver = mock(AppiumDriver.class); - private MutableCapabilities dummyMutableCapabilities = mock(MutableCapabilities.class); + private MutableCapabilities dummyMutableCapabilities = spy(new MutableCapabilities()); @Rule public MockitoRule initRule = MockitoJUnit.rule(); @@ -27,10 +27,11 @@ public class SauceMobileSessionTest { @Before public void setUp() { doReturn(dummyAppiumDriver).when(sauceMobileSession).createAppiumDriver(any(URL.class), any(MutableCapabilities.class)); + doReturn(dummyAppiumDriver).when(sauceMobileOptsSession).createAppiumDriver(any(URL.class), any(MutableCapabilities.class)); } @Test - public void sauceMObileSessionCreatesDefaultOptions() { + public void createsDefaultOptions() { SauceMobileOptions sauceOptions = sauceMobileSession.getSauceOptions(); assertEquals(Browser.CHROME, sauceOptions.getBrowserName()); @@ -42,12 +43,26 @@ public void sauceMObileSessionCreatesDefaultOptions() { } @Test - public void sauceMobileSessionUsesProvidedSauceOptions() { - doReturn(dummyMutableCapabilities).when(sauceMobileOptions).toCapabilities(); - doReturn(dummyAppiumDriver).when(sauceMobileOptsSession).createAppiumDriver(any(URL.class), eq(dummyMutableCapabilities)); + public void usesProvidedSauceOptions() { + doReturn(dummyMutableCapabilities).when(sauceMobileOptions).toCapabilities(true); sauceMobileOptsSession.start(); - verify(sauceMobileOptions).toCapabilities(); + verify(sauceMobileOptions).toCapabilities(true); + verify(sauceMobileOptsSession).getSauceUrl(); + verify(sauceMobileOptsSession).createAppiumDriver(any(URL.class), eq(dummyMutableCapabilities)); + } + + @Test + public void supportsJWPEndpoints() { + sauceMobileOptsSession.setDataCenter(DataCenter.US_WEST); + dummyMutableCapabilities.setCapability("username", "username"); + dummyMutableCapabilities.setCapability("accessKey", "accessKey"); + doReturn(dummyMutableCapabilities).when(sauceMobileOptions).toCapabilities(false); + + sauceMobileOptsSession.start(); + + verify(sauceMobileOptions).toCapabilities(false); + verify(sauceMobileOptsSession).getSauceUrl(eq("username"), eq("accessKey")); } } diff --git a/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimBrowserTest.java b/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimBrowserTest.java index 6508df94..f65a95c1 100644 --- a/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimBrowserTest.java +++ b/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimBrowserTest.java @@ -1,6 +1,8 @@ package com.saucelabs.saucebindings.acceptance; +import com.saucelabs.saucebindings.DataCenter; import com.saucelabs.saucebindings.SauceMobileSession; +import org.junit.After; import org.junit.Test; import org.openqa.selenium.remote.RemoteWebDriver; @@ -11,12 +13,34 @@ public class SauceEmuSimBrowserTest { private SauceMobileSession session = new SauceMobileSession(); private RemoteWebDriver webDriver; + @After + public void tearDown() { + session.stop(true); + } + @Test public void defaultsToLegacy() { webDriver = session.start(); + assertNotNull(webDriver); assertTrue(session.getSauceUrl().toString().contains("ondemand.saucelabs")); + } - session.stop(true); + @Test + public void runsUSWest() { + session.setDataCenter(DataCenter.US_WEST); + webDriver = session.start(); + + assertNotNull(webDriver); + assertTrue(session.getSauceUrl().toString().contains("us-west-1")); + } + + @Test + public void runsEUCentral() { + session.setDataCenter(DataCenter.EU_CENTRAL); + webDriver = session.start(); + + assertNotNull(webDriver); + assertTrue(session.getSauceUrl().toString().contains("eu-central-1")); } } From 6e64aad47e0297d7c883ecc2a7cfa8688d4cfa0d Mon Sep 17 00:00:00 2001 From: titusfortner Date: Sun, 12 Apr 2020 18:33:46 -0500 Subject: [PATCH 06/10] [java] add support for real devices on test object platforms --- .../saucelabs/saucebindings/DataCenter.java | 10 ++- .../saucebindings/SauceMobileOptions.java | 40 +++++++++--- .../saucebindings/SauceMobileSession.java | 7 +- .../saucebindings/SauceMobileSessionTest.java | 9 ++- .../SauceRealDeviceBrowserTest.java | 64 +++++++++++++++++++ 5 files changed, 112 insertions(+), 18 deletions(-) create mode 100644 java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceRealDeviceBrowserTest.java diff --git a/java/src/main/java/com/saucelabs/saucebindings/DataCenter.java b/java/src/main/java/com/saucelabs/saucebindings/DataCenter.java index 1fe924ba..c7bad7bf 100644 --- a/java/src/main/java/com/saucelabs/saucebindings/DataCenter.java +++ b/java/src/main/java/com/saucelabs/saucebindings/DataCenter.java @@ -7,7 +7,11 @@ public enum DataCenter { US_WEST("https://ondemand.us-west-1.saucelabs.com/wd/hub"), US_EAST("https://ondemand.us-east-1.saucelabs.com/wd/hub"), HEADLESS("https://ondemand.us-east-1.saucelabs.com/wd/hub"), - EU_CENTRAL("https://ondemand.eu-central-1.saucelabs.com/wd/hub"); + EU_CENTRAL("https://ondemand.eu-central-1.saucelabs.com/wd/hub"), + US_MOBILE("https://us1.appium.testobject.com/wd/hub"), + EU_MOBILE("https://eu1.appium.testobject.com/wd/hub"), + US_TEST_OBJECT("https://us1-manual.app.testobject.com/wd/hub"), + EU_TEST_OBJECT("https://appium.testobject.com/wd/hub"); @Getter private final String value; @@ -19,6 +23,10 @@ public boolean supportsW3C() { return value.equals("https://ondemand.saucelabs.com/wd/hub"); } + public boolean isTestObject() { + return value.contains("testobject"); + } + public String toString() { return value; } diff --git a/java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java b/java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java index e851645e..50fd97d5 100644 --- a/java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java +++ b/java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java @@ -18,9 +18,9 @@ public class SauceMobileOptions extends SauceOptions { private SaucePlatform platformName = SaucePlatform.ANDROID; // Defined in Appium - private String deviceName = "Android GoogleAPI Emulator"; + private String deviceName; private String deviceOrientation = "portrait"; - private String platformVersion = "8.1"; + private String platformVersion = "9"; // Supported by Sauce private String appiumVersion = "1.15.0"; @@ -45,22 +45,22 @@ private SauceMobileOptions(MutableCapabilities options) { appiumCapabilities = new MutableCapabilities(options.asMap()); } - public MutableCapabilities toCapabilities(boolean w3c) { + public MutableCapabilities toCapabilities(DataCenter dataCenter) { mobileW3COptions.forEach((capability) -> { addCapabilityIfDefined(appiumCapabilities, capability); }); - if (w3c) { + if (dataCenter.supportsW3C()) { useW3cCapabilities(); } else { - useJwpCapabilities(); + useJwpCapabilities(dataCenter.isTestObject()); } return appiumCapabilities; } private void useW3cCapabilities() { MutableCapabilities sauceCapabilities = new MutableCapabilities(); - addAuthentication(sauceCapabilities); + useSaucePlatform(sauceCapabilities); appiumDefinedOptions.forEach((capability) -> { addAppiumCapabilityIfDefined(appiumCapabilities, capability); @@ -73,8 +73,15 @@ private void useW3cCapabilities() { appiumCapabilities.setCapability("sauce:options", sauceCapabilities); } - private void useJwpCapabilities() { - addAuthentication(appiumCapabilities); + private void useJwpCapabilities(boolean to) { + if (to) { + appiumCapabilities.setCapability("testobject_api_key", getTestObjectKey()); + if (deviceName == null) { + this.deviceName = "Google Pixel XL"; + } + } else { + useSaucePlatform(appiumCapabilities); + } appiumDefinedOptions.forEach((capability) -> { addCapabilityIfDefined(appiumCapabilities, capability); @@ -85,10 +92,27 @@ private void useJwpCapabilities() { }); } + private void useSaucePlatform(MutableCapabilities capabilities) { + if (deviceName == null) { + this.deviceName = "Android GoogleAPI Emulator"; + } + addAuthentication(capabilities); + } + private void addAppiumCapabilityIfDefined(MutableCapabilities capabilities, String capability) { Object value = getCapability(capability); if (value != null) { capabilities.setCapability("appium:" + capability, value); } } + + String getTestObjectKey() { + if (getSystemProperty("TEST_OBJECT_KEY") != null) { + return getSystemProperty("TEST_OBJECT_KEY"); + } else if (getEnvironmentVariable("TEST_OBJECT_KEY") != null) { + return getEnvironmentVariable("TEST_OBJECT_KEY"); + } else { + throw new SauceEnvironmentVariablesNotSetException("Test Object API Key was not provided"); + } + } } diff --git a/java/src/main/java/com/saucelabs/saucebindings/SauceMobileSession.java b/java/src/main/java/com/saucelabs/saucebindings/SauceMobileSession.java index de79164d..87e8f7f3 100644 --- a/java/src/main/java/com/saucelabs/saucebindings/SauceMobileSession.java +++ b/java/src/main/java/com/saucelabs/saucebindings/SauceMobileSession.java @@ -22,13 +22,12 @@ public SauceMobileSession(SauceMobileOptions options) { } public AppiumDriver start() { - MutableCapabilities capabilities; + MutableCapabilities capabilities = sauceOptions.toCapabilities(getDataCenter()); + URL url; - if (dataCenter.supportsW3C()) { - capabilities = sauceOptions.toCapabilities(true); + if (dataCenter.supportsW3C() || dataCenter.isTestObject()) { url = getSauceUrl(); } else { - capabilities = sauceOptions.toCapabilities(false); String username = (String) capabilities.getCapability("username"); String key = (String) capabilities.getCapability("accessKey"); url = getSauceUrl(username, key); diff --git a/java/src/test/java/com/saucelabs/saucebindings/SauceMobileSessionTest.java b/java/src/test/java/com/saucelabs/saucebindings/SauceMobileSessionTest.java index 3fbb811f..880b72fa 100644 --- a/java/src/test/java/com/saucelabs/saucebindings/SauceMobileSessionTest.java +++ b/java/src/test/java/com/saucelabs/saucebindings/SauceMobileSessionTest.java @@ -11,7 +11,6 @@ import java.net.URL; import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; import static org.mockito.Mockito.*; public class SauceMobileSessionTest { @@ -44,11 +43,11 @@ public void createsDefaultOptions() { @Test public void usesProvidedSauceOptions() { - doReturn(dummyMutableCapabilities).when(sauceMobileOptions).toCapabilities(true); + doReturn(dummyMutableCapabilities).when(sauceMobileOptions).toCapabilities(sauceMobileOptsSession.getDataCenter()); sauceMobileOptsSession.start(); - verify(sauceMobileOptions).toCapabilities(true); + verify(sauceMobileOptions).toCapabilities(sauceMobileOptsSession.getDataCenter()); verify(sauceMobileOptsSession).getSauceUrl(); verify(sauceMobileOptsSession).createAppiumDriver(any(URL.class), eq(dummyMutableCapabilities)); } @@ -58,11 +57,11 @@ public void supportsJWPEndpoints() { sauceMobileOptsSession.setDataCenter(DataCenter.US_WEST); dummyMutableCapabilities.setCapability("username", "username"); dummyMutableCapabilities.setCapability("accessKey", "accessKey"); - doReturn(dummyMutableCapabilities).when(sauceMobileOptions).toCapabilities(false); + doReturn(dummyMutableCapabilities).when(sauceMobileOptions).toCapabilities(sauceMobileOptsSession.getDataCenter()); sauceMobileOptsSession.start(); - verify(sauceMobileOptions).toCapabilities(false); + verify(sauceMobileOptions).toCapabilities(sauceMobileOptsSession.getDataCenter()); verify(sauceMobileOptsSession).getSauceUrl(eq("username"), eq("accessKey")); } } diff --git a/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceRealDeviceBrowserTest.java b/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceRealDeviceBrowserTest.java new file mode 100644 index 00000000..da669ece --- /dev/null +++ b/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceRealDeviceBrowserTest.java @@ -0,0 +1,64 @@ +package com.saucelabs.saucebindings.acceptance; + +import com.saucelabs.saucebindings.DataCenter; +import com.saucelabs.saucebindings.SauceMobileOptions; +import com.saucelabs.saucebindings.SauceMobileSession; +import io.appium.java_client.AppiumDriver; +import org.junit.After; +import org.junit.Ignore; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; + +public class SauceRealDeviceBrowserTest { + private SauceMobileSession session = new SauceMobileSession(); + private AppiumDriver webDriver; + + @After + public void tearDown() { + session.stop(true); + } + + @Ignore + public void runsUSMobile() { + session.setDataCenter(DataCenter.US_MOBILE); + webDriver = session.start(); + + assertTrue(webDriver.getRemoteAddress().toString().contains("us1.appium.testobject")); + } + + @Test + public void runsEUMobile() { + session.setDataCenter(DataCenter.EU_MOBILE); + webDriver = session.start(); + + assertTrue(webDriver.getRemoteAddress().toString().contains("eu1.appium.testobject")); + } + + @Ignore + public void runsUSTestObject() { + session.setDataCenter(DataCenter.US_TEST_OBJECT); + webDriver = session.start(); + + assertTrue(webDriver.getRemoteAddress().toString().contains("us1-manual.app.testobject")); + } + + @Test + public void runsEUTestObject() { + session.setDataCenter(DataCenter.EU_TEST_OBJECT); + webDriver = session.start(); + + assertTrue(webDriver.getRemoteAddress().toString().contains("//appium.testobject")); + } + + @Ignore + public void runsUnifiedPlatform() { + SauceMobileOptions sauceMobileOptions = new SauceMobileOptions(); + sauceMobileOptions.setDeviceName("Google Pixel XL Real"); + session = new SauceMobileSession(sauceMobileOptions); + session.setDataCenter(DataCenter.US_WEST); + webDriver = session.start(); + + assertTrue(webDriver.getRemoteAddress().toString().contains("ondemand.saucelabs")); + } +} From fb84617bbfcee94d98df90f2019e41871aee4066 Mon Sep 17 00:00:00 2001 From: titusfortner Date: Sun, 12 Apr 2020 19:53:43 -0500 Subject: [PATCH 07/10] [java] add support for running with native application --- .../saucebindings/SauceMobileOptions.java | 8 ++- .../acceptance/SauceEmuSimAppTest.java | 59 +++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimAppTest.java diff --git a/java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java b/java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java index 50fd97d5..5e8e8a02 100644 --- a/java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java +++ b/java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java @@ -18,6 +18,7 @@ public class SauceMobileOptions extends SauceOptions { private SaucePlatform platformName = SaucePlatform.ANDROID; // Defined in Appium + private String app; private String deviceName; private String deviceOrientation = "portrait"; private String platformVersion = "9"; @@ -33,6 +34,7 @@ public class SauceMobileOptions extends SauceOptions { "appiumVersion"); public static final List appiumDefinedOptions = List.of( + "app", "deviceName", "platformVersion", "deviceOrientation"); @@ -41,11 +43,15 @@ public SauceMobileOptions() { this(new MutableCapabilities()); } - private SauceMobileOptions(MutableCapabilities options) { + public SauceMobileOptions(MutableCapabilities options) { appiumCapabilities = new MutableCapabilities(options.asMap()); } public MutableCapabilities toCapabilities(DataCenter dataCenter) { + if (app != null) { + browserName = null; + } + mobileW3COptions.forEach((capability) -> { addCapabilityIfDefined(appiumCapabilities, capability); }); diff --git a/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimAppTest.java b/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimAppTest.java new file mode 100644 index 00000000..a1fcbc22 --- /dev/null +++ b/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimAppTest.java @@ -0,0 +1,59 @@ +package com.saucelabs.saucebindings.acceptance; + +import com.saucelabs.saucebindings.DataCenter; +import com.saucelabs.saucebindings.SauceMobileOptions; +import com.saucelabs.saucebindings.SauceMobileSession; +import io.appium.java_client.AppiumDriver; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.openqa.selenium.MutableCapabilities; + +import static org.junit.Assert.assertTrue; + +// TODO: Convert these into unit tests; Integration tests are not unique +public class SauceEmuSimAppTest { + private SauceMobileOptions options; + private SauceMobileSession session; + private AppiumDriver webDriver; + + @Before + public void setUp() { + MutableCapabilities appiumOptions = new MutableCapabilities(); + appiumOptions.setCapability("appWaitActivity", "com.swaglabsmobileapp.MainActivity"); + + options = new SauceMobileOptions(appiumOptions); + String app = "https://github.com/saucelabs/sample-app-mobile/releases/download/2.3.0/Android.SauceLabs.Mobile.Sample.app.2.3.0.apk"; + options.setApp(app); + + session = new SauceMobileSession(options); + } + + @After + public void tearDown() { + session.stop(true); + } + + @Test + public void defaultsToLegacy() { + webDriver = session.start(); + + assertTrue(webDriver.getRemoteAddress().toString().contains("ondemand.saucelabs")); + } + + @Test + public void runsUSWest() { + session.setDataCenter(DataCenter.US_WEST); + webDriver = session.start(); + + assertTrue(webDriver.getRemoteAddress().toString().contains("us-west-1")); + } + + @Test + public void runsEUCentral() { + session.setDataCenter(DataCenter.EU_CENTRAL); + webDriver = session.start(); + + assertTrue(webDriver.getRemoteAddress().toString().contains("eu-central-1")); + } +} From cc3a8c21be67744a3c50d1f16f5dd0a7872a54ec Mon Sep 17 00:00:00 2001 From: titusfortner Date: Sun, 12 Apr 2020 20:02:50 -0500 Subject: [PATCH 08/10] [java] add fields for all supported mobile commands --- .../saucebindings/SauceMobileOptions.java | 57 ++++++++++++++++++- .../SauceRealDeviceBrowserTest.java | 7 +-- 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java b/java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java index 5e8e8a02..ee0e680b 100644 --- a/java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java +++ b/java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java @@ -18,31 +18,74 @@ public class SauceMobileOptions extends SauceOptions { private SaucePlatform platformName = SaucePlatform.ANDROID; // Defined in Appium + // These are the only values that are handled by Sauce Labs by default + // Additional values will be populated by Appium's IOSOptions & AndroidOptions class instances private String app; private String deviceName; private String deviceOrientation = "portrait"; - private String platformVersion = "9"; + private String platformVersion = "10"; + private String automationName; // Supported by Sauce private String appiumVersion = "1.15.0"; + private String deviceType; // "table" or "phone" + + // Supported by Sauce for Real Devices + private String testobject_app_id; + private String privateDeviceOnly; + private String tabletOnly; + private String phoneOnly; + private String carrierConnectivityOnly; + private String recordDeviceVitals; + private String cacheId; + private String testobject_test_live_view_url; + private String testobject_test_report_url; + private String testobject_test_report_api_url; + private String testobject_session_creation_timeout; + private String commandTimeouts; + private String crosswalkApplication; + private String autoGrantPermissions; + private String enableAnimations; + private String name; public static final List mobileW3COptions = List.of( "browserName", "platformName"); public static final List mobileSauceDefinedOptions = List.of( - "appiumVersion"); + "appiumVersion", + "deviceType"); public static final List appiumDefinedOptions = List.of( "app", + "automationName", "deviceName", "platformVersion", "deviceOrientation"); + public static final List realDeviceSauceDefinedOptions = List.of( + "testobject_app_id", + "privateDeviceOnly", + "tabletOnly", + "phoneOnly", + "carrierConnectivityOnly", + "recordDeviceVitals", + "cacheId", + "testobject_test_live_view_url", + "testobject_test_report_url", + "testobject_test_report_api_url", + "testobject_session_creation_timeout", + "commandTimeouts", + "crosswalkApplication", + "autoGrantPermissions", + "enableAnimations", + "name"); + public SauceMobileOptions() { this(new MutableCapabilities()); } + // TODO: require users to work with Appium's MobileOptions class similar to Selenium public SauceMobileOptions(MutableCapabilities options) { appiumCapabilities = new MutableCapabilities(options.asMap()); } @@ -76,6 +119,10 @@ private void useW3cCapabilities() { addCapabilityIfDefined(sauceCapabilities, capability); }); + sauceDefinedOptions.forEach((capability) -> { + addCapabilityIfDefined(appiumCapabilities, capability); + }); + appiumCapabilities.setCapability("sauce:options", sauceCapabilities); } @@ -83,7 +130,7 @@ private void useJwpCapabilities(boolean to) { if (to) { appiumCapabilities.setCapability("testobject_api_key", getTestObjectKey()); if (deviceName == null) { - this.deviceName = "Google Pixel XL"; + this.deviceName = "Google Pixel 2"; } } else { useSaucePlatform(appiumCapabilities); @@ -96,6 +143,10 @@ private void useJwpCapabilities(boolean to) { mobileSauceDefinedOptions.forEach((capability) -> { addCapabilityIfDefined(appiumCapabilities, capability); }); + + realDeviceSauceDefinedOptions.forEach((capability) -> { + addCapabilityIfDefined(appiumCapabilities, capability); + }); } private void useSaucePlatform(MutableCapabilities capabilities) { diff --git a/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceRealDeviceBrowserTest.java b/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceRealDeviceBrowserTest.java index da669ece..100a6516 100644 --- a/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceRealDeviceBrowserTest.java +++ b/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceRealDeviceBrowserTest.java @@ -5,7 +5,6 @@ import com.saucelabs.saucebindings.SauceMobileSession; import io.appium.java_client.AppiumDriver; import org.junit.After; -import org.junit.Ignore; import org.junit.Test; import static org.junit.Assert.assertTrue; @@ -19,7 +18,7 @@ public void tearDown() { session.stop(true); } - @Ignore + @Test public void runsUSMobile() { session.setDataCenter(DataCenter.US_MOBILE); webDriver = session.start(); @@ -35,7 +34,7 @@ public void runsEUMobile() { assertTrue(webDriver.getRemoteAddress().toString().contains("eu1.appium.testobject")); } - @Ignore + @Test public void runsUSTestObject() { session.setDataCenter(DataCenter.US_TEST_OBJECT); webDriver = session.start(); @@ -51,7 +50,7 @@ public void runsEUTestObject() { assertTrue(webDriver.getRemoteAddress().toString().contains("//appium.testobject")); } - @Ignore + @Test public void runsUnifiedPlatform() { SauceMobileOptions sauceMobileOptions = new SauceMobileOptions(); sauceMobileOptions.setDeviceName("Google Pixel XL Real"); From fa3b39b51177056bba81b957d795e48793a5cd75 Mon Sep 17 00:00:00 2001 From: titusfortner Date: Mon, 13 Apr 2020 13:55:47 -0500 Subject: [PATCH 09/10] SQUASH - fix codacy issues --- .../main/java/com/saucelabs/saucebindings/DataCenter.java | 2 +- .../com/saucelabs/saucebindings/SauceMobileOptions.java | 2 +- .../saucelabs/saucebindings/SauceMobileSessionTest.java | 7 ++++++- .../com/saucelabs/saucebindings/SauceSessionTest.java | 8 ++++++-- .../saucebindings/acceptance/SauceEmuSimAppTest.java | 3 +-- .../acceptance/SauceRealDeviceBrowserTest.java | 3 ++- 6 files changed, 17 insertions(+), 8 deletions(-) diff --git a/java/src/main/java/com/saucelabs/saucebindings/DataCenter.java b/java/src/main/java/com/saucelabs/saucebindings/DataCenter.java index c7bad7bf..e79ab0c1 100644 --- a/java/src/main/java/com/saucelabs/saucebindings/DataCenter.java +++ b/java/src/main/java/com/saucelabs/saucebindings/DataCenter.java @@ -20,7 +20,7 @@ public enum DataCenter { } public boolean supportsW3C() { - return value.equals("https://ondemand.saucelabs.com/wd/hub"); + return ("https://ondemand.saucelabs.com/wd/hub".equals(value)); } public boolean isTestObject() { diff --git a/java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java b/java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java index ee0e680b..d430f346 100644 --- a/java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java +++ b/java/src/main/java/com/saucelabs/saucebindings/SauceMobileOptions.java @@ -163,7 +163,7 @@ private void addAppiumCapabilityIfDefined(MutableCapabilities capabilities, Stri } } - String getTestObjectKey() { + protected String getTestObjectKey() { if (getSystemProperty("TEST_OBJECT_KEY") != null) { return getSystemProperty("TEST_OBJECT_KEY"); } else if (getEnvironmentVariable("TEST_OBJECT_KEY") != null) { diff --git a/java/src/test/java/com/saucelabs/saucebindings/SauceMobileSessionTest.java b/java/src/test/java/com/saucelabs/saucebindings/SauceMobileSessionTest.java index 880b72fa..30f84862 100644 --- a/java/src/test/java/com/saucelabs/saucebindings/SauceMobileSessionTest.java +++ b/java/src/test/java/com/saucelabs/saucebindings/SauceMobileSessionTest.java @@ -11,7 +11,12 @@ import java.net.URL; import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; public class SauceMobileSessionTest { private SauceMobileSession sauceMobileSession = spy(new SauceMobileSession()); diff --git a/java/src/test/java/com/saucelabs/saucebindings/SauceSessionTest.java b/java/src/test/java/com/saucelabs/saucebindings/SauceSessionTest.java index 060d6dd6..a3c241ee 100644 --- a/java/src/test/java/com/saucelabs/saucebindings/SauceSessionTest.java +++ b/java/src/test/java/com/saucelabs/saucebindings/SauceSessionTest.java @@ -12,8 +12,12 @@ import java.net.URL; import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; public class SauceSessionTest { private SauceOptions sauceOptions = spy(new SauceOptions()); diff --git a/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimAppTest.java b/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimAppTest.java index a1fcbc22..1bd8be43 100644 --- a/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimAppTest.java +++ b/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimAppTest.java @@ -13,7 +13,6 @@ // TODO: Convert these into unit tests; Integration tests are not unique public class SauceEmuSimAppTest { - private SauceMobileOptions options; private SauceMobileSession session; private AppiumDriver webDriver; @@ -22,7 +21,7 @@ public void setUp() { MutableCapabilities appiumOptions = new MutableCapabilities(); appiumOptions.setCapability("appWaitActivity", "com.swaglabsmobileapp.MainActivity"); - options = new SauceMobileOptions(appiumOptions); + SauceMobileOptions options = new SauceMobileOptions(appiumOptions); String app = "https://github.com/saucelabs/sample-app-mobile/releases/download/2.3.0/Android.SauceLabs.Mobile.Sample.app.2.3.0.apk"; options.setApp(app); diff --git a/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceRealDeviceBrowserTest.java b/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceRealDeviceBrowserTest.java index 100a6516..0010cf91 100644 --- a/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceRealDeviceBrowserTest.java +++ b/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceRealDeviceBrowserTest.java @@ -5,6 +5,7 @@ import com.saucelabs.saucebindings.SauceMobileSession; import io.appium.java_client.AppiumDriver; import org.junit.After; +import org.junit.Ignore; import org.junit.Test; import static org.junit.Assert.assertTrue; @@ -50,7 +51,7 @@ public void runsEUTestObject() { assertTrue(webDriver.getRemoteAddress().toString().contains("//appium.testobject")); } - @Test + @Ignore public void runsUnifiedPlatform() { SauceMobileOptions sauceMobileOptions = new SauceMobileOptions(); sauceMobileOptions.setDeviceName("Google Pixel XL Real"); From 4bf7e90c2390c21a46475700c45831ca53ffdfe6 Mon Sep 17 00:00:00 2001 From: joshgrant Date: Thu, 16 Apr 2020 14:23:46 -0400 Subject: [PATCH 10/10] possible idea - single SauceSession class, multiple SauceOption classes --- .../com/saucelabs/saucebindings/Browser.java | 1 + .../saucebindings/DeviceOrientation.java | 18 +++++ .../saucebindings/SauceAndroidOptions.java | 30 ++++++++ .../saucebindings/SauceIOSOptions.java | 30 ++++++++ .../saucebindings/SauceMobileSession.java | 2 +- .../saucelabs/saucebindings/SauceOptions.java | 12 ++-- .../saucebindings/SaucePlatform.java | 1 + .../saucelabs/saucebindings/SauceSession.java | 52 +++++++++++--- .../saucebindings/examples/BasicUsage.java | 2 +- .../SauceAndroidOptionsTest.java | 18 +++++ .../saucebindings/SauceIOSOptionsTest.java | 19 +++++ .../saucebindings/SauceMobileSessionTest.java | 72 ------------------- .../acceptance/SauceEmuSimAppTest.java | 58 --------------- .../acceptance/SauceEmuSimBrowserTest.java | 30 +++++--- .../SauceRealDeviceBrowserTest.java | 20 +++--- 15 files changed, 197 insertions(+), 168 deletions(-) create mode 100644 java/src/main/java/com/saucelabs/saucebindings/DeviceOrientation.java create mode 100644 java/src/main/java/com/saucelabs/saucebindings/SauceAndroidOptions.java create mode 100644 java/src/main/java/com/saucelabs/saucebindings/SauceIOSOptions.java create mode 100644 java/src/test/java/com/saucelabs/saucebindings/SauceAndroidOptionsTest.java create mode 100644 java/src/test/java/com/saucelabs/saucebindings/SauceIOSOptionsTest.java delete mode 100644 java/src/test/java/com/saucelabs/saucebindings/SauceMobileSessionTest.java delete mode 100644 java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimAppTest.java diff --git a/java/src/main/java/com/saucelabs/saucebindings/Browser.java b/java/src/main/java/com/saucelabs/saucebindings/Browser.java index 5ea8940d..6576c521 100644 --- a/java/src/main/java/com/saucelabs/saucebindings/Browser.java +++ b/java/src/main/java/com/saucelabs/saucebindings/Browser.java @@ -7,6 +7,7 @@ import java.util.Set; public enum Browser { + NONE(""), CHROME("chrome"), INTERNET_EXPLORER("internet explorer"), EDGE("MicrosoftEdge"), diff --git a/java/src/main/java/com/saucelabs/saucebindings/DeviceOrientation.java b/java/src/main/java/com/saucelabs/saucebindings/DeviceOrientation.java new file mode 100644 index 00000000..3e48ad56 --- /dev/null +++ b/java/src/main/java/com/saucelabs/saucebindings/DeviceOrientation.java @@ -0,0 +1,18 @@ +package com.saucelabs.saucebindings; + +import lombok.Getter; + +public enum DeviceOrientation { + PORTRAIT("portrait"), + LANDSCAPE("landscape"); + + @Getter private final String value; + + DeviceOrientation(String value) { + this.value = value; + } + + public String toString() { + return value; + } +} diff --git a/java/src/main/java/com/saucelabs/saucebindings/SauceAndroidOptions.java b/java/src/main/java/com/saucelabs/saucebindings/SauceAndroidOptions.java new file mode 100644 index 00000000..72eafa98 --- /dev/null +++ b/java/src/main/java/com/saucelabs/saucebindings/SauceAndroidOptions.java @@ -0,0 +1,30 @@ +package com.saucelabs.saucebindings; + +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +import org.openqa.selenium.MutableCapabilities; + +@Accessors(chain = true) +@Setter @Getter +public class SauceAndroidOptions extends SauceOptions { + + // minimal configuration + private DeviceOrientation deviceOrientation; + private String deviceName; + private String platformVersion; + + public SauceAndroidOptions(String deviceName, String platformVersion, DeviceOrientation deviceOrientation){ + super(); + this.platformName = SaucePlatform.ANDROID; + this.browserName = Browser.NONE; + this.browserVersion = ""; + this.deviceName = deviceName; + this.platformVersion = platformVersion; + this.deviceOrientation = deviceOrientation; + } + + public SauceAndroidOptions(MutableCapabilities capabilities){ + super(capabilities); + } +} diff --git a/java/src/main/java/com/saucelabs/saucebindings/SauceIOSOptions.java b/java/src/main/java/com/saucelabs/saucebindings/SauceIOSOptions.java new file mode 100644 index 00000000..49316405 --- /dev/null +++ b/java/src/main/java/com/saucelabs/saucebindings/SauceIOSOptions.java @@ -0,0 +1,30 @@ +package com.saucelabs.saucebindings; + +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +import org.openqa.selenium.MutableCapabilities; + +@Accessors(chain = true) +@Setter @Getter +public class SauceIOSOptions extends SauceOptions { + + // minimal configuration + private DeviceOrientation deviceOrientation; + private String deviceName; + private String platformVersion; + + public SauceIOSOptions(String deviceName, String platformVersion, DeviceOrientation deviceOrientation){ + super(); + this.platformName = SaucePlatform.IOS; + this.browserName = Browser.NONE; + this.platformVersion = ""; + this.deviceName = deviceName; + this.platformVersion = platformVersion; + this.deviceOrientation = deviceOrientation; + } + + public SauceIOSOptions(MutableCapabilities capabilities){ + super(capabilities); + } +} diff --git a/java/src/main/java/com/saucelabs/saucebindings/SauceMobileSession.java b/java/src/main/java/com/saucelabs/saucebindings/SauceMobileSession.java index 87e8f7f3..c93c9503 100644 --- a/java/src/main/java/com/saucelabs/saucebindings/SauceMobileSession.java +++ b/java/src/main/java/com/saucelabs/saucebindings/SauceMobileSession.java @@ -33,7 +33,7 @@ public AppiumDriver start() { url = getSauceUrl(username, key); } - driver = createAppiumDriver(url, capabilities); + //driver = createRemoteWebDriver(url, capabilities); return driver; } diff --git a/java/src/main/java/com/saucelabs/saucebindings/SauceOptions.java b/java/src/main/java/com/saucelabs/saucebindings/SauceOptions.java index 56417e9d..da50b738 100644 --- a/java/src/main/java/com/saucelabs/saucebindings/SauceOptions.java +++ b/java/src/main/java/com/saucelabs/saucebindings/SauceOptions.java @@ -25,10 +25,12 @@ public class SauceOptions { @Setter(AccessLevel.NONE) private MutableCapabilities seleniumCapabilities; public TimeoutStore timeout = new TimeoutStore(); - // w3c Settings - private Browser browserName = Browser.CHROME; - private String browserVersion = "latest"; - private SaucePlatform platformName = SaucePlatform.WINDOWS_10; + // w3c settings - applies to any sauce session + protected Browser browserName = Browser.CHROME; + protected SaucePlatform platformName = SaucePlatform.WINDOWS_10; + protected String browserVersion = "latest"; + + // w3c settings - applies only to VDC private PageLoadStrategy pageLoadStrategy; private Boolean acceptInsecureCerts = null; private Proxy proxy; @@ -164,7 +166,7 @@ public Map getTimeouts() { return timeout.getTimeouts(); } - private SauceOptions(MutableCapabilities options) { + protected SauceOptions(MutableCapabilities options) { seleniumCapabilities = new MutableCapabilities(options.asMap()); if (options.getCapability("browserName") != null) { setCapability("browserName", options.getCapability("browserName")); diff --git a/java/src/main/java/com/saucelabs/saucebindings/SaucePlatform.java b/java/src/main/java/com/saucelabs/saucebindings/SaucePlatform.java index 3eadbf19..f0b142dd 100644 --- a/java/src/main/java/com/saucelabs/saucebindings/SaucePlatform.java +++ b/java/src/main/java/com/saucelabs/saucebindings/SaucePlatform.java @@ -8,6 +8,7 @@ public enum SaucePlatform { ANDROID("Android"), + IOS("iOS"), WINDOWS_10("Windows 10"), WINDOWS_8_1("Windows 8.1"), WINDOWS_8("Windows 8"), diff --git a/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java b/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java index 4d28a7e3..596a085f 100755 --- a/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java +++ b/java/src/main/java/com/saucelabs/saucebindings/SauceSession.java @@ -1,5 +1,8 @@ package com.saucelabs.saucebindings; +import io.appium.java_client.AppiumDriver; +import io.appium.java_client.android.AndroidDriver; +import io.appium.java_client.ios.IOSDriver; import lombok.Getter; import lombok.Setter; import org.openqa.selenium.InvalidArgumentException; @@ -11,22 +14,37 @@ public class SauceSession { @Getter @Setter protected DataCenter dataCenter = DataCenter.US_LEGACY; - @Getter private final SauceOptions sauceOptions; + @Getter private SauceOptions sauceOptions; @Setter private URL sauceUrl; - - @Getter private RemoteWebDriver driver; + @Getter private RemoteWebDriver webDriver; + @Getter private AppiumDriver appDriver; public SauceSession() { this(new SauceOptions()); } public SauceSession(SauceOptions options) { - sauceOptions = options; + this.sauceOptions = options; } public RemoteWebDriver start() { - driver = createRemoteWebDriver(getSauceUrl(), sauceOptions.toCapabilities()); - return driver; + String environment = sauceOptions.toCapabilities().getCapability("platformName").toString(); + String browserName = sauceOptions.toCapabilities().getBrowserName(); + + if (browserName.equals("")){ + if (environment.toLowerCase().equals("android")){ + return createAndroidDriver(getSauceUrl(), sauceOptions.toCapabilities()); + } + else if (environment.toLowerCase().equals("ios")) { + return createIOSDriver(getSauceUrl(), sauceOptions.toCapabilities()); + } + else { + throw new InvalidArgumentException("Invalid Sauce Labs capabilities. Please set a browser name or set platformName as \"Android\" or \"IOS\"."); + } + } + else { + return createRemoteWebDriver(getSauceUrl(), sauceOptions.toCapabilities()); + } } public URL getSauceUrl() { @@ -45,6 +63,14 @@ protected RemoteWebDriver createRemoteWebDriver(URL url, MutableCapabilities cap return new RemoteWebDriver(url, capabilities); } + protected AppiumDriver createIOSDriver(URL url, MutableCapabilities capabilities) { + return new IOSDriver<>(url, capabilities); + } + + protected AppiumDriver createAndroidDriver(URL url, MutableCapabilities capabilities) { + return new AndroidDriver<>(url, capabilities); + } + public void stop(Boolean passed) { String result = passed ? "passed" : "failed"; stop(result); @@ -56,12 +82,20 @@ public void stop(String result) { } private void updateResult(String result) { - getDriver().executeScript("sauce:job-result=" + result); + if (webDriver != null) + getWebDriver().executeScript("sauce:job-result=" + result); + else { + System.out.println("use API for mobile case"); + } + } private void stop() { - if(getDriver() !=null) { - getDriver().quit(); + if(getWebDriver() !=null) { + getWebDriver().quit(); + } + if(getAppDriver() != null){ + getAppDriver().quit(); } } } diff --git a/java/src/main/java/com/saucelabs/saucebindings/examples/BasicUsage.java b/java/src/main/java/com/saucelabs/saucebindings/examples/BasicUsage.java index 0347bcd6..8759b6a2 100644 --- a/java/src/main/java/com/saucelabs/saucebindings/examples/BasicUsage.java +++ b/java/src/main/java/com/saucelabs/saucebindings/examples/BasicUsage.java @@ -9,7 +9,7 @@ public static void main(String[] argv){ sauce.start(); - sauce.getDriver().get("https://www.saucedemo.com/"); + sauce.getWebDriver().get("https://www.saucedemo.com/"); sauce.stop(true); } diff --git a/java/src/test/java/com/saucelabs/saucebindings/SauceAndroidOptionsTest.java b/java/src/test/java/com/saucelabs/saucebindings/SauceAndroidOptionsTest.java new file mode 100644 index 00000000..c16aac01 --- /dev/null +++ b/java/src/test/java/com/saucelabs/saucebindings/SauceAndroidOptionsTest.java @@ -0,0 +1,18 @@ +package com.saucelabs.saucebindings; + +import org.junit.Assert; +import org.junit.Test; + +public class SauceAndroidOptionsTest { + + @Test + public void defaultConstructor() { + SauceAndroidOptions options = new SauceAndroidOptions("Android Emulator", "9.0", DeviceOrientation.PORTRAIT); + + Assert.assertEquals(SaucePlatform.ANDROID, options.getPlatformName()); + Assert.assertEquals("9.0", options.getPlatformVersion()); + Assert.assertEquals("Android Emulator", options.getDeviceName()); + Assert.assertEquals(Browser.NONE, options.getBrowserName()); + Assert.assertEquals("", options.getBrowserVersion()); + } +} diff --git a/java/src/test/java/com/saucelabs/saucebindings/SauceIOSOptionsTest.java b/java/src/test/java/com/saucelabs/saucebindings/SauceIOSOptionsTest.java new file mode 100644 index 00000000..33b9dd24 --- /dev/null +++ b/java/src/test/java/com/saucelabs/saucebindings/SauceIOSOptionsTest.java @@ -0,0 +1,19 @@ +package com.saucelabs.saucebindings; + +import org.junit.Assert; +import org.junit.Test; + +public class SauceIOSOptionsTest { + + @Test + public void defaultConstructor() { + SauceIOSOptions options = new SauceIOSOptions("iPhone X Simulator", "13.0", DeviceOrientation.PORTRAIT); + + Assert.assertEquals(SaucePlatform.IOS, options.getPlatformName()); + Assert.assertEquals("13.0", options.getPlatformVersion()); + Assert.assertEquals("iPhone X Simulator", options.getDeviceName()); + Assert.assertEquals(Browser.NONE, options.getBrowserName()); + Assert.assertEquals("", options.getBrowserVersion()); + + } +} diff --git a/java/src/test/java/com/saucelabs/saucebindings/SauceMobileSessionTest.java b/java/src/test/java/com/saucelabs/saucebindings/SauceMobileSessionTest.java deleted file mode 100644 index 30f84862..00000000 --- a/java/src/test/java/com/saucelabs/saucebindings/SauceMobileSessionTest.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.saucelabs.saucebindings; - -import io.appium.java_client.AppiumDriver; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; -import org.openqa.selenium.MutableCapabilities; - -import java.net.URL; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; - -public class SauceMobileSessionTest { - private SauceMobileSession sauceMobileSession = spy(new SauceMobileSession()); - private SauceMobileOptions sauceMobileOptions = spy(new SauceMobileOptions()); - private SauceMobileSession sauceMobileOptsSession = spy(new SauceMobileSession(sauceMobileOptions)); - private AppiumDriver dummyAppiumDriver = mock(AppiumDriver.class); - private MutableCapabilities dummyMutableCapabilities = spy(new MutableCapabilities()); - - @Rule - public MockitoRule initRule = MockitoJUnit.rule(); - - @Before - public void setUp() { - doReturn(dummyAppiumDriver).when(sauceMobileSession).createAppiumDriver(any(URL.class), any(MutableCapabilities.class)); - doReturn(dummyAppiumDriver).when(sauceMobileOptsSession).createAppiumDriver(any(URL.class), any(MutableCapabilities.class)); - } - - @Test - public void createsDefaultOptions() { - SauceMobileOptions sauceOptions = sauceMobileSession.getSauceOptions(); - - assertEquals(Browser.CHROME, sauceOptions.getBrowserName()); - assertEquals(SaucePlatform.ANDROID, sauceOptions.getPlatformName()); - assertEquals("1.15.0", sauceOptions.getAppiumVersion()); - assertEquals("Android GoogleAPI Emulator", sauceOptions.getDeviceName()); - assertEquals("portrait", sauceOptions.getDeviceOrientation()); - assertEquals("8.1", sauceOptions.getPlatformVersion()); - } - - @Test - public void usesProvidedSauceOptions() { - doReturn(dummyMutableCapabilities).when(sauceMobileOptions).toCapabilities(sauceMobileOptsSession.getDataCenter()); - - sauceMobileOptsSession.start(); - - verify(sauceMobileOptions).toCapabilities(sauceMobileOptsSession.getDataCenter()); - verify(sauceMobileOptsSession).getSauceUrl(); - verify(sauceMobileOptsSession).createAppiumDriver(any(URL.class), eq(dummyMutableCapabilities)); - } - - @Test - public void supportsJWPEndpoints() { - sauceMobileOptsSession.setDataCenter(DataCenter.US_WEST); - dummyMutableCapabilities.setCapability("username", "username"); - dummyMutableCapabilities.setCapability("accessKey", "accessKey"); - doReturn(dummyMutableCapabilities).when(sauceMobileOptions).toCapabilities(sauceMobileOptsSession.getDataCenter()); - - sauceMobileOptsSession.start(); - - verify(sauceMobileOptions).toCapabilities(sauceMobileOptsSession.getDataCenter()); - verify(sauceMobileOptsSession).getSauceUrl(eq("username"), eq("accessKey")); - } -} diff --git a/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimAppTest.java b/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimAppTest.java deleted file mode 100644 index 1bd8be43..00000000 --- a/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimAppTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.saucelabs.saucebindings.acceptance; - -import com.saucelabs.saucebindings.DataCenter; -import com.saucelabs.saucebindings.SauceMobileOptions; -import com.saucelabs.saucebindings.SauceMobileSession; -import io.appium.java_client.AppiumDriver; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.openqa.selenium.MutableCapabilities; - -import static org.junit.Assert.assertTrue; - -// TODO: Convert these into unit tests; Integration tests are not unique -public class SauceEmuSimAppTest { - private SauceMobileSession session; - private AppiumDriver webDriver; - - @Before - public void setUp() { - MutableCapabilities appiumOptions = new MutableCapabilities(); - appiumOptions.setCapability("appWaitActivity", "com.swaglabsmobileapp.MainActivity"); - - SauceMobileOptions options = new SauceMobileOptions(appiumOptions); - String app = "https://github.com/saucelabs/sample-app-mobile/releases/download/2.3.0/Android.SauceLabs.Mobile.Sample.app.2.3.0.apk"; - options.setApp(app); - - session = new SauceMobileSession(options); - } - - @After - public void tearDown() { - session.stop(true); - } - - @Test - public void defaultsToLegacy() { - webDriver = session.start(); - - assertTrue(webDriver.getRemoteAddress().toString().contains("ondemand.saucelabs")); - } - - @Test - public void runsUSWest() { - session.setDataCenter(DataCenter.US_WEST); - webDriver = session.start(); - - assertTrue(webDriver.getRemoteAddress().toString().contains("us-west-1")); - } - - @Test - public void runsEUCentral() { - session.setDataCenter(DataCenter.EU_CENTRAL); - webDriver = session.start(); - - assertTrue(webDriver.getRemoteAddress().toString().contains("eu-central-1")); - } -} diff --git a/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimBrowserTest.java b/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimBrowserTest.java index f65a95c1..e933b3bf 100644 --- a/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimBrowserTest.java +++ b/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceEmuSimBrowserTest.java @@ -1,7 +1,6 @@ package com.saucelabs.saucebindings.acceptance; -import com.saucelabs.saucebindings.DataCenter; -import com.saucelabs.saucebindings.SauceMobileSession; +import com.saucelabs.saucebindings.*; import org.junit.After; import org.junit.Test; import org.openqa.selenium.remote.RemoteWebDriver; @@ -10,8 +9,8 @@ import static org.junit.Assert.assertTrue; public class SauceEmuSimBrowserTest { - private SauceMobileSession session = new SauceMobileSession(); - private RemoteWebDriver webDriver; + private SauceSession session = new SauceSession(); + private RemoteWebDriver driver; @After public void tearDown() { @@ -20,27 +19,38 @@ public void tearDown() { @Test public void defaultsToLegacy() { - webDriver = session.start(); + driver = session.start(); - assertNotNull(webDriver); + assertNotNull(driver); assertTrue(session.getSauceUrl().toString().contains("ondemand.saucelabs")); } @Test public void runsUSWest() { session.setDataCenter(DataCenter.US_WEST); - webDriver = session.start(); + driver = session.start(); - assertNotNull(webDriver); + assertNotNull(driver); assertTrue(session.getSauceUrl().toString().contains("us-west-1")); } @Test public void runsEUCentral() { session.setDataCenter(DataCenter.EU_CENTRAL); - webDriver = session.start(); + driver = session.start(); - assertNotNull(webDriver); + assertNotNull(driver); assertTrue(session.getSauceUrl().toString().contains("eu-central-1")); } + + @Test + public void androidEmulatorCase() { + SauceAndroidOptions options = new SauceAndroidOptions("Android Emulator", "9.0", DeviceOrientation.PORTRAIT); + options.setBrowserName(Browser.CHROME); + session = new SauceSession(options); + driver = session.start(); + + assertNotNull(driver); + assertTrue(session.getSauceUrl().toString().contains("us-west-1")); + } } diff --git a/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceRealDeviceBrowserTest.java b/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceRealDeviceBrowserTest.java index 0010cf91..de7adafa 100644 --- a/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceRealDeviceBrowserTest.java +++ b/java/src/test/java/com/saucelabs/saucebindings/acceptance/SauceRealDeviceBrowserTest.java @@ -3,16 +3,17 @@ import com.saucelabs.saucebindings.DataCenter; import com.saucelabs.saucebindings.SauceMobileOptions; import com.saucelabs.saucebindings.SauceMobileSession; +import com.saucelabs.saucebindings.SauceSession; import io.appium.java_client.AppiumDriver; import org.junit.After; import org.junit.Ignore; import org.junit.Test; +import org.openqa.selenium.remote.RemoteWebDriver; import static org.junit.Assert.assertTrue; public class SauceRealDeviceBrowserTest { - private SauceMobileSession session = new SauceMobileSession(); - private AppiumDriver webDriver; + private SauceSession session = new SauceMobileSession(); @After public void tearDown() { @@ -22,33 +23,29 @@ public void tearDown() { @Test public void runsUSMobile() { session.setDataCenter(DataCenter.US_MOBILE); - webDriver = session.start(); - assertTrue(webDriver.getRemoteAddress().toString().contains("us1.appium.testobject")); + assertTrue(session.getSauceUrl().toString().contains("us1.appium.testobject")); } @Test public void runsEUMobile() { session.setDataCenter(DataCenter.EU_MOBILE); - webDriver = session.start(); - assertTrue(webDriver.getRemoteAddress().toString().contains("eu1.appium.testobject")); + assertTrue(session.getSauceUrl().toString().contains("eu1.appium.testobject")); } @Test public void runsUSTestObject() { session.setDataCenter(DataCenter.US_TEST_OBJECT); - webDriver = session.start(); - assertTrue(webDriver.getRemoteAddress().toString().contains("us1-manual.app.testobject")); + assertTrue(session.getSauceUrl().toString().contains("us1-manual.app.testobject")); } @Test public void runsEUTestObject() { session.setDataCenter(DataCenter.EU_TEST_OBJECT); - webDriver = session.start(); - assertTrue(webDriver.getRemoteAddress().toString().contains("//appium.testobject")); + assertTrue(session.getSauceUrl().toString().contains("//appium.testobject")); } @Ignore @@ -57,8 +54,7 @@ public void runsUnifiedPlatform() { sauceMobileOptions.setDeviceName("Google Pixel XL Real"); session = new SauceMobileSession(sauceMobileOptions); session.setDataCenter(DataCenter.US_WEST); - webDriver = session.start(); - assertTrue(webDriver.getRemoteAddress().toString().contains("ondemand.saucelabs")); + assertTrue(session.getSauceUrl().toString().contains("ondemand.saucelabs")); } }