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 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());