diff --git a/README.md b/README.md
index 5782a7ec9..675bc01e1 100644
--- a/README.md
+++ b/README.md
@@ -147,7 +147,8 @@ Appium java client has dedicated classes to support the following Appium drivers
- [UiAutomator2](https://github.com/appium/appium-uiautomator2-driver) and [Espresso](https://github.com/appium/appium-espresso-driver): [AndroidDriver](src/main/java/io/appium/java_client/android/AndroidDriver.java)
- [XCUITest](https://github.com/appium/appium-xcuitest-driver): [IOSDriver](src/main/java/io/appium/java_client/ios/IOSDriver.java)
-- [Windows](https://github.com/appium/appium-windows-driver): [WindowsDriver](src/main/java/io/appium/java_client/windows/WindowsDriver.java)
+- [Windows (deprecated, not supported since Appium 4)](https://github.com/appium/appium-windows-driver): [WindowsDriver](src/main/java/io/appium/java_client/windows/WindowsDriver.java)
+- [Wincore](https://github.com/appium/appium-wincore-driver): [WincoreDriver](src/main/java/io/appium/java_client/wincore/WincoreDriver.java)
- [Safari](https://github.com/appium/appium-safari-driver): [SafariDriver](src/main/java/io/appium/java_client/safari/SafariDriver.java)
- [Gecko](https://github.com/appium/appium-geckodriver): [GeckoDriver](src/main/java/io/appium/java_client/gecko/GeckoDriver.java)
- [Mac2](https://github.com/appium/appium-mac2-driver): [Mac2Driver](src/main/java/io/appium/java_client/mac/Mac2Driver.java)
diff --git a/src/main/java/io/appium/java_client/remote/AutomationName.java b/src/main/java/io/appium/java_client/remote/AutomationName.java
index ed5e9c699..35a0ddbcf 100644
--- a/src/main/java/io/appium/java_client/remote/AutomationName.java
+++ b/src/main/java/io/appium/java_client/remote/AutomationName.java
@@ -29,8 +29,16 @@ public interface AutomationName {
String ESPRESSO = "Espresso";
/** The automation name of the Mac2 driver for macOS. */
String MAC2 = "Mac2";
- /** The automation name of the Windows driver. */
+ /**
+ * The automation name of the Windows driver.
+ *
+ * @deprecated The Windows driver is deprecated and not supported since Appium 4.
+ * Use {@link #WINCORE} instead.
+ */
+ @Deprecated
String WINDOWS = "Windows";
+ /** The automation name of the Wincore driver, the successor of the Windows driver. */
+ String WINCORE = "Wincore";
/** The automation name of the Safari driver. */
String SAFARI = "Safari";
/** The automation name of the Gecko driver for Firefox. */
diff --git a/src/main/java/io/appium/java_client/wincore/WincoreDriver.java b/src/main/java/io/appium/java_client/wincore/WincoreDriver.java
new file mode 100644
index 000000000..56f414cd8
--- /dev/null
+++ b/src/main/java/io/appium/java_client/wincore/WincoreDriver.java
@@ -0,0 +1,263 @@
+/*
+ * 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.wincore;
+
+import io.appium.java_client.AppiumClientConfig;
+import io.appium.java_client.AppiumDriver;
+import io.appium.java_client.CommandExecutionHelper;
+import io.appium.java_client.PullsFiles;
+import io.appium.java_client.PushesFiles;
+import io.appium.java_client.http.HttpClient;
+import io.appium.java_client.remote.AppiumCommandExecutor;
+import io.appium.java_client.remote.AutomationName;
+import io.appium.java_client.remote.SupportsContextSwitching;
+import io.appium.java_client.screenrecording.CanRecordScreen;
+import io.appium.java_client.service.local.AppiumDriverLocalService;
+import io.appium.java_client.service.local.AppiumServiceBuilder;
+import org.jspecify.annotations.Nullable;
+import org.openqa.selenium.Capabilities;
+import org.openqa.selenium.Platform;
+
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.Map;
+
+import static io.appium.java_client.MobileCommand.PULL_FILE;
+import static io.appium.java_client.MobileCommand.PUSH_FILE;
+import static java.util.Objects.requireNonNull;
+
+/**
+ * WincoreDriver is an officially supported Appium driver created to automate Windows apps.
+ * It is the successor of the Windows driver, which is deprecated and not supported since Appium 4,
+ * see {@link io.appium.java_client.windows.WindowsDriver}.
+ * Read https://github.com/appium/appium-wincore-driver for more details.
+ */
+public class WincoreDriver extends AppiumDriver implements
+ PullsFiles,
+ PushesFiles,
+ SupportsContextSwitching,
+ CanRecordScreen {
+ private static final String PLATFORM_NAME = Platform.WINDOWS.name();
+ private static final String AUTOMATION_NAME = AutomationName.WINCORE;
+
+ /**
+ * Creates a new instance based on command {@code executor} and {@code capabilities}.
+ *
+ * @param executor is an instance of {@link AppiumCommandExecutor}
+ * or class that extends it. Default commands or another vendor-specific
+ * commands may be specified there.
+ * @param capabilities take a look at {@link Capabilities}
+ */
+ public WincoreDriver(AppiumCommandExecutor executor, Capabilities capabilities) {
+ super(executor, ensurePlatformAndAutomationNames(capabilities, PLATFORM_NAME, AUTOMATION_NAME));
+ }
+
+ /**
+ * Creates a new instance based on Appium server URL and {@code capabilities}.
+ *
+ * @param remoteAddress is the address of remotely/locally started Appium server
+ * @param capabilities take a look at {@link Capabilities}
+ */
+ public WincoreDriver(URL remoteAddress, Capabilities capabilities) {
+ super(remoteAddress, ensurePlatformAndAutomationNames(
+ capabilities, PLATFORM_NAME, AUTOMATION_NAME));
+ }
+
+ /**
+ * Creates a new instance based on Appium server URL, HTTP client factory and {@code capabilities}.
+ *
+ * @param remoteAddress is the address of remotely/locally started Appium server
+ * @param httpClientFactory take a look at {@link HttpClient.Factory}
+ * @param capabilities take a look at {@link Capabilities}
+ */
+ public WincoreDriver(URL remoteAddress, HttpClient.Factory httpClientFactory, Capabilities capabilities) {
+ super(remoteAddress, httpClientFactory, ensurePlatformAndAutomationNames(
+ capabilities, PLATFORM_NAME, AUTOMATION_NAME));
+ }
+
+ /**
+ * Creates a new instance based on Appium driver local service and {@code capabilities}.
+ *
+ * @param service take a look at {@link AppiumDriverLocalService}
+ * @param capabilities take a look at {@link Capabilities}
+ */
+ public WincoreDriver(AppiumDriverLocalService service, Capabilities capabilities) {
+ super(service, ensurePlatformAndAutomationNames(capabilities, PLATFORM_NAME, AUTOMATION_NAME));
+ }
+
+ /**
+ * Creates a new instance based on Appium driver local service, HTTP client factory and {@code capabilities}.
+ *
+ * @param service take a look at {@link AppiumDriverLocalService}
+ * @param httpClientFactory take a look at {@link HttpClient.Factory}
+ * @param capabilities take a look at {@link Capabilities}
+ */
+ public WincoreDriver(AppiumDriverLocalService service, HttpClient.Factory httpClientFactory,
+ Capabilities capabilities) {
+ super(service, httpClientFactory, ensurePlatformAndAutomationNames(
+ capabilities, PLATFORM_NAME, AUTOMATION_NAME));
+ }
+
+ /**
+ * Creates a new instance based on Appium service builder and {@code capabilities}.
+ *
+ * @param builder take a look at {@link AppiumServiceBuilder}
+ * @param capabilities take a look at {@link Capabilities}
+ */
+ public WincoreDriver(AppiumServiceBuilder builder, Capabilities capabilities) {
+ super(builder, ensurePlatformAndAutomationNames(capabilities, PLATFORM_NAME, AUTOMATION_NAME));
+ }
+
+ /**
+ * Creates a new instance based on Appium service builder, HTTP client factory and {@code capabilities}.
+ *
+ * @param builder take a look at {@link AppiumServiceBuilder}
+ * @param httpClientFactory take a look at {@link HttpClient.Factory}
+ * @param capabilities take a look at {@link Capabilities}
+ */
+ public WincoreDriver(AppiumServiceBuilder builder, HttpClient.Factory httpClientFactory,
+ Capabilities capabilities) {
+ super(builder, httpClientFactory, ensurePlatformAndAutomationNames(
+ capabilities, PLATFORM_NAME, AUTOMATION_NAME));
+ }
+
+ /**
+ * Creates a new instance based on HTTP client factory and {@code capabilities}.
+ *
+ * @param httpClientFactory take a look at {@link HttpClient.Factory}
+ * @param capabilities take a look at {@link Capabilities}
+ */
+ public WincoreDriver(HttpClient.Factory httpClientFactory, Capabilities capabilities) {
+ super(httpClientFactory, ensurePlatformAndAutomationNames(
+ capabilities, PLATFORM_NAME, AUTOMATION_NAME));
+ }
+
+ /**
+ * Creates a new instance connected to an already running driver session.
+ * Intended for debugging purposes only; the caller maintains the session state.
+ *
+ * @param remoteSessionAddress The address of the **running** session including the session identifier.
+ */
+ public WincoreDriver(URL remoteSessionAddress) {
+ super(remoteSessionAddress, PLATFORM_NAME, AUTOMATION_NAME);
+ }
+
+ /**
+ * Creates a new instance based on the given AppiumClientConfig and {@code capabilities}.
+ * The HTTP client is default client generated by {@link HttpClient.Factory#createDefault()}.
+ * For example:
+ *
+ *
+ *
+ * AppiumClientConfig appiumClientConfig = AppiumClientConfig.defaultConfig()
+ * .directConnect(true)
+ * .baseUri(URI.create("WebDriver URL"))
+ * .readTimeout(Duration.ofMinutes(5));
+ * WincoreOptions options = new WincoreOptions();
+ * WincoreDriver driver = new WincoreDriver(appiumClientConfig, options);
+ *
+ *
+ *
+ * @param appiumClientConfig take a look at {@link AppiumClientConfig}
+ * @param capabilities take a look at {@link Capabilities}
+ *
+ */
+ public WincoreDriver(AppiumClientConfig appiumClientConfig, Capabilities capabilities) {
+ super(appiumClientConfig, ensurePlatformAndAutomationNames(
+ capabilities, PLATFORM_NAME, AUTOMATION_NAME));
+ }
+
+ /**
+ * Creates a new instance based on {@code capabilities}.
+ *
+ * @param capabilities take a look at {@link Capabilities}
+ */
+ public WincoreDriver(Capabilities capabilities) {
+ super(ensurePlatformAndAutomationNames(capabilities, PLATFORM_NAME, AUTOMATION_NAME));
+ }
+
+ /**
+ * Pulls a file from the remote system. The Wincore driver has no `mobile:` extension for it.
+ * The server must enable the {@code wincore:modify_fs} insecure feature,
+ * for example {@code --allow-insecure=wincore:modify_fs}.
+ *
+ * @param remotePath Path to the file to read data from the remote device.
+ * @return A byte array of Base64 encoded data.
+ */
+ @Override
+ public byte[] pullFile(String remotePath) {
+ return decodeBase64(CommandExecutionHelper.execute(this, Map.entry(PULL_FILE, Map.of("path", remotePath))));
+ }
+
+ /**
+ * Not supported by the Wincore driver.
+ *
+ * @param remotePath Path to the folder to read data from the remote device.
+ * @return Never returns normally.
+ * @throws UnsupportedOperationException always.
+ */
+ @Override
+ public byte[] pullFolder(String remotePath) {
+ throw new UnsupportedOperationException("The Wincore driver cannot pull folders");
+ }
+
+ /**
+ * Saves base64-encoded data as a file on the remote system. The Wincore driver has no `mobile:` extension for it.
+ * The server must enable the {@code wincore:modify_fs} insecure feature,
+ * for example {@code --allow-insecure=wincore:modify_fs}.
+ *
+ * @param remotePath Path to the file to write data to on the remote device.
+ * @param base64Data Base64 encoded byte array of the data to write to the remote device.
+ */
+ @Override
+ public void pushFile(String remotePath, byte[] base64Data) {
+ CommandExecutionHelper.execute(this, Map.entry(PUSH_FILE, Map.of(
+ "path", remotePath,
+ "data", new String(base64Data, StandardCharsets.UTF_8)
+ )));
+ }
+
+ /**
+ * Starts the screen recording with the default options. The driver returns no value,
+ * so the options overload is used to stay null-safe.
+ *
+ * @return `not used`.
+ */
+ @Override
+ public String startRecordingScreen() {
+ return startRecordingScreen(new WincoreStartScreenRecordingOptions());
+ }
+
+ private static byte[] decodeBase64(@Nullable String base64String) {
+ return Base64.getDecoder().decode(requireNonNull(base64String).getBytes(StandardCharsets.UTF_8));
+ }
+
+ /**
+ * Launch the application app under test after it was closed.
+ */
+ public void launchApp() {
+ CommandExecutionHelper.executeScript(this, "windows: launchApp");
+ }
+
+ /**
+ * Close the app under test.
+ */
+ public void closeApp() {
+ CommandExecutionHelper.executeScript(this, "windows: closeApp");
+ }
+}
diff --git a/src/main/java/io/appium/java_client/wincore/WincoreStartScreenRecordingOptions.java b/src/main/java/io/appium/java_client/wincore/WincoreStartScreenRecordingOptions.java
new file mode 100644
index 000000000..b86932342
--- /dev/null
+++ b/src/main/java/io/appium/java_client/wincore/WincoreStartScreenRecordingOptions.java
@@ -0,0 +1,163 @@
+/*
+ * 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.wincore;
+
+import io.appium.java_client.screenrecording.BaseStartScreenRecordingOptions;
+
+import java.time.Duration;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static java.util.Optional.ofNullable;
+
+/** Wincore-specific options for starting a screen recording. */
+public class WincoreStartScreenRecordingOptions
+ extends BaseStartScreenRecordingOptions {
+ /**
+ * Creates a new instance.
+ */
+ public WincoreStartScreenRecordingOptions() {
+ }
+
+ private Integer fps;
+ private String videoFilter;
+ private String preset;
+ private Boolean captureCursor;
+ private Boolean captureClicks;
+ private String audioInput;
+
+ /**
+ * Creates a new options instance.
+ *
+ * @return a new {@link WincoreStartScreenRecordingOptions} instance.
+ */
+ public static WincoreStartScreenRecordingOptions startScreenRecordingOptions() {
+ return new WincoreStartScreenRecordingOptions();
+ }
+
+ /**
+ * The count of frames per second in the resulting video.
+ * Increasing fps value also increases the size of the resulting
+ * video file and the CPU usage.
+ *
+ * @param fps The actual frames per second value.
+ * The default value is 15.
+ * @return self instance for chaining.
+ */
+ public WincoreStartScreenRecordingOptions withFps(int fps) {
+ this.fps = fps;
+ return this;
+ }
+
+ /**
+ * Whether to capture the mouse cursor while recording
+ * the screen. Disabled by default.
+ *
+ * @return self instance for chaining.
+ */
+ public WincoreStartScreenRecordingOptions enableCursorCapture() {
+ this.captureCursor = true;
+ return this;
+ }
+
+ /**
+ * Whether to capture the click gestures while recording
+ * the screen. Disabled by default.
+ *
+ * @return self instance for chaining.
+ */
+ public WincoreStartScreenRecordingOptions enableClicksCapture() {
+ this.captureClicks = true;
+ return this;
+ }
+
+ /**
+ * If provided then the given audio input will be used to record the computer audio
+ * along with the desktop video. The list of available devices could be retrieved using
+ * `ffmpeg -list_devices true -f dshow -i dummy` command.
+ *
+ * @param audioInput One of valid audio input names listed by ffmpeg
+ * @return self instance for chaining.
+ */
+ public WincoreStartScreenRecordingOptions withAudioInput(String audioInput) {
+ this.audioInput = audioInput;
+ return this;
+ }
+
+ /**
+ * The video filter spec to apply for ffmpeg.
+ * See https://trac.ffmpeg.org/wiki/FilteringGuide for more details on the possible values.
+ * Example: Set it to `scale=ifnot(gte(iw\,1024)\,iw\,1024):-2` in order to limit the video width
+ * to 1024px. The height will be adjusted automatically to match the actual screen aspect ratio.
+ *
+ * @param videoFilter Valid ffmpeg video filter spec string.
+ * @return self instance for chaining.
+ */
+ public WincoreStartScreenRecordingOptions withVideoFilter(String videoFilter) {
+ this.videoFilter = videoFilter;
+ return this;
+ }
+
+ /**
+ * A preset is a collection of options that will provide a certain encoding speed to compression ratio.
+ * A slower preset will provide better compression (compression is quality per filesize).
+ * This means that, for example, if you target a certain file size or constant bit rate, you will
+ * achieve better quality with a slower preset. Read https://trac.ffmpeg.org/wiki/Encode/H.264
+ * for more details.
+ *
+ * @param preset One of the supported encoding presets. Possible values are:
+ * - ultrafast
+ * - superfast
+ * - veryfast (default)
+ * - faster
+ * - fast
+ * - medium
+ * - slow
+ * - slower
+ * - veryslow
+ * @return self instance for chaining.
+ */
+ public WincoreStartScreenRecordingOptions withPreset(String preset) {
+ this.preset = preset;
+ return this;
+ }
+
+ /**
+ * The maximum recording time. The default value is 600 seconds (10 minutes).
+ * The minimum time resolution unit is one second.
+ *
+ * @param timeLimit The actual time limit of the recorded video.
+ * @return self instance for chaining.
+ */
+ @Override
+ public WincoreStartScreenRecordingOptions withTimeLimit(Duration timeLimit) {
+ return super.withTimeLimit(timeLimit);
+ }
+
+ @Override
+ public Map build() {
+ var map = new HashMap<>(super.build());
+ ofNullable(fps).map(x -> map.put("videoFps", x));
+ ofNullable(preset).map(x -> map.put("preset", x));
+ ofNullable(videoFilter).map(x -> map.put("videoFilter", x));
+ ofNullable(captureClicks).map(x -> map.put("captureClicks", x));
+ ofNullable(captureCursor).map(x -> map.put("captureCursor", x));
+ ofNullable(audioInput).map(x -> map.put("audioInput", x));
+ return Collections.unmodifiableMap(map);
+ }
+}
diff --git a/src/main/java/io/appium/java_client/wincore/WincoreStopScreenRecordingOptions.java b/src/main/java/io/appium/java_client/wincore/WincoreStopScreenRecordingOptions.java
new file mode 100644
index 000000000..0bda75260
--- /dev/null
+++ b/src/main/java/io/appium/java_client/wincore/WincoreStopScreenRecordingOptions.java
@@ -0,0 +1,39 @@
+/*
+ * 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.wincore;
+
+import io.appium.java_client.screenrecording.BaseStopScreenRecordingOptions;
+
+/** Wincore-specific options for stopping a screen recording. */
+public class WincoreStopScreenRecordingOptions extends
+ BaseStopScreenRecordingOptions {
+ /**
+ * Creates a new instance.
+ */
+ public WincoreStopScreenRecordingOptions() {
+ }
+
+ /**
+ * Creates a new options instance.
+ *
+ * @return a new {@link WincoreStopScreenRecordingOptions} instance.
+ */
+ public static WincoreStopScreenRecordingOptions stopScreenRecordingOptions() {
+ return new WincoreStopScreenRecordingOptions();
+ }
+
+}
diff --git a/src/main/java/io/appium/java_client/wincore/options/SupportsChromedriverCdnUrlOption.java b/src/main/java/io/appium/java_client/wincore/options/SupportsChromedriverCdnUrlOption.java
new file mode 100644
index 000000000..2989f8c6d
--- /dev/null
+++ b/src/main/java/io/appium/java_client/wincore/options/SupportsChromedriverCdnUrlOption.java
@@ -0,0 +1,55 @@
+/*
+ * 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.wincore.options;
+
+import io.appium.java_client.remote.options.BaseOptions;
+import io.appium.java_client.remote.options.CanSetCapability;
+import org.openqa.selenium.Capabilities;
+
+import java.util.Optional;
+
+/**
+ * Provides getters and setters for the {@code chromedriverCdnUrl} capability.
+ *
+ * @param options type, used for chaining.
+ */
+public interface SupportsChromedriverCdnUrlOption> extends
+ Capabilities, CanSetCapability {
+ /**
+ * Name of the {@code chromedriverCdnUrl} capability.
+ */
+ String CHROMEDRIVER_CDN_URL_OPTION = "chromedriverCdnUrl";
+
+ /**
+ * The custom CDN URL to download chromedriver binaries from.
+ *
+ * @param value The capability value.
+ * @return self instance for chaining.
+ */
+ default T setChromedriverCdnUrl(String value) {
+ return amend(CHROMEDRIVER_CDN_URL_OPTION, value);
+ }
+
+ /**
+ * Get the custom CDN URL to download chromedriver binaries from.
+ *
+ * @return The capability value.
+ */
+ default Optional getChromedriverCdnUrl() {
+ return Optional.ofNullable((String) getCapability(CHROMEDRIVER_CDN_URL_OPTION));
+ }
+}
diff --git a/src/main/java/io/appium/java_client/wincore/options/SupportsChromedriverExecutablePathOption.java b/src/main/java/io/appium/java_client/wincore/options/SupportsChromedriverExecutablePathOption.java
new file mode 100644
index 000000000..640bc9557
--- /dev/null
+++ b/src/main/java/io/appium/java_client/wincore/options/SupportsChromedriverExecutablePathOption.java
@@ -0,0 +1,55 @@
+/*
+ * 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.wincore.options;
+
+import io.appium.java_client.remote.options.BaseOptions;
+import io.appium.java_client.remote.options.CanSetCapability;
+import org.openqa.selenium.Capabilities;
+
+import java.util.Optional;
+
+/**
+ * Provides getters and setters for the {@code chromedriverExecutablePath} capability.
+ *
+ * @param options type, used for chaining.
+ */
+public interface SupportsChromedriverExecutablePathOption> extends
+ Capabilities, CanSetCapability {
+ /**
+ * Name of the {@code chromedriverExecutablePath} capability.
+ */
+ String CHROMEDRIVER_EXECUTABLE_PATH_OPTION = "chromedriverExecutablePath";
+
+ /**
+ * Full path to the local chromedriver binary on the server file system.
+ *
+ * @param value The capability value.
+ * @return self instance for chaining.
+ */
+ default T setChromedriverExecutablePath(String value) {
+ return amend(CHROMEDRIVER_EXECUTABLE_PATH_OPTION, value);
+ }
+
+ /**
+ * Get the path to the local chromedriver binary on the server file system.
+ *
+ * @return The capability value.
+ */
+ default Optional getChromedriverExecutablePath() {
+ return Optional.ofNullable((String) getCapability(CHROMEDRIVER_EXECUTABLE_PATH_OPTION));
+ }
+}
diff --git a/src/main/java/io/appium/java_client/wincore/options/SupportsDelayAfterClickOption.java b/src/main/java/io/appium/java_client/wincore/options/SupportsDelayAfterClickOption.java
new file mode 100644
index 000000000..e7d74355c
--- /dev/null
+++ b/src/main/java/io/appium/java_client/wincore/options/SupportsDelayAfterClickOption.java
@@ -0,0 +1,58 @@
+/*
+ * 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.wincore.options;
+
+import io.appium.java_client.remote.options.BaseOptions;
+import io.appium.java_client.remote.options.CanSetCapability;
+import org.openqa.selenium.Capabilities;
+
+import java.time.Duration;
+import java.util.Optional;
+
+import static io.appium.java_client.internal.CapabilityHelpers.toDuration;
+
+/**
+ * Provides getters and setters for the {@code delayAfterClick} capability.
+ *
+ * @param options type, used for chaining.
+ */
+public interface SupportsDelayAfterClickOption> extends
+ Capabilities, CanSetCapability {
+ /**
+ * Name of the {@code delayAfterClick} capability.
+ */
+ String DELAY_AFTER_CLICK_OPTION = "delayAfterClick";
+
+ /**
+ * The delay after each click. The minimum time resolution unit is one millisecond.
+ *
+ * @param value The delay value.
+ * @return self instance for chaining.
+ */
+ default T setDelayAfterClick(Duration value) {
+ return amend(DELAY_AFTER_CLICK_OPTION, value.toMillis());
+ }
+
+ /**
+ * Get the delay after each click.
+ *
+ * @return The capability value.
+ */
+ default Optional getDelayAfterClick() {
+ return Optional.ofNullable(toDuration(getCapability(DELAY_AFTER_CLICK_OPTION)));
+ }
+}
diff --git a/src/main/java/io/appium/java_client/wincore/options/SupportsDelayBeforeClickOption.java b/src/main/java/io/appium/java_client/wincore/options/SupportsDelayBeforeClickOption.java
new file mode 100644
index 000000000..7bdbce853
--- /dev/null
+++ b/src/main/java/io/appium/java_client/wincore/options/SupportsDelayBeforeClickOption.java
@@ -0,0 +1,58 @@
+/*
+ * 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.wincore.options;
+
+import io.appium.java_client.remote.options.BaseOptions;
+import io.appium.java_client.remote.options.CanSetCapability;
+import org.openqa.selenium.Capabilities;
+
+import java.time.Duration;
+import java.util.Optional;
+
+import static io.appium.java_client.internal.CapabilityHelpers.toDuration;
+
+/**
+ * Provides getters and setters for the {@code delayBeforeClick} capability.
+ *
+ * @param options type, used for chaining.
+ */
+public interface SupportsDelayBeforeClickOption> extends
+ Capabilities, CanSetCapability {
+ /**
+ * Name of the {@code delayBeforeClick} capability.
+ */
+ String DELAY_BEFORE_CLICK_OPTION = "delayBeforeClick";
+
+ /**
+ * The delay before each click. The minimum time resolution unit is one millisecond.
+ *
+ * @param value The delay value.
+ * @return self instance for chaining.
+ */
+ default T setDelayBeforeClick(Duration value) {
+ return amend(DELAY_BEFORE_CLICK_OPTION, value.toMillis());
+ }
+
+ /**
+ * Get the delay before each click.
+ *
+ * @return The capability value.
+ */
+ default Optional getDelayBeforeClick() {
+ return Optional.ofNullable(toDuration(getCapability(DELAY_BEFORE_CLICK_OPTION)));
+ }
+}
diff --git a/src/main/java/io/appium/java_client/wincore/options/SupportsEdgedriverCdnUrlOption.java b/src/main/java/io/appium/java_client/wincore/options/SupportsEdgedriverCdnUrlOption.java
new file mode 100644
index 000000000..bb6f08c33
--- /dev/null
+++ b/src/main/java/io/appium/java_client/wincore/options/SupportsEdgedriverCdnUrlOption.java
@@ -0,0 +1,55 @@
+/*
+ * 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.wincore.options;
+
+import io.appium.java_client.remote.options.BaseOptions;
+import io.appium.java_client.remote.options.CanSetCapability;
+import org.openqa.selenium.Capabilities;
+
+import java.util.Optional;
+
+/**
+ * Provides getters and setters for the {@code edgedriverCdnUrl} capability.
+ *
+ * @param options type, used for chaining.
+ */
+public interface SupportsEdgedriverCdnUrlOption> extends
+ Capabilities, CanSetCapability {
+ /**
+ * Name of the {@code edgedriverCdnUrl} capability.
+ */
+ String EDGEDRIVER_CDN_URL_OPTION = "edgedriverCdnUrl";
+
+ /**
+ * The custom CDN URL to download msedgedriver binaries from.
+ *
+ * @param value The capability value.
+ * @return self instance for chaining.
+ */
+ default T setEdgedriverCdnUrl(String value) {
+ return amend(EDGEDRIVER_CDN_URL_OPTION, value);
+ }
+
+ /**
+ * Get the custom CDN URL to download msedgedriver binaries from.
+ *
+ * @return The capability value.
+ */
+ default Optional getEdgedriverCdnUrl() {
+ return Optional.ofNullable((String) getCapability(EDGEDRIVER_CDN_URL_OPTION));
+ }
+}
diff --git a/src/main/java/io/appium/java_client/wincore/options/SupportsEdgedriverExecutablePathOption.java b/src/main/java/io/appium/java_client/wincore/options/SupportsEdgedriverExecutablePathOption.java
new file mode 100644
index 000000000..98663b97a
--- /dev/null
+++ b/src/main/java/io/appium/java_client/wincore/options/SupportsEdgedriverExecutablePathOption.java
@@ -0,0 +1,55 @@
+/*
+ * 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.wincore.options;
+
+import io.appium.java_client.remote.options.BaseOptions;
+import io.appium.java_client.remote.options.CanSetCapability;
+import org.openqa.selenium.Capabilities;
+
+import java.util.Optional;
+
+/**
+ * Provides getters and setters for the {@code edgedriverExecutablePath} capability.
+ *
+ * @param options type, used for chaining.
+ */
+public interface SupportsEdgedriverExecutablePathOption> extends
+ Capabilities, CanSetCapability {
+ /**
+ * Name of the {@code edgedriverExecutablePath} capability.
+ */
+ String EDGEDRIVER_EXECUTABLE_PATH_OPTION = "edgedriverExecutablePath";
+
+ /**
+ * Full path to the local msedgedriver binary on the server file system.
+ *
+ * @param value The capability value.
+ * @return self instance for chaining.
+ */
+ default T setEdgedriverExecutablePath(String value) {
+ return amend(EDGEDRIVER_EXECUTABLE_PATH_OPTION, value);
+ }
+
+ /**
+ * Get the path to the local msedgedriver binary on the server file system.
+ *
+ * @return The capability value.
+ */
+ default Optional getEdgedriverExecutablePath() {
+ return Optional.ofNullable((String) getCapability(EDGEDRIVER_EXECUTABLE_PATH_OPTION));
+ }
+}
diff --git a/src/main/java/io/appium/java_client/wincore/options/SupportsFfmpegExecutablePathOption.java b/src/main/java/io/appium/java_client/wincore/options/SupportsFfmpegExecutablePathOption.java
new file mode 100644
index 000000000..d075f18f2
--- /dev/null
+++ b/src/main/java/io/appium/java_client/wincore/options/SupportsFfmpegExecutablePathOption.java
@@ -0,0 +1,55 @@
+/*
+ * 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.wincore.options;
+
+import io.appium.java_client.remote.options.BaseOptions;
+import io.appium.java_client.remote.options.CanSetCapability;
+import org.openqa.selenium.Capabilities;
+
+import java.util.Optional;
+
+/**
+ * Provides getters and setters for the {@code ffmpegExecutablePath} capability.
+ *
+ * @param options type, used for chaining.
+ */
+public interface SupportsFfmpegExecutablePathOption> extends
+ Capabilities, CanSetCapability {
+ /**
+ * Name of the {@code ffmpegExecutablePath} capability.
+ */
+ String FFMPEG_EXECUTABLE_PATH_OPTION = "ffmpegExecutablePath";
+
+ /**
+ * Full path to the local ffmpeg binary on the server file system, used for screen recording.
+ *
+ * @param value The capability value.
+ * @return self instance for chaining.
+ */
+ default T setFfmpegExecutablePath(String value) {
+ return amend(FFMPEG_EXECUTABLE_PATH_OPTION, value);
+ }
+
+ /**
+ * Get the path to the local ffmpeg binary on the server file system.
+ *
+ * @return The capability value.
+ */
+ default Optional getFfmpegExecutablePath() {
+ return Optional.ofNullable((String) getCapability(FFMPEG_EXECUTABLE_PATH_OPTION));
+ }
+}
diff --git a/src/main/java/io/appium/java_client/wincore/options/SupportsIsolatedScriptExecutionOption.java b/src/main/java/io/appium/java_client/wincore/options/SupportsIsolatedScriptExecutionOption.java
new file mode 100644
index 000000000..c51809012
--- /dev/null
+++ b/src/main/java/io/appium/java_client/wincore/options/SupportsIsolatedScriptExecutionOption.java
@@ -0,0 +1,58 @@
+/*
+ * 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.wincore.options;
+
+import io.appium.java_client.remote.options.BaseOptions;
+import io.appium.java_client.remote.options.CanSetCapability;
+import org.openqa.selenium.Capabilities;
+
+import java.util.Optional;
+
+import static io.appium.java_client.internal.CapabilityHelpers.toSafeBoolean;
+
+/**
+ * Provides getters and setters for the {@code isolatedScriptExecution} capability.
+ *
+ * @param options type, used for chaining.
+ */
+public interface SupportsIsolatedScriptExecutionOption> extends
+ Capabilities, CanSetCapability {
+ /**
+ * Name of the {@code isolatedScriptExecution} capability.
+ */
+ String ISOLATED_SCRIPT_EXECUTION_OPTION = "isolatedScriptExecution";
+
+ /**
+ * Whether the {@code prerun} and {@code postrun} PowerShell scripts are executed in an isolated
+ * PowerShell instance. Disabled by default.
+ *
+ * @param value True to enable, false to disable.
+ * @return self instance for chaining.
+ */
+ default T setIsolatedScriptExecution(boolean value) {
+ return amend(ISOLATED_SCRIPT_EXECUTION_OPTION, value);
+ }
+
+ /**
+ * Get whether the PowerShell scripts are executed in an isolated PowerShell instance.
+ *
+ * @return The capability value.
+ */
+ default Optional isIsolatedScriptExecution() {
+ return Optional.ofNullable(toSafeBoolean(getCapability(ISOLATED_SCRIPT_EXECUTION_OPTION)));
+ }
+}
diff --git a/src/main/java/io/appium/java_client/wincore/options/SupportsLogFileOption.java b/src/main/java/io/appium/java_client/wincore/options/SupportsLogFileOption.java
new file mode 100644
index 000000000..c80182a6f
--- /dev/null
+++ b/src/main/java/io/appium/java_client/wincore/options/SupportsLogFileOption.java
@@ -0,0 +1,55 @@
+/*
+ * 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.wincore.options;
+
+import io.appium.java_client.remote.options.BaseOptions;
+import io.appium.java_client.remote.options.CanSetCapability;
+import org.openqa.selenium.Capabilities;
+
+import java.util.Optional;
+
+/**
+ * Provides getters and setters for the {@code logFile} capability.
+ *
+ * @param options type, used for chaining.
+ */
+public interface SupportsLogFileOption> extends
+ Capabilities, CanSetCapability {
+ /**
+ * Name of the {@code logFile} capability.
+ */
+ String LOG_FILE_OPTION = "logFile";
+
+ /**
+ * Path to the file on the server file system, where the driver log is mirrored.
+ *
+ * @param value The capability value.
+ * @return self instance for chaining.
+ */
+ default T setLogFile(String value) {
+ return amend(LOG_FILE_OPTION, value);
+ }
+
+ /**
+ * Get the path to the file where the driver log is mirrored.
+ *
+ * @return The capability value.
+ */
+ default Optional getLogFile() {
+ return Optional.ofNullable((String) getCapability(LOG_FILE_OPTION));
+ }
+}
diff --git a/src/main/java/io/appium/java_client/wincore/options/SupportsMsForceQuitOption.java b/src/main/java/io/appium/java_client/wincore/options/SupportsMsForceQuitOption.java
new file mode 100644
index 000000000..af5db2ff9
--- /dev/null
+++ b/src/main/java/io/appium/java_client/wincore/options/SupportsMsForceQuitOption.java
@@ -0,0 +1,58 @@
+/*
+ * 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.wincore.options;
+
+import io.appium.java_client.remote.options.BaseOptions;
+import io.appium.java_client.remote.options.CanSetCapability;
+import org.openqa.selenium.Capabilities;
+
+import java.util.Optional;
+
+import static io.appium.java_client.internal.CapabilityHelpers.toSafeBoolean;
+
+/**
+ * Provides getters and setters for the {@code ms:forcequit} capability.
+ *
+ * @param options type, used for chaining.
+ */
+public interface SupportsMsForceQuitOption> extends
+ Capabilities, CanSetCapability {
+ /**
+ * Name of the {@code ms:forcequit} capability.
+ */
+ String MS_FORCE_QUIT_OPTION = "ms:forcequit";
+
+ /**
+ * Whether the application process is force-killed at the end of the session. Only applies if
+ * {@code shouldCloseApp} is enabled.
+ *
+ * @param value True to enable, false to disable.
+ * @return self instance for chaining.
+ */
+ default T setForceQuit(boolean value) {
+ return amend(MS_FORCE_QUIT_OPTION, value);
+ }
+
+ /**
+ * Get whether the application process is force-killed at the end of the session.
+ *
+ * @return The capability value.
+ */
+ default Optional isForceQuit() {
+ return Optional.ofNullable(toSafeBoolean(getCapability(MS_FORCE_QUIT_OPTION)));
+ }
+}
diff --git a/src/main/java/io/appium/java_client/wincore/options/SupportsPerfMetricsOption.java b/src/main/java/io/appium/java_client/wincore/options/SupportsPerfMetricsOption.java
new file mode 100644
index 000000000..ed7f6f7c9
--- /dev/null
+++ b/src/main/java/io/appium/java_client/wincore/options/SupportsPerfMetricsOption.java
@@ -0,0 +1,59 @@
+/*
+ * 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.wincore.options;
+
+import io.appium.java_client.remote.options.BaseOptions;
+import io.appium.java_client.remote.options.CanSetCapability;
+import org.openqa.selenium.Capabilities;
+
+import java.util.Optional;
+
+import static io.appium.java_client.internal.CapabilityHelpers.toSafeBoolean;
+
+/**
+ * Provides getters and setters for the {@code perfMetrics} capability.
+ *
+ * @param options type, used for chaining.
+ */
+public interface SupportsPerfMetricsOption> extends
+ Capabilities, CanSetCapability {
+ /**
+ * Name of the {@code perfMetrics} capability.
+ */
+ String PERF_METRICS_OPTION = "perfMetrics";
+
+ /**
+ * Whether the per-session performance counters are collected. They are read and reset via the
+ * {@code windows: getPerfMetrics} and {@code windows: resetPerfMetrics} extensions. Disabled by
+ * default.
+ *
+ * @param value True to enable, false to disable.
+ * @return self instance for chaining.
+ */
+ default T setPerfMetrics(boolean value) {
+ return amend(PERF_METRICS_OPTION, value);
+ }
+
+ /**
+ * Get whether the per-session performance counters are collected.
+ *
+ * @return The capability value.
+ */
+ default Optional isPerfMetrics() {
+ return Optional.ofNullable(toSafeBoolean(getCapability(PERF_METRICS_OPTION)));
+ }
+}
diff --git a/src/main/java/io/appium/java_client/wincore/options/SupportsShouldCloseAppOption.java b/src/main/java/io/appium/java_client/wincore/options/SupportsShouldCloseAppOption.java
new file mode 100644
index 000000000..73828d2e1
--- /dev/null
+++ b/src/main/java/io/appium/java_client/wincore/options/SupportsShouldCloseAppOption.java
@@ -0,0 +1,58 @@
+/*
+ * 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.wincore.options;
+
+import io.appium.java_client.remote.options.BaseOptions;
+import io.appium.java_client.remote.options.CanSetCapability;
+import org.openqa.selenium.Capabilities;
+
+import java.util.Optional;
+
+import static io.appium.java_client.internal.CapabilityHelpers.toSafeBoolean;
+
+/**
+ * Provides getters and setters for the {@code shouldCloseApp} capability.
+ *
+ * @param options type, used for chaining.
+ */
+public interface SupportsShouldCloseAppOption> extends
+ Capabilities, CanSetCapability {
+ /**
+ * Name of the {@code shouldCloseApp} capability.
+ */
+ String SHOULD_CLOSE_APP_OPTION = "shouldCloseApp";
+
+ /**
+ * Whether to close the application window at the end of the session. Ignored for the {@code
+ * Root} app. Enabled by default.
+ *
+ * @param value True to enable, false to disable.
+ * @return self instance for chaining.
+ */
+ default T setShouldCloseApp(boolean value) {
+ return amend(SHOULD_CLOSE_APP_OPTION, value);
+ }
+
+ /**
+ * Get whether the application window is closed at the end of the session.
+ *
+ * @return The capability value.
+ */
+ default Optional isShouldCloseApp() {
+ return Optional.ofNullable(toSafeBoolean(getCapability(SHOULD_CLOSE_APP_OPTION)));
+ }
+}
diff --git a/src/main/java/io/appium/java_client/wincore/options/SupportsSmoothPointerMoveOption.java b/src/main/java/io/appium/java_client/wincore/options/SupportsSmoothPointerMoveOption.java
new file mode 100644
index 000000000..0aaabedc2
--- /dev/null
+++ b/src/main/java/io/appium/java_client/wincore/options/SupportsSmoothPointerMoveOption.java
@@ -0,0 +1,55 @@
+/*
+ * 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.wincore.options;
+
+import io.appium.java_client.remote.options.BaseOptions;
+import io.appium.java_client.remote.options.CanSetCapability;
+import org.openqa.selenium.Capabilities;
+
+import java.util.Optional;
+
+/**
+ * Provides getters and setters for the {@code smoothPointerMove} capability.
+ *
+ * @param options type, used for chaining.
+ */
+public interface SupportsSmoothPointerMoveOption> extends
+ Capabilities, CanSetCapability {
+ /**
+ * Name of the {@code smoothPointerMove} capability.
+ */
+ String SMOOTH_POINTER_MOVE_OPTION = "smoothPointerMove";
+
+ /**
+ * The CSS easing function used to interpolate the mouse pointer movement, for example {@code ease-in}.
+ *
+ * @param value The capability value.
+ * @return self instance for chaining.
+ */
+ default T setSmoothPointerMove(String value) {
+ return amend(SMOOTH_POINTER_MOVE_OPTION, value);
+ }
+
+ /**
+ * Get the CSS easing function used to interpolate the mouse pointer movement.
+ *
+ * @return The capability value.
+ */
+ default Optional getSmoothPointerMove() {
+ return Optional.ofNullable((String) getCapability(SMOOTH_POINTER_MOVE_OPTION));
+ }
+}
diff --git a/src/main/java/io/appium/java_client/wincore/options/SupportsWaitForAppLaunchOption.java b/src/main/java/io/appium/java_client/wincore/options/SupportsWaitForAppLaunchOption.java
new file mode 100644
index 000000000..a2cbc1b35
--- /dev/null
+++ b/src/main/java/io/appium/java_client/wincore/options/SupportsWaitForAppLaunchOption.java
@@ -0,0 +1,66 @@
+/*
+ * 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.wincore.options;
+
+import io.appium.java_client.remote.options.BaseOptions;
+import io.appium.java_client.remote.options.CanSetCapability;
+import org.openqa.selenium.Capabilities;
+
+import java.time.Duration;
+import java.util.Optional;
+
+import static io.appium.java_client.internal.CapabilityHelpers.toDuration;
+
+/**
+ * Provides getters and setters for the {@code ms:waitForAppLaunch} capability.
+ * The driver treats values up to 120 as seconds and greater values as milliseconds.
+ *
+ * @param options type, used for chaining.
+ */
+public interface SupportsWaitForAppLaunchOption> extends
+ Capabilities, CanSetCapability {
+ /**
+ * Name of the {@code ms:waitForAppLaunch} capability.
+ */
+ String MS_WAIT_FOR_APP_LAUNCH_OPTION = "ms:waitForAppLaunch";
+
+ /**
+ * The time to wait for the application window after the app launch is initiated.
+ * Whole seconds up to 120 are sent as seconds, anything else is sent as milliseconds.
+ * Durations shorter than 121 ms cannot be expressed and are rounded up to one second.
+ *
+ * @param timeout The timeout value.
+ * @return self instance for chaining.
+ */
+ default T setWaitForAppLaunch(Duration timeout) {
+ long ms = timeout.toMillis();
+ if (ms <= 120_000 && ms % 1000 == 0) {
+ return amend(MS_WAIT_FOR_APP_LAUNCH_OPTION, ms / 1000);
+ }
+ return amend(MS_WAIT_FOR_APP_LAUNCH_OPTION, ms > 120 ? ms : 1);
+ }
+
+ /**
+ * Get the time to wait for the application window after the app launch is initiated.
+ *
+ * @return The timeout value.
+ */
+ default Optional doesWaitForAppLaunch() {
+ return Optional.ofNullable(toDuration(getCapability(MS_WAIT_FOR_APP_LAUNCH_OPTION), raw ->
+ raw > 120 ? Duration.ofMillis(raw) : Duration.ofSeconds(raw)));
+ }
+}
diff --git a/src/main/java/io/appium/java_client/wincore/options/SupportsWebviewEnabledOption.java b/src/main/java/io/appium/java_client/wincore/options/SupportsWebviewEnabledOption.java
new file mode 100644
index 000000000..39bb25b53
--- /dev/null
+++ b/src/main/java/io/appium/java_client/wincore/options/SupportsWebviewEnabledOption.java
@@ -0,0 +1,57 @@
+/*
+ * 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.wincore.options;
+
+import io.appium.java_client.remote.options.BaseOptions;
+import io.appium.java_client.remote.options.CanSetCapability;
+import org.openqa.selenium.Capabilities;
+
+import java.util.Optional;
+
+import static io.appium.java_client.internal.CapabilityHelpers.toSafeBoolean;
+
+/**
+ * Provides getters and setters for the {@code webviewEnabled} capability.
+ *
+ * @param options type, used for chaining.
+ */
+public interface SupportsWebviewEnabledOption> extends
+ Capabilities, CanSetCapability {
+ /**
+ * Name of the {@code webviewEnabled} capability.
+ */
+ String WEBVIEW_ENABLED_OPTION = "webviewEnabled";
+
+ /**
+ * Whether the automation of WebView2, Chrome and Edge web contents over the Chrome DevTools Protocol is enabled.
+ *
+ * @param value True to enable, false to disable.
+ * @return self instance for chaining.
+ */
+ default T setWebviewEnabled(boolean value) {
+ return amend(WEBVIEW_ENABLED_OPTION, value);
+ }
+
+ /**
+ * Get whether the automation of web contents is enabled.
+ *
+ * @return The capability value.
+ */
+ default Optional isWebviewEnabled() {
+ return Optional.ofNullable(toSafeBoolean(getCapability(WEBVIEW_ENABLED_OPTION)));
+ }
+}
diff --git a/src/main/java/io/appium/java_client/wincore/options/WincoreOptions.java b/src/main/java/io/appium/java_client/wincore/options/WincoreOptions.java
new file mode 100644
index 000000000..d2e782593
--- /dev/null
+++ b/src/main/java/io/appium/java_client/wincore/options/WincoreOptions.java
@@ -0,0 +1,143 @@
+/*
+ * 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.wincore.options;
+
+import io.appium.java_client.android.options.context.SupportsWebviewDevtoolsPortOption;
+import io.appium.java_client.remote.AutomationName;
+import io.appium.java_client.remote.MobilePlatform;
+import io.appium.java_client.remote.options.BaseOptions;
+import io.appium.java_client.remote.options.SupportsAppOption;
+import io.appium.java_client.remote.options.SupportsDeviceNameOption;
+import io.appium.java_client.remote.options.SupportsPostrunOption;
+import io.appium.java_client.remote.options.SupportsPrerunOption;
+import io.appium.java_client.windows.options.PowerShellData;
+import io.appium.java_client.windows.options.SupportsAppArgumentsOption;
+import io.appium.java_client.windows.options.SupportsAppTopLevelWindowOption;
+import io.appium.java_client.windows.options.SupportsAppWorkingDirOption;
+import org.openqa.selenium.Capabilities;
+
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * Capabilities of the Wincore driver.
+ * See https://github.com/appium/appium-wincore-driver#capabilities
+ * for more details.
+ *
+ * The driver replaces appium-windows-driver, which is deprecated and not supported since Appium 4, see
+ * {@link io.appium.java_client.windows.options.WindowsOptions}.
+ */
+public class WincoreOptions extends BaseOptions implements
+ SupportsAppOption,
+ SupportsDeviceNameOption,
+ SupportsAppArgumentsOption,
+ SupportsAppTopLevelWindowOption,
+ SupportsAppWorkingDirOption,
+ SupportsWaitForAppLaunchOption,
+ SupportsMsForceQuitOption,
+ SupportsShouldCloseAppOption,
+ SupportsIsolatedScriptExecutionOption,
+ SupportsSmoothPointerMoveOption,
+ SupportsDelayBeforeClickOption,
+ SupportsDelayAfterClickOption,
+ SupportsWebviewEnabledOption,
+ SupportsWebviewDevtoolsPortOption,
+ SupportsChromedriverExecutablePathOption,
+ SupportsEdgedriverExecutablePathOption,
+ SupportsChromedriverCdnUrlOption,
+ SupportsEdgedriverCdnUrlOption,
+ SupportsFfmpegExecutablePathOption,
+ SupportsLogFileOption,
+ SupportsPerfMetricsOption,
+ SupportsPrerunOption,
+ SupportsPostrunOption {
+ /** Creates options with the default capabilities set. */
+ public WincoreOptions() {
+ setCommonOptions();
+ }
+
+ /**
+ * Creates options from the given capabilities.
+ *
+ * @param source The capabilities to copy.
+ */
+ public WincoreOptions(Capabilities source) {
+ super(source);
+ setCommonOptions();
+ }
+
+ /**
+ * Creates options from the given capabilities map.
+ *
+ * @param source The capabilities to copy.
+ */
+ public WincoreOptions(Map source) {
+ super(source);
+ setCommonOptions();
+ }
+
+ private void setCommonOptions() {
+ setPlatformName(MobilePlatform.WINDOWS);
+ setAutomationName(AutomationName.WINCORE);
+ }
+
+ /**
+ * An object containing either script or command key. The value of
+ * each key must be a valid PowerShell script or command to be
+ * executed prior to the session startup.
+ *
+ * @param script E.g. {script: 'Get-Process outlook -ErrorAction SilentlyContinue'}.
+ * @return self instance for chaining.
+ */
+ public WincoreOptions setPrerun(PowerShellData script) {
+ return amend(PRERUN_OPTION, script.toMap());
+ }
+
+ /**
+ * Get the prerun script.
+ *
+ * @return Prerun script.
+ */
+ public Optional getPrerun() {
+ //noinspection unchecked
+ return Optional.ofNullable(getCapability(PRERUN_OPTION))
+ .map(v -> new PowerShellData((Map) v));
+ }
+
+ /**
+ * An object containing either script or command key. The value of
+ * each key must be a valid PowerShell script or command to be
+ * executed after the session is finished.
+ *
+ * @param script E.g. {script: 'Get-Process outlook -ErrorAction SilentlyContinue'}.
+ * @return self instance for chaining.
+ */
+ public WincoreOptions setPostrun(PowerShellData script) {
+ return amend(POSTRUN_OPTION, script.toMap());
+ }
+
+ /**
+ * Get the postrun script.
+ *
+ * @return Postrun script.
+ */
+ public Optional getPostrun() {
+ //noinspection unchecked
+ return Optional.ofNullable(getCapability(POSTRUN_OPTION))
+ .map(v -> new PowerShellData((Map) v));
+ }
+}
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 5db88bf58..d4684f989 100644
--- a/src/main/java/io/appium/java_client/windows/WindowsDriver.java
+++ b/src/main/java/io/appium/java_client/windows/WindowsDriver.java
@@ -42,9 +42,13 @@
import static java.util.Objects.requireNonNull;
/**
- * WindowsDriver is an officially supported Appium driver created to automate Windows apps.
+ * WindowsDriver is an Appium driver created to automate Windows apps.
* Read https://github.com/appium/appium-windows-driver for more details.
+ *
+ * @deprecated The Windows driver is deprecated and not supported since Appium 4.
+ * Use {@link io.appium.java_client.wincore.WincoreDriver} instead.
*/
+@Deprecated
public class WindowsDriver extends AppiumDriver implements
PullsFiles,
PushesFiles,
diff --git a/src/main/java/io/appium/java_client/windows/WindowsStartScreenRecordingOptions.java b/src/main/java/io/appium/java_client/windows/WindowsStartScreenRecordingOptions.java
index ef4a4b4bf..de2c21a0a 100644
--- a/src/main/java/io/appium/java_client/windows/WindowsStartScreenRecordingOptions.java
+++ b/src/main/java/io/appium/java_client/windows/WindowsStartScreenRecordingOptions.java
@@ -25,7 +25,13 @@
import static java.util.Optional.ofNullable;
-/** Windows-specific options for starting a screen recording. */
+/**
+ * Windows-specific options for starting a screen recording.
+ *
+ * @deprecated The Windows driver is deprecated and not supported since Appium 4.
+ * Use {@link io.appium.java_client.wincore.WincoreStartScreenRecordingOptions} instead.
+ */
+@Deprecated
public class WindowsStartScreenRecordingOptions
extends BaseStartScreenRecordingOptions {
/**
diff --git a/src/main/java/io/appium/java_client/windows/WindowsStopScreenRecordingOptions.java b/src/main/java/io/appium/java_client/windows/WindowsStopScreenRecordingOptions.java
index 90c3a9fc6..7de721548 100644
--- a/src/main/java/io/appium/java_client/windows/WindowsStopScreenRecordingOptions.java
+++ b/src/main/java/io/appium/java_client/windows/WindowsStopScreenRecordingOptions.java
@@ -18,7 +18,13 @@
import io.appium.java_client.screenrecording.BaseStopScreenRecordingOptions;
-/** Windows-specific options for stopping a screen recording. */
+/**
+ * Windows-specific options for stopping a screen recording.
+ *
+ * @deprecated The Windows driver is deprecated and not supported since Appium 4.
+ * Use {@link io.appium.java_client.wincore.WincoreStopScreenRecordingOptions} instead.
+ */
+@Deprecated
public class WindowsStopScreenRecordingOptions extends
BaseStopScreenRecordingOptions {
/**
diff --git a/src/main/java/io/appium/java_client/windows/options/SupportsCreateSessionTimeoutOption.java b/src/main/java/io/appium/java_client/windows/options/SupportsCreateSessionTimeoutOption.java
index b36174f28..19a9b891c 100644
--- a/src/main/java/io/appium/java_client/windows/options/SupportsCreateSessionTimeoutOption.java
+++ b/src/main/java/io/appium/java_client/windows/options/SupportsCreateSessionTimeoutOption.java
@@ -27,9 +27,13 @@
/**
* Support for the {@code createSessionTimeout} capability: the timeout for creating a session.
- *
- * @param the concrete options type, returned for chaining
+ *
+ * @param the concrete options type, returned for chaining
+ *
+ * @deprecated The Windows driver is deprecated and not supported since Appium 4.
+ * Its successor, the Wincore driver, does not support this capability.
*/
+@Deprecated
public interface SupportsCreateSessionTimeoutOption> extends
Capabilities, CanSetCapability {
/**
diff --git a/src/main/java/io/appium/java_client/windows/options/SupportsMsExperimentalWebDriverOption.java b/src/main/java/io/appium/java_client/windows/options/SupportsMsExperimentalWebDriverOption.java
index ade5084df..ce5f7be49 100644
--- a/src/main/java/io/appium/java_client/windows/options/SupportsMsExperimentalWebDriverOption.java
+++ b/src/main/java/io/appium/java_client/windows/options/SupportsMsExperimentalWebDriverOption.java
@@ -26,9 +26,13 @@
/**
* Support for the {@code ms:experimental-webdriver} capability: whether experimental driver features are enabled.
- *
- * @param the concrete options type, returned for chaining
+ *
+ * @param the concrete options type, returned for chaining
+ *
+ * @deprecated The Windows driver is deprecated and not supported since Appium 4.
+ * Its successor, the Wincore driver, does not support this capability.
*/
+@Deprecated
public interface SupportsMsExperimentalWebDriverOption> extends
Capabilities, CanSetCapability {
/**
diff --git a/src/main/java/io/appium/java_client/windows/options/SupportsMsWaitForAppLaunchOption.java b/src/main/java/io/appium/java_client/windows/options/SupportsMsWaitForAppLaunchOption.java
index 8e766cc7d..d53ac49c3 100644
--- a/src/main/java/io/appium/java_client/windows/options/SupportsMsWaitForAppLaunchOption.java
+++ b/src/main/java/io/appium/java_client/windows/options/SupportsMsWaitForAppLaunchOption.java
@@ -27,9 +27,13 @@
/**
* Support for the {@code ms:waitForAppLaunch} capability: the time to wait for the application to launch.
- *
- * @param the concrete options type, returned for chaining
+ *
+ * @param the concrete options type, returned for chaining
+ *
+ * @deprecated The Windows driver is deprecated and not supported since Appium 4.
+ * Use {@link io.appium.java_client.wincore.options.SupportsWaitForAppLaunchOption} instead.
*/
+@Deprecated
public interface SupportsMsWaitForAppLaunchOption> extends
Capabilities, CanSetCapability {
/**
diff --git a/src/main/java/io/appium/java_client/windows/options/SupportsSystemPortOption.java b/src/main/java/io/appium/java_client/windows/options/SupportsSystemPortOption.java
index 8e12a01f8..e900fa687 100644
--- a/src/main/java/io/appium/java_client/windows/options/SupportsSystemPortOption.java
+++ b/src/main/java/io/appium/java_client/windows/options/SupportsSystemPortOption.java
@@ -26,9 +26,13 @@
/**
* Support for the {@code systemPort} capability: the port the driver server listens on.
- *
- * @param the concrete options type, returned for chaining
+ *
+ * @param the concrete options type, returned for chaining
+ *
+ * @deprecated The Windows driver is deprecated and not supported since Appium 4.
+ * Its successor, the Wincore driver, does not support this capability.
*/
+@Deprecated
public interface SupportsSystemPortOption> extends
Capabilities, CanSetCapability {
/**
diff --git a/src/main/java/io/appium/java_client/windows/options/WindowsOptions.java b/src/main/java/io/appium/java_client/windows/options/WindowsOptions.java
index 9d7d54e9d..80fff5d0e 100644
--- a/src/main/java/io/appium/java_client/windows/options/WindowsOptions.java
+++ b/src/main/java/io/appium/java_client/windows/options/WindowsOptions.java
@@ -30,9 +30,10 @@
/**
* https://github.com/appium/appium-windows-driver#usage.
*
- * Note: appium-windows-driver is deprecated in favor of appium-wincore-driver,
- * which has its own automation name and capability set.
+ * @deprecated The Windows driver is deprecated and not supported since Appium 4.
+ * Use {@link io.appium.java_client.wincore.options.WincoreOptions} instead.
*/
+@Deprecated
public class WindowsOptions extends BaseOptions implements
SupportsAppOption,
SupportsAppArgumentsOption,
diff --git a/src/test/java/io/appium/java_client/drivers/options/OptionsBuildingTest.java b/src/test/java/io/appium/java_client/drivers/options/OptionsBuildingTest.java
index 4ab700ca3..f5a9716a8 100644
--- a/src/test/java/io/appium/java_client/drivers/options/OptionsBuildingTest.java
+++ b/src/test/java/io/appium/java_client/drivers/options/OptionsBuildingTest.java
@@ -32,6 +32,7 @@
import io.appium.java_client.remote.AutomationName;
import io.appium.java_client.safari.options.SafariOptions;
import io.appium.java_client.safari.options.WebrtcData;
+import io.appium.java_client.wincore.options.WincoreOptions;
import io.appium.java_client.windows.options.PowerShellData;
import io.appium.java_client.windows.options.WindowsOptions;
import org.junit.jupiter.api.Test;
@@ -130,6 +131,45 @@ public void canBuildWindowsOptions() {
assertEquals("yolo command", options.getPostrun().orElse(null).getCommand().orElse(null));
}
+ @Test
+ public void canBuildWincoreOptions() {
+ WincoreOptions options = new WincoreOptions();
+ assertEquals(Platform.WINDOWS, options.getPlatformName());
+ assertEquals(AutomationName.WINCORE, options.getAutomationName().orElse(null));
+ options.setShouldCloseApp(false)
+ .setDelayBeforeClick(Duration.ofMillis(150))
+ .setSmoothPointerMove("ease-in")
+ .setPerfMetrics(true)
+ .setForceQuit(true)
+ .setPrerun(new PowerShellData().withScript("yolo prescript"));
+ assertEquals(false, options.isShouldCloseApp().orElse(null));
+ assertEquals(Duration.ofMillis(150), options.getDelayBeforeClick().orElse(null));
+ assertEquals("ease-in", options.getSmoothPointerMove().orElse(null));
+ assertTrue(options.isPerfMetrics().orElse(false));
+ assertTrue(options.isForceQuit().orElse(false));
+ assertEquals("yolo prescript", options.getPrerun().orElse(null).getScript().orElse(null));
+ assertEquals(150L, options.asMap().get("appium:delayBeforeClick"));
+ assertEquals(true, options.asMap().get("ms:forcequit"));
+ }
+
+ @Test
+ public void wincoreWaitForAppLaunchRespectsTheDriverUnitDetection() {
+ var options = new WincoreOptions();
+ var cases = new Object[][] {
+ {Duration.ofSeconds(90), 90L, Duration.ofSeconds(90)},
+ {Duration.ofSeconds(120), 120L, Duration.ofSeconds(120)},
+ {Duration.ofSeconds(121), 121_000L, Duration.ofSeconds(121)},
+ {Duration.ofMinutes(3), 180_000L, Duration.ofMinutes(3)},
+ {Duration.ofMillis(1500), 1500L, Duration.ofMillis(1500)},
+ {Duration.ofMillis(50), 1L, Duration.ofSeconds(1)},
+ };
+ for (var c : cases) {
+ options.setWaitForAppLaunch((Duration) c[0]);
+ assertEquals(c[1], options.asMap().get("ms:waitForAppLaunch"));
+ assertEquals(c[2], options.doesWaitForAppLaunch().orElse(null));
+ }
+ }
+
@Test
public void canBuildMac2Options() {
Mac2Options options = new Mac2Options();
diff --git a/src/test/java/io/appium/java_client/remote/ExtensionCommandsOverHttpTest.java b/src/test/java/io/appium/java_client/remote/ExtensionCommandsOverHttpTest.java
index c88845982..4190850f1 100644
--- a/src/test/java/io/appium/java_client/remote/ExtensionCommandsOverHttpTest.java
+++ b/src/test/java/io/appium/java_client/remote/ExtensionCommandsOverHttpTest.java
@@ -22,6 +22,9 @@
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.PowerACState;
import io.appium.java_client.android.options.UiAutomator2Options;
+import io.appium.java_client.wincore.WincoreDriver;
+import io.appium.java_client.wincore.WincoreStartScreenRecordingOptions;
+import io.appium.java_client.wincore.options.WincoreOptions;
import io.appium.java_client.windows.WindowsDriver;
import io.appium.java_client.windows.options.WindowsOptions;
import org.junit.jupiter.api.AfterEach;
@@ -37,9 +40,14 @@
import java.util.Base64;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* Checks the commands that the drivers send for the features that have `mobile:` or `windows:` extensions
@@ -79,6 +87,12 @@ private synchronized void handle(HttpExchange exchange) throws IOException {
json = "{\"value\":\"" + Base64.getEncoder().encodeToString("data".getBytes(StandardCharsets.UTF_8))
+ "\"}";
break;
+ case "GET /session/s1/contexts":
+ json = "{\"value\":[\"NATIVE_APP\",\"WEBVIEW_1\"]}";
+ break;
+ case "GET /session/s1/context":
+ json = "{\"value\":\"WEBVIEW_1\"}";
+ break;
default:
json = "{\"value\":null}";
break;
@@ -142,4 +156,67 @@ void windowsAppIsLaunchedAndClosedWithTheDriverExtensions() throws IOException {
driver.launchApp();
assertEquals("windows: launchApp", lastBody().get("script"));
}
+
+ @Test
+ void wincoreFilesAreTransferredWithTheDriverCommands() throws IOException {
+ var driver = new WincoreDriver(url(), new WincoreOptions());
+
+ assertArrayEquals("data".getBytes(StandardCharsets.UTF_8), driver.pullFile("C:\\a.txt"));
+ assertEquals("POST /session/s1/appium/device/pull_file", lastRequest());
+ assertEquals(Map.of("path", "C:\\a.txt"), lastBody());
+
+ driver.pushFile("C:\\b.txt", "ZGF0YQ==".getBytes(StandardCharsets.UTF_8));
+ assertEquals("POST /session/s1/appium/device/push_file", lastRequest());
+ assertEquals(Map.of("path", "C:\\b.txt", "data", "ZGF0YQ=="), lastBody());
+
+ assertThrows(UnsupportedOperationException.class, () -> driver.pullFolder("C:\\dir"));
+ }
+
+ @Test
+ void wincoreAppIsLaunchedAndClosedWithTheDriverExtensions() throws IOException {
+ var driver = new WincoreDriver(url(), new WincoreOptions());
+
+ driver.closeApp();
+ assertEquals("windows: closeApp", lastBody().get("script"));
+
+ driver.launchApp();
+ assertEquals("windows: launchApp", lastBody().get("script"));
+ }
+
+ @Test
+ void wincoreScreenRecordingUsesTheVideoFpsParameter() throws IOException {
+ var driver = new WincoreDriver(url(), new WincoreOptions());
+
+ driver.startRecordingScreen(new WincoreStartScreenRecordingOptions().withFps(30));
+
+ assertEquals("POST /session/s1/appium/start_recording_screen", lastRequest());
+ var options = (Map, ?>) lastBody().get("options");
+ assertEquals(30, ((Number) options.get("videoFps")).intValue());
+ assertFalse(options.containsKey("fps"));
+ }
+
+ @Test
+ void wincoreDefaultScreenRecordingToleratesTheEmptyResponse() throws IOException {
+ var driver = new WincoreDriver(url(), new WincoreOptions());
+
+ assertNull(driver.startRecordingScreen());
+ assertEquals("POST /session/s1/appium/start_recording_screen", lastRequest());
+ }
+
+ @Test
+ void wincoreSwitchesContexts() throws IOException {
+ var driver = new WincoreDriver(url(), new WincoreOptions());
+
+ assertEquals(Set.of("NATIVE_APP", "WEBVIEW_1"), driver.getContextHandles());
+ assertEquals("GET /session/s1/contexts", lastRequest());
+
+ assertEquals("WEBVIEW_1", driver.getContext());
+ assertEquals("GET /session/s1/context", lastRequest());
+
+ driver.context("WEBVIEW_1");
+ assertEquals("POST /session/s1/context", lastRequest());
+ assertEquals(Map.of("name", "WEBVIEW_1"), lastBody());
+
+ assertTrue(driver.isBrowser());
+ }
}