diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index e5981b475..caf838f59 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -27,4 +27,4 @@ jobs: java-version: ${{ matrix.java }} cache: 'gradle' - name: Build with Gradle - run: ./gradlew clean build -x test -x checkstyleTest + run: ./gradlew clean build -x unitTest -x checkstyleTest diff --git a/build.gradle b/build.gradle index 084b502cb..b0116c43b 100644 --- a/build.gradle +++ b/build.gradle @@ -191,6 +191,15 @@ processResources { ] } +task unitTest( type: Test ) { + useJUnitPlatform() + testLogging.showStandardStreams = true + testLogging.exceptionFormat = 'full' + filter { + includeTestsMatching 'io.appium.java_client.internal.*' + } +} + task xcuiTest( type: Test ) { useJUnitPlatform() testLogging.showStandardStreams = true diff --git a/gradle.properties b/gradle.properties index b11361057..9b086f575 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,4 +7,4 @@ signing.secretKeyRingFile=PathToYourKeyRingFile ossrhUsername=your-jira-id ossrhPassword=your-jira-password -selenium.version=4.4.0 +selenium.version=4.5.0 diff --git a/src/main/java/io/appium/java_client/AppiumClientConfig.java b/src/main/java/io/appium/java_client/AppiumClientConfig.java new file mode 100644 index 000000000..2e6128c03 --- /dev/null +++ b/src/main/java/io/appium/java_client/AppiumClientConfig.java @@ -0,0 +1,191 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.appium.java_client; + +import org.openqa.selenium.Credentials; +import org.openqa.selenium.internal.Require; +import org.openqa.selenium.remote.http.AddSeleniumUserAgent; +import org.openqa.selenium.remote.http.ClientConfig; +import org.openqa.selenium.remote.http.Filter; + +import java.net.Proxy; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.time.Duration; + +/** + * A class to store the appium http client configuration. + */ +public class AppiumClientConfig extends ClientConfig { + private final boolean directConnect; + + private static final Filter DEFAULT_FILTER = new AddSeleniumUserAgent(); + + private static final Duration DEFAULT_READ_TIMEOUT = Duration.ofMinutes(10); + + private static final Duration DEFAULT_CONNECTION_TIMEOUT = Duration.ofSeconds(10); + + /** + * Client side configuration. + * + * @param baseUri Base URL the client sends HTTP request to. + * @param connectionTimeout The client connection timeout. + * @param readTimeout The client read timeout. + * @param filters Filters to modify incoming {@link org.openqa.selenium.remote.http.HttpRequest} or outgoing + * {@link org.openqa.selenium.remote.http.HttpResponse}. + * @param proxy The client proxy preference. + * @param credentials Credentials used for authenticating http requests + * @param directConnect If directConnect is enabled. + */ + protected AppiumClientConfig( + URI baseUri, + Duration connectionTimeout, + Duration readTimeout, + Filter filters, + Proxy proxy, + Credentials credentials, + Boolean directConnect) { + super(baseUri, connectionTimeout, readTimeout, filters, proxy, credentials); + + this.directConnect = Require.nonNull("Direct Connect", directConnect); + } + + /** + * Return the instance of {@link AppiumClientConfig} with a default config. + * @return the instance of {@link AppiumClientConfig}. + */ + public static AppiumClientConfig defaultConfig() { + return new AppiumClientConfig( + null, + DEFAULT_CONNECTION_TIMEOUT, + DEFAULT_READ_TIMEOUT, + DEFAULT_FILTER, + null, + null, + false); + } + + /** + * Return the instance of {@link AppiumClientConfig} from the given {@link ClientConfig} parameters. + * @param clientConfig take a look at {@link ClientConfig} + * @return the instance of {@link AppiumClientConfig}. + */ + public static AppiumClientConfig fromClientConfig(ClientConfig clientConfig) { + return new AppiumClientConfig( + clientConfig.baseUri(), + clientConfig.connectionTimeout(), + clientConfig.readTimeout(), + clientConfig.filter(), + clientConfig.proxy(), + clientConfig.credentials(), + false); + } + + private AppiumClientConfig buildAppiumClientConfig(ClientConfig clientConfig, Boolean directConnect) { + return new AppiumClientConfig( + clientConfig.baseUri(), + clientConfig.connectionTimeout(), + clientConfig.readTimeout(), + clientConfig.filter(), + clientConfig.proxy(), + clientConfig.credentials(), + directConnect); + } + + @Override + public AppiumClientConfig baseUri(URI baseUri) { + ClientConfig clientConfig = super.baseUri(baseUri); + return buildAppiumClientConfig(clientConfig, directConnect); + } + + @Override + public AppiumClientConfig baseUrl(URL baseUrl) { + try { + return baseUri(Require.nonNull("Base URL", baseUrl).toURI()); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + + @Override + public AppiumClientConfig connectionTimeout(Duration timeout) { + ClientConfig clientConfig = super.connectionTimeout(timeout); + return buildAppiumClientConfig(clientConfig, directConnect); + } + + @Override + public AppiumClientConfig readTimeout(Duration timeout) { + ClientConfig clientConfig = super.connectionTimeout(timeout); + return buildAppiumClientConfig(clientConfig, directConnect); + } + + @Override + public AppiumClientConfig withFilter(Filter filter) { + ClientConfig clientConfig = super.withFilter(filter); + return buildAppiumClientConfig(clientConfig, directConnect); + } + + @Override + public AppiumClientConfig withRetries() { + ClientConfig clientConfig = super.withRetries(); + return buildAppiumClientConfig(clientConfig, directConnect); + } + + + @Override + public ClientConfig proxy(Proxy proxy) { + ClientConfig clientConfig = super.proxy(proxy); + return buildAppiumClientConfig(clientConfig, directConnect); + } + + @Override + public AppiumClientConfig authenticateAs(Credentials credentials) { + ClientConfig clientConfig = super.authenticateAs(credentials); + return buildAppiumClientConfig(clientConfig, directConnect); + } + + /** + * Whether enable directConnect feature described in + * + * Connecting Directly to Appium Hosts in Distributed Environments. + * + * @param directConnect if enable the directConnect feature + * @return A new instance of AppiumClientConfig + */ + public AppiumClientConfig directConnect(boolean directConnect) { + // follows ClientConfig's design + return new AppiumClientConfig( + this.baseUri(), + this.connectionTimeout(), + this.readTimeout(), + this.filter(), + this.proxy(), + this.credentials(), + directConnect + ); + } + + /** + * Whether enable directConnect feature is enabled. + * + * @return If the directConnect is enabled. Defaults false. + */ + public boolean isDirectConnectEnabled() { + return directConnect; + } +} diff --git a/src/main/java/io/appium/java_client/AppiumDriver.java b/src/main/java/io/appium/java_client/AppiumDriver.java index 0f109af2c..d814657c6 100644 --- a/src/main/java/io/appium/java_client/AppiumDriver.java +++ b/src/main/java/io/appium/java_client/AppiumDriver.java @@ -41,7 +41,6 @@ import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.remote.Response; import org.openqa.selenium.remote.html5.RemoteLocationContext; -import org.openqa.selenium.remote.http.ClientConfig; import org.openqa.selenium.remote.http.HttpClient; import org.openqa.selenium.remote.http.HttpMethod; @@ -84,7 +83,7 @@ public AppiumDriver(HttpCommandExecutor executor, Capabilities capabilities) { this.remoteAddress = executor.getAddressOfRemoteServer(); } - public AppiumDriver(ClientConfig clientConfig, Capabilities capabilities) { + public AppiumDriver(AppiumClientConfig clientConfig, Capabilities capabilities) { this(new AppiumCommandExecutor(MobileCommand.commandRepository, clientConfig), capabilities); } 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 76810cac3..92ed19370 100644 --- a/src/main/java/io/appium/java_client/android/AndroidDriver.java +++ b/src/main/java/io/appium/java_client/android/AndroidDriver.java @@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableMap; +import io.appium.java_client.AppiumClientConfig; import io.appium.java_client.AppiumDriver; import io.appium.java_client.CommandExecutionHelper; import io.appium.java_client.ExecuteCDPCommand; @@ -203,7 +204,32 @@ public AndroidDriver(HttpClient.Factory httpClientFactory, Capabilities capabili * */ public AndroidDriver(ClientConfig clientConfig, Capabilities capabilities) { - super(clientConfig, ensurePlatformName(capabilities, ANDROID_PLATFORM)); + super(AppiumClientConfig.fromClientConfig(clientConfig), ensurePlatformName(capabilities, + ANDROID_PLATFORM)); + } + + /** + * Creates a new instance based on the given ClientConfig and {@code capabilities}. + * The HTTP client is default client generated by {@link HttpCommandExecutor#getDefaultClientFactory}. + * For example: + * + *
+ *
+ * AppiumClientConfig appiumClientConfig = AppiumClientConfig.defaultConfig()
+ * .directConnect(true)
+ * .baseUri(URI.create("WebDriver URL"))
+ * .readTimeout(Duration.ofMinutes(5));
+ * UiAutomator2Options options = new UiAutomator2Options();
+ * AndroidDriver driver = new AndroidDriver(appiumClientConfig, options);
+ *
+ *
+ *
+ * @param appiumClientConfig take a look at {@link AppiumClientConfig}
+ * @param capabilities take a look at {@link Capabilities}
+ *
+ */
+ public AndroidDriver(AppiumClientConfig appiumClientConfig, Capabilities capabilities) {
+ super(appiumClientConfig, ensurePlatformName(capabilities, ANDROID_PLATFORM));
}
/**
diff --git a/src/main/java/io/appium/java_client/gecko/GeckoDriver.java b/src/main/java/io/appium/java_client/gecko/GeckoDriver.java
index 43d2072c8..6a7a55cab 100644
--- a/src/main/java/io/appium/java_client/gecko/GeckoDriver.java
+++ b/src/main/java/io/appium/java_client/gecko/GeckoDriver.java
@@ -16,6 +16,7 @@
package io.appium.java_client.gecko;
+import io.appium.java_client.AppiumClientConfig;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.remote.AutomationName;
import io.appium.java_client.service.local.AppiumDriverLocalService;
@@ -94,7 +95,31 @@ public GeckoDriver(HttpClient.Factory httpClientFactory, Capabilities capabiliti
*
*/
public GeckoDriver(ClientConfig clientConfig, Capabilities capabilities) {
- super(clientConfig, ensureAutomationName(capabilities, AUTOMATION_NAME));
+ super(AppiumClientConfig.fromClientConfig(clientConfig), ensureAutomationName(capabilities, AUTOMATION_NAME));
+ }
+
+ /**
+ * Creates a new instance based on the given ClientConfig and {@code capabilities}.
+ * The HTTP client is default client generated by {@link HttpCommandExecutor#getDefaultClientFactory}.
+ * For example:
+ *
+ *
+ *
+ * AppiumClientConfig appiumClientConfig = AppiumClientConfig.defaultConfig()
+ * .directConnect(true)
+ * .baseUri(URI.create("WebDriver URL"))
+ * .readTimeout(Duration.ofMinutes(5));
+ * GeckoOptions options = new GeckoOptions();
+ * GeckoDriver driver = new GeckoDriver(options, appiumClientConfig);
+ *
+ *
+ *
+ * @param appiumClientConfig take a look at {@link AppiumClientConfig}
+ * @param capabilities take a look at {@link Capabilities}
+ *
+ */
+ public GeckoDriver(AppiumClientConfig appiumClientConfig, Capabilities capabilities) {
+ super(appiumClientConfig, ensureAutomationName(capabilities, AUTOMATION_NAME));
}
public GeckoDriver(Capabilities capabilities) {
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 18ecf3065..00098b14c 100644
--- a/src/main/java/io/appium/java_client/ios/IOSDriver.java
+++ b/src/main/java/io/appium/java_client/ios/IOSDriver.java
@@ -21,6 +21,7 @@
import com.google.common.collect.ImmutableMap;
+import io.appium.java_client.AppiumClientConfig;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.HasAppStrings;
import io.appium.java_client.HasDeviceTime;
@@ -192,9 +193,35 @@ public IOSDriver(HttpClient.Factory httpClientFactory, Capabilities capabilities
*
*/
public IOSDriver(ClientConfig clientConfig, Capabilities capabilities) {
- super(clientConfig, ensurePlatformName(capabilities, PLATFORM_NAME));
+ super(AppiumClientConfig.fromClientConfig(clientConfig),
+ ensurePlatformName(capabilities, PLATFORM_NAME));
}
+ /**
+ * Creates a new instance based on the given ClientConfig and {@code capabilities}.
+ * The HTTP client is default client generated by {@link HttpCommandExecutor#getDefaultClientFactory}.
+ * For example:
+ *
+ *
+ *
+ * AppiumClientConfig appiumClientConfig = AppiumClientConfig.defaultConfig()
+ * .directConnect(true)
+ * .baseUri(URI.create("WebDriver URL"))
+ * .readTimeout(Duration.ofMinutes(5));
+ * XCUITestOptions options = new XCUITestOptions();
+ * IOSDriver driver = new IOSDriver(options, appiumClientConfig);
+ *
+ *
+ *
+ * @param appiumClientConfig take a look at {@link AppiumClientConfig}
+ * @param capabilities take a look at {@link Capabilities}
+ *
+ */
+ public IOSDriver(AppiumClientConfig appiumClientConfig, Capabilities capabilities) {
+ super(appiumClientConfig, ensurePlatformName(capabilities, PLATFORM_NAME));
+ }
+
+
/**
* Creates a new instance based on {@code capabilities}.
*
diff --git a/src/main/java/io/appium/java_client/mac/Mac2Driver.java b/src/main/java/io/appium/java_client/mac/Mac2Driver.java
index b76de5943..905cbec77 100644
--- a/src/main/java/io/appium/java_client/mac/Mac2Driver.java
+++ b/src/main/java/io/appium/java_client/mac/Mac2Driver.java
@@ -16,6 +16,7 @@
package io.appium.java_client.mac;
+import io.appium.java_client.AppiumClientConfig;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.PerformsTouchActions;
import io.appium.java_client.remote.AutomationName;
@@ -105,7 +106,32 @@ public Mac2Driver(HttpClient.Factory httpClientFactory, Capabilities capabilitie
*
*/
public Mac2Driver(ClientConfig clientConfig, Capabilities capabilities) {
- super(clientConfig, ensurePlatformAndAutomationNames(
+ super(AppiumClientConfig.fromClientConfig(clientConfig), ensurePlatformAndAutomationNames(
+ capabilities, PLATFORM_NAME, AUTOMATION_NAME));
+ }
+
+ /**
+ * Creates a new instance based on the given ClientConfig and {@code capabilities}.
+ * The HTTP client is default client generated by {@link HttpCommandExecutor#getDefaultClientFactory}.
+ * For example:
+ *
+ *
+ *
+ * AppiumClientConfig appiumClientConfig = AppiumClientConfig.defaultConfig()
+ * .directConnect(true)
+ * .baseUri(URI.create("WebDriver URL"))
+ * .readTimeout(Duration.ofMinutes(5));
+ * Mac2Options options = new Mac2Options();
+ * Mac2Driver driver = new Mac2Driver(appiumClientConfig, options);
+ *
+ *
+ *
+ * @param appiumClientConfig take a look at {@link AppiumClientConfig}
+ * @param capabilities take a look at {@link Capabilities}
+ *
+ */
+ public Mac2Driver(AppiumClientConfig appiumClientConfig, Capabilities capabilities) {
+ super(appiumClientConfig, ensurePlatformAndAutomationNames(
capabilities, PLATFORM_NAME, AUTOMATION_NAME));
}
diff --git a/src/main/java/io/appium/java_client/remote/AppiumCommandExecutor.java b/src/main/java/io/appium/java_client/remote/AppiumCommandExecutor.java
index 01c551fb4..ec792852a 100644
--- a/src/main/java/io/appium/java_client/remote/AppiumCommandExecutor.java
+++ b/src/main/java/io/appium/java_client/remote/AppiumCommandExecutor.java
@@ -24,9 +24,9 @@
import com.google.common.base.Supplier;
import com.google.common.base.Throwables;
+import io.appium.java_client.AppiumClientConfig;
import org.openqa.selenium.SessionNotCreatedException;
import org.openqa.selenium.WebDriverException;
-import org.openqa.selenium.internal.Require;
import org.openqa.selenium.remote.Command;
import org.openqa.selenium.remote.CommandCodec;
import org.openqa.selenium.remote.CommandExecutor;
@@ -38,17 +38,18 @@
import org.openqa.selenium.remote.Response;
import org.openqa.selenium.remote.ResponseCodec;
import org.openqa.selenium.remote.codec.w3c.W3CHttpCommandCodec;
-import org.openqa.selenium.remote.http.ClientConfig;
import org.openqa.selenium.remote.http.HttpClient;
import org.openqa.selenium.remote.http.HttpRequest;
import org.openqa.selenium.remote.http.HttpResponse;
import org.openqa.selenium.remote.service.DriverService;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.ConnectException;
+import java.net.MalformedURLException;
import java.net.URL;
-import java.time.Duration;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
@@ -56,49 +57,71 @@
public class AppiumCommandExecutor extends HttpCommandExecutor {
// https://github.com/appium/appium-base-driver/pull/400
private static final String IDEMPOTENCY_KEY_HEADER = "X-Idempotency-Key";
- private static final Duration DEFAULT_READ_TIMEOUT = Duration.ofMinutes(10);
private final Optional
+ *
+ * AppiumClientConfig appiumClientConfig = AppiumClientConfig.defaultConfig()
+ * .directConnect(true)
+ * .baseUri(URI.create("WebDriver URL"))
+ * .readTimeout(Duration.ofMinutes(5));
+ * SafariOptions options = new SafariOptions();
+ * SafariDriver driver = new SafariDriver(appiumClientConfig, options);
+ *
+ *
+ *
+ * @param appiumClientConfig take a look at {@link AppiumClientConfig}
+ * @param capabilities take a look at {@link Capabilities}
+ *
+ */
+ public SafariDriver(AppiumClientConfig appiumClientConfig, Capabilities capabilities) {
+ super(appiumClientConfig, ensurePlatformAndAutomationNames(
capabilities, PLATFORM_NAME, AUTOMATION_NAME));
}
diff --git a/src/main/java/io/appium/java_client/windows/WindowsDriver.java b/src/main/java/io/appium/java_client/windows/WindowsDriver.java
index 82af6e02d..9a441d68a 100644
--- a/src/main/java/io/appium/java_client/windows/WindowsDriver.java
+++ b/src/main/java/io/appium/java_client/windows/WindowsDriver.java
@@ -16,6 +16,7 @@
package io.appium.java_client.windows;
+import io.appium.java_client.AppiumClientConfig;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileCommand;
import io.appium.java_client.PerformsTouchActions;
@@ -45,6 +46,7 @@ public WindowsDriver(HttpCommandExecutor executor, Capabilities capabilities) {
super(executor, ensurePlatformAndAutomationNames(capabilities, PLATFORM_NAME, AUTOMATION_NAME));
}
+
public WindowsDriver(URL remoteAddress, Capabilities capabilities) {
super(remoteAddress, ensurePlatformAndAutomationNames(
capabilities, PLATFORM_NAME, AUTOMATION_NAME));
@@ -100,7 +102,32 @@ public WindowsDriver(HttpClient.Factory httpClientFactory, Capabilities capabili
*
*/
public WindowsDriver(ClientConfig clientConfig, Capabilities capabilities) {
- super(clientConfig, ensurePlatformAndAutomationNames(
+ super(AppiumClientConfig.fromClientConfig(clientConfig), ensurePlatformAndAutomationNames(
+ capabilities, PLATFORM_NAME, AUTOMATION_NAME));
+ }
+
+ /**
+ * Creates a new instance based on the given ClientConfig and {@code capabilities}.
+ * The HTTP client is default client generated by {@link HttpCommandExecutor#getDefaultClientFactory}.
+ * For example:
+ *
+ *
+ *
+ * AppiumClientConfig appiumClientConfig = AppiumClientConfig.defaultConfig()
+ * .directConnect(true)
+ * .baseUri(URI.create("WebDriver URL"))
+ * .readTimeout(Duration.ofMinutes(5));
+ * WindowsOptions options = new WindowsOptions();
+ * WindowsDriver driver = new WindowsDriver(appiumClientConfig, options);
+ *
+ *
+ *
+ * @param appiumClientConfig take a look at {@link AppiumClientConfig}
+ * @param capabilities take a look at {@link Capabilities}
+ *
+ */
+ public WindowsDriver(AppiumClientConfig appiumClientConfig, Capabilities capabilities) {
+ super(appiumClientConfig, ensurePlatformAndAutomationNames(
capabilities, PLATFORM_NAME, AUTOMATION_NAME));
}
diff --git a/src/test/java/io/appium/java_client/events/stubs/EmptyWebDriver.java b/src/test/java/io/appium/java_client/events/stubs/EmptyWebDriver.java
index 5316f56e4..01104b988 100644
--- a/src/test/java/io/appium/java_client/events/stubs/EmptyWebDriver.java
+++ b/src/test/java/io/appium/java_client/events/stubs/EmptyWebDriver.java
@@ -202,10 +202,6 @@ public Timeouts timeouts() {
return null;
}
- public ImeHandler ime() {
- return null;
- }
-
public Window window() {
return new StubWindow();
}
diff --git a/src/test/java/io/appium/java_client/internal/ConfigTest.java b/src/test/java/io/appium/java_client/internal/ConfigTest.java
index df8611458..05559de27 100644
--- a/src/test/java/io/appium/java_client/internal/ConfigTest.java
+++ b/src/test/java/io/appium/java_client/internal/ConfigTest.java
@@ -9,13 +9,14 @@
import org.junit.jupiter.api.Test;
class ConfigTest {
- private static final String EXISTING_KEY = "selenium.version";
+ private static final String SELENIUM_EXISTING_KEY = "selenium.version";
+
private static final String MISSING_KEY = "bla";
@Test
void verifyGettingExistingValue() {
- assertThat(Config.main().getValue(EXISTING_KEY, String.class).length(), greaterThan(0));
- assertTrue(Config.main().getOptionalValue(EXISTING_KEY, String.class).isPresent());
+ assertThat(Config.main().getValue(SELENIUM_EXISTING_KEY, String.class).length(), greaterThan(0));
+ assertTrue(Config.main().getOptionalValue(SELENIUM_EXISTING_KEY, String.class).isPresent());
}
@Test
@@ -25,7 +26,7 @@ void verifyGettingNonExistingValue() {
@Test
void verifyGettingExistingValueWithWrongClass() {
- assertThrows(ClassCastException.class, () -> Config.main().getValue(EXISTING_KEY, Integer.class));
+ assertThrows(ClassCastException.class, () -> Config.main().getValue(SELENIUM_EXISTING_KEY, Integer.class));
}
@Test
diff --git a/src/test/java/io/appium/java_client/internal/DirectConnectTest.java b/src/test/java/io/appium/java_client/internal/DirectConnectTest.java
new file mode 100644
index 000000000..93b345474
--- /dev/null
+++ b/src/test/java/io/appium/java_client/internal/DirectConnectTest.java
@@ -0,0 +1,56 @@
+package io.appium.java_client.internal;
+
+import io.appium.java_client.remote.DirectConnect;
+import org.junit.jupiter.api.Test;
+
+import java.net.MalformedURLException;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class DirectConnectTest {
+
+ @Test
+ void hasValidDirectConnectValuesWithoutAppiumPrefix() throws MalformedURLException {
+ Map