Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .azure-templates/bootstrap_steps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ steps:
npm config set prefix $NVM_DIR/versions/node/`node --version`
node --version

npm install -g appium@beta
npm install -g appium@next
6 changes: 5 additions & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ variables:
XCODE_VERSION: 11.5
IOS_PLATFORM_VERSION: 13.5
IOS_DEVICE_NAME: iPhone X
NODE_VERSION: 12.x
NODE_VERSION: 14.x
JDK_VERSION: 1.8

jobs:
- job: Android_E2E_Tests
steps:
- template: .azure-templates/bootstrap_steps.yml
- script: $NVM_DIR/versions/node/`node --version`/bin/appium driver install uiautomator2
displayName: Install UIA2 driver
- script: |
echo "y" | $ANDROID_HOME/tools/bin/sdkmanager --install 'system-images;$(ANDROID_EMU_TARGET);$(ANDROID_EMU_TAG);$(ANDROID_EMU_ABI)'
echo "no" | $ANDROID_HOME/tools/bin/avdmanager create avd -n "$(ANDROID_EMU_NAME)" -k 'system-images;$(ANDROID_EMU_TARGET);$(ANDROID_EMU_TAG);$(ANDROID_EMU_ABI)' --force
Expand Down Expand Up @@ -50,6 +52,8 @@ jobs:
sudo xcode-select -s /Applications/Xcode_$(XCODE_VERSION).app/Contents/Developer
xcrun simctl list
displayName: Simulator configuration
- script: $NVM_DIR/versions/node/`node --version`/bin/appium driver install xcuitest
displayName: Install XCUITest driver
- task: Gradle@2
inputs:
gradleWrapperFile: 'gradlew'
Expand Down
12 changes: 12 additions & 0 deletions docs/v7-to-v8-migration-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,15 @@ for more details on how to properly apply W3C Actions to your automation context
- AppiumDriver methods `resetApp`, `launchApp` and `closeApp` have been deprecated as
they are going to be removed from future Appium versions. Check
https://github.com/appium/appium/issues/15807 for more details.

## AppiumDriverLocalService

- The default URL the server is listening on has been changed, and it
does not contain the `/wd/hub` suffix anymore (e.g. `http://0.0.0.0:4723/wd/hub`
became `http://0.0.0.0:4723/`). This has been done in order
to align the actual behavior with Appium v2. If you still would like to use
v8 of the Java client with Appium v1.2x, where the server URL contains the `/wd/hub` suffix
by default, then consider providing `--base-path` setting explicitly while
building `AppiumServiceBuilder` instance (e.g. `.withArgument(GeneralServerFlag.BASEPATH, "/wd/hub")`).
Older versions of Appium server (v1.19 and older) won't work with `AppiumDriverLocalService`,
because they don't allow provisioning of base path in form of a command line argument.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

import com.google.common.annotations.VisibleForTesting;

import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;

import org.openqa.selenium.net.UrlChecker;
Expand All @@ -37,6 +38,7 @@
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.time.Duration;
import java.util.List;
Expand All @@ -52,7 +54,7 @@

