diff --git a/pom.xml b/pom.xml
index 86648582a..809cf807e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -38,6 +38,11 @@
cglib
3.1
+
+ commons-validator
+ commons-validator
+ 1.4.1
+
jar
java-client
@@ -65,6 +70,12 @@
https://github.com/jonahss
jonahss
+
+ tichomirovsergey@gmail.com
+ Sergey Tikhomirov
+ https://github.com/TikhomirovSergey
+ TikhomirovSergey
+
diff --git a/src/main/java/io/appium/java_client/AppiumDriver.java b/src/main/java/io/appium/java_client/AppiumDriver.java
index 76c565fad..aa06d33c7 100644
--- a/src/main/java/io/appium/java_client/AppiumDriver.java
+++ b/src/main/java/io/appium/java_client/AppiumDriver.java
@@ -46,6 +46,8 @@
import static io.appium.java_client.MobileCommand.SHAKE;
import static io.appium.java_client.MobileCommand.START_ACTIVITY;
import static io.appium.java_client.MobileCommand.TOGGLE_LOCATION_SERVICES;
+
+import io.appium.java_client.remote.AppiumCommandExecutor;
import io.appium.java_client.remote.MobileCapabilityType;
import java.net.URL;
@@ -55,6 +57,8 @@
import javax.xml.bind.DatatypeConverter;
+import io.appium.java_client.service.local.AppiumDriverLocalService;
+import io.appium.java_client.service.local.AppiumServiceBuilder;
import org.openqa.selenium.By;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.Dimension;
@@ -64,14 +68,7 @@
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.html5.Location;
-import org.openqa.selenium.remote.CommandInfo;
-import org.openqa.selenium.remote.DesiredCapabilities;
-import org.openqa.selenium.remote.DriverCommand;
-import org.openqa.selenium.remote.ErrorHandler;
-import org.openqa.selenium.remote.ExecuteMethod;
-import org.openqa.selenium.remote.HttpCommandExecutor;
-import org.openqa.selenium.remote.RemoteWebElement;
-import org.openqa.selenium.remote.Response;
+import org.openqa.selenium.remote.*;
import org.openqa.selenium.remote.html5.RemoteLocationContext;
import org.openqa.selenium.remote.http.HttpMethod;
@@ -197,76 +194,34 @@ protected static ImmutableMap getCommandImmutableMap(
return builder.build();
}
- public AppiumDriver(URL remoteAddress, Capabilities desiredCapabilities) {
+ private AppiumDriver(CommandExecutor executor, Capabilities capabilities){
+ super(executor, capabilities);
+ this.executeMethod = new AppiumExecutionMethod(this);
+ locationContext = new RemoteLocationContext(executeMethod);
+ super.setErrorHandler(errorHandler);
+ }
- super(remoteAddress, desiredCapabilities);
-
- this.executeMethod = new AppiumExecutionMethod(this);
- this.remoteAddress = remoteAddress;
- locationContext = new RemoteLocationContext(executeMethod);
-
- ImmutableMap.Builder builder = ImmutableMap
- .builder();
- builder.put(RESET, postC("/session/:sessionId/appium/app/reset"))
- .put(GET_STRINGS,
- postC("/session/:sessionId/appium/app/strings"))
- .put(KEY_EVENT,
- postC("/session/:sessionId/appium/device/keyevent"))
- .put(CURRENT_ACTIVITY,
- getC("/session/:sessionId/appium/device/current_activity"))
- .put(SET_VALUE,
- postC("/session/:sessionId/appium/element/:id/value"))
- .put(PULL_FILE,
- postC("/session/:sessionId/appium/device/pull_file"))
- .put(PULL_FOLDER,
- postC("/session/:sessionId/appium/device/pull_folder"))
- .put(HIDE_KEYBOARD,
- postC("/session/:sessionId/appium/device/hide_keyboard"))
- .put(PUSH_FILE,
- postC("/session/:sessionId/appium/device/push_file"))
- .put(RUN_APP_IN_BACKGROUND,
- postC("/session/:sessionId/appium/app/background"))
- .put(PERFORM_TOUCH_ACTION,
- postC("/session/:sessionId/touch/perform"))
- .put(PERFORM_MULTI_TOUCH,
- postC("/session/:sessionId/touch/multi/perform"))
- .put(IS_APP_INSTALLED,
- postC("/session/:sessionId/appium/device/app_installed"))
- .put(INSTALL_APP,
- postC("/session/:sessionId/appium/device/install_app"))
- .put(REMOVE_APP,
- postC("/session/:sessionId/appium/device/remove_app"))
- .put(LAUNCH_APP, postC("/session/:sessionId/appium/app/launch"))
- .put(CLOSE_APP, postC("/session/:sessionId/appium/app/close"))
- .put(END_TEST_COVERAGE,
- postC("/session/:sessionId/appium/app/end_test_coverage"))
- .put(LOCK, postC("/session/:sessionId/appium/device/lock"))
- .put(IS_LOCKED,
- postC("/session/:sessionId/appium/device/is_locked"))
- .put(SHAKE, postC("/session/:sessionId/appium/device/shake"))
- .put(COMPLEX_FIND,
- postC("/session/:sessionId/appium/app/complex_find"))
- .put(OPEN_NOTIFICATIONS,
- postC("/session/:sessionId/appium/device/open_notifications"))
- .put(GET_NETWORK_CONNECTION,
- getC("/session/:sessionId/network_connection"))
- .put(SET_NETWORK_CONNECTION,
- postC("/session/:sessionId/network_connection"))
- .put(GET_SETTINGS, getC("/session/:sessionId/appium/settings"))
- .put(SET_SETTINGS, postC("/session/:sessionId/appium/settings"))
- .put(START_ACTIVITY,
- postC("/session/:sessionId/appium/device/start_activity"))
- .put(TOGGLE_LOCATION_SERVICES, postC("/session/:sessionId/appium/device/toggle_location_services"));
-
- ImmutableMap mobileCommands = builder.build();
-
- HttpCommandExecutor mobileExecutor = new HttpCommandExecutor(
- mobileCommands, remoteAddress);
- super.setCommandExecutor(mobileExecutor);
-
- super.setErrorHandler(errorHandler);
+ public AppiumDriver(URL remoteAddress, Capabilities desiredCapabilities) {
+ this(new AppiumCommandExecutor(
+ getMobileCommands(), remoteAddress), desiredCapabilities);
+ this.remoteAddress = remoteAddress;
}
+ public AppiumDriver(AppiumDriverLocalService service, Capabilities desiredCapabilities) {
+ this(new AppiumCommandExecutor(
+ getMobileCommands(), service), desiredCapabilities);
+ this.remoteAddress = service.getUrl();
+ }
+
+ public AppiumDriver(AppiumServiceBuilder builder, Capabilities desiredCapabilities) {
+ this(builder.build(), desiredCapabilities);
+ }
+
+ public AppiumDriver(Capabilities desiredCapabilities) {
+ this(AppiumDriverLocalService.buildDefaultService(), desiredCapabilities);
+ }
+
+
@Override
protected Response execute(String command) {
return super.execute(command, ImmutableMap.of());
@@ -708,6 +663,63 @@ private static CommandInfo postC(String url) {
return new CommandInfo(url, HttpMethod.POST);
}
+ private static ImmutableMap getMobileCommands(){
+ ImmutableMap.Builder builder = ImmutableMap
+ .builder();
+ builder.put(RESET, postC("/session/:sessionId/appium/app/reset"))
+ .put(GET_STRINGS,
+ postC("/session/:sessionId/appium/app/strings"))
+ .put(KEY_EVENT,
+ postC("/session/:sessionId/appium/device/keyevent"))
+ .put(CURRENT_ACTIVITY,
+ getC("/session/:sessionId/appium/device/current_activity"))
+ .put(SET_VALUE,
+ postC("/session/:sessionId/appium/element/:id/value"))
+ .put(PULL_FILE,
+ postC("/session/:sessionId/appium/device/pull_file"))
+ .put(PULL_FOLDER,
+ postC("/session/:sessionId/appium/device/pull_folder"))
+ .put(HIDE_KEYBOARD,
+ postC("/session/:sessionId/appium/device/hide_keyboard"))
+ .put(PUSH_FILE,
+ postC("/session/:sessionId/appium/device/push_file"))
+ .put(RUN_APP_IN_BACKGROUND,
+ postC("/session/:sessionId/appium/app/background"))
+ .put(PERFORM_TOUCH_ACTION,
+ postC("/session/:sessionId/touch/perform"))
+ .put(PERFORM_MULTI_TOUCH,
+ postC("/session/:sessionId/touch/multi/perform"))
+ .put(IS_APP_INSTALLED,
+ postC("/session/:sessionId/appium/device/app_installed"))
+ .put(INSTALL_APP,
+ postC("/session/:sessionId/appium/device/install_app"))
+ .put(REMOVE_APP,
+ postC("/session/:sessionId/appium/device/remove_app"))
+ .put(LAUNCH_APP, postC("/session/:sessionId/appium/app/launch"))
+ .put(CLOSE_APP, postC("/session/:sessionId/appium/app/close"))
+ .put(END_TEST_COVERAGE,
+ postC("/session/:sessionId/appium/app/end_test_coverage"))
+ .put(LOCK, postC("/session/:sessionId/appium/device/lock"))
+ .put(IS_LOCKED,
+ postC("/session/:sessionId/appium/device/is_locked"))
+ .put(SHAKE, postC("/session/:sessionId/appium/device/shake"))
+ .put(COMPLEX_FIND,
+ postC("/session/:sessionId/appium/app/complex_find"))
+ .put(OPEN_NOTIFICATIONS,
+ postC("/session/:sessionId/appium/device/open_notifications"))
+ .put(GET_NETWORK_CONNECTION,
+ getC("/session/:sessionId/network_connection"))
+ .put(SET_NETWORK_CONNECTION,
+ postC("/session/:sessionId/network_connection"))
+ .put(GET_SETTINGS, getC("/session/:sessionId/appium/settings"))
+ .put(SET_SETTINGS, postC("/session/:sessionId/appium/settings"))
+ .put(START_ACTIVITY,
+ postC("/session/:sessionId/appium/device/start_activity"))
+ .put(TOGGLE_LOCATION_SERVICES, postC("/session/:sessionId/appium/device/toggle_location_services"));
+
+ return builder.build();
+ }
+
@SuppressWarnings("unused")
private static CommandInfo deleteC(String url) {
return new CommandInfo(url, HttpMethod.DELETE);
diff --git a/src/main/java/io/appium/java_client/DefaultGenericMobileDriver.java b/src/main/java/io/appium/java_client/DefaultGenericMobileDriver.java
index 767ca47f0..777031dd8 100644
--- a/src/main/java/io/appium/java_client/DefaultGenericMobileDriver.java
+++ b/src/main/java/io/appium/java_client/DefaultGenericMobileDriver.java
@@ -6,10 +6,10 @@
import org.openqa.selenium.By;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.WebElement;
+import org.openqa.selenium.remote.CommandExecutor;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.remote.Response;
-import java.net.URL;
import java.util.List;
import java.util.Map;
@@ -18,8 +18,8 @@ abstract class DefaultGenericMobileDriver extends RemoteWe
GenericSearchContext, GenericFindsById, GenericFindsByXPath, GenericFindsByLinkText, GenericFindsByTagName,
GenericFindsByClassName, GenericFindsByCssSelector, GenericFindsByName{
- public DefaultGenericMobileDriver(URL remoteAddress, Capabilities desiredCapabilities) {
- super(remoteAddress, desiredCapabilities);
+ public DefaultGenericMobileDriver(CommandExecutor executor, Capabilities desiredCapabilities){
+ super(executor, desiredCapabilities);
}
@Override
diff --git a/src/main/java/io/appium/java_client/android/AndroidDriver.java b/src/main/java/io/appium/java_client/android/AndroidDriver.java
index d05c971d4..8548b5072 100644
--- a/src/main/java/io/appium/java_client/android/AndroidDriver.java
+++ b/src/main/java/io/appium/java_client/android/AndroidDriver.java
@@ -9,6 +9,8 @@
import io.appium.java_client.android.internal.JsonToAndroidElementConverter;
import io.appium.java_client.remote.MobilePlatform;
+import io.appium.java_client.service.local.AppiumDriverLocalService;
+import io.appium.java_client.service.local.AppiumServiceBuilder;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.Response;
@@ -51,6 +53,24 @@ public AndroidDriver(URL remoteAddress, Capabilities desiredCapabilities) {
this.setElementConverter(new JsonToAndroidElementConverter(this));
}
+ public AndroidDriver(AppiumDriverLocalService service, Capabilities desiredCapabilities) {
+ super(service, substituteMobilePlatform(desiredCapabilities,
+ ANDROID_PLATFORM));
+ this.setElementConverter(new JsonToAndroidElementConverter(this));
+ }
+
+ public AndroidDriver(AppiumServiceBuilder builder, Capabilities desiredCapabilities) {
+ super(builder, substituteMobilePlatform(desiredCapabilities,
+ ANDROID_PLATFORM));
+ this.setElementConverter(new JsonToAndroidElementConverter(this));
+ }
+
+ public AndroidDriver(Capabilities desiredCapabilities) {
+ super(substituteMobilePlatform(desiredCapabilities,
+ ANDROID_PLATFORM));
+ this.setElementConverter(new JsonToAndroidElementConverter(this));
+ }
+
/**
* Scroll forward to the element which has a description or name which contains the input text.
* The scrolling is performed on the first scrollView present on the UI
diff --git a/src/main/java/io/appium/java_client/ios/IOSDriver.java b/src/main/java/io/appium/java_client/ios/IOSDriver.java
index f122ee0a5..79d327810 100644
--- a/src/main/java/io/appium/java_client/ios/IOSDriver.java
+++ b/src/main/java/io/appium/java_client/ios/IOSDriver.java
@@ -9,6 +9,8 @@
import io.appium.java_client.ios.internal.JsonToIOSElementConverter;
import io.appium.java_client.remote.MobilePlatform;
+import io.appium.java_client.service.local.AppiumDriverLocalService;
+import io.appium.java_client.service.local.AppiumServiceBuilder;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.WebElement;
@@ -36,7 +38,25 @@ public IOSDriver(URL remoteAddress, Capabilities desiredCapabilities) {
super(remoteAddress, substituteMobilePlatform(desiredCapabilities,
IOS_PLATFORM));
this.setElementConverter(new JsonToIOSElementConverter(this));
- }
+ }
+
+ public IOSDriver(AppiumDriverLocalService service, Capabilities desiredCapabilities) {
+ super(service, substituteMobilePlatform(desiredCapabilities,
+ IOS_PLATFORM));
+ this.setElementConverter(new JsonToIOSElementConverter(this));
+ }
+
+ public IOSDriver(AppiumServiceBuilder builder, Capabilities desiredCapabilities) {
+ super(builder, substituteMobilePlatform(desiredCapabilities,
+ IOS_PLATFORM));
+ this.setElementConverter(new JsonToIOSElementConverter(this));
+ }
+
+ public IOSDriver(Capabilities desiredCapabilities) {
+ super(substituteMobilePlatform(desiredCapabilities,
+ IOS_PLATFORM));
+ this.setElementConverter(new JsonToIOSElementConverter(this));
+ }
/**
* Scroll to the element whose 'text' attribute contains the input text.
@@ -44,7 +64,7 @@ public IOSDriver(URL remoteAddress, Capabilities desiredCapabilities) {
* @param text input text contained in text attribute
*/
@SuppressWarnings("unchecked")
-@Override
+ @Override
public RequiredElementType scrollTo(String text) {
return (RequiredElementType) ((ScrollsTo>)
findElementByClassName("UIATableView")).scrollTo(text);
@@ -56,7 +76,7 @@ public RequiredElementType scrollTo(String text) {
* @param text input text to match
*/
@SuppressWarnings("unchecked")
-@Override
+ @Override
public RequiredElementType scrollToExact(String text) {
return (RequiredElementType) ((ScrollsTo>)
findElementByClassName("UIATableView")).scrollToExact(text);
diff --git a/src/main/java/io/appium/java_client/remote/AppiumCommandExecutor.java b/src/main/java/io/appium/java_client/remote/AppiumCommandExecutor.java
new file mode 100644
index 000000000..633f34028
--- /dev/null
+++ b/src/main/java/io/appium/java_client/remote/AppiumCommandExecutor.java
@@ -0,0 +1,56 @@
+package io.appium.java_client.remote;
+
+
+import com.google.common.base.Throwables;
+import org.openqa.selenium.WebDriverException;
+import org.openqa.selenium.remote.*;
+import org.openqa.selenium.remote.http.HttpClient;
+import org.openqa.selenium.remote.service.DriverService;
+
+import java.io.IOException;
+import java.net.ConnectException;
+import java.net.URL;
+import java.util.Map;
+
+public class AppiumCommandExecutor extends HttpCommandExecutor{
+
+ private final DriverService service;
+
+ public AppiumCommandExecutor(Map additionalCommands, URL addressOfRemoteServer) {
+ super(additionalCommands, addressOfRemoteServer);
+ service = null;
+ }
+
+ public AppiumCommandExecutor(Map additionalCommands, DriverService service) {
+ super(additionalCommands, service.getUrl());
+ this.service = service;
+ }
+
+ @Override
+ public Response execute(Command command) throws IOException, WebDriverException {
+ if (DriverCommand.NEW_SESSION.equals(command.getName()) && service != null) {
+ service.start();
+ }
+
+ try {
+ return super.execute(command);
+ } catch (Throwable t) {
+ Throwable rootCause = Throwables.getRootCause(t);
+ if (rootCause instanceof ConnectException &&
+ rootCause.getMessage().contains("Connection refused") && service != null){
+ if (service.isRunning())
+ throw new WebDriverException("The session is closed!", t);
+
+ if (!service.isRunning())
+ throw new WebDriverException("The appium server has accidentally died!", t);
+ }
+ Throwables.propagateIfPossible(t);
+ throw new WebDriverException(t);
+ } finally {
+ if (DriverCommand.QUIT.equals(command.getName()) && service != null) {
+ service.stop();
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/io/appium/java_client/service/local/AppiumDriverLocalService.java b/src/main/java/io/appium/java_client/service/local/AppiumDriverLocalService.java
new file mode 100644
index 000000000..5890ea88e
--- /dev/null
+++ b/src/main/java/io/appium/java_client/service/local/AppiumDriverLocalService.java
@@ -0,0 +1,147 @@
+package io.appium.java_client.service.local;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import org.apache.commons.lang3.StringUtils;
+import org.openqa.selenium.net.UrlChecker;
+import org.openqa.selenium.os.CommandLine;
+import org.openqa.selenium.remote.service.DriverService;
+
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.concurrent.TimeUnit;
+
+
+public final class AppiumDriverLocalService extends DriverService {
+
+ private static final String URL_MASK = "http://%s:%d/wd/hub";
+ private final File nodeJSExec;
+ private final int nodeJSPort;
+ private final ImmutableList nodeJSArgs;
+ private final ImmutableMap nodeJSEnvironment;
+ private final String ipAddress;
+ private final long startupTimeout;
+ private final TimeUnit timeUnit;
+
+
+ private CommandLine process = null;
+
+ AppiumDriverLocalService(String ipAddress, File nodeJSExec, int nodeJSPort,
+ ImmutableList nodeJSArgs,
+ ImmutableMap nodeJSEnvironment,
+ long startupTimeout,
+ TimeUnit timeUnit) throws IOException {
+ super(nodeJSExec, nodeJSPort, nodeJSArgs, nodeJSEnvironment);
+ this.ipAddress = ipAddress;
+ this.nodeJSExec = nodeJSExec;
+ this.nodeJSPort = nodeJSPort;
+ this.nodeJSArgs = nodeJSArgs;
+ this.nodeJSEnvironment = nodeJSEnvironment;
+ this.startupTimeout = startupTimeout;
+ this.timeUnit = timeUnit;
+ }
+
+ /**
+ * @return The base URL for the managed appium server.
+ */
+ @Override
+ public URL getUrl() {
+ try {
+ return new URL(String.format(URL_MASK, ipAddress,
+ nodeJSPort));
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public boolean isRunning() {
+ if (process == null)
+ return false;
+
+ try {
+ ping(500, TimeUnit.MILLISECONDS);
+ return true;
+ } catch (UrlChecker.TimeoutException e) {
+ return false;
+ }
+
+ }
+
+ private void ping(long time, TimeUnit timeUnit) throws UrlChecker.TimeoutException{
+ URL url = getUrl();
+ try {
+ URL status = new URL(url.toString() + "/status");
+ new UrlChecker().waitUntilAvailable(time, timeUnit, status);
+ } catch (MalformedURLException e) {
+ throw new RuntimeException("There is something wrong with the URL " + url.toString().toString() + "/status");
+ }
+ }
+
+ /**
+ * Starts the defined appium server
+ * @throws AppiumServerHasNotBeenStartedLocallyException If an error occurs while spawning the child process.
+ * @see #stop()
+ */
+ public synchronized void start() throws AppiumServerHasNotBeenStartedLocallyException {
+
+ if (isRunning())
+ return;
+
+ try {
+ process = new CommandLine(this.nodeJSExec.getCanonicalPath(), nodeJSArgs.toArray(new String[] {}));
+ process.setEnvironmentVariables(nodeJSEnvironment);
+ process.copyOutputTo(System.err);
+ process.executeAsync();
+ ping(startupTimeout, timeUnit);
+ } catch (Throwable e) {
+ destroyProcess();
+ String msgTxt = "The local appium server has not been started. " +
+ "The given Node.js executable: " + this.nodeJSExec.getAbsolutePath() + " Arguments: " + nodeJSArgs.toString() + " " + "\n";
+ String processStream = process.getStdOut();
+ if (!StringUtils.isBlank(processStream))
+ msgTxt = msgTxt + "Process output: " + processStream + "\n";
+
+ throw new AppiumServerHasNotBeenStartedLocallyException(msgTxt,
+ e);
+ }
+ }
+
+ /**
+ * Stops this service is it is currently running. This method will attempt to block until the
+ * server has been fully shutdown.
+ *
+ * @see #start()
+ */
+ @Override
+ public synchronized void stop() {
+ destroyProcess();
+ }
+
+
+ private void destroyProcess(){
+ if (process != null)
+ process.destroy();
+ }
+
+ /**
+ * @return String logs if the server has been run.
+ * null is returned otherwise.
+ */
+ public String getStdOut() {
+ if (process != null)
+ return process.getStdOut();
+
+ return null;
+ }
+
+ public static AppiumDriverLocalService buildDefaultService(){
+ return buildService(new AppiumServiceBuilder());
+ }
+
+ public static AppiumDriverLocalService buildService(AppiumServiceBuilder builder){
+ return builder.build();
+ }
+
+}
diff --git a/src/main/java/io/appium/java_client/service/local/AppiumServerHasNotBeenStartedLocallyException.java b/src/main/java/io/appium/java_client/service/local/AppiumServerHasNotBeenStartedLocallyException.java
new file mode 100644
index 000000000..b5b46a146
--- /dev/null
+++ b/src/main/java/io/appium/java_client/service/local/AppiumServerHasNotBeenStartedLocallyException.java
@@ -0,0 +1,13 @@
+package io.appium.java_client.service.local;
+
+
+public class AppiumServerHasNotBeenStartedLocallyException extends RuntimeException{
+
+ public AppiumServerHasNotBeenStartedLocallyException(String messege, Throwable t){
+ super(messege, t);
+ }
+
+ public AppiumServerHasNotBeenStartedLocallyException(String messege){
+ super(messege);
+ }
+}
diff --git a/src/main/java/io/appium/java_client/service/local/AppiumServiceBuilder.java b/src/main/java/io/appium/java_client/service/local/AppiumServiceBuilder.java
new file mode 100644
index 000000000..35a1a5565
--- /dev/null
+++ b/src/main/java/io/appium/java_client/service/local/AppiumServiceBuilder.java
@@ -0,0 +1,307 @@
+package io.appium.java_client.service.local;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import io.appium.java_client.service.local.flags.ServerArgument;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.validator.routines.InetAddressValidator;
+import org.openqa.selenium.Platform;
+import org.openqa.selenium.remote.service.DriverService;
+
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+
+public final class AppiumServiceBuilder extends DriverService.Builder {
+
+ private static final String NODE_MODULES_FOLDER = "node_modules";
+ private static final String APPIUM_FOLDER = "appium";
+ private static final String BIN_FOLDER = "bin";
+ private static final String APPIUM_JS = "appium.js";
+ private static final String APPIUM_NODE_MASK = File.separator +
+ APPIUM_FOLDER + File.separator + BIN_FOLDER + File.separator + APPIUM_JS;
+
+ public static final String APPIUM_NODE_PROPERTY = "appium.node.path";
+ public static final String DEFAULT_LOCAL_IP_ADDRESS = "0.0.0.0";
+
+ private static final int DEFAULT_APPIUM_PORT = 4723;
+
+ private final static String COMMAND_WHICH_EXTRACTS_DEFAULT_PATH_TO_APPIUM = "npm -g ls --depth=0";
+ private final static String COMMAND_WHICH_EXTRACTS_DEFAULT_PATH_TO_APPIUM_WIN = "npm.cmd -g ls --depth=0";
+
+ private static final int REQUIRED_MAJOR_NODE_JS = 0;
+ private static final int REQUIRED_MINOR_NODE_JS = 0;
+
+ final Map serverArguments = new HashMap<>();
+ private File appiumJS;
+ private String ipAddress = DEFAULT_LOCAL_IP_ADDRESS;
+
+ //The first starting is slow sometimes on some
+ //environment
+ private long startupTimeout = 120;
+ private TimeUnit timeUnit = TimeUnit.SECONDS;
+
+
+ private static String returnCommandThatSearchesForDefaultNode(){
+ if (Platform.getCurrent().is(Platform.WINDOWS))
+ return COMMAND_WHICH_EXTRACTS_DEFAULT_PATH_TO_APPIUM_WIN;
+ return COMMAND_WHICH_EXTRACTS_DEFAULT_PATH_TO_APPIUM;
+ }
+
+ private static String getProcessOutput(InputStream stream ) throws IOException {
+ BufferedReader reader = new BufferedReader(
+ new InputStreamReader(stream));
+ String result = reader.readLine();
+ reader.close();
+ return result;
+ }
+
+ private static void validateNodeJSVersion(){
+ Runtime rt = Runtime.getRuntime();
+ String result = null;
+ try {
+ Process p = rt.exec("node -v");
+ p.waitFor();
+ result = getProcessOutput(p.getInputStream());
+ } catch (Exception e) {
+ throw new InvalidNodeJSInstance("Node.js is not installed", e);
+ }
+ String versionNum = result.replace("v","");
+ String[] tokens = versionNum.split("\\.");
+ if (Integer.parseInt(tokens[0]) < REQUIRED_MAJOR_NODE_JS ||
+ Integer.parseInt(tokens[1]) < REQUIRED_MINOR_NODE_JS)
+ throw new InvalidNodeJSInstance("Current node.js version " + versionNum + "is lower than " +
+ "required (" + REQUIRED_MAJOR_NODE_JS + "." + REQUIRED_MINOR_NODE_JS + " or greater)");
+ }
+
+ private static File findNodeInCurrentFileSystem(){
+ Runtime rt = Runtime.getRuntime();
+ String instancePath;
+ try {
+ Process p = rt.exec(returnCommandThatSearchesForDefaultNode());
+ p.waitFor();
+ instancePath = getProcessOutput(p.getInputStream());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ File result;
+ if (StringUtils.isBlank(instancePath) || !(result = new File(instancePath + File.separator + NODE_MODULES_FOLDER +
+ APPIUM_NODE_MASK)).exists())
+ throw new InvalidServerInstanceException( "There is no installed nodes! Please install " +
+ " node via NPM (https://www.npmjs.com/package/appium#using-node-js) or download and " +
+ "install Appium app (http://appium.io/downloads.html)",
+ new IOException("The installed appium node package has not been found."));
+
+ return result;
+ }
+
+ private static void validateNodeStructure(File node){
+ String absoluteNodePath = node.getAbsolutePath();
+
+ if (!node.exists())
+ throw new InvalidServerInstanceException("The invalid appium node " + absoluteNodePath + " has been defined",
+ new IOException("The node " + absoluteNodePath + "doesn't exist"));
+
+ if (!absoluteNodePath.endsWith(APPIUM_NODE_MASK))
+ throw new InvalidServerInstanceException("It is probably there is the corrupted appium server installation. Path " +
+ absoluteNodePath + "doesn't match " + APPIUM_NODE_MASK);
+ }
+
+ public AppiumServiceBuilder() {
+ usingPort(DEFAULT_APPIUM_PORT);
+ }
+
+ @Override
+ protected File findDefaultExecutable() {
+ validateNodeJSVersion();
+ Runtime rt = Runtime.getRuntime();
+ Process p;
+ try {
+ p = rt.exec("node");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ OutputStream outputStream = p.getOutputStream();
+ PrintStream out = new PrintStream(outputStream) ;
+ out.println("console.log(process.execPath);") ;
+ out.close();
+
+ try {
+ return new File(getProcessOutput(p.getInputStream()));
+ }
+ catch (Throwable t){
+ throw new RuntimeException(t);
+ }
+ }
+
+ /**
+ * Boolean arguments have a special moment:
+ * the presence of an arguments means "true". This method
+ * was designed for these cases
+ * @param argument is an instance which contains the argument name
+ * @return the self-reference
+ */
+ public AppiumServiceBuilder withArgument(ServerArgument argument) {
+ serverArguments.put(argument.getArgument(), "");
+ return this;
+ }
+
+ /**
+ *
+ * @param argument is an instance which contains the argument name
+ * @param value A non null string value. (Warn!!!) Boolean arguments have a special moment:
+ * the presence of an arguments means "true". At this case an empty string
+ * should be defined
+ * @return the self-reference
+ */
+ public AppiumServiceBuilder withArgument(ServerArgument argument, String value){
+ serverArguments.put(argument.getArgument(), value);
+ return this;
+ }
+
+ public AppiumServiceBuilder withAppiumJS(File appiumJS){
+ this.appiumJS = appiumJS;
+ return this;
+ }
+
+ public AppiumServiceBuilder withIPAddress(String ipAddress){
+ this.ipAddress = ipAddress;
+ return this;
+ }
+
+ public AppiumServiceBuilder withStartUpTimeOut(long time, TimeUnit timeUnit){
+ checkNotNull(timeUnit);
+ checkArgument(time > 0, "Time value should be greater than zero", time);
+ this.startupTimeout = time;
+ this.timeUnit = timeUnit;
+ return this;
+ }
+
+
+ void checkAppiumJS(){
+ if (appiumJS != null){
+ validateNodeStructure(appiumJS);
+ return;
+ }
+
+ String appiumJS = System.getProperty(APPIUM_NODE_PROPERTY);
+ if (appiumJS !=null){
+ File node = new File(appiumJS);
+ validateNodeStructure(node);
+ this.appiumJS = node;
+ return;
+ }
+
+ this.appiumJS = findNodeInCurrentFileSystem();
+ }
+
+ @Override
+ protected ImmutableList createArgs() {
+ List argList = new ArrayList<>();
+ checkAppiumJS();
+ argList.add(appiumJS.getAbsolutePath());
+ argList.add("--port");
+ argList.add(String.valueOf(getPort()));
+
+ if (StringUtils.isBlank(ipAddress))
+ ipAddress = DEFAULT_LOCAL_IP_ADDRESS;
+ else {
+ InetAddressValidator validator = InetAddressValidator.getInstance();
+ if (!validator.isValid(ipAddress) && !validator.isValidInet4Address(ipAddress) &&
+ !validator.isValidInet6Address(ipAddress))
+ throw new IllegalArgumentException("The invalid IP address " + ipAddress + " is defined");
+ }
+ argList.add("--address");
+ argList.add(ipAddress);
+
+ File log = getLogFile();
+ if (log != null){
+ argList.add("--log");
+ argList.add(log.getAbsolutePath());
+ }
+
+ Set> entries = serverArguments.entrySet();
+ Iterator> iterator = entries.iterator();
+ while (iterator.hasNext()){
+ Map.Entry entry = iterator.next();
+ String argument = entry.getKey();
+ String value = entry.getValue();
+ if (StringUtils.isBlank(argument) || StringUtils.isBlank(value))
+ continue;
+
+ argList.add(argument);
+ argList.add(value);
+ }
+
+ ImmutableList result = new ImmutableList.Builder().addAll(argList).build();
+ return result;
+ }
+
+ /**
+ * Sets which Node.js the builder will use.
+ *
+ * @param nodeJSExecutable The executable Node.js to use.
+ * @return A self reference.
+ */
+ public AppiumServiceBuilder usingDriverExecutable(File nodeJSExecutable) {
+ return super.usingDriverExecutable(nodeJSExecutable);
+ }
+
+ /**
+ * Sets which port the appium server should be started on. A value of 0 indicates that any
+ * free port may be used.
+ *
+ * @param port The port to use; must be non-negative.
+ * @return A self reference.
+ */
+ public AppiumServiceBuilder usingPort(int port) {
+ return super.usingPort(port);
+ }
+
+ /**
+ * Configures the appium server to start on any available port.
+ *
+ * @return A self reference.
+ */
+ public AppiumServiceBuilder usingAnyFreePort() {
+ return super.usingAnyFreePort();
+ }
+
+ /**
+ * Defines the environment for the launched appium server.
+ *
+ * @param environment A map of the environment variables to launch the
+ * appium server with.
+ * @return A self reference.
+ */
+ @Override
+ public AppiumServiceBuilder withEnvironment(Map environment) {
+ return super.withEnvironment(environment);
+ }
+
+ /**
+ * Configures the appium server to write log to the given file.
+ *
+ * @param logFile A file to write log to.
+ * @return A self reference.
+ */
+ public AppiumServiceBuilder withLogFile(File logFile) {
+ return super.withLogFile(logFile);
+ }
+
+ @Override
+ protected AppiumDriverLocalService createDriverService(File nodeJSExecutable, int nodeJSPort, ImmutableList nodeArguments,
+ ImmutableMap nodeEnvironment) {
+ try {
+ return new AppiumDriverLocalService(ipAddress, nodeJSExecutable, nodeJSPort, nodeArguments, nodeEnvironment,
+ startupTimeout, timeUnit);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/main/java/io/appium/java_client/service/local/InvalidNodeJSInstance.java b/src/main/java/io/appium/java_client/service/local/InvalidNodeJSInstance.java
new file mode 100644
index 000000000..3b17a9231
--- /dev/null
+++ b/src/main/java/io/appium/java_client/service/local/InvalidNodeJSInstance.java
@@ -0,0 +1,11 @@
+package io.appium.java_client.service.local;
+
+public class InvalidNodeJSInstance extends RuntimeException{
+ public InvalidNodeJSInstance(String message){
+ super(message);
+ }
+
+ public InvalidNodeJSInstance(String message, Throwable t){
+ super(message, t);
+ }
+}
diff --git a/src/main/java/io/appium/java_client/service/local/InvalidServerInstanceException.java b/src/main/java/io/appium/java_client/service/local/InvalidServerInstanceException.java
new file mode 100644
index 000000000..acfbdd338
--- /dev/null
+++ b/src/main/java/io/appium/java_client/service/local/InvalidServerInstanceException.java
@@ -0,0 +1,15 @@
+package io.appium.java_client.service.local;
+
+
+public class InvalidServerInstanceException extends RuntimeException {
+
+ private static String MESSAGE_PREFIX = "Invalid server instance exception has occured: ";
+
+ public InvalidServerInstanceException(String messege, Throwable t){
+ super(MESSAGE_PREFIX + messege, t);
+ }
+
+ public InvalidServerInstanceException(String messege){
+ super(MESSAGE_PREFIX + messege);
+ }
+}
diff --git a/src/main/java/io/appium/java_client/service/local/flags/AndroidServerFlag.java b/src/main/java/io/appium/java_client/service/local/flags/AndroidServerFlag.java
new file mode 100644
index 000000000..2e43b28ef
--- /dev/null
+++ b/src/main/java/io/appium/java_client/service/local/flags/AndroidServerFlag.java
@@ -0,0 +1,154 @@
+package io.appium.java_client.service.local.flags;
+
+/**
+* Here is the list of Android specific server arguments.
+* All flags are optional, but some are required in conjunction with certain others.
+* The full list is available here: {@link http://appium.io/slate/en/master/?ruby#appium-server-arguments}
+* Android specific arguments are marked by (Android-only)
+*/
+public enum AndroidServerFlag implements ServerArgument{
+ /**
+ * Port to use on device to talk to Appium
+ * Sample:
+ * --bootstrap-port 4724
+ */
+ BOOTSTRAP_PORT_NUMBER("--bootstrap-port"),
+ /**
+ * Java package of the Android app you want to run (e.g.,
+ * com.example.android.MyApp)
+ * Sample:
+ * --app-pkg com.example.android.MyApp
+ */
+ PACKAGE("--app-pkg"),
+ /**
+ * Activity name for the Android activity you want to launch
+ * from your package (e.g., MainActivity)
+ * Sample:
+ * --app-activity MainActivity
+ */
+ ACTIVITY("--app-activity"),
+ /**
+ * Package name for the Android activity you want to wait for
+ * (e.g., com.example.android.MyApp)
+ * Sample:
+ * --app-wait-package com.example.android.MyApp
+ */
+ APP_WAIT_PACKAGE("--app-wait-package"),
+ /**
+ * Activity name for the Android activity you want to wait
+ * for (e.g., SplashActivity)
+ * Sample:
+ * --app-wait-activity SplashActivity
+ */
+ APP_WAIT_ACTIVITY("--app-wait-activity"),
+ /**
+ * Fully qualified instrumentation class.
+ * Passed to -w in adb shell am instrument -e coverage true -w
+ * Sample:
+ * --android-coverage com.my.Pkg/com.my.Pkg.instrumentation.MyInstrumentation
+ */
+ ANDROID_COVERAGE("--android-coverage"),
+ /**
+ * Name of the avd to launch
+ * Sample:
+ * --avd @default
+ */
+ AVD("--avd"),
+ /**
+ * Additional emulator arguments to launch the avd
+ * Sample:
+ * --avd-args -no-snapshot-load
+ */
+ AVD_ARGS("--avg-args"),
+ /**
+ * Timeout in seconds while waiting for device to become
+ * ready
+ * Sample:
+ * --device-ready-timeout 5
+ */
+ DEVICE_READY_TIMEOUT("--device-ready-timeout"),
+ /**
+ * Local port used for communication with Selendroid
+ * Sample:
+ * --selendroid-port 8080
+ */
+ SELENDROID_PORT("--selendroid-port"),
+ /**
+ * When set the keystore will be used to sign apks.
+ * Default: false
+ */
+ USE_KEY_STORE("--use-keystore"),
+ /**
+ * Path to keystore
+ * Sample:
+ * --keystore-path /Users/user/.android/debug.keystore
+ */
+ KEY_STORE_PATH("--keystore-path"),
+ /**
+ * Password to keystore
+ * Default: android
+ */
+ KEY_STORE_PASSWORD("--keystore-password"),
+ /**
+ * Key alias
+ * Default: androiddebugkey
+ */
+ KEY_ALIAS("--key-alias"),
+ /**
+ * Key password
+ * Default: android
+ */
+ KEY_PASSWORD("--key-password"),
+ /**
+ * Intent action which will be used to start activity
+ * Default: android.intent.action.MAIN
+ * Sample:
+ * --intent-action android.intent.action.MAIN
+ */
+ INTENT_ACTION("--intent-action"),
+ /**
+ * Intent category which will be used to start activity
+ * Default: android.intent.category.LAUNCHER
+ * Sample:
+ * --intent-category android.intent.category.APP_CONTACTS
+ */
+ INTENT_CATEGORY("--intent-category"),
+ /**
+ * Flags that will be used to start activity
+ * Default: 0x10200000
+ * Sample:
+ * --intent-flags 0x10200000
+ */
+ INTENT_FLAGS("--intent-flags"),
+ /**
+ * Additional intent arguments that will be used to start
+ * activity
+ * Default: null
+ * Sample:
+ * --intent-args 0x10200000
+ */
+ INTENT_ARGUMENTS("--intent-args"),
+ /**
+ * When included, refrains from stopping the app before
+ * restart
+ * Default: false
+ */
+ DO_NOT_STOP_APP_ON_RESET("--dont-stop-app-on-reset"),
+ /**
+ * If set, prevents Appium from killing the adb server
+ * instance
+ * Default: false
+ */
+ SUPPRESS_ADB_KILL_SERVER("--suppress-adb-kill-server");
+
+ private final String arg;
+
+ private AndroidServerFlag(String arg) {
+ this.arg = arg;
+ }
+
+ @Override
+ public String getArgument() {
+ return arg;
+ }
+}
diff --git a/src/main/java/io/appium/java_client/service/local/flags/GeneralServerFlag.java b/src/main/java/io/appium/java_client/service/local/flags/GeneralServerFlag.java
new file mode 100644
index 000000000..c901627ba
--- /dev/null
+++ b/src/main/java/io/appium/java_client/service/local/flags/GeneralServerFlag.java
@@ -0,0 +1,194 @@
+package io.appium.java_client.service.local.flags;
+
+/**
+ * Here is the list of common Appium server arguments.
+ * All flags are optional, but some are required in conjunction with certain others.
+ * The full list is available here: {@link http://appium.io/slate/en/master/?ruby#appium-server-arguments}
+ */
+public enum GeneralServerFlag implements ServerArgument{
+ /**
+ * Enter REPL mode
+ */
+ SHELL("--shell"),
+ /**
+ * IOS: abs path to simulator-compiled .app file or the bundle_id of the desired target on device; Android: abs path to .apk file
+ * Sample
+ * --app /abs/path/to/my.app
+ */
+ APP("--app"),
+ /**
+ * Unique device identifier of the connected physical device
+ * Sample
+ * --udid 1adsf-sdfas-asdf-123sdf
+ */
+ UIID("--udid"),
+ /**
+ * callback IP Address (default: same as address)
+ * Sample
+ * --callback-address 127.0.0.1
+ */
+ CALLBACK_ADDRESS("--callback-address"),
+ /**
+ * callback port (default: same as port)
+ * Sample
+ * --callback-port 4723
+ */
+ CALLBACK_PORT("--callback-port"),
+ /**
+ * Enables session override (clobbering)
+ * Default: false
+ */
+ SESSION_OVERRIDE("--session-override"),
+ /**
+ * Don’t reset app state between sessions (IOS: don’t delete app plist files; Android: don’t uninstall app before new session)
+ * Default: false
+ */
+ NO_RESET("--no-reset"),
+ /**
+ * Pre-launch the application before allowing the first session (Requires –app and, for Android, –app-pkg and –app-activity)
+ * Default: false
+ */
+ PRE_LAUNCH("--pre-launch"),
+ /**
+ * The message log level to be shown
+ * Sample:
+ * --log-level debug
+ */
+ LOG_LEVEL("--log-level"),
+ /**
+ * Show timestamps in console output
+ * Default: false
+ */
+ LOG_TIMESTAMP("log-timestamp"),
+ /**
+ * Use local timezone for timestamps
+ * Default: false
+ */
+ LOCAL_TIMEZONE("--local-timezone"),
+ /**
+ * Don’t use colors in console output
+ * Default: false
+ */
+ LOG_NO_COLORS("--log-no-colors"),
+ /**
+ * Also send log output to this HTTP listener
+ * Sample:
+ * --webhook localhost:9876
+ */
+ WEB_HOOK("--webhook"),
+ /**
+ * Name of the mobile device to use
+ * Sample:
+ * --device-name iPhone Retina (4-inch), Android Emulator
+ */
+ DEVICE_NAME("--device-name"),
+ /**
+ * Name of the mobile platform: iOS, Android, or FirefoxOS
+ * Sample:
+ * --platform-name iOS
+ */
+ PLATFORM_NAME("--platform-name"),
+ /**
+ * Version of the mobile platform
+ * Sample:
+ * --platform-version 7.1
+ */
+ PLATFORM_VERSION("--platform-version"),
+ /**
+ * Name of the automation tool: Appium or Selendroid
+ * Sample:
+ * --automation-name Appium
+ */
+ AUTOMATION_NAME("--automation-name"),
+ /**
+ * Name of the mobile browser: Safari or Chrome
+ * Sample:
+ * --browser-name Safari
+ */
+ BROWSER_NAME("--browser-name"),
+ /**
+ * Language for the iOS simulator / Android Emulator
+ * Sample:
+ * --language en
+ */
+ LANGUAGE("--language"),
+ /**
+ * Locale for the iOS simulator / Android Emulator
+ * Sample:
+ * --locale en_US
+ */
+ LOCALE("--locale"),
+ /**
+ * Configuration JSON file to register Appium with selenium grid
+ * Sample:
+ * --nodeconfig /abs/path/to/nodeconfig.json
+ */
+ CONFIGURATION_FILE("--nodeconfig"),
+ /**
+ * IP Address of robot
+ * Sample:
+ * --robot-address 0.0.0.0
+ */
+ ROBOT_ADDRESS("--robot-address"),
+ /**
+ * Port for robot
+ * Sample:
+ * --robot-port 4242
+ */
+ ROBOT_PORT("--robot-port"),
+ /**
+ * Port upon which ChromeDriver will run
+ * Sample:
+ * --chromedriver-port 9515
+ */
+ CHROME_DRIVER_PORT("--chromedriver-port"),
+ /**
+ * ChromeDriver executable full path
+ */
+ CHROME_DRIVER_EXECUTABLE("--chromedriver-executable"),
+ /**
+ * Show info about the Appium server configuration and exit
+ * Default: false
+ */
+ SHOW_CONFIG("--show-config"),
+ /**
+ * Bypass Appium’s checks to ensure we can read/write necessary files
+ * Default: false
+ */
+ NO_PERMS_CHECKS( "--no-perms-check"),
+ /**
+ * The default command timeout for the server to use for all sessions. Will
+ * still be overridden by newCommandTimeout cap
+ * Default: 60
+ */
+ COMMAND_TIMEOUT("--command-timeout"),
+ /**
+ * Cause sessions to fail if desired caps are sent in that Appium does not
+ * recognize as valid for the selected device
+ * Default: false
+ */
+ STRICT_CAPS("--strict-caps"),
+ /**
+ * Absolute path to directory Appium can use to manage temporary files, like
+ * built-in iOS apps it needs to move around. On *nix/Mac defaults to /tmp,
+ * on Windows defaults to C:\Windows\Temp
+ */
+ TEMP_DIRECTORY("--tmp"),
+ /**
+ * Add exaggerated spacing in logs to help with visual inspection
+ * Default: false
+ */
+ DEBUG_LOG_SPACING("--debug-log-spacing");
+ ;
+
+ private final String arg;
+
+ GeneralServerFlag(String arg) {
+ this.arg = arg;
+ }
+
+ @Override
+ public String getArgument() {
+ return arg;
+ }
+}
diff --git a/src/main/java/io/appium/java_client/service/local/flags/IOSServerFlag.java b/src/main/java/io/appium/java_client/service/local/flags/IOSServerFlag.java
new file mode 100644
index 000000000..89da26283
--- /dev/null
+++ b/src/main/java/io/appium/java_client/service/local/flags/IOSServerFlag.java
@@ -0,0 +1,133 @@
+package io.appium.java_client.service.local.flags;
+
+/**
+* Here is the list of iOS specific server arguments.
+* All flags are optional, but some are required in conjunction with certain others.
+* The full list is available here: {@link http://appium.io/slate/en/master/?ruby#appium-server-arguments}
+* iOS specific arguments are marked by (IOS-only)
+*/
+public enum IOSServerFlag implements ServerArgument{
+ /**
+ * the relative path of the dir where Localizable.strings file
+ * resides
+ * Default: en.lproj
+ * Sample:
+ * --localizable-strings-dir en.lproj
+ */
+ LOCALIZABLE_STRING_PATH("--localizable-strings-dir"),
+ /**
+ * absolute path to compiled .ipa file
+ * Sample:
+ * --ipa /abs/path/to/my.ipa
+ */
+ IPA_ABSOLUTE_PATH("--ipa"),
+ /**
+ * How many times to retry launching Instruments before saying it
+ * crashed or timed out
+ * Sample:
+ * --backend-retries 3
+ */
+ BACK_END_RETRIES("--backend-retries"),
+ /**
+ * how long in ms to wait for Instruments to launch
+ * Default: 90000
+ */
+ LAUNCH_TIMEOUT("--launch-timeout"),
+ /**
+ * IOS has a weird built-in unavoidable delay. We patch this in
+ * appium. If you do not want it patched, pass in this flag.
+ * Default: false
+ */
+ USE_NATIVE_INSTRUMENTS("--native-instruments-lib"),
+ /**
+ * Use the safari app
+ * Default: false
+ */
+ SAFARI("--safari"),
+ /**
+ * use the default simulator that instruments launches
+ * on its own
+ * Default: false
+ *
+ */
+ DEFAULT_DEVICE("--default-device"),
+ /**
+ * Use the iPhone Simulator no matter what the app wants
+ * Default: false
+ */
+ FORCE_IPHONE_SIMULATOR("--force-iphone"),
+ /**
+ * Use the iPad Simulator no matter what the app wants
+ * Default: false
+ */
+ FORCE_IPAD_SIMULATOR("--force-ipad"),
+ /**
+ * Calendar format for the iOS simulator
+ * Default: null
+ * Sample:
+ * --calendar-format gregorian
+ */
+ CALENDAR_FORMAT("--calendar-format"),
+ /**
+ * use LANDSCAPE or PORTRAIT to initialize all requests to this
+ * orientation
+ * Sample:
+ * --orientation LANDSCAPE
+ */
+ ORIENTATION("--orientation"),
+ /**
+ * .tracetemplate file to use with Instruments
+ * Sample:
+ * --tracetemplate /Users/me/Automation.tracetemplate
+ */
+ TRACE_TEMPLATE_FILE_PATH("--tracetemplate"),
+ /**
+ * custom path to the instruments commandline tool
+ * Sample:
+ * --instruments /path/to/instruments
+ */
+ CUSTOM_INSTRUMENTS_PATH("--instruments"),
+ /**
+ * if set, the iOS simulator log will be written to the console
+ * Default: false
+ */
+ SHOW_SIMULATOR_LOG("--show-sim-log"),
+ /**
+ * if set, the iOS system log will be written to the console
+ * Default: false
+ */
+ SHOW_IOS_LOG("--show-ios-log"),
+ /**
+ * Whether to keep keychains (Library/Keychains) when reset app
+ * between sessions
+ * Default: false
+ */
+ KEEP_KEYCHAINS("--keep-keychains"),
+ /**
+ * Xcode 6 has a bug on some platforms where a certain simulator can only be
+ * launched without error if all other simulator devices are first deleted.
+ * This option causes Appium to delete all devices other than the one being
+ * used by Appium. Note that this is a permanent deletion, and you are
+ * responsible for using simctl or xcode to manage the categories of devices
+ * used with Appium
.
+ * Default: false
+ */
+ ISOLATE_SIM_DEVICE("--isolate-sim-device"),
+ /**
+ * Absolute path to directory Appium use to save ios instruments traces,
+ * defaults to /appium-instruments
+ * Default: null
+ */
+ TRACE_DIRECTORY_ABSOLUTE_PATH("--trace-dir");
+
+ private final String arg;
+
+ private IOSServerFlag(String arg) {
+ this.arg = arg;
+ }
+
+ @Override
+ public String getArgument() {
+ return arg;
+ }
+}
diff --git a/src/main/java/io/appium/java_client/service/local/flags/ServerArgument.java b/src/main/java/io/appium/java_client/service/local/flags/ServerArgument.java
new file mode 100644
index 000000000..de5d50d04
--- /dev/null
+++ b/src/main/java/io/appium/java_client/service/local/flags/ServerArgument.java
@@ -0,0 +1,5 @@
+package io.appium.java_client.service.local.flags;
+
+public interface ServerArgument {
+ String getArgument();
+}
diff --git a/src/test/java/io/appium/java_client/AppiumDriverTest.java b/src/test/java/io/appium/java_client/AppiumDriverTest.java
index 9ea74b749..728a9d085 100644
--- a/src/test/java/io/appium/java_client/AppiumDriverTest.java
+++ b/src/test/java/io/appium/java_client/AppiumDriverTest.java
@@ -21,17 +21,14 @@
import io.appium.java_client.remote.MobileCapabilityType;
import io.appium.java_client.remote.MobilePlatform;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
+import io.appium.java_client.service.local.AppiumDriverLocalService;
+import org.junit.*;
import org.openqa.selenium.ScreenOrientation;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.html5.Location;
import org.openqa.selenium.remote.DesiredCapabilities;
import java.io.File;
-import java.net.URL;
-
import static org.junit.Assert.assertEquals;
/**
@@ -40,9 +37,19 @@
public class AppiumDriverTest {
private AppiumDriver> driver;
+ private static AppiumDriverLocalService service;
+
+ @BeforeClass
+ public static void beforeClass() throws Exception{
+ service = AppiumDriverLocalService.buildDefaultService();
+ service.start();
+ }
@Before
- public void setup() throws Exception {
+ public void setUp() throws Exception {
+ if (service == null || !service.isRunning())
+ throw new RuntimeException("An appium server node is not started!");
+
File appDir = new File("src/test/java/io/appium/java_client");
File app = new File(appDir, "UICatalog.app.zip");
DesiredCapabilities capabilities = new DesiredCapabilities();
@@ -51,7 +58,7 @@ public void setup() throws Exception {
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, MobilePlatform.IOS);
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator");
capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
- driver = new IOSDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
+ driver = new IOSDriver(service.getUrl(), capabilities);
}
@After
@@ -98,4 +105,9 @@ public void geolocationTest() {
driver.setLocation(location);
}
+ @AfterClass
+ public static void afterClass(){
+ if (service != null)
+ service.stop();
+ }
}
diff --git a/src/test/java/io/appium/java_client/ContextTest.java b/src/test/java/io/appium/java_client/ContextTest.java
index f2c0d9a69..8ded5e96d 100644
--- a/src/test/java/io/appium/java_client/ContextTest.java
+++ b/src/test/java/io/appium/java_client/ContextTest.java
@@ -20,15 +20,12 @@
import io.appium.java_client.ios.IOSDriver;
import io.appium.java_client.remote.MobileCapabilityType;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
+import io.appium.java_client.service.local.AppiumDriverLocalService;
+import org.junit.*;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import java.io.File;
-import java.net.URL;
-
import static org.junit.Assert.assertEquals;
/**
@@ -37,9 +34,19 @@
public class ContextTest {
private AppiumDriver> driver;
+ private static AppiumDriverLocalService service;
+
+ @BeforeClass
+ public static void beforeClass() throws Exception{
+ service = AppiumDriverLocalService.buildDefaultService();
+ service.start();
+ }
@Before
- public void setup() throws Exception {
+ public void setUp() throws Exception {
+ if (service == null || !service.isRunning())
+ throw new RuntimeException("An appium server node is not started!");
+
File appDir = new File("src/test/java/io/appium/java_client");
File app = new File(appDir, "WebViewApp.app.zip");
DesiredCapabilities capabilities = new DesiredCapabilities();
@@ -47,7 +54,7 @@ public void setup() throws Exception {
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.1");
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator");
capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
- driver = new IOSDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
+ driver = new IOSDriver(service.getUrl(), capabilities);
}
@After
@@ -77,4 +84,10 @@ public void testContextError() {
driver.context("Planet of the Ape-ium");
}
+ @AfterClass
+ public static void afterClass(){
+ if (service != null)
+ service.stop();
+ }
+
}
diff --git a/src/test/java/io/appium/java_client/android/AndroidAccessibilityTest.java b/src/test/java/io/appium/java_client/android/AndroidAccessibilityTest.java
index 6b8681d8a..3a2830b07 100644
--- a/src/test/java/io/appium/java_client/android/AndroidAccessibilityTest.java
+++ b/src/test/java/io/appium/java_client/android/AndroidAccessibilityTest.java
@@ -5,30 +5,37 @@
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileBy;
import io.appium.java_client.MobileElement;
-import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.remote.MobileCapabilityType;
import java.io.File;
-import java.net.URL;
import java.util.List;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
+import io.appium.java_client.service.local.AppiumDriverLocalService;
+import org.junit.*;
import org.openqa.selenium.remote.DesiredCapabilities;
public class AndroidAccessibilityTest {
private AppiumDriver driver;
+ private static AppiumDriverLocalService service;
+
+ @BeforeClass
+ public static void beforeClass() throws Exception{
+ service = AppiumDriverLocalService.buildDefaultService();
+ service.start();
+ }
@Before
public void setUp() throws Exception {
+ if (service == null || !service.isRunning())
+ throw new RuntimeException("An appium server node is not started!");
+
File appDir = new File("src/test/java/io/appium/java_client");
File app = new File(appDir, "ApiDemos-debug.apk");
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
- driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
+ driver = new AndroidDriver(service.getUrl(), capabilities);
}
@After
@@ -61,4 +68,10 @@ public void MobileElementsByTest() {
assertTrue(elements.size() > 0);
}
+ @AfterClass
+ public static void afterClass(){
+ if (service != null)
+ service.stop();
+ }
+
}
diff --git a/src/test/java/io/appium/java_client/android/AndroidDriverTest.java b/src/test/java/io/appium/java_client/android/AndroidDriverTest.java
index 9419a0698..925011c2a 100644
--- a/src/test/java/io/appium/java_client/android/AndroidDriverTest.java
+++ b/src/test/java/io/appium/java_client/android/AndroidDriverTest.java
@@ -20,15 +20,13 @@
import io.appium.java_client.AppiumSetting;
import io.appium.java_client.NetworkConnectionSetting;
import io.appium.java_client.remote.MobileCapabilityType;
+import io.appium.java_client.service.local.AppiumDriverLocalService;
import org.apache.commons.codec.binary.Base64;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
+import org.junit.*;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import java.io.File;
-import java.net.URL;
import static org.junit.Assert.*;
@@ -38,9 +36,19 @@
public class AndroidDriverTest {
private AndroidDriver> driver;
+ private static AppiumDriverLocalService service;
+
+ @BeforeClass
+ public static void beforeClass() throws Exception{
+ service = AppiumDriverLocalService.buildDefaultService();
+ service.start();
+ }
@Before
public void setup() throws Exception {
+ if (service == null || !service.isRunning())
+ throw new RuntimeException("An appium server node is not started!");
+
File appDir = new File("src/test/java/io/appium/java_client");
File app = new File(appDir, "ApiDemos-debug.apk");
DesiredCapabilities capabilities = new DesiredCapabilities();
@@ -48,7 +56,7 @@ public void setup() throws Exception {
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
capabilities.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, 120);
- driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
+ driver = new AndroidDriver(service.getUrl(), capabilities);
}
@After
@@ -174,4 +182,10 @@ public void scrollToExactTest() {
public void toggleLocationServicesTest() {
driver.toggleLocationServices();
}
+
+ @AfterClass
+ public static void afterClass(){
+ if (service != null)
+ service.stop();
+ }
}
diff --git a/src/test/java/io/appium/java_client/android/AndroidGestureTest.java b/src/test/java/io/appium/java_client/android/AndroidGestureTest.java
index bc330654b..3aa6bf274 100644
--- a/src/test/java/io/appium/java_client/android/AndroidGestureTest.java
+++ b/src/test/java/io/appium/java_client/android/AndroidGestureTest.java
@@ -19,15 +19,13 @@
import io.appium.java_client.*;
import io.appium.java_client.remote.MobileCapabilityType;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
+import io.appium.java_client.service.local.AppiumDriverLocalService;
+import org.junit.*;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import java.io.File;
-import java.net.URL;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertEquals;
@@ -38,16 +36,26 @@
*/
public class AndroidGestureTest {
private AndroidDriver driver;
+ private static AppiumDriverLocalService service;
+
+ @BeforeClass
+ public static void beforeClass() throws Exception{
+ service = AppiumDriverLocalService.buildDefaultService();
+ service.start();
+ }
@Before
public void setup() throws Exception {
+ if (service == null || !service.isRunning())
+ throw new RuntimeException("An appium server node is not started!");
+
File appDir = new File("src/test/java/io/appium/java_client");
File app = new File(appDir, "ApiDemos-debug.apk");
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "");
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
- driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
+ driver = new AndroidDriver(service.getUrl(), capabilities);
}
@After
@@ -135,4 +143,10 @@ public void elementGestureTest(){
System.out.println("UP Bottom + 10 Top - 20");
}
+
+ @AfterClass
+ public static void afterClass(){
+ if (service != null)
+ service.stop();
+ }
}
diff --git a/src/test/java/io/appium/java_client/android/AndroidUIAutomatorTest.java b/src/test/java/io/appium/java_client/android/AndroidUIAutomatorTest.java
index 7af50b3e5..f18c1b0a7 100644
--- a/src/test/java/io/appium/java_client/android/AndroidUIAutomatorTest.java
+++ b/src/test/java/io/appium/java_client/android/AndroidUIAutomatorTest.java
@@ -4,14 +4,12 @@
import io.appium.java_client.MobileElement;
import io.appium.java_client.remote.MobileCapabilityType;
import io.appium.java_client.remote.MobilePlatform;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
+import io.appium.java_client.service.local.AppiumDriverLocalService;
+import org.junit.*;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import java.io.File;
-import java.net.URL;
import java.util.List;
import static org.junit.Assert.assertEquals;
@@ -23,9 +21,19 @@
public class AndroidUIAutomatorTest {
private AndroidDriver driver;
+ private static AppiumDriverLocalService service;
+
+ @BeforeClass
+ public static void beforeClass() throws Exception{
+ service = AppiumDriverLocalService.buildDefaultService();
+ service.start();
+ }
@Before
public void setup() throws Exception {
+ if (service == null || !service.isRunning())
+ throw new RuntimeException("An appium server node is not started!");
+
File appDir = new File("src/test/java/io/appium/java_client");
File app = new File(appDir, "ApiDemos-debug.apk");
DesiredCapabilities capabilities = new DesiredCapabilities();
@@ -33,7 +41,7 @@ public void setup() throws Exception {
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, MobilePlatform.ANDROID);
capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
- driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
+ driver = new AndroidDriver(service.getUrl(), capabilities);
}
@After
@@ -79,4 +87,10 @@ public void ErrorTest() {
driver.findElementByAndroidUIAutomator(null);
}
+
+ @AfterClass
+ public static void afterClass(){
+ if (service != null)
+ service.stop();
+ }
}
\ No newline at end of file
diff --git a/src/test/java/io/appium/java_client/ios/IOSAccessibilityIdTest.java b/src/test/java/io/appium/java_client/ios/IOSAccessibilityIdTest.java
index e41c8be9e..44f189c2a 100644
--- a/src/test/java/io/appium/java_client/ios/IOSAccessibilityIdTest.java
+++ b/src/test/java/io/appium/java_client/ios/IOSAccessibilityIdTest.java
@@ -8,12 +8,10 @@
import io.appium.java_client.remote.MobileCapabilityType;
import java.io.File;
-import java.net.URL;
import java.util.List;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
+import io.appium.java_client.service.local.AppiumDriverLocalService;
+import org.junit.*;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
@@ -23,9 +21,19 @@
public class IOSAccessibilityIdTest {
private AppiumDriver> driver;
+ private static AppiumDriverLocalService service;
- @Before
+ @BeforeClass
+ public static void beforeClass() throws Exception{
+ service = AppiumDriverLocalService.buildDefaultService();
+ service.start();
+ }
+
+ @Before
public void setup() throws Exception {
+ if (service == null || !service.isRunning())
+ throw new RuntimeException("An appium server node is not started!");
+
File appDir = new File("src/test/java/io/appium/java_client");
File app = new File(appDir, "UICatalog.app.zip");
DesiredCapabilities capabilities = new DesiredCapabilities();
@@ -33,7 +41,7 @@ public void setup() throws Exception {
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.1");
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator");
capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
- driver = new IOSDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
+ driver = new IOSDriver(service.getUrl(), capabilities);
}
@After
@@ -64,4 +72,10 @@ public void MobileElementsByTest() {
List extends WebElement> elements = driver.findElements(MobileBy.AccessibilityId("UICatalog"));
assertTrue(elements.size() > 0);
}
+
+ @AfterClass
+ public static void afterClass(){
+ if (service != null)
+ service.stop();
+ }
}
diff --git a/src/test/java/io/appium/java_client/ios/IOSDriverTest.java b/src/test/java/io/appium/java_client/ios/IOSDriverTest.java
index 03f3ef449..af595eb36 100644
--- a/src/test/java/io/appium/java_client/ios/IOSDriverTest.java
+++ b/src/test/java/io/appium/java_client/ios/IOSDriverTest.java
@@ -21,16 +21,14 @@
import io.appium.java_client.remote.HideKeyboardStrategy;
import io.appium.java_client.remote.MobileCapabilityType;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
+import io.appium.java_client.service.local.AppiumDriverLocalService;
+import org.junit.*;
import org.openqa.selenium.Point;
import org.openqa.selenium.remote.DesiredCapabilities;
import java.io.File;
-import java.net.URL;
import static org.junit.Assert.assertEquals;
@@ -43,9 +41,19 @@
public class IOSDriverTest {
private IOSDriver driver;
+ private static AppiumDriverLocalService service;
+
+ @BeforeClass
+ public static void beforeClass() throws Exception{
+ service = AppiumDriverLocalService.buildDefaultService();
+ service.start();
+ }
@Before
public void setup() throws Exception {
+ if (service == null || !service.isRunning())
+ throw new RuntimeException("An appium server node is not started!");
+
File appDir = new File("src/test/java/io/appium/java_client");
File app = new File(appDir, "UICatalog.app.zip");
DesiredCapabilities capabilities = new DesiredCapabilities();
@@ -53,7 +61,7 @@ public void setup() throws Exception {
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.1");
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator");
capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
- driver = new IOSDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
+ driver = new IOSDriver(service.getUrl(), capabilities);
}
@After
@@ -113,4 +121,10 @@ public void scrollToExactTest() {
Point after = searchBar.getLocation();
assertNotEquals(before, after);
}
+
+ @AfterClass
+ public static void afterClass(){
+ if (service != null)
+ service.stop();
+ }
}
diff --git a/src/test/java/io/appium/java_client/ios/IosUIAutomationTest.java b/src/test/java/io/appium/java_client/ios/IosUIAutomationTest.java
index c397ef60a..3fb29ce4f 100644
--- a/src/test/java/io/appium/java_client/ios/IosUIAutomationTest.java
+++ b/src/test/java/io/appium/java_client/ios/IosUIAutomationTest.java
@@ -1,17 +1,14 @@
package io.appium.java_client.ios;
import io.appium.java_client.MobileBy;
-import io.appium.java_client.ios.IOSDriver;
import io.appium.java_client.remote.MobileCapabilityType;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
+import io.appium.java_client.service.local.AppiumDriverLocalService;
+import org.junit.*;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import java.io.File;
-import java.net.URL;
import java.util.List;
import static org.junit.Assert.assertEquals;
@@ -22,9 +19,19 @@
public class IosUIAutomationTest {
private IOSDriver driver;
+ private static AppiumDriverLocalService service;
+
+ @BeforeClass
+ public static void beforeClass() throws Exception{
+ service = AppiumDriverLocalService.buildDefaultService();
+ service.start();
+ }
@Before
public void setup() throws Exception {
+ if (service == null || !service.isRunning())
+ throw new RuntimeException("An appium server node is not started!");
+
File appDir = new File("src/test/java/io/appium/java_client");
File app = new File(appDir, "UICatalog.app.zip");
DesiredCapabilities capabilities = new DesiredCapabilities();
@@ -32,7 +39,7 @@ public void setup() throws Exception {
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.1");
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator");
capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
- driver = new IOSDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
+ driver = new IOSDriver(service.getUrl(), capabilities);
}
@After
@@ -68,4 +75,10 @@ public void MobileElementsByTest() {
public void ErrorTest() {
driver.findElementByIosUIAutomation(null);
}
+
+ @AfterClass
+ public static void afterClass(){
+ if (service != null)
+ service.stop();
+ }
}
diff --git a/src/test/java/io/appium/java_client/ios/iOSGestureTest.java b/src/test/java/io/appium/java_client/ios/iOSGestureTest.java
index 289b08990..0e9462ff7 100644
--- a/src/test/java/io/appium/java_client/ios/iOSGestureTest.java
+++ b/src/test/java/io/appium/java_client/ios/iOSGestureTest.java
@@ -22,15 +22,12 @@
import io.appium.java_client.MultiTouchAction;
import io.appium.java_client.SwipeElementDirection;
import io.appium.java_client.TouchAction;
-import io.appium.java_client.ios.IOSDriver;
import io.appium.java_client.remote.MobileCapabilityType;
import java.io.File;
-import java.net.URL;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
+import io.appium.java_client.service.local.AppiumDriverLocalService;
+import org.junit.*;
import org.openqa.selenium.Alert;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
@@ -43,9 +40,19 @@
public class iOSGestureTest {
private AppiumDriver driver;
+ private static AppiumDriverLocalService service;
+
+ @BeforeClass
+ public static void beforeClass() throws Exception{
+ service = AppiumDriverLocalService.buildDefaultService();
+ service.start();
+ }
@Before
public void setup() throws Exception {
+ if (service == null || !service.isRunning())
+ throw new RuntimeException("An appium server node is not started!");
+
File appDir = new File("src/test/java/io/appium/java_client");
File app = new File(appDir, "TestApp.app.zip");
DesiredCapabilities capabilities = new DesiredCapabilities();
@@ -53,7 +60,7 @@ public void setup() throws Exception {
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.1");
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator");
capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
- driver = new IOSDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
+ driver = new IOSDriver(service.getUrl(), capabilities);
}
@After
@@ -146,4 +153,10 @@ public void elementGestureTest(){
e.swipe(SwipeElementDirection.RIGHT,2000);
e.swipe(SwipeElementDirection.RIGHT, 5, 5, 2000);
}
+
+ @AfterClass
+ public static void afterClass(){
+ if (service != null)
+ service.stop();
+ }
}
diff --git a/src/test/java/io/appium/java_client/localserver/ServerBuilderTest.java b/src/test/java/io/appium/java_client/localserver/ServerBuilderTest.java
new file mode 100644
index 000000000..8ffbb04ae
--- /dev/null
+++ b/src/test/java/io/appium/java_client/localserver/ServerBuilderTest.java
@@ -0,0 +1,113 @@
+package io.appium.java_client.localserver;
+
+import io.appium.java_client.service.local.AppiumDriverLocalService;
+import io.appium.java_client.service.local.AppiumServiceBuilder;
+import io.appium.java_client.service.local.flags.GeneralServerFlag;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openqa.selenium.Platform;
+
+import java.io.*;
+import java.util.Properties;
+
+import static org.junit.Assert.assertEquals;
+
+public class ServerBuilderTest {
+
+ private static Properties properties;
+
+ @BeforeClass
+ public static void beforeClass() throws Exception{
+ File file = new File("src/test/java/io/appium/java_client/localserver/custom_node_path.properties");
+ FileInputStream fileInput = new FileInputStream(file);
+ properties = new Properties();
+ properties.load(fileInput);
+ fileInput.close();
+ }
+
+ private static File findCustomNode(){
+ Platform current = Platform.getCurrent();
+ if (current.is(Platform.WINDOWS))
+ return new File(String.valueOf(properties.get("path.to.custom.node.win")));
+
+ if (current.is(Platform.MAC))
+ return new File(String.valueOf(properties.get("path.to.custom.node.macos")));
+
+ return new File(String.valueOf(properties.get("path.to.custom.node.linux")));
+ }
+
+ @Test
+ public void checkAbilityToBuildDefaultService(){
+ AppiumDriverLocalService.buildDefaultService();
+ }
+
+ @Test
+ public void checkAbilityToBuildServiceWithDefinedParametersAndNodeSetInProperties(){
+ try {
+ String definedNode = findCustomNode().getAbsolutePath();
+ System.setProperty(AppiumServiceBuilder.APPIUM_NODE_PROPERTY, definedNode);
+ AppiumDriverLocalService.buildService(new AppiumServiceBuilder().withIPAddress("127.0.0.1").
+ usingPort(4000).withArgument(GeneralServerFlag.LOG_TIMESTAMP,""));
+ }
+ finally {
+ System.clearProperty(AppiumServiceBuilder.APPIUM_NODE_PROPERTY);
+ }
+ }
+
+ @Test
+ public void checkAbilityToStartServiceOnAFreePort(){
+ try {
+ String definedNode = findCustomNode().getAbsolutePath();
+ System.setProperty(AppiumServiceBuilder.APPIUM_NODE_PROPERTY, definedNode);
+ AppiumDriverLocalService service = AppiumDriverLocalService.buildService(new AppiumServiceBuilder().withIPAddress("127.0.0.1").
+ usingAnyFreePort().withArgument(GeneralServerFlag.LOG_TIMESTAMP));
+ service.start();
+ assertEquals(true, service.isRunning());
+ service.stop();
+ }
+ finally {
+ System.clearProperty(AppiumServiceBuilder.APPIUM_NODE_PROPERTY);
+ }
+ }
+
+ @Test
+ public void checkAbilityToBuildServiceWithDefinedParametersAndExternallyDefinedNode(){
+ File definedNode = findCustomNode();
+ AppiumDriverLocalService.buildService(new AppiumServiceBuilder().withAppiumJS(definedNode).withIPAddress("127.0.0.1").
+ usingPort(4000).withArgument(GeneralServerFlag.LOG_TIMESTAMP,""));
+ }
+
+ @Test
+ public void checkStartingOfDefaultService(){
+ AppiumDriverLocalService service = AppiumDriverLocalService.buildDefaultService();
+ service.start();
+ assertEquals(true, service.isRunning());
+ service.stop();
+ }
+
+ @Test
+ public void checkStartingOfTheServiceDefinedByProperty(){
+ try {
+ String definedNode = findCustomNode().getAbsolutePath();
+ System.setProperty(AppiumServiceBuilder.APPIUM_NODE_PROPERTY, definedNode);
+ AppiumDriverLocalService service = AppiumDriverLocalService.buildService(new AppiumServiceBuilder().withIPAddress("127.0.0.1").
+ usingPort(4000).withArgument(GeneralServerFlag.LOG_TIMESTAMP));
+ service.start();
+ assertEquals(true, service.isRunning());
+ service.stop();
+ }
+ finally {
+ System.clearProperty(AppiumServiceBuilder.APPIUM_NODE_PROPERTY);
+ }
+ }
+
+ @Test
+ public void checkStartingOfTheServiceDefinedExternally(){
+ File definedNode = findCustomNode();
+ AppiumDriverLocalService service = AppiumDriverLocalService.buildService(new AppiumServiceBuilder().withAppiumJS(definedNode).withIPAddress("127.0.0.1").
+ usingPort(4000).withArgument(GeneralServerFlag.LOG_TIMESTAMP,""));
+ service.start();
+ assertEquals(true, service.isRunning());
+ service.stop();
+ }
+}
diff --git a/src/test/java/io/appium/java_client/localserver/StartingAppLocally.java b/src/test/java/io/appium/java_client/localserver/StartingAppLocally.java
new file mode 100644
index 000000000..468eb9c08
--- /dev/null
+++ b/src/test/java/io/appium/java_client/localserver/StartingAppLocally.java
@@ -0,0 +1,116 @@
+package io.appium.java_client.localserver;
+
+import io.appium.java_client.MobileElement;
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.ios.IOSDriver;
+import io.appium.java_client.remote.AutomationName;
+import io.appium.java_client.remote.MobileCapabilityType;
+import io.appium.java_client.remote.MobilePlatform;
+import io.appium.java_client.service.local.AppiumServiceBuilder;
+import io.appium.java_client.service.local.flags.GeneralServerFlag;
+import org.junit.Test;
+import org.openqa.selenium.Capabilities;
+import org.openqa.selenium.remote.DesiredCapabilities;
+
+import java.io.File;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+public class StartingAppLocally {
+
+ @Test
+ public void startingAndroidAppWithCapabilitiesOnlyTest(){
+ File appDir = new File("src/test/java/io/appium/java_client");
+ File app = new File(appDir, "ApiDemos-debug.apk");
+ DesiredCapabilities capabilities = new DesiredCapabilities();
+ capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
+ capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
+ capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, AutomationName.APPIUM);
+
+ AndroidDriver driver = new AndroidDriver<>(capabilities);;
+ try {
+ Capabilities caps = driver.getCapabilities();
+
+ assertEquals(true, caps.getCapability(MobileCapabilityType.AUTOMATION_NAME).equals(AutomationName.APPIUM));
+ assertEquals(true, caps.getCapability(MobileCapabilityType.PLATFORM_NAME).equals(MobilePlatform.ANDROID));
+ assertNotEquals(null, caps.getCapability(MobileCapabilityType.DEVICE_NAME));
+ assertEquals(true, caps.getCapability(MobileCapabilityType.APP).equals(app.getAbsolutePath()));
+ }
+ finally {
+ driver.quit();
+ }
+ }
+
+ @Test
+ public void startingAndroidAppWithCapabilitiesAndServiceTest(){
+ File appDir = new File("src/test/java/io/appium/java_client");
+ File app = new File(appDir, "ApiDemos-debug.apk");
+ DesiredCapabilities capabilities = new DesiredCapabilities();
+ capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
+
+ AppiumServiceBuilder builder = new AppiumServiceBuilder().withArgument(GeneralServerFlag.AUTOMATION_NAME, AutomationName.APPIUM).
+ withArgument(GeneralServerFlag.APP, app.getAbsolutePath());
+
+ AndroidDriver driver = new AndroidDriver<>(builder, capabilities);;
+ try {
+ Capabilities caps = driver.getCapabilities();
+
+ assertEquals(true, caps.getCapability(MobileCapabilityType.PLATFORM_NAME).equals(MobilePlatform.ANDROID));
+ assertNotEquals(null, caps.getCapability(MobileCapabilityType.DEVICE_NAME));
+ }
+ finally {
+ driver.quit();
+ }
+ }
+
+ @Test
+ public void startingIOSAppWithCapabilitiesOnlyTest(){
+ File appDir = new File("src/test/java/io/appium/java_client");
+ File app = new File(appDir, "UICatalog.app.zip");
+
+ DesiredCapabilities capabilities = new DesiredCapabilities();
+ capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.1");
+ capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator");
+ capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
+ capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, AutomationName.APPIUM);
+
+ IOSDriver driver = new IOSDriver<>(capabilities);;
+ try {
+ Capabilities caps = driver.getCapabilities();
+
+ assertEquals(true, caps.getCapability(MobileCapabilityType.AUTOMATION_NAME).equals(AutomationName.APPIUM));
+ assertEquals(true, caps.getCapability(MobileCapabilityType.PLATFORM_NAME).equals(MobilePlatform.IOS));
+ assertNotEquals(null, caps.getCapability(MobileCapabilityType.DEVICE_NAME));
+ assertEquals(true, caps.getCapability(MobileCapabilityType.PLATFORM_VERSION).equals("7.1"));
+ assertEquals(true, caps.getCapability(MobileCapabilityType.APP).equals(app.getAbsolutePath()));
+ }
+ finally {
+ driver.quit();
+ }
+ }
+
+
+ @Test
+ public void startingIOSAppWithCapabilitiesAndServiseTest(){
+ File appDir = new File("src/test/java/io/appium/java_client");
+ File app = new File(appDir, "UICatalog.app.zip");
+
+ DesiredCapabilities capabilities = new DesiredCapabilities();
+ capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator");
+
+ AppiumServiceBuilder builder = new AppiumServiceBuilder().withArgument(GeneralServerFlag.AUTOMATION_NAME, AutomationName.APPIUM).
+ withArgument(GeneralServerFlag.APP, app.getAbsolutePath()).withArgument(GeneralServerFlag.PLATFORM_VERSION, "7.1");
+
+ IOSDriver driver = new IOSDriver<>(builder, capabilities);;
+ try {
+ Capabilities caps = driver.getCapabilities();
+ assertEquals(true, caps.getCapability(MobileCapabilityType.PLATFORM_NAME).equals(MobilePlatform.IOS));
+ assertNotEquals(null, caps.getCapability(MobileCapabilityType.DEVICE_NAME));
+ }
+ finally {
+ driver.quit();
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/io/appium/java_client/localserver/custom_node_path.properties b/src/test/java/io/appium/java_client/localserver/custom_node_path.properties
new file mode 100644
index 000000000..7aac7b0c7
--- /dev/null
+++ b/src/test/java/io/appium/java_client/localserver/custom_node_path.properties
@@ -0,0 +1,3 @@
+path.to.custom.node.win=C:/Program Files (x86)/Appium/node_modules/appium/bin/appium.js
+path.to.custom.node.macos=/Applications/Appium.app/Contents/Resources/node_modules/appium/bin/appium.js
+path.to.custom.node.linux=specify your path on your own
diff --git a/src/test/java/io/appium/java_client/pagefactory_tests/AndroidPageObjectTest.java b/src/test/java/io/appium/java_client/pagefactory_tests/AndroidPageObjectTest.java
index 37561ed2c..5467ec519 100644
--- a/src/test/java/io/appium/java_client/pagefactory_tests/AndroidPageObjectTest.java
+++ b/src/test/java/io/appium/java_client/pagefactory_tests/AndroidPageObjectTest.java
@@ -14,14 +14,11 @@
import io.appium.java_client.remote.MobileCapabilityType;
import java.io.File;
-import java.net.URL;
import java.util.List;
import java.util.concurrent.TimeUnit;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
+import io.appium.java_client.service.local.AppiumDriverLocalService;
+import org.junit.*;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
@@ -32,7 +29,10 @@
public class AndroidPageObjectTest {
- private WebDriver driver;
+ private static WebDriver driver;
+ private static AppiumDriverLocalService service;
+ private boolean populated = false;
+
@FindBy(className = "android.widget.TextView")
private List textVieWs;
@@ -170,22 +170,35 @@ public class AndroidPageObjectTest {
private WebElement elementWhenAndroidLocatorIsNotDefinedAndThereIsInvalidFindBy;
@SuppressWarnings("rawtypes")
- @Before
- public void setUp() throws Exception {
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ service = AppiumDriverLocalService.buildDefaultService();
+ service.start();
+
File appDir = new File("src/test/java/io/appium/java_client");
File app = new File(appDir, "ApiDemos-debug.apk");
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
- driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
-
- //This time out is set because test can be run on slow Android SDK emulator
- PageFactory.initElements(new AppiumFieldDecorator(driver, 5, TimeUnit.SECONDS), this);
+ driver = new AndroidDriver(service.getUrl(), capabilities);
}
- @After
- public void tearDown() throws Exception {
+ @Before
+ public void setUp() throws Exception {
+ if (!populated)
+ //This time out is set because test can be run on slow Android SDK emulator
+ PageFactory.initElements(new AppiumFieldDecorator(driver, 5, TimeUnit.SECONDS), this);
+
+ populated = true;
+ }
+
+ @AfterClass
+ public static void afterClass() throws Exception {
+ if (driver != null)
driver.quit();
+
+ if (service != null)
+ service.stop();
}
@Test
diff --git a/src/test/java/io/appium/java_client/pagefactory_tests/IOSfMobileBrowserCompatibilityTest.java b/src/test/java/io/appium/java_client/pagefactory_tests/IOSfMobileBrowserCompatibilityTest.java
index 59025ac94..d25a35276 100644
--- a/src/test/java/io/appium/java_client/pagefactory_tests/IOSfMobileBrowserCompatibilityTest.java
+++ b/src/test/java/io/appium/java_client/pagefactory_tests/IOSfMobileBrowserCompatibilityTest.java
@@ -7,11 +7,10 @@
import io.appium.java_client.pagefactory.iOSFindBy;
import io.appium.java_client.remote.MobileBrowserType;
import io.appium.java_client.remote.MobileCapabilityType;
-
-import java.net.URL;
import java.util.List;
import java.util.concurrent.TimeUnit;
+import io.appium.java_client.service.local.AppiumDriverLocalService;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -27,6 +26,7 @@
public class IOSfMobileBrowserCompatibilityTest {
private WebDriver driver;
+ private AppiumDriverLocalService service;
@FindBy(name = "q")
@AndroidFindBy(uiAutomator = "new UiSelector().resourceId(\"android:id/someId\")")
@@ -47,17 +47,24 @@ public class IOSfMobileBrowserCompatibilityTest {
@Before
public void setUp() throws Exception {
- DesiredCapabilities capabilities = new DesiredCapabilities();
- capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, MobileBrowserType.SAFARI);
- capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.1");
- capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator");
- driver = new IOSDriver<>(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
- PageFactory.initElements(new AppiumFieldDecorator(driver, 5, TimeUnit.SECONDS), this);
+ service = AppiumDriverLocalService.buildDefaultService();
+ service.start();
+
+ DesiredCapabilities capabilities = new DesiredCapabilities();
+ capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, MobileBrowserType.SAFARI);
+ capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.1");
+ capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator");
+ driver = new IOSDriver<>(service.getUrl(), capabilities);
+ PageFactory.initElements(new AppiumFieldDecorator(driver, 5, TimeUnit.SECONDS), this);
}
@After
public void tearDown() throws Exception {
- driver.quit();
+ if (driver != null)
+ driver.quit();
+
+ if (service != null)
+ service.stop();
}
@Test
diff --git a/src/test/java/io/appium/java_client/pagefactory_tests/MobileBrowserCompatibilityTest.java b/src/test/java/io/appium/java_client/pagefactory_tests/MobileBrowserCompatibilityTest.java
index 8072cfdb6..a1e43a274 100644
--- a/src/test/java/io/appium/java_client/pagefactory_tests/MobileBrowserCompatibilityTest.java
+++ b/src/test/java/io/appium/java_client/pagefactory_tests/MobileBrowserCompatibilityTest.java
@@ -7,10 +7,10 @@
import io.appium.java_client.remote.MobileBrowserType;
import io.appium.java_client.remote.MobileCapabilityType;
-import java.net.URL;
import java.util.List;
import java.util.concurrent.TimeUnit;
+import io.appium.java_client.service.local.AppiumDriverLocalService;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -30,6 +30,7 @@ public class MobileBrowserCompatibilityTest {
@FindBy(name = "q")
@AndroidFindBy(uiAutomator = "new UiSelector().resourceId(\"android:id/someId\")")
private WebElement searchTextField;
+ private AppiumDriverLocalService service;
@AndroidFindBys({
@AndroidFindBy(className = "someClass"),
@@ -43,17 +44,24 @@ public class MobileBrowserCompatibilityTest {
@Before
public void setUp() throws Exception {
- DesiredCapabilities capabilities = new DesiredCapabilities();
- capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
- capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, MobileBrowserType.BROWSER);
- driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
- //This time out is set because test can be run on slow Android SDK emulator
- PageFactory.initElements(new AppiumFieldDecorator(driver, 5, TimeUnit.SECONDS), this);
+ service = AppiumDriverLocalService.buildDefaultService();
+ service.start();
+
+ DesiredCapabilities capabilities = new DesiredCapabilities();
+ capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
+ capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, MobileBrowserType.BROWSER);
+ driver = new AndroidDriver(service.getUrl(), capabilities);
+ //This time out is set because test can be run on slow Android SDK emulator
+ PageFactory.initElements(new AppiumFieldDecorator(driver, 5, TimeUnit.SECONDS), this);
}
@After
public void tearDown() throws Exception {
- driver.quit();
+ if (driver != null)
+ driver.quit();
+
+ if (service != null)
+ service.stop();
}
@Test
diff --git a/src/test/java/io/appium/java_client/pagefactory_tests/SelendroidModeTest.java b/src/test/java/io/appium/java_client/pagefactory_tests/SelendroidModeTest.java
index 09c652bb7..f1c527dc6 100644
--- a/src/test/java/io/appium/java_client/pagefactory_tests/SelendroidModeTest.java
+++ b/src/test/java/io/appium/java_client/pagefactory_tests/SelendroidModeTest.java
@@ -9,17 +9,14 @@
import io.appium.java_client.remote.AutomationName;
import io.appium.java_client.remote.MobileCapabilityType;
+import io.appium.java_client.service.local.AppiumDriverLocalService;
+import org.junit.*;
import org.openqa.selenium.WebElement;
import java.io.File;
-import java.net.URL;
import java.util.List;
import java.util.concurrent.TimeUnit;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.FindBy;
@@ -28,7 +25,9 @@
public class SelendroidModeTest {
private static int SELENDROID_PORT = 9999;
- private WebDriver driver;
+ private static WebDriver driver;
+ private static AppiumDriverLocalService service;
+ private boolean populated = false;
@SelendroidFindBy(id = "text1")
private WebElement textId;
@@ -73,8 +72,11 @@ public class SelendroidModeTest {
@SelendroidFindBy(partialLinkText = "ccessibilit")
private WebElement textPartialLink;
- @Before
- public void setUp() throws Exception {
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ service = AppiumDriverLocalService.buildDefaultService();
+ service.start();
+
File appDir = new File("src/test/java/io/appium/java_client");
File app = new File(appDir, "ApiDemos-debug.apk");
DesiredCapabilities capabilities = new DesiredCapabilities();
@@ -82,15 +84,25 @@ public void setUp() throws Exception {
capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, AutomationName.SELENDROID);
capabilities.setCapability(MobileCapabilityType.SELENDROID_PORT, SELENDROID_PORT);
- driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
+ driver = new AndroidDriver(service.getUrl(), capabilities);
+ }
- //This time out is set because test can be run on slow Android SDK emulator
- PageFactory.initElements(new AppiumFieldDecorator(driver, 5, TimeUnit.SECONDS), this);
+ @Before
+ public void setUp() throws Exception {
+ if (!populated)
+ //This time out is set because test can be run on slow Android SDK emulator
+ PageFactory.initElements(new AppiumFieldDecorator(driver, 5, TimeUnit.SECONDS), this);
+
+ populated = true;
}
- @After
- public void tearDown() throws Exception {
- driver.quit();
+ @AfterClass
+ public static void afterClass() throws Exception {
+ if (driver != null)
+ driver.quit();
+
+ if (service != null)
+ service.stop();
}
@Test
diff --git a/src/test/java/io/appium/java_client/pagefactory_tests/iOSPageObjectTest.java b/src/test/java/io/appium/java_client/pagefactory_tests/iOSPageObjectTest.java
index 96dc142bc..dc1528698 100644
--- a/src/test/java/io/appium/java_client/pagefactory_tests/iOSPageObjectTest.java
+++ b/src/test/java/io/appium/java_client/pagefactory_tests/iOSPageObjectTest.java
@@ -12,13 +12,10 @@
import io.appium.java_client.remote.MobileCapabilityType;
import java.io.File;
-import java.net.URL;
import java.util.List;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
+import io.appium.java_client.service.local.AppiumDriverLocalService;
+import org.junit.*;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
@@ -29,7 +26,10 @@
public class iOSPageObjectTest {
- private WebDriver driver;
+ private static WebDriver driver;
+ private static AppiumDriverLocalService service;
+ private boolean populated = false;
+
@FindBy(className = "UIAButton")
private List uiButtons;
@@ -125,26 +125,40 @@ public class iOSPageObjectTest {
@FindBy(css = "e.e1.e2")
private WebElement elementWhenAndroidLocatorIsNotDefinedAndThereIsInvalidFindBy;
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ service = AppiumDriverLocalService.buildDefaultService();
+ service.start();
+
+ File appDir = new File("src/test/java/io/appium/java_client");
+ File app = new File(appDir, "TestApp.app.zip");
+ DesiredCapabilities capabilities = new DesiredCapabilities();
+ capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "");
+ capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.1");
+ capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator");
+ capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
+ driver = new IOSDriver(service.getUrl(), capabilities);
+ }
+
@SuppressWarnings("rawtypes")
@Before
public void setUp() throws Exception {
- File appDir = new File("src/test/java/io/appium/java_client");
- File app = new File(appDir, "TestApp.app.zip");
- DesiredCapabilities capabilities = new DesiredCapabilities();
- capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "");
- capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.1");
- capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator");
- capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
- driver = new IOSDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
-
- PageFactory.initElements(new AppiumFieldDecorator(driver), this);
- }
+ if (!populated)
+ PageFactory.initElements(new AppiumFieldDecorator(driver), this);
- @After
- public void tearDown() throws Exception {
- driver.quit();
+ populated = true;
}
+ @AfterClass
+ public static void afterClass() throws Exception {
+ if (driver != null)
+ driver.quit();
+
+ if (service != null)
+ service.stop();
+ }
+
@Test
public void findByElementsTest() {
Assert.assertNotEquals(0, uiButtons.size());