public final class AppiumDriverLocalService extends DriverService {

private static final String URL_MASK = "http://%s:%d/wd/hub";
private static final String URL_MASK = "http://%s:%d/";
private static final Logger LOG = LoggerFactory.getLogger(AppiumDriverLocalService.class);
private static final Pattern LOG_MESSAGE_PATTERN = Pattern.compile("^(.*)\\R");
private static final Pattern LOGGER_CONTEXT_PATTERN = Pattern.compile("^(\\[debug\\] )?\\[(.+?)\\]");
Expand All @@ -66,11 +68,14 @@ public final class AppiumDriverLocalService extends DriverService {
private final ReentrantLock lock = new ReentrantLock(true); //uses "fair" thread ordering policy
private final ListOutputStream stream = new ListOutputStream().add(System.out);
private final URL url;
private String basePath;

private CommandLine process = null;

AppiumDriverLocalService(String ipAddress, File nodeJSExec, int nodeJSPort, Duration startupTimeout,
List<String> nodeJSArgs, Map<String, String> nodeJSEnvironment) throws IOException {
AppiumDriverLocalService(String ipAddress, File nodeJSExec,
int nodeJSPort, Duration startupTimeout,
List<String> nodeJSArgs, Map<String, String> nodeJSEnvironment
) throws IOException {
super(nodeJSExec, nodeJSPort, startupTimeout, nodeJSArgs, nodeJSEnvironment);
this.nodeJSExec = nodeJSExec;
this.nodeJSArgs = nodeJSArgs;
Expand All @@ -87,14 +92,34 @@ public static AppiumDriverLocalService buildService(AppiumServiceBuilder builder
return builder.build();
}

public AppiumDriverLocalService withBasePath(String basePath) {
this.basePath = basePath;
return this;
}

public String getBasePath() {
return this.basePath;
}

@SneakyThrows
private static URL addSuffix(URL url, String suffix) {
return url.toURI().resolve("." + (suffix.startsWith("/") ? suffix : "/" + suffix)).toURL();
}

@SneakyThrows
@SuppressWarnings("SameParameterValue")
private static URL replaceHost(URL source, String oldHost, String newHost) {
return new URL(source.toString().replace(oldHost, newHost));
}

/**
* Base URL.
*
* @return The base URL for the managed appium server.
*/
@Override
public URL getUrl() {
return url;
return basePath == null ? url : addSuffix(url, basePath);
}

@Override
Expand Down Expand Up @@ -125,7 +150,7 @@ public boolean isRunning() {

private void ping(Duration timeout) throws UrlChecker.TimeoutException, MalformedURLException {
// The operating system might block direct access to the universal broadcast IP address
URL status = new URL(url.toString().replace(BROADCAST_IP_ADDRESS, "127.0.0.1") + "/status");
URL status = addSuffix(replaceHost(getUrl(), BROADCAST_IP_ADDRESS, "127.0.0.1"), "/status");
new UrlChecker().waitUntilAvailable(timeout.toMillis(), TimeUnit.MILLISECONDS, status);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@
import io.appium.java_client.remote.AndroidMobileCapabilityType;
import io.appium.java_client.remote.MobileBrowserType;
import io.appium.java_client.remote.MobileCapabilityType;
import io.appium.java_client.service.local.flags.GeneralServerFlag;
import io.appium.java_client.service.local.flags.ServerArgument;

import lombok.SneakyThrows;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
Expand Down Expand Up @@ -446,16 +448,15 @@ public AppiumServiceBuilder withLogFile(File logFile) {
return super.withLogFile(logFile);
}

@SneakyThrows
@Override
protected AppiumDriverLocalService createDriverService(File nodeJSExecutable, int nodeJSPort,
Duration startupTimeout,
List<String> nodeArguments,
Map<String, String> nodeEnvironment) {
try {
return new AppiumDriverLocalService(ipAddress, nodeJSExecutable, nodeJSPort, startupTimeout, nodeArguments,
nodeEnvironment);
} catch (IOException e) {
throw new RuntimeException(e);
}
String basePath = serverArguments.getOrDefault(
GeneralServerFlag.BASEPATH.getArgument(), serverArguments.get("-pa"));
return new AppiumDriverLocalService(ipAddress, nodeJSExecutable, nodeJSPort, startupTimeout, nodeArguments,
nodeEnvironment).withBasePath(basePath);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package io.appium.java_client.service.local.flags;


/**
* Here is the list of common Appium server arguments.
*/
Expand All @@ -43,7 +42,10 @@ public enum GeneralServerFlag implements ServerArgument {
* Pre-launch the application before allowing the first session
* (Requires –app and, for Android, –app-pkg and –app-activity).
* Default: false
*
* @deprecated This argument has been removed from Appium 2.0
*/
@Deprecated
PRE_LAUNCH("--pre-launch"),
/**
* The message log level to be shown.
Expand Down Expand Up @@ -75,14 +77,6 @@ public enum GeneralServerFlag implements ServerArgument {
* --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"),
/**
* Show info about the Appium server configuration and exit. Default: false
*/
Expand Down Expand Up @@ -140,33 +134,21 @@ public enum GeneralServerFlag implements ServerArgument {
* Plugins are available with Appium as of Appium 2.0.
* To activate all plugins, you can use the single string "all" as the value (e.g --plugins=all)
* Default: []
* Sample: --plugins=device-farm,images
* Sample: --use-plugins=device-farm,images
*/
PLUGINS("--plugins"),
USE_PLUGINS("--use-plugins"),
/**
* A comma-separated list of installed driver names that should be active for this server.
* All drivers will be active by default.
* Default: []
* Sample: --drivers=uiautomator2,xcuitest
* Sample: --use-drivers=uiautomator2,xcuitest
*/
DRIVERS("--drivers"),
USE_DRIVERS("--use-drivers"),
/**
* Base path to use as the prefix for all webdriver routes running on this server.
* Sample: --base-path=/wd/hub
*/
BASEPATH("--base-path"),
/**
* Set the default desired client arguments for a plugin.
* Default: []
* Sample: [ '{"images":{"foo1": "bar1", "foo2": "bar2"}}' | /path/to/pluginArgs.json ]
*/
PLUGINARGS("--plugin-args"),
/**
* Set the default desired client arguments for a driver.
* Default: []
* Sample: [ '{"xcuitest": {"foo1": "bar1", "foo2": "bar2"}}' | /path/to/driverArgs.json ]
*/
DRIVERARGS("--driver-args");
BASEPATH("--base-path");

private final String arg;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,29 @@

import io.appium.java_client.android.options.UiAutomator2Options;
import io.appium.java_client.service.local.AppiumDriverLocalService;
import io.appium.java_client.service.local.AppiumServerHasNotBeenStartedLocallyException;

import io.appium.java_client.service.local.AppiumServiceBuilder;
import org.junit.AfterClass;
import org.junit.BeforeClass;

import static io.appium.java_client.TestResources.apiDemosApk;

public class BaseAndroidTest {
public static final String APP_ID = "io.appium.android.apis";
protected static final int PORT = 4723;

private static AppiumDriverLocalService service;
protected static AndroidDriver driver;

/**
* initialization.
*/
@BeforeClass public static void beforeClass() {
service = AppiumDriverLocalService.buildDefaultService();
service = new AppiumServiceBuilder()
.withIPAddress("127.0.0.1")
.usingPort(PORT)
.build();
service.start();
if (service == null || !service.isRunning()) {
throw new AppiumServerHasNotBeenStartedLocallyException(
"An appium server node is not started!");
}

UiAutomator2Options options = new UiAutomator2Options()
.setDeviceName("Android Emulator")
Expand Down
13 changes: 4 additions & 9 deletions src/test/java/io/appium/java_client/ios/AppIOSTest.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package io.appium.java_client.ios;

import io.appium.java_client.ios.options.XCUITestOptions;
import io.appium.java_client.service.local.AppiumServerHasNotBeenStartedLocallyException;
import org.junit.BeforeClass;
import org.openqa.selenium.SessionNotCreatedException;

import java.net.URL;
import java.time.Duration;

import static io.appium.java_client.TestResources.testAppZip;
Expand All @@ -16,22 +14,19 @@ public class AppIOSTest extends BaseIOSTest {

@BeforeClass
public static void beforeClass() throws Exception {
final String ip = startAppiumServer();

if (service == null || !service.isRunning()) {
throw new AppiumServerHasNotBeenStartedLocallyException("An appium server node is not started!");
}
startAppiumServer();

XCUITestOptions options = new XCUITestOptions()
.setPlatformVersion(PLATFORM_VERSION)
.setDeviceName(DEVICE_NAME)
.setCommandTimeouts(Duration.ofSeconds(240))
.setApp(testAppZip().toAbsolutePath().toString())
.setWdaLaunchTimeout(WDA_LAUNCH_TIMEOUT);
try {
driver = new IOSDriver(new URL("http://" + ip + ":" + PORT + "/wd/hub"), options);
driver = new IOSDriver(service.getUrl(), options);
} catch (SessionNotCreatedException e) {
options.useNewWDA();
driver = new IOSDriver(new URL("http://" + ip + ":" + PORT + "/wd/hub"), options);
driver = new IOSDriver(service.getUrl(), options);
}
}
}
22 changes: 11 additions & 11 deletions src/test/java/io/appium/java_client/ios/BaseIOSTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,33 @@
import io.appium.java_client.service.local.AppiumServiceBuilder;
import org.junit.AfterClass;

import java.net.SocketException;
import java.net.UnknownHostException;
import java.time.Duration;

import static io.appium.java_client.TestUtils.getLocalIp4Address;

public class BaseIOSTest {

protected static AppiumDriverLocalService service;
protected static IOSDriver driver;
protected static final int PORT = 4723;
public static final String DEVICE_NAME = System.getenv("IOS_DEVICE_NAME") != null
? System.getenv("IOS_DEVICE_NAME") : "iPhone 12";
? System.getenv("IOS_DEVICE_NAME")
: "iPhone 12";
public static final String PLATFORM_VERSION = System.getenv("IOS_PLATFORM_VERSION") != null
? System.getenv("IOS_PLATFORM_VERSION") : "14.5";
? System.getenv("IOS_PLATFORM_VERSION")
: "14.5";
public static final Duration WDA_LAUNCH_TIMEOUT = Duration.ofSeconds(240);

/**
* Starts a local server.
*
* @return ip of a local host
* @throws UnknownHostException when it is impossible to get ip address of a local host
* @return service instance
*/
public static String startAppiumServer() throws UnknownHostException, SocketException {
service = new AppiumServiceBuilder().usingPort(PORT).build();
public static AppiumDriverLocalService startAppiumServer() {
service = new AppiumServiceBuilder()
.withIPAddress("127.0.0.1")
.usingPort(PORT)
.build();
service.start();
return getLocalIp4Address();
return service;
}

/**
Expand Down
Loading