From 3fdbb74eb2c234c01a4b0f751ec17d6602ef3bc4 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Fri, 29 Oct 2021 16:32:38 +0200 Subject: [PATCH 1/7] chore: Include more tests into the pipeline --- azure-pipelines.yml | 14 +++++++++++++- build.gradle | 14 ++++++++++++++ .../appium/java_client/touch/FailsWithMatcher.java | 2 +- .../java_client/touch/TouchOptionsTests.java | 3 +-- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 91256cf5c..f5713384c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -19,7 +19,6 @@ variables: jobs: - job: Android_E2E_Tests -# timeoutInMinutes: '90' steps: - template: .azure-templates/bootstrap_steps.yml - script: | @@ -61,3 +60,16 @@ jobs: publishJUnitResults: true tasks: 'build' options: 'xcuiTest -x checkstyleTest -x test -x signMavenJavaPublication' +- job: Misc_Tests + steps: + - task: Gradle@2 + inputs: + gradleWrapperFile: 'gradlew' + gradleOptions: '-Xmx3072m' + javaHomeOption: 'JDKVersion' + jdkVersionOption: "$(JDK_VERSION)" + jdkArchitectureOption: 'x64' + publishJUnitResults: true + tasks: 'build' + options: 'miscTest -x checkstyleTest -x test -x signMavenJavaPublication' + diff --git a/build.gradle b/build.gradle index b26a68384..cf8e3e373 100644 --- a/build.gradle +++ b/build.gradle @@ -211,5 +211,19 @@ task uiAutomationTest( type: Test ) { includeTestsMatching 'io.appium.java_client.android.SettingTest' includeTestsMatching 'io.appium.java_client.android.ClipboardTest' includeTestsMatching '*.AndroidAppStringsTest' + includeTestsMatching '*.pagefactory_tests.widget.tests.android.*' + includeTestsMatching '*.pagefactory_tests.widget.tests.AndroidPageObjectTest' + includeTestsMatching 'io.appium.java_client.service.local.*' + } +} + +task miscTest( type: Test ) { + useJUnit() + testLogging.showStandardStreams = true + testLogging.exceptionFormat = 'full' + filter { + includeTestsMatching 'io.appium.java_client.touch.*' + includeTestsMatching 'io.appium.java_client.events.*' + includeTestsMatching 'io.appium.java_client.remote.*' } } diff --git a/src/test/java/io/appium/java_client/touch/FailsWithMatcher.java b/src/test/java/io/appium/java_client/touch/FailsWithMatcher.java index 93c1dd804..f4ac4bec8 100644 --- a/src/test/java/io/appium/java_client/touch/FailsWithMatcher.java +++ b/src/test/java/io/appium/java_client/touch/FailsWithMatcher.java @@ -22,7 +22,7 @@ public static Matcher failsWith( public static Matcher failsWith( final Class throwableType, final Matcher throwableMatcher) { - return new FailsWithMatcher<>(allOf(instanceOf(throwableType), throwableMatcher)); + return new FailsWithMatcher(allOf(instanceOf(throwableType), throwableMatcher)); } @Override diff --git a/src/test/java/io/appium/java_client/touch/TouchOptionsTests.java b/src/test/java/io/appium/java_client/touch/TouchOptionsTests.java index 4476ed33e..1500e2f81 100644 --- a/src/test/java/io/appium/java_client/touch/TouchOptionsTests.java +++ b/src/test/java/io/appium/java_client/touch/TouchOptionsTests.java @@ -18,7 +18,6 @@ import io.appium.java_client.touch.offset.PointOption; import org.junit.Test; import org.openqa.selenium.Point; -import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.RemoteWebElement; import java.util.ArrayList; @@ -31,7 +30,7 @@ public class TouchOptionsTests { @Test(expected = IllegalArgumentException.class) public void invalidEmptyPointOptionsShouldFailOnBuild() { - new PointOption().build(); + new PointOption<>().build(); fail("The exception throwing was expected"); } From 1c73b4c681a5711b165dd9ad241d8503fbd10b48 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Fri, 29 Oct 2021 17:02:37 +0200 Subject: [PATCH 2/7] Split android and iOS tests --- build.gradle | 10 +- .../local/AppiumDriverLocalServiceTest.java | 40 ------- ...ava => StartingAppLocallyAndroidTest.java} | 91 ++------------- .../local/StartingAppLocallyIosTest.java | 107 ++++++++++++++++++ 4 files changed, 118 insertions(+), 130 deletions(-) delete mode 100644 src/test/java/io/appium/java_client/service/local/AppiumDriverLocalServiceTest.java rename src/test/java/io/appium/java_client/service/local/{StartingAppLocallyTest.java => StartingAppLocallyAndroidTest.java} (57%) create mode 100644 src/test/java/io/appium/java_client/service/local/StartingAppLocallyIosTest.java diff --git a/build.gradle b/build.gradle index cf8e3e373..8d744333b 100644 --- a/build.gradle +++ b/build.gradle @@ -189,15 +189,11 @@ task xcuiTest( type: Test ) { testLogging.showStandardStreams = true testLogging.exceptionFormat = 'full' filter { - includeTestsMatching '*.appium.element.generation.ios.*' - includeTestsMatching '*.appium.AppiumFluentWaitTest' includeTestsMatching 'io.appium.java_client.ios.*' includeTestsMatching '*.pagefactory_tests.XCUITModeTest' includeTestsMatching '*.pagefactory_tests.widget.tests.combined.*' includeTestsMatching '*.pagefactory_tests.widget.tests.ios.*' - includeTestsMatching '*.StartingAppLocallyTest.startingIOSAppWithCapabilitiesAndServiceTest' - includeTestsMatching '*.StartingAppLocallyTest.startingIOSAppWithCapabilitiesAndFlagsOnServerSideTest' - exclude '**/UIAutomationTest.class' + includeTestsMatching 'io.appium.java_client.service.local.StartingAppLocallyIosTest' exclude '**/IOSScreenRecordTest.class' exclude '**/ImagesComparisonTest.class' } @@ -213,7 +209,9 @@ task uiAutomationTest( type: Test ) { includeTestsMatching '*.AndroidAppStringsTest' includeTestsMatching '*.pagefactory_tests.widget.tests.android.*' includeTestsMatching '*.pagefactory_tests.widget.tests.AndroidPageObjectTest' - includeTestsMatching 'io.appium.java_client.service.local.*' + includeTestsMatching 'io.appium.java_client.service.local.StartingAppLocallyAndroidTest' + includeTestsMatching 'io.appium.java_client.service.local.ServerBuilderTest' + includeTestsMatching 'io.appium.java_client.service.local.ThreadSafetyTest' } } diff --git a/src/test/java/io/appium/java_client/service/local/AppiumDriverLocalServiceTest.java b/src/test/java/io/appium/java_client/service/local/AppiumDriverLocalServiceTest.java deleted file mode 100644 index e6d51247b..000000000 --- a/src/test/java/io/appium/java_client/service/local/AppiumDriverLocalServiceTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package io.appium.java_client.service.local; - -import static io.appium.java_client.service.local.AppiumDriverLocalService.parseSlf4jContextFromLogMessage; -import static org.junit.Assert.assertEquals; -import static org.slf4j.LoggerFactory.getLogger; -import static org.slf4j.event.Level.DEBUG; -import static org.slf4j.event.Level.INFO; - -import org.junit.Test; -import org.slf4j.event.Level; - -public class AppiumDriverLocalServiceTest { - - @Test - public void canParseSlf4jLoggerContext() { - assertLoggerContext(INFO, "appium.service.androidbootstrap", - "[AndroidBootstrap] [BOOTSTRAP LOG] [debug] json loading complete."); - assertLoggerContext(INFO, "appium.service.adb", - "[ADB] Cannot read version codes of "); - assertLoggerContext(INFO, "appium.service.xcuitest", - "[XCUITest] Determining device to run tests on: udid: '1234567890', real device: true"); - assertLoggerContext(INFO, "appium.service", - "no-prefix log message."); - assertLoggerContext(INFO, "appium.service", - "no-prefix log [not-a-logger-name] message."); - assertLoggerContext(DEBUG, "appium.service.mjsonwp", - "[debug] [MJSONWP] Calling AppiumDriver.getStatus() with args: []"); - assertLoggerContext(DEBUG, "appium.service.xcuitest", - "[debug] [XCUITest] Xcode version set to 'x.y.z' "); - assertLoggerContext(DEBUG, "appium.service.jsonwpproxy", - "[debug] [JSONWP Proxy] Proxying [GET /status] to [GET http://localhost:18218/status] with no body"); - } - - private void assertLoggerContext(Level expectedLevel, String expectedLoggerName, String logMessage) { - Slf4jLogMessageContext ctx = parseSlf4jContextFromLogMessage(logMessage); - assertEquals(expectedLoggerName, ctx.getName()); - assertEquals(expectedLevel, ctx.getLevel()); - assertEquals(getLogger(expectedLoggerName), ctx.getLogger()); - } -} diff --git a/src/test/java/io/appium/java_client/service/local/StartingAppLocallyTest.java b/src/test/java/io/appium/java_client/service/local/StartingAppLocallyAndroidTest.java similarity index 57% rename from src/test/java/io/appium/java_client/service/local/StartingAppLocallyTest.java rename to src/test/java/io/appium/java_client/service/local/StartingAppLocallyAndroidTest.java index 467d6c21f..ee7eb82e2 100644 --- a/src/test/java/io/appium/java_client/service/local/StartingAppLocallyTest.java +++ b/src/test/java/io/appium/java_client/service/local/StartingAppLocallyAndroidTest.java @@ -16,19 +16,8 @@ package io.appium.java_client.service.local; -import static io.appium.java_client.TestResources.apiDemosApk; -import static io.appium.java_client.TestResources.uiCatalogAppZip; -import static io.github.bonigarcia.wdm.WebDriverManager.chromedriver; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - import io.appium.java_client.android.AndroidDriver; import io.appium.java_client.android.options.UiAutomator2Options; -import io.appium.java_client.ios.BaseIOSTest; -import io.appium.java_client.ios.IOSDriver; -import io.appium.java_client.ios.options.XCUITestOptions; import io.appium.java_client.remote.AutomationName; import io.appium.java_client.remote.MobileCapabilityType; import io.appium.java_client.remote.MobilePlatform; @@ -36,11 +25,16 @@ import io.github.bonigarcia.wdm.WebDriverManager; import org.junit.Test; import org.openqa.selenium.Capabilities; -import org.openqa.selenium.Platform; import java.time.Duration; -public class StartingAppLocallyTest { +import static io.appium.java_client.TestResources.apiDemosApk; +import static io.github.bonigarcia.wdm.WebDriverManager.chromedriver; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +public class StartingAppLocallyAndroidTest { @Test public void startingAndroidAppWithCapabilitiesOnlyTest() { @@ -118,75 +112,4 @@ public void startingAndroidAppWithCapabilitiesAndFlagsOnServerSideTest() { driver.quit(); } } - - @Test - public void startingIOSAppWithCapabilitiesOnlyTest() { - XCUITestOptions options = new XCUITestOptions() - .setPlatformVersion(BaseIOSTest.PLATFORM_VERSION) - .setDeviceName(BaseIOSTest.DEVICE_NAME) - .setApp(uiCatalogAppZip().toAbsolutePath().toString()) - .setWdaLaunchTimeout(BaseIOSTest.WDA_LAUNCH_TIMEOUT); - IOSDriver driver = new IOSDriver(options); - try { - XCUITestOptions caps = new XCUITestOptions(driver.getCapabilities()); - - assertEquals(AutomationName.IOS_XCUI_TEST, caps.getAutomationName().orElse(null)); - assertEquals(Platform.IOS, caps.getPlatformName()); - assertNotNull(caps.getDeviceName().orElse(null)); - assertEquals(BaseIOSTest.PLATFORM_VERSION, caps.getPlatformVersion().orElse(null)); - assertEquals(uiCatalogAppZip().toAbsolutePath().toString(), caps.getApp().orElse(null)); - } finally { - driver.quit(); - } - } - - - @Test - public void startingIOSAppWithCapabilitiesAndServiceTest() { - XCUITestOptions options = new XCUITestOptions() - .setPlatformVersion(BaseIOSTest.PLATFORM_VERSION) - .setDeviceName(BaseIOSTest.DEVICE_NAME) - .setApp(uiCatalogAppZip().toAbsolutePath().toString()) - .setWdaLaunchTimeout(BaseIOSTest.WDA_LAUNCH_TIMEOUT); - - AppiumServiceBuilder builder = new AppiumServiceBuilder() - .withArgument(GeneralServerFlag.SESSION_OVERRIDE) - .withArgument(GeneralServerFlag.STRICT_CAPS); - - IOSDriver driver = new IOSDriver(builder, options); - try { - Capabilities caps = driver.getCapabilities(); - assertTrue(caps.getCapability(MobileCapabilityType.PLATFORM_NAME) - .toString().equalsIgnoreCase(MobilePlatform.IOS)); - assertNotNull(caps.getCapability(MobileCapabilityType.DEVICE_NAME)); - } finally { - driver.quit(); - } - } - - @Test - public void startingIOSAppWithCapabilitiesAndFlagsOnServerSideTest() { - XCUITestOptions serverOptions = new XCUITestOptions() - .setPlatformVersion(BaseIOSTest.PLATFORM_VERSION) - .setDeviceName(BaseIOSTest.DEVICE_NAME) - .setWdaLaunchTimeout(BaseIOSTest.WDA_LAUNCH_TIMEOUT); - - XCUITestOptions clientOptions = new XCUITestOptions() - .setApp(uiCatalogAppZip().toAbsolutePath().toString()); - - AppiumServiceBuilder builder = new AppiumServiceBuilder() - .withArgument(GeneralServerFlag.SESSION_OVERRIDE) - .withArgument(GeneralServerFlag.STRICT_CAPS) - .withCapabilities(serverOptions); - - IOSDriver driver = new IOSDriver(builder, clientOptions); - try { - XCUITestOptions caps = new XCUITestOptions(driver.getCapabilities()); - assertEquals(Platform.IOS, caps.getPlatformName()); - assertNotNull(caps.getDeviceName().orElse(null)); - assertFalse(driver.isBrowser()); - } finally { - driver.quit(); - } - } } diff --git a/src/test/java/io/appium/java_client/service/local/StartingAppLocallyIosTest.java b/src/test/java/io/appium/java_client/service/local/StartingAppLocallyIosTest.java new file mode 100644 index 000000000..b7bc4786c --- /dev/null +++ b/src/test/java/io/appium/java_client/service/local/StartingAppLocallyIosTest.java @@ -0,0 +1,107 @@ +/* + * 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.service.local; + +import static io.appium.java_client.TestResources.uiCatalogAppZip; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import io.appium.java_client.ios.BaseIOSTest; +import io.appium.java_client.ios.IOSDriver; +import io.appium.java_client.ios.options.XCUITestOptions; +import io.appium.java_client.remote.AutomationName; +import io.appium.java_client.remote.MobileCapabilityType; +import io.appium.java_client.remote.MobilePlatform; +import io.appium.java_client.service.local.flags.GeneralServerFlag; +import org.junit.Test; +import org.openqa.selenium.Capabilities; +import org.openqa.selenium.Platform; + +public class StartingAppLocallyIosTest { + @Test + public void startingIOSAppWithCapabilitiesOnlyTest() { + XCUITestOptions options = new XCUITestOptions() + .setPlatformVersion(BaseIOSTest.PLATFORM_VERSION) + .setDeviceName(BaseIOSTest.DEVICE_NAME) + .setApp(uiCatalogAppZip().toAbsolutePath().toString()) + .setWdaLaunchTimeout(BaseIOSTest.WDA_LAUNCH_TIMEOUT); + IOSDriver driver = new IOSDriver(options); + try { + XCUITestOptions caps = new XCUITestOptions(driver.getCapabilities()); + + assertEquals(AutomationName.IOS_XCUI_TEST, caps.getAutomationName().orElse(null)); + assertEquals(Platform.IOS, caps.getPlatformName()); + assertNotNull(caps.getDeviceName().orElse(null)); + assertEquals(BaseIOSTest.PLATFORM_VERSION, caps.getPlatformVersion().orElse(null)); + assertEquals(uiCatalogAppZip().toAbsolutePath().toString(), caps.getApp().orElse(null)); + } finally { + driver.quit(); + } + } + + + @Test + public void startingIOSAppWithCapabilitiesAndServiceTest() { + XCUITestOptions options = new XCUITestOptions() + .setPlatformVersion(BaseIOSTest.PLATFORM_VERSION) + .setDeviceName(BaseIOSTest.DEVICE_NAME) + .setApp(uiCatalogAppZip().toAbsolutePath().toString()) + .setWdaLaunchTimeout(BaseIOSTest.WDA_LAUNCH_TIMEOUT); + + AppiumServiceBuilder builder = new AppiumServiceBuilder() + .withArgument(GeneralServerFlag.SESSION_OVERRIDE) + .withArgument(GeneralServerFlag.STRICT_CAPS); + + IOSDriver driver = new IOSDriver(builder, options); + try { + Capabilities caps = driver.getCapabilities(); + assertTrue(caps.getCapability(MobileCapabilityType.PLATFORM_NAME) + .toString().equalsIgnoreCase(MobilePlatform.IOS)); + assertNotNull(caps.getCapability(MobileCapabilityType.DEVICE_NAME)); + } finally { + driver.quit(); + } + } + + @Test + public void startingIOSAppWithCapabilitiesAndFlagsOnServerSideTest() { + XCUITestOptions serverOptions = new XCUITestOptions() + .setPlatformVersion(BaseIOSTest.PLATFORM_VERSION) + .setDeviceName(BaseIOSTest.DEVICE_NAME) + .setWdaLaunchTimeout(BaseIOSTest.WDA_LAUNCH_TIMEOUT); + + XCUITestOptions clientOptions = new XCUITestOptions() + .setApp(uiCatalogAppZip().toAbsolutePath().toString()); + + AppiumServiceBuilder builder = new AppiumServiceBuilder() + .withArgument(GeneralServerFlag.SESSION_OVERRIDE) + .withArgument(GeneralServerFlag.STRICT_CAPS) + .withCapabilities(serverOptions); + + IOSDriver driver = new IOSDriver(builder, clientOptions); + try { + XCUITestOptions caps = new XCUITestOptions(driver.getCapabilities()); + assertEquals(Platform.IOS, caps.getPlatformName()); + assertNotNull(caps.getDeviceName().orElse(null)); + assertFalse(driver.isBrowser()); + } finally { + driver.quit(); + } + } +} From ba66c62beeb49e0ea94aaea31dc74115db92d39d Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Fri, 29 Oct 2021 20:55:00 +0200 Subject: [PATCH 3/7] Add options tests --- build.gradle | 1 + .../android/options/EspressoOptions.java | 2 + .../signing/SupportsKeystoreOptions.java | 2 +- .../ios/options/other/CommandTimeouts.java | 77 +++++++++ .../other/SupportsCommandTimeoutsOption.java | 41 ++--- .../simulator/PasteboardSyncState.java | 16 ++ .../ios/options/simulator/Permissions.java | 63 ++++++++ .../simulator/SupportsPermissionsOption.java | 47 ++---- .../remote/options/BaseMapOptionData.java | 11 ++ .../drivers/options/OptionsBuildingTest.java | 146 ++++++++++++++++++ 10 files changed, 343 insertions(+), 63 deletions(-) create mode 100644 src/main/java/io/appium/java_client/ios/options/other/CommandTimeouts.java create mode 100644 src/main/java/io/appium/java_client/ios/options/simulator/Permissions.java create mode 100644 src/test/java/io/appium/java_client/drivers/options/OptionsBuildingTest.java diff --git a/build.gradle b/build.gradle index 8d744333b..4cd6ab8de 100644 --- a/build.gradle +++ b/build.gradle @@ -223,5 +223,6 @@ task miscTest( type: Test ) { includeTestsMatching 'io.appium.java_client.touch.*' includeTestsMatching 'io.appium.java_client.events.*' includeTestsMatching 'io.appium.java_client.remote.*' + includeTestsMatching 'io.appium.java_client.drivers.options.*' } } diff --git a/src/main/java/io/appium/java_client/android/options/EspressoOptions.java b/src/main/java/io/appium/java_client/android/options/EspressoOptions.java index 6d3df918d..0baebf02f 100644 --- a/src/main/java/io/appium/java_client/android/options/EspressoOptions.java +++ b/src/main/java/io/appium/java_client/android/options/EspressoOptions.java @@ -75,6 +75,7 @@ import io.appium.java_client.android.options.mjpeg.SupportsMjpegScreenshotUrlOption; import io.appium.java_client.android.options.mjpeg.SupportsMjpegServerPortOption; import io.appium.java_client.android.options.other.SupportsDisableSuppressAccessibilityServiceOption; +import io.appium.java_client.android.options.server.SupportsEspressoBuildConfigOption; import io.appium.java_client.android.options.server.SupportsEspressoServerLaunchTimeoutOption; import io.appium.java_client.android.options.server.SupportsForceEspressoRebuildOption; import io.appium.java_client.android.options.server.SupportsShowGradleLogOption; @@ -113,6 +114,7 @@ public class EspressoOptions extends BaseOptions implements SupportsForceEspressoRebuildOption, SupportsShowGradleLogOption, SupportsOrientationOption, + SupportsEspressoBuildConfigOption, // App options: https://github.com/appium/appium-uiautomator2-driver#app SupportsAppOption, SupportsAppPackageOption, diff --git a/src/main/java/io/appium/java_client/android/options/signing/SupportsKeystoreOptions.java b/src/main/java/io/appium/java_client/android/options/signing/SupportsKeystoreOptions.java index 4a79dbc67..5fbfcc2ce 100644 --- a/src/main/java/io/appium/java_client/android/options/signing/SupportsKeystoreOptions.java +++ b/src/main/java/io/appium/java_client/android/options/signing/SupportsKeystoreOptions.java @@ -38,7 +38,7 @@ public interface SupportsKeystoreOptions> extends * @param keystoreConfig The keystore config to use. * @return self instance for chaining. */ - default T useKeystore(KeystoreConfig keystoreConfig) { + default T setKeystoreConfig(KeystoreConfig keystoreConfig) { return amend(USE_KEYSTORE_OPTION, true) .amend(KEYSTORE_PATH_OPTION, keystoreConfig.getPath()) .amend(KEYSTORE_PASSWORD_OPTION, keystoreConfig.getPassword()) diff --git a/src/main/java/io/appium/java_client/ios/options/other/CommandTimeouts.java b/src/main/java/io/appium/java_client/ios/options/other/CommandTimeouts.java new file mode 100644 index 000000000..36b435a90 --- /dev/null +++ b/src/main/java/io/appium/java_client/ios/options/other/CommandTimeouts.java @@ -0,0 +1,77 @@ +/* + * 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.ios.options.other; + +import io.appium.java_client.internal.CapabilityHelpers; +import io.appium.java_client.remote.options.BaseMapOptionData; + +import java.time.Duration; +import java.util.Map; +import java.util.Optional; + +public class CommandTimeouts extends BaseMapOptionData { + public static final String DEFAULT_COMMAND = "default"; + + public CommandTimeouts() { + } + + public CommandTimeouts(Map timeouts) { + super(timeouts); + } + + public CommandTimeouts(String json) { + super(json); + } + + /** + * Sets the timeout for the particular Appium command that + * is proxied to WDA. + * Command names you can find in logs, look for + * "Executing command 'command_name'" records. + * Timeout value is expected to contain max milliseconds to wait for + * the given WDA command to be executed before terminating the session forcefully. + * + * @param commandName The command name. + * @param timeout Command timeout. + * @return self instance for chaining. + */ + public CommandTimeouts withCommandTimeout(String commandName, Duration timeout) { + return assignOptionValue(commandName, timeout.toMillis()); + } + + /** + * Sets the default timeout for all Appium commands that + * are proxied to WDA. + * + * @param timeout Commands timeout. + * @return self instance for chaining. + */ + public CommandTimeouts withDefaultCommandTimeout(Duration timeout) { + return withCommandTimeout(DEFAULT_COMMAND, timeout); + } + + /** + * Get the command timeout. + * + * @param commandName The command name + * @return Timeout value. + */ + public Optional getCommandTimeout(String commandName) { + Optional result = getOptionValue(commandName); + return result.map(CapabilityHelpers::toDuration); + } +} diff --git a/src/main/java/io/appium/java_client/ios/options/other/SupportsCommandTimeoutsOption.java b/src/main/java/io/appium/java_client/ios/options/other/SupportsCommandTimeoutsOption.java index 42935504b..0afd1a9a8 100644 --- a/src/main/java/io/appium/java_client/ios/options/other/SupportsCommandTimeoutsOption.java +++ b/src/main/java/io/appium/java_client/ios/options/other/SupportsCommandTimeoutsOption.java @@ -16,14 +16,16 @@ package io.appium.java_client.ios.options.other; -import com.google.gson.JsonObject; import io.appium.java_client.remote.options.BaseOptions; import io.appium.java_client.remote.options.CanSetCapability; import org.openqa.selenium.Capabilities; +import org.openqa.selenium.internal.Either; import java.time.Duration; import java.util.Optional; +import static io.appium.java_client.internal.CapabilityHelpers.toDuration; + public interface SupportsCommandTimeoutsOption> extends Capabilities, CanSetCapability { String COMMAND_TIMEOUTS_OPTION = "commandTimeouts"; @@ -31,33 +33,19 @@ public interface SupportsCommandTimeoutsOption> extends /** * Custom timeout(s) in milliseconds for WDA backend commands execution. * This might be useful if WDA backend freezes unexpectedly or requires too - * much time to fail and blocks automated test execution. The value is expected - * to be of type string and can either contain max milliseconds to wait for - * each WDA command to be executed before terminating the session forcefully - * or a valid JSON string, where keys are internal Appium command names (you - * can find these in logs, look for "Executing command 'command_name'" records) - * and values are timeouts in milliseconds. You can also set the 'default' key - * to assign the timeout for all other commands not explicitly enumerated as - * JSON keys. + * much time to fail and blocks automated test execution. * - * @param timeouts E.g. '{"findElement": 40000, "findElements": 40000}'. + * @param timeouts Command timeouts. * @return self instance for chaining. */ - default T setCommandTimeouts(JsonObject timeouts) { + default T setCommandTimeouts(CommandTimeouts timeouts) { return amend(COMMAND_TIMEOUTS_OPTION, timeouts.toString()); } /** - * Custom timeout(s) in milliseconds for WDA backend commands execution. + * Custom timeout for all WDA backend commands execution. * This might be useful if WDA backend freezes unexpectedly or requires too - * much time to fail and blocks automated test execution. The value is expected - * to be of type string and can either contain max milliseconds to wait for - * each WDA command to be executed before terminating the session forcefully - * or a valid JSON string, where keys are internal Appium command names (you - * can find these in logs, look for "Executing command 'command_name'" records) - * and values are timeouts in milliseconds. You can also set the 'default' key - * to assign the timeout for all other commands not explicitly enumerated as - * JSON keys. + * much time to fail and blocks automated test execution. * * @param timeout The timeout value for all commands. * @return self instance for chaining. @@ -69,11 +57,14 @@ default T setCommandTimeouts(Duration timeout) { /** * Get custom timeout(s) in milliseconds for WDA backend commands execution. * - * @return Command timeouts. + * @return Either a global timeout duration or detailed command timeouts. */ - default Optional getCommandTimeouts() { - return Optional.ofNullable( - (String) getCapability(COMMAND_TIMEOUTS_OPTION) - ); + default Optional> getCommandTimeouts() { + return Optional.ofNullable(getCapability(COMMAND_TIMEOUTS_OPTION)) + .map(String::valueOf) + .map((v) -> v.trim().startsWith("{") + ? Either.left(new CommandTimeouts(v)) + : Either.right(toDuration(v)) + ); } } diff --git a/src/main/java/io/appium/java_client/ios/options/simulator/PasteboardSyncState.java b/src/main/java/io/appium/java_client/ios/options/simulator/PasteboardSyncState.java index 2252a37bf..885229dd8 100644 --- a/src/main/java/io/appium/java_client/ios/options/simulator/PasteboardSyncState.java +++ b/src/main/java/io/appium/java_client/ios/options/simulator/PasteboardSyncState.java @@ -1,3 +1,19 @@ +/* + * 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.ios.options.simulator; public enum PasteboardSyncState { diff --git a/src/main/java/io/appium/java_client/ios/options/simulator/Permissions.java b/src/main/java/io/appium/java_client/ios/options/simulator/Permissions.java new file mode 100644 index 000000000..53094e5ab --- /dev/null +++ b/src/main/java/io/appium/java_client/ios/options/simulator/Permissions.java @@ -0,0 +1,63 @@ +/* + * 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.ios.options.simulator; + +import io.appium.java_client.remote.options.BaseMapOptionData; + +import java.util.Map; +import java.util.Optional; + +public class Permissions extends BaseMapOptionData { + public Permissions() { + } + + public Permissions(Map permissions) { + super(permissions); + } + + public Permissions(String json) { + super(json); + } + + /** + * Since Xcode SDK 11.4 Apple provides native APIs to interact with + * application settings. Check the output of `xcrun simctl privacy booted` + * command to get the list of available permission names. Use yes, no + * and unset as values in order to grant, revoke or reset the corresponding + * permission. Below Xcode SDK 11.4 it is required that applesimutils package + * is installed and available in PATH. The list of available service names + * and statuses can be found at https://github.com/wix/AppleSimulatorUtils. + * For example: {"com.apple.mobilecal": {"calendar": "YES"}} + * + * @param bundleId The app identifier to change permissions for. + * @param mapping Permissions mapping, where keys are perm names and vales are YES/NO. + * @return self instance for chaining. + */ + public Permissions withAppPermissions(String bundleId, Map mapping) { + return assignOptionValue(bundleId, mapping); + } + + /** + * Get permissions mapping for the given app bundle identifier. + * + * @param bundleId App bundle identifier. + * @return Permissions mapping. + */ + public Optional> getAppPermissions(String bundleId) { + return getOptionValue(bundleId); + } +} diff --git a/src/main/java/io/appium/java_client/ios/options/simulator/SupportsPermissionsOption.java b/src/main/java/io/appium/java_client/ios/options/simulator/SupportsPermissionsOption.java index 2aca0a82a..e3a4b36c2 100644 --- a/src/main/java/io/appium/java_client/ios/options/simulator/SupportsPermissionsOption.java +++ b/src/main/java/io/appium/java_client/ios/options/simulator/SupportsPermissionsOption.java @@ -16,7 +16,6 @@ package io.appium.java_client.ios.options.simulator; -import com.google.gson.JsonObject; import io.appium.java_client.remote.options.BaseOptions; import io.appium.java_client.remote.options.CanSetCapability; import org.openqa.selenium.Capabilities; @@ -28,49 +27,23 @@ public interface SupportsPermissionsOption> extends String PERMISSIONS_OPTION = "permissions"; /** - * Allows to set permissions for the specified application bundle on - * Simulator only. The capability value is expected to be a valid JSON - * with {"bundleId1": {"serviceName1": "serviceStatus1", ...}, ...} - * format. Since Xcode SDK 11.4 Apple provides native APIs to interact with - * application settings. Check the output of xcrun simctl privacy booted - * command to get the list of available permission names. Use yes, no - * and unset as values in order to grant, revoke or reset the corresponding - * permission. Below Xcode SDK 11.4 it is required that applesimutils package - * is installed and available in PATH. The list of available service names - * and statuses can be found at https://github.com/wix/AppleSimulatorUtils. + * Allows setting of permissions for the specified application bundle on + * Simulator only. * - * @param json For example {"com.apple.mobilecal": {"calendar": "YES"}} + * @param permissions Permissions mapping. * @return self instance for chaining. */ - default T setPermissions(JsonObject json) { - return amend(PERMISSIONS_OPTION, json.toString()); + default T setPermissions(Permissions permissions) { + return amend(PERMISSIONS_OPTION, permissions.toString()); } /** - * Allows to set permissions for the specified application bundle on - * Simulator only. The capability value is expected to be a valid JSON - * string with {"bundleId1": {"serviceName1": "serviceStatus1", ...}, ...} - * format. Since Xcode SDK 11.4 Apple provides native APIs to interact with - * application settings. Check the output of xcrun simctl privacy booted - * command to get the list of available permission names. Use yes, no - * and unset as values in order to grant, revoke or reset the corresponding - * permission. Below Xcode SDK 11.4 it is required that applesimutils package - * is installed and available in PATH. The list of available service names - * and statuses can be found at https://github.com/wix/AppleSimulatorUtils. + * Get Simulator permissions. * - * @param json For example {"com.apple.mobilecal": {"calendar": "YES"}} - * @return self instance for chaining. - */ - default T setPermissions(String json) { - return amend(PERMISSIONS_OPTION, json); - } - - /** - * Get Simulator permissions.. - * - * @return Permissions json. + * @return Permissions object. */ - default Optional getPermissions() { - return Optional.ofNullable((String) getCapability(PERMISSIONS_OPTION)); + default Optional getPermissions() { + return Optional.ofNullable(getCapability(PERMISSIONS_OPTION)) + .map((v) -> new Permissions(String.valueOf(v))); } } diff --git a/src/main/java/io/appium/java_client/remote/options/BaseMapOptionData.java b/src/main/java/io/appium/java_client/remote/options/BaseMapOptionData.java index 004d1bdf5..b5e05c2e9 100644 --- a/src/main/java/io/appium/java_client/remote/options/BaseMapOptionData.java +++ b/src/main/java/io/appium/java_client/remote/options/BaseMapOptionData.java @@ -16,7 +16,9 @@ package io.appium.java_client.remote.options; +import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; import java.util.Collections; import java.util.HashMap; @@ -33,6 +35,11 @@ public BaseMapOptionData(Map options) { this.options = options; } + public BaseMapOptionData(String json) { + //noinspection unchecked + this((Map) new Gson().fromJson(json, Map.class)); + } + /** * Sets the given value on the data object. * @@ -70,6 +77,10 @@ public Map toMap() { return Optional.ofNullable(options).orElseGet(Collections::emptyMap); } + public JsonObject toJson() { + return new GsonBuilder().create().toJsonTree(toMap()).getAsJsonObject(); + } + @Override public String toString() { return new GsonBuilder().create().toJson(toMap()); 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 new file mode 100644 index 000000000..9b099cb5c --- /dev/null +++ b/src/test/java/io/appium/java_client/drivers/options/OptionsBuildingTest.java @@ -0,0 +1,146 @@ +/* + * 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.drivers.options; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import io.appium.java_client.android.options.EspressoOptions; +import io.appium.java_client.android.options.UiAutomator2Options; +import io.appium.java_client.android.options.localization.AppLocale; +import io.appium.java_client.android.options.server.EspressoBuildConfig; +import io.appium.java_client.android.options.signing.KeystoreConfig; +import io.appium.java_client.ios.options.XCUITestOptions; +import io.appium.java_client.ios.options.other.CommandTimeouts; +import io.appium.java_client.ios.options.simulator.Permissions; +import io.appium.java_client.mac.options.Mac2Options; +import io.appium.java_client.remote.AutomationName; +import io.appium.java_client.windows.options.RunScript; +import io.appium.java_client.windows.options.WindowsOptions; +import org.junit.Test; +import org.openqa.selenium.Platform; + +import java.net.MalformedURLException; +import java.net.URL; +import java.time.Duration; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +@SuppressWarnings("ConstantConditions") +public class OptionsBuildingTest { + @Test + public void canBuildXcuiTestOptions() throws MalformedURLException { + XCUITestOptions options = new XCUITestOptions(); + assertEquals(options.getPlatformName(), Platform.IOS); + assertEquals(options.getAutomationName().orElse(null), AutomationName.IOS_XCUI_TEST); + options.setNewCommandTimeout(Duration.ofSeconds(10)) + .noReset() + .setWdaBaseUrl("http://localhost:8000") + .setPermissions(new Permissions() + .withAppPermissions("com.apple.MobileSafari", + ImmutableMap.of("calendar", "YES"))) + .setSafariSocketChunkSize(10) + .setCommandTimeouts(new CommandTimeouts() + .withCommandTimeout("yolo", Duration.ofSeconds(1))); + assertEquals(options.getNewCommandTimeout().orElse(null), Duration.ofSeconds(10)); + assertEquals(options.getWdaBaseUrl().orElse(null), new URL("http://localhost:8000")); + assertNotNull(options.getPermissions() + .map((v) -> v.getAppPermissions("com.apple.MobileSafari")) + .orElse(null)); + assertEquals(10L, (long) options.getSafariSocketChunkSize().orElse(0)); + assertEquals(1L, options.getCommandTimeouts().orElse(null).left() + .getCommandTimeout("yolo").orElse(null).getSeconds()); + } + + @Test + public void canBuildUiAutomator2Options() throws MalformedURLException { + UiAutomator2Options options = new UiAutomator2Options(); + assertEquals(options.getPlatformName(), Platform.ANDROID); + assertEquals(options.getAutomationName().orElse(null), AutomationName.ANDROID_UIAUTOMATOR2); + options.setNewCommandTimeout(Duration.ofSeconds(10)) + .noReset() + .setAdbExecTimeout(Duration.ofSeconds(3)) + .suppressKillServer() + .setMjpegScreenshotUrl(new URL("http://yolo.com")) + .setKeystoreConfig(new KeystoreConfig("path", "password", "keyAlias", "keyPassword")); + assertEquals(options.getNewCommandTimeout().orElse(null), Duration.ofSeconds(10)); + assertEquals(options.getAdbExecTimeout().orElse(null), Duration.ofSeconds(3)); + assertEquals(options.getMjpegScreenshotUrl().orElse(null), new URL("http://yolo.com")); + assertEquals(options.getKeystoreConfig().orElse(null).getPath(), "path"); + assertEquals(options.getKeystoreConfig().orElse(null).getKeyAlias(), "keyAlias"); + assertTrue(options.doesSuppressKillServer().orElse(false)); + } + + @Test + public void canBuildEspressoOptions() { + EspressoOptions options = new EspressoOptions(); + assertEquals(options.getPlatformName(), Platform.ANDROID); + assertEquals(options.getAutomationName().orElse(null), AutomationName.ESPRESSO); + options.setNewCommandTimeout(Duration.ofSeconds(10)) + .forceEspressoRebuild() + .setAppLocale(new AppLocale() + .withCountry("CN") + .withLanguage("zh") + .withVariant("hans")) + .setEspressoBuildConfig(new EspressoBuildConfig() + .withAdditionalAppDependencies(ImmutableList.of( + "com.dep1:1.2.3", + "com.dep2:1.2.3" + )) + ); + assertEquals(options.getNewCommandTimeout().orElse(null), Duration.ofSeconds(10)); + assertEquals(options.getAppLocale().orElse(null).getCountry().orElse(null), "CN"); + assertEquals(options.getEspressoBuildConfig().orElse(null) + .left().getAdditionalAppDependencies().orElse(null).size(), 2); + assertTrue(options.doesForceEspressoRebuild().orElse(false)); + } + + @Test + public void canBuildWindowsOptions() { + WindowsOptions options = new WindowsOptions(); + assertEquals(options.getPlatformName(), Platform.WINDOWS); + assertEquals(options.getAutomationName().orElse(null), AutomationName.WINDOWS); + options.setNewCommandTimeout(Duration.ofSeconds(10)) + .setPrerun(new RunScript() + .withScript("yolo prescript")) + .setPostrun(new RunScript() + .withCommand("yolo command")); + assertEquals(options.getNewCommandTimeout().orElse(null), Duration.ofSeconds(10)); + assertEquals(options.getPrerun().orElse(null).getScript().orElse(null), "yolo prescript"); + assertEquals(options.getPostrun().orElse(null).getCommand().orElse(null), "yolo command"); + } + + @Test + public void canBuildMac2Options() { + Mac2Options options = new Mac2Options(); + assertEquals(options.getPlatformName(), Platform.MAC); + assertEquals(options.getAutomationName().orElse(null), AutomationName.MAC2); + options.setNewCommandTimeout(Duration.ofSeconds(10)) + .skipAppKill() + .setPrerun(new io.appium.java_client.mac.options.RunScript() + .withScript("yolo prescript")) + .setPostrun(new io.appium.java_client.mac.options.RunScript() + .withCommand("yolo command")); + assertEquals(options.getNewCommandTimeout().orElse(null), Duration.ofSeconds(10)); + assertEquals(options.getPrerun().orElse(null).getScript().orElse(null), "yolo prescript"); + assertEquals(options.getPostrun().orElse(null).getCommand().orElse(null), "yolo command"); + assertTrue(options.doesSkipAppKill().orElse(false)); + assertFalse(options.doesEventTimings().isPresent()); + } +} From 305e176fcd92c266b27357a29f1236f6be0c6cf4 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Sat, 30 Oct 2021 08:28:56 +0200 Subject: [PATCH 4/7] Address comments --- .../android/options/app/ActivityOptions.java | 3 +- .../options/server/EspressoBuildConfig.java | 93 ++++--------------- .../remote/options/BaseMapOptionData.java | 8 +- .../drivers/options/OptionsBuildingTest.java | 54 +++++------ 4 files changed, 53 insertions(+), 105 deletions(-) diff --git a/src/main/java/io/appium/java_client/android/options/app/ActivityOptions.java b/src/main/java/io/appium/java_client/android/options/app/ActivityOptions.java index de328149f..6a3db25d7 100644 --- a/src/main/java/io/appium/java_client/android/options/app/ActivityOptions.java +++ b/src/main/java/io/appium/java_client/android/options/app/ActivityOptions.java @@ -16,6 +16,7 @@ package io.appium.java_client.android.options.app; +import io.appium.java_client.internal.CapabilityHelpers; import io.appium.java_client.remote.options.BaseMapOptionData; import java.util.Map; @@ -48,6 +49,6 @@ public ActivityOptions withLaunchDisplayId(int id) { */ public Optional getLaunchDisplayId() { Optional result = getOptionValue("launchDisplayId"); - return result.map((v) -> Integer.parseInt(String.valueOf(v))); + return result.map(CapabilityHelpers::toInteger); } } diff --git a/src/main/java/io/appium/java_client/android/options/server/EspressoBuildConfig.java b/src/main/java/io/appium/java_client/android/options/server/EspressoBuildConfig.java index 28763a79a..209cdcac2 100644 --- a/src/main/java/io/appium/java_client/android/options/server/EspressoBuildConfig.java +++ b/src/main/java/io/appium/java_client/android/options/server/EspressoBuildConfig.java @@ -16,57 +16,42 @@ package io.appium.java_client.android.options.server; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; +import io.appium.java_client.internal.CapabilityHelpers; +import io.appium.java_client.remote.options.BaseMapOptionData; -import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; -public class EspressoBuildConfig { +public class EspressoBuildConfig extends BaseMapOptionData { public static final String TOOLS_VERSION = "toolsVersions"; public static final String ADDITIONAL_APP_DEPENDENCIES = "additionalAppDependencies"; public static final String ADDITIONAL_ANDROID_TEST_DEPENDENCIES = "additionalAndroidTestDependencies"; - private JsonObject json; - public EspressoBuildConfig() { - } - - public EspressoBuildConfig(JsonObject json) { - this.json = json; + super(); } public EspressoBuildConfig(String json) { - this(JsonParser.parseString(json).getAsJsonObject()); + super(json); } private EspressoBuildConfig assignToolsVersionsField(String name, Object value) { - if (json == null) { - json = new JsonObject(); - } - boolean hasTools = json.has(TOOLS_VERSION); - JsonObject toolsVersions = hasTools - ? json.getAsJsonObject(TOOLS_VERSION) - : new JsonObject(); - if (value instanceof Number) { - toolsVersions.addProperty(name, (Number) value); - } else { - toolsVersions.addProperty(name, String.valueOf(value)); - } - if (!hasTools) { - json.add(TOOLS_VERSION, toolsVersions); + Optional> toolsVersionsOptional = getOptionValue(TOOLS_VERSION); + Map toolsVersions = toolsVersionsOptional.orElseGet(HashMap::new); + toolsVersions.put(name, value); + if (!toolsVersionsOptional.isPresent()) { + assignOptionValue(TOOLS_VERSION, toolsVersions); } return this; } private Optional getToolsVersionsFieldValue(String name) { + Optional> toolsVersionsOptional = getOptionValue(TOOLS_VERSION); //noinspection unchecked - return json == null || !json.has(TOOLS_VERSION) - ? Optional.empty() - : Optional.ofNullable((R) json.getAsJsonObject(TOOLS_VERSION).get(name)); + return toolsVersionsOptional.map((v) -> (R) v.getOrDefault(name, null)); } /** @@ -167,7 +152,7 @@ public EspressoBuildConfig withMinSdk(int apiLevel) { */ public Optional getMinSdkVersion() { Optional result = getToolsVersionsFieldValue("minSdk"); - return result.map((v) -> Integer.parseInt(String.valueOf(v))); + return result.map(CapabilityHelpers::toInteger); } /** @@ -188,7 +173,7 @@ public EspressoBuildConfig withTargetSdk(int apiLevel) { */ public Optional getTargetSdkVersion() { Optional result = getToolsVersionsFieldValue("targetSdk"); - return result.map((v) -> Integer.parseInt(String.valueOf(v))); + return result.map(CapabilityHelpers::toInteger); } /** @@ -211,35 +196,6 @@ public Optional getKotlinVersion() { return getToolsVersionsFieldValue("kotlin"); } - private EspressoBuildConfig assignDependenciesField(String name, List value) { - if (json == null) { - json = new JsonObject(); - } - boolean hasField = json.has(name); - JsonArray dependencies = hasField - ? json.getAsJsonArray(name) - : new JsonArray(); - while (dependencies.size() > 0) { - dependencies.remove(0); - } - value.forEach(dependencies::add); - if (!hasField) { - json.add(name, dependencies); - } - return this; - } - - private Optional> getDependenciesValue(String name) { - return json == null - ? Optional.empty() - : Optional.ofNullable(json.getAsJsonArray(name)) - .map((v) -> { - List result = new ArrayList<>(); - v.forEach((x) -> result.add(String.valueOf(x))); - return result; - }); - } - /** * Set a non-empty array of dependent module names with their versions. * The scripts add all these items as "implementation" lines of dependencies @@ -249,7 +205,7 @@ private Optional> getDependenciesValue(String name) { * @return self instance for chaining. */ public EspressoBuildConfig withAdditionalAppDependencies(List dependencies) { - return assignDependenciesField(ADDITIONAL_APP_DEPENDENCIES, dependencies); + return assignOptionValue(ADDITIONAL_APP_DEPENDENCIES, dependencies); } /** @@ -258,7 +214,7 @@ public EspressoBuildConfig withAdditionalAppDependencies(List dependenci * @return Dependent module names with their versions. */ public Optional> getAdditionalAppDependencies() { - return getDependenciesValue(ADDITIONAL_APP_DEPENDENCIES); + return getOptionValue(ADDITIONAL_APP_DEPENDENCIES); } /** @@ -270,7 +226,7 @@ public Optional> getAdditionalAppDependencies() { * @return self instance for chaining. */ public EspressoBuildConfig withAdditionalAndroidTestDependencies(List dependencies) { - return assignDependenciesField(ADDITIONAL_ANDROID_TEST_DEPENDENCIES, dependencies); + return assignOptionValue(ADDITIONAL_ANDROID_TEST_DEPENDENCIES, dependencies); } /** @@ -279,15 +235,6 @@ public EspressoBuildConfig withAdditionalAndroidTestDependencies(List de * @return Dependent module names with their versions. */ public Optional> getAdditionalAndroidTestDependencies() { - return getDependenciesValue(ADDITIONAL_ANDROID_TEST_DEPENDENCIES); - } - - public JsonObject toJson() { - return Optional.ofNullable(json).orElseGet(JsonObject::new); - } - - @Override - public String toString() { - return toJson().toString(); + return getOptionValue(ADDITIONAL_ANDROID_TEST_DEPENDENCIES); } } diff --git a/src/main/java/io/appium/java_client/remote/options/BaseMapOptionData.java b/src/main/java/io/appium/java_client/remote/options/BaseMapOptionData.java index b5e05c2e9..a7b75e3d7 100644 --- a/src/main/java/io/appium/java_client/remote/options/BaseMapOptionData.java +++ b/src/main/java/io/appium/java_client/remote/options/BaseMapOptionData.java @@ -17,7 +17,6 @@ package io.appium.java_client.remote.options; import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.google.gson.JsonObject; import java.util.Collections; @@ -27,6 +26,7 @@ public abstract class BaseMapOptionData> { private Map options; + private static final Gson gson = new Gson(); public BaseMapOptionData() { } @@ -37,7 +37,7 @@ public BaseMapOptionData(Map options) { public BaseMapOptionData(String json) { //noinspection unchecked - this((Map) new Gson().fromJson(json, Map.class)); + this((Map) gson.fromJson(json, Map.class)); } /** @@ -78,11 +78,11 @@ public Map toMap() { } public JsonObject toJson() { - return new GsonBuilder().create().toJsonTree(toMap()).getAsJsonObject(); + return gson.toJsonTree(toMap()).getAsJsonObject(); } @Override public String toString() { - return new GsonBuilder().create().toJson(toMap()); + return gson.toJson(toMap()); } } 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 9b099cb5c..eab85ed88 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 @@ -47,8 +47,8 @@ public class OptionsBuildingTest { @Test public void canBuildXcuiTestOptions() throws MalformedURLException { XCUITestOptions options = new XCUITestOptions(); - assertEquals(options.getPlatformName(), Platform.IOS); - assertEquals(options.getAutomationName().orElse(null), AutomationName.IOS_XCUI_TEST); + assertEquals(Platform.IOS, options.getPlatformName()); + assertEquals(AutomationName.IOS_XCUI_TEST, options.getAutomationName().orElse(null)); options.setNewCommandTimeout(Duration.ofSeconds(10)) .noReset() .setWdaBaseUrl("http://localhost:8000") @@ -58,8 +58,8 @@ public void canBuildXcuiTestOptions() throws MalformedURLException { .setSafariSocketChunkSize(10) .setCommandTimeouts(new CommandTimeouts() .withCommandTimeout("yolo", Duration.ofSeconds(1))); - assertEquals(options.getNewCommandTimeout().orElse(null), Duration.ofSeconds(10)); - assertEquals(options.getWdaBaseUrl().orElse(null), new URL("http://localhost:8000")); + assertEquals(Duration.ofSeconds(10), options.getNewCommandTimeout().orElse(null)); + assertEquals(new URL("http://localhost:8000"), options.getWdaBaseUrl().orElse(null)); assertNotNull(options.getPermissions() .map((v) -> v.getAppPermissions("com.apple.MobileSafari")) .orElse(null)); @@ -71,27 +71,27 @@ public void canBuildXcuiTestOptions() throws MalformedURLException { @Test public void canBuildUiAutomator2Options() throws MalformedURLException { UiAutomator2Options options = new UiAutomator2Options(); - assertEquals(options.getPlatformName(), Platform.ANDROID); - assertEquals(options.getAutomationName().orElse(null), AutomationName.ANDROID_UIAUTOMATOR2); + assertEquals(Platform.ANDROID, options.getPlatformName()); + assertEquals(AutomationName.ANDROID_UIAUTOMATOR2, options.getAutomationName().orElse(null)); options.setNewCommandTimeout(Duration.ofSeconds(10)) .noReset() .setAdbExecTimeout(Duration.ofSeconds(3)) .suppressKillServer() .setMjpegScreenshotUrl(new URL("http://yolo.com")) .setKeystoreConfig(new KeystoreConfig("path", "password", "keyAlias", "keyPassword")); - assertEquals(options.getNewCommandTimeout().orElse(null), Duration.ofSeconds(10)); - assertEquals(options.getAdbExecTimeout().orElse(null), Duration.ofSeconds(3)); - assertEquals(options.getMjpegScreenshotUrl().orElse(null), new URL("http://yolo.com")); - assertEquals(options.getKeystoreConfig().orElse(null).getPath(), "path"); - assertEquals(options.getKeystoreConfig().orElse(null).getKeyAlias(), "keyAlias"); + assertEquals(Duration.ofSeconds(10), options.getNewCommandTimeout().orElse(null)); + assertEquals(Duration.ofSeconds(3), options.getAdbExecTimeout().orElse(null)); + assertEquals(new URL("http://yolo.com"), options.getMjpegScreenshotUrl().orElse(null)); + assertEquals("path", options.getKeystoreConfig().orElse(null).getPath()); + assertEquals("keyAlias", options.getKeystoreConfig().orElse(null).getKeyAlias()); assertTrue(options.doesSuppressKillServer().orElse(false)); } @Test public void canBuildEspressoOptions() { EspressoOptions options = new EspressoOptions(); - assertEquals(options.getPlatformName(), Platform.ANDROID); - assertEquals(options.getAutomationName().orElse(null), AutomationName.ESPRESSO); + assertEquals(Platform.ANDROID, options.getPlatformName()); + assertEquals(AutomationName.ESPRESSO, options.getAutomationName().orElse(null)); options.setNewCommandTimeout(Duration.ofSeconds(10)) .forceEspressoRebuild() .setAppLocale(new AppLocale() @@ -104,42 +104,42 @@ public void canBuildEspressoOptions() { "com.dep2:1.2.3" )) ); - assertEquals(options.getNewCommandTimeout().orElse(null), Duration.ofSeconds(10)); - assertEquals(options.getAppLocale().orElse(null).getCountry().orElse(null), "CN"); - assertEquals(options.getEspressoBuildConfig().orElse(null) - .left().getAdditionalAppDependencies().orElse(null).size(), 2); + assertEquals(Duration.ofSeconds(10), options.getNewCommandTimeout().orElse(null)); + assertEquals("CN", options.getAppLocale().orElse(null).getCountry().orElse(null)); + assertEquals(2, options.getEspressoBuildConfig().orElse(null) + .left().getAdditionalAppDependencies().orElse(null).size()); assertTrue(options.doesForceEspressoRebuild().orElse(false)); } @Test public void canBuildWindowsOptions() { WindowsOptions options = new WindowsOptions(); - assertEquals(options.getPlatformName(), Platform.WINDOWS); - assertEquals(options.getAutomationName().orElse(null), AutomationName.WINDOWS); + assertEquals(Platform.WINDOWS, options.getPlatformName()); + assertEquals(AutomationName.WINDOWS, options.getAutomationName().orElse(null)); options.setNewCommandTimeout(Duration.ofSeconds(10)) .setPrerun(new RunScript() .withScript("yolo prescript")) .setPostrun(new RunScript() .withCommand("yolo command")); - assertEquals(options.getNewCommandTimeout().orElse(null), Duration.ofSeconds(10)); - assertEquals(options.getPrerun().orElse(null).getScript().orElse(null), "yolo prescript"); - assertEquals(options.getPostrun().orElse(null).getCommand().orElse(null), "yolo command"); + assertEquals(Duration.ofSeconds(10), options.getNewCommandTimeout().orElse(null)); + assertEquals("yolo prescript", options.getPrerun().orElse(null).getScript().orElse(null)); + assertEquals("yolo command", options.getPostrun().orElse(null).getCommand().orElse(null)); } @Test public void canBuildMac2Options() { Mac2Options options = new Mac2Options(); - assertEquals(options.getPlatformName(), Platform.MAC); - assertEquals(options.getAutomationName().orElse(null), AutomationName.MAC2); + assertEquals(Platform.MAC, options.getPlatformName()); + assertEquals(AutomationName.MAC2, options.getAutomationName().orElse(null)); options.setNewCommandTimeout(Duration.ofSeconds(10)) .skipAppKill() .setPrerun(new io.appium.java_client.mac.options.RunScript() .withScript("yolo prescript")) .setPostrun(new io.appium.java_client.mac.options.RunScript() .withCommand("yolo command")); - assertEquals(options.getNewCommandTimeout().orElse(null), Duration.ofSeconds(10)); - assertEquals(options.getPrerun().orElse(null).getScript().orElse(null), "yolo prescript"); - assertEquals(options.getPostrun().orElse(null).getCommand().orElse(null), "yolo command"); + assertEquals(Duration.ofSeconds(10), options.getNewCommandTimeout().orElse(null)); + assertEquals("yolo prescript", options.getPrerun().orElse(null).getScript().orElse(null)); + assertEquals("yolo command", options.getPostrun().orElse(null).getCommand().orElse(null)); assertTrue(options.doesSkipAppKill().orElse(false)); assertFalse(options.doesEventTimings().isPresent()); } From eada98c705999e615c2bc3fee5d8e8bd63cb7373 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Sat, 30 Oct 2021 10:16:39 +0200 Subject: [PATCH 5/7] Simplify config set --- .../options/server/SupportsEspressoBuildConfigOption.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/appium/java_client/android/options/server/SupportsEspressoBuildConfigOption.java b/src/main/java/io/appium/java_client/android/options/server/SupportsEspressoBuildConfigOption.java index 9444bc9ef..93eb19831 100644 --- a/src/main/java/io/appium/java_client/android/options/server/SupportsEspressoBuildConfigOption.java +++ b/src/main/java/io/appium/java_client/android/options/server/SupportsEspressoBuildConfigOption.java @@ -50,7 +50,7 @@ default T setEspressoBuildConfig(String configPath) { * @return self instance for chaining. */ default T setEspressoBuildConfig(EspressoBuildConfig config) { - return amend(ESPRESSO_BUILD_CONFIG_OPTION, config.toJson().toString()); + return amend(ESPRESSO_BUILD_CONFIG_OPTION, config.toString()); } /** From a3c310f32aab07368cbe33a997ba5d7bb1c74471 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Sat, 30 Oct 2021 14:46:50 +0200 Subject: [PATCH 6/7] Simplify prerun/postrun --- .../{RunScript.java => AppleScriptData.java} | 24 +++--- .../java_client/mac/options/Mac2Options.java | 57 ++++++++++++++- .../mac/options/SupportsPostrunOption.java | 54 -------------- .../mac/options/SupportsPrerunOption.java | 54 -------------- .../options/RunScript.java | 10 +-- .../remote/options/SupportsPostrunOption.java | 30 ++++++++ .../remote/options/SupportsPrerunOption.java | 30 ++++++++ .../windows/options/PowerShellData.java | 73 +++++++++++++++++++ .../options/SupportsPostrunOption.java | 55 -------------- .../windows/options/SupportsPrerunOption.java | 55 -------------- .../windows/options/WindowsOptions.java | 59 ++++++++++++++- .../drivers/options/OptionsBuildingTest.java | 15 ++-- 12 files changed, 269 insertions(+), 247 deletions(-) rename src/main/java/io/appium/java_client/mac/options/{RunScript.java => AppleScriptData.java} (72%) delete mode 100644 src/main/java/io/appium/java_client/mac/options/SupportsPostrunOption.java delete mode 100644 src/main/java/io/appium/java_client/mac/options/SupportsPrerunOption.java rename src/main/java/io/appium/java_client/{windows => remote}/options/RunScript.java (86%) create mode 100644 src/main/java/io/appium/java_client/remote/options/SupportsPostrunOption.java create mode 100644 src/main/java/io/appium/java_client/remote/options/SupportsPrerunOption.java create mode 100644 src/main/java/io/appium/java_client/windows/options/PowerShellData.java delete mode 100644 src/main/java/io/appium/java_client/windows/options/SupportsPostrunOption.java delete mode 100644 src/main/java/io/appium/java_client/windows/options/SupportsPrerunOption.java diff --git a/src/main/java/io/appium/java_client/mac/options/RunScript.java b/src/main/java/io/appium/java_client/mac/options/AppleScriptData.java similarity index 72% rename from src/main/java/io/appium/java_client/mac/options/RunScript.java rename to src/main/java/io/appium/java_client/mac/options/AppleScriptData.java index 4960d7e86..ce2507f20 100644 --- a/src/main/java/io/appium/java_client/mac/options/RunScript.java +++ b/src/main/java/io/appium/java_client/mac/options/AppleScriptData.java @@ -16,16 +16,16 @@ package io.appium.java_client.mac.options; -import io.appium.java_client.remote.options.BaseMapOptionData; +import io.appium.java_client.remote.options.RunScript; import java.util.Map; import java.util.Optional; -public class RunScript extends BaseMapOptionData { - public RunScript() { +public class AppleScriptData extends RunScript { + public AppleScriptData() { } - public RunScript(Map options) { + public AppleScriptData(Map options) { super(options); } @@ -35,8 +35,9 @@ public RunScript(Map options) { * @param script A valid AppleScript. * @return self instance for chaining. */ - public RunScript withScript(String script) { - return assignOptionValue("script", script); + @Override + public AppleScriptData withScript(String script) { + return super.withScript(script); } /** @@ -44,8 +45,9 @@ public RunScript withScript(String script) { * * @return AppleScript snippet. */ + @Override public Optional getScript() { - return getOptionValue("script"); + return super.getScript(); } /** @@ -54,8 +56,9 @@ public Optional getScript() { * @param command A valid AppleScript. * @return self instance for chaining. */ - public RunScript withCommand(String command) { - return assignOptionValue("command", command); + @Override + public AppleScriptData withCommand(String command) { + return super.withCommand(command); } /** @@ -63,7 +66,8 @@ public RunScript withCommand(String command) { * * @return AppleScript snippet. */ + @Override public Optional getCommand() { - return getOptionValue("command"); + return super.getCommand(); } } diff --git a/src/main/java/io/appium/java_client/mac/options/Mac2Options.java b/src/main/java/io/appium/java_client/mac/options/Mac2Options.java index 47214f677..37e31575a 100644 --- a/src/main/java/io/appium/java_client/mac/options/Mac2Options.java +++ b/src/main/java/io/appium/java_client/mac/options/Mac2Options.java @@ -19,9 +19,12 @@ 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.SupportsPostrunOption; +import io.appium.java_client.remote.options.SupportsPrerunOption; import org.openqa.selenium.Capabilities; import java.util.Map; +import java.util.Optional; /** * https://github.com/appium/appium-mac2-driver#capabilities @@ -37,8 +40,8 @@ public class Mac2Options extends BaseOptions implements SupportsServerStartupTimeoutOption, SupportsSkipAppKillOption, SupportsShowServerLogsOption, - SupportsPrerunOption, - SupportsPostrunOption { + SupportsPrerunOption, + SupportsPostrunOption { public Mac2Options() { setCommonOptions(); } @@ -57,4 +60,54 @@ private void setCommonOptions() { setPlatformName(MobilePlatform.MAC); setAutomationName(AutomationName.MAC2); } + + /** + * An object containing either script or command key. The value of + * each key must be a valid AppleScript script or command to be + * executed after before Mac2Driver session is started. See + * https://github.com/appium/appium-mac2-driver#applescript-commands-execution + * for more details. + * + * @param script A valid AppleScript snippet. + * @return self instance for chaining. + */ + public Mac2Options setPrerun(AppleScriptData 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 AppleScriptData((Map) v)); + } + + /** + * An object containing either script or command key. The value of + * each key must be a valid AppleScript script or command to be + * executed after Mac2Driver session is stopped. See + * https://github.com/appium/appium-mac2-driver#applescript-commands-execution + * for more details. + * + * @param script A valid AppleScript snippet. + * @return self instance for chaining. + */ + public Mac2Options setPostrun(AppleScriptData 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 AppleScriptData((Map) v)); + } } diff --git a/src/main/java/io/appium/java_client/mac/options/SupportsPostrunOption.java b/src/main/java/io/appium/java_client/mac/options/SupportsPostrunOption.java deleted file mode 100644 index 69430019b..000000000 --- a/src/main/java/io/appium/java_client/mac/options/SupportsPostrunOption.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.mac.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.Map; -import java.util.Optional; - -public interface SupportsPostrunOption> extends - Capabilities, CanSetCapability { - String POSTRUN_OPTION = "postrun"; - - /** - * An object containing either script or command key. The value of - * each key must be a valid AppleScript script or command to be - * executed after Mac2Driver session is stopped. See - * https://github.com/appium/appium-mac2-driver#applescript-commands-execution - * for more details. - * - * @param script A valid AppleScript snippet. - * @return self instance for chaining. - */ - default T setPostrun(RunScript script) { - return amend(POSTRUN_OPTION, script.toMap()); - } - - /** - * Get the postrun script. - * - * @return Postrun script. - */ - default Optional getPostrun() { - //noinspection unchecked - return Optional.ofNullable(getCapability(POSTRUN_OPTION)) - .map((v) -> new RunScript((Map) v)); - } -} diff --git a/src/main/java/io/appium/java_client/mac/options/SupportsPrerunOption.java b/src/main/java/io/appium/java_client/mac/options/SupportsPrerunOption.java deleted file mode 100644 index 61b8d0897..000000000 --- a/src/main/java/io/appium/java_client/mac/options/SupportsPrerunOption.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.mac.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.Map; -import java.util.Optional; - -public interface SupportsPrerunOption> extends - Capabilities, CanSetCapability { - String PRERUN_OPTION = "prerun"; - - /** - * An object containing either script or command key. The value of - * each key must be a valid AppleScript script or command to be - * executed after before Mac2Driver session is started. See - * https://github.com/appium/appium-mac2-driver#applescript-commands-execution - * for more details. - * - * @param script A valid AppleScript snippet. - * @return self instance for chaining. - */ - default T setPrerun(RunScript script) { - return amend(PRERUN_OPTION, script.toMap()); - } - - /** - * Get the prerun script. - * - * @return Prerun script. - */ - default Optional getPrerun() { - //noinspection unchecked - return Optional.ofNullable(getCapability(PRERUN_OPTION)) - .map((v) -> new RunScript((Map) v)); - } -} diff --git a/src/main/java/io/appium/java_client/windows/options/RunScript.java b/src/main/java/io/appium/java_client/remote/options/RunScript.java similarity index 86% rename from src/main/java/io/appium/java_client/windows/options/RunScript.java rename to src/main/java/io/appium/java_client/remote/options/RunScript.java index e31fa38fc..e75eeee96 100644 --- a/src/main/java/io/appium/java_client/windows/options/RunScript.java +++ b/src/main/java/io/appium/java_client/remote/options/RunScript.java @@ -14,14 +14,12 @@ * limitations under the License. */ -package io.appium.java_client.windows.options; - -import io.appium.java_client.remote.options.BaseMapOptionData; +package io.appium.java_client.remote.options; import java.util.Map; import java.util.Optional; -public class RunScript extends BaseMapOptionData { +public abstract class RunScript> extends BaseMapOptionData { public RunScript() { } @@ -35,7 +33,7 @@ public RunScript(Map options) { * @param script A valid PowerShell script. * @return self instance for chaining. */ - public RunScript withScript(String script) { + public T withScript(String script) { return assignOptionValue("script", script); } @@ -54,7 +52,7 @@ public Optional getScript() { * @param command A valid PowerShell script. * @return self instance for chaining. */ - public RunScript withCommand(String command) { + public T withCommand(String command) { return assignOptionValue("command", command); } diff --git a/src/main/java/io/appium/java_client/remote/options/SupportsPostrunOption.java b/src/main/java/io/appium/java_client/remote/options/SupportsPostrunOption.java new file mode 100644 index 000000000..2e9618f7f --- /dev/null +++ b/src/main/java/io/appium/java_client/remote/options/SupportsPostrunOption.java @@ -0,0 +1,30 @@ +/* + * 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.remote.options; + +import org.openqa.selenium.Capabilities; + +import java.util.Optional; + +public interface SupportsPostrunOption, S extends RunScript> + extends Capabilities, CanSetCapability { + String POSTRUN_OPTION = "postrun"; + + T setPostrun(S script); + + Optional getPostrun(); +} diff --git a/src/main/java/io/appium/java_client/remote/options/SupportsPrerunOption.java b/src/main/java/io/appium/java_client/remote/options/SupportsPrerunOption.java new file mode 100644 index 000000000..cc6199da5 --- /dev/null +++ b/src/main/java/io/appium/java_client/remote/options/SupportsPrerunOption.java @@ -0,0 +1,30 @@ +/* + * 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.remote.options; + +import org.openqa.selenium.Capabilities; + +import java.util.Optional; + +public interface SupportsPrerunOption, S extends RunScript> + extends Capabilities, CanSetCapability { + String PRERUN_OPTION = "prerun"; + + T setPrerun(S script); + + Optional getPrerun(); +} diff --git a/src/main/java/io/appium/java_client/windows/options/PowerShellData.java b/src/main/java/io/appium/java_client/windows/options/PowerShellData.java new file mode 100644 index 000000000..2cdd648a1 --- /dev/null +++ b/src/main/java/io/appium/java_client/windows/options/PowerShellData.java @@ -0,0 +1,73 @@ +/* + * 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.windows.options; + +import io.appium.java_client.remote.options.RunScript; + +import java.util.Map; +import java.util.Optional; + +public class PowerShellData extends RunScript { + public PowerShellData() { + } + + public PowerShellData(Map options) { + super(options); + } + + /** + * Allows to provide a multiline PowerShell script. + * + * @param script A valid PowerShell script. + * @return self instance for chaining. + */ + @Override + public PowerShellData withScript(String script) { + return super.withScript(script); + } + + /** + * Get a multiline PowerShell script. + * + * @return PowerShell script. + */ + @Override + public Optional getScript() { + return super.getScript(); + } + + /** + * Allows to provide a single-line PowerShell script. + * + * @param command A valid PowerShell script. + * @return self instance for chaining. + */ + @Override + public PowerShellData withCommand(String command) { + return super.withCommand(command); + } + + /** + * Get a single-line PowerShell script. + * + * @return PowerShell script. + */ + @Override + public Optional getCommand() { + return super.getCommand(); + } +} diff --git a/src/main/java/io/appium/java_client/windows/options/SupportsPostrunOption.java b/src/main/java/io/appium/java_client/windows/options/SupportsPostrunOption.java deleted file mode 100644 index b766820c3..000000000 --- a/src/main/java/io/appium/java_client/windows/options/SupportsPostrunOption.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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.windows.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.Map; -import java.util.Optional; - -public interface SupportsPostrunOption> extends - Capabilities, CanSetCapability { - String POSTRUN_OPTION = "postrun"; - - /** - * 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 an WinAppDriver session is finished. - * See - * https://github.com/appium/appium-windows-driver#power-shell-commands-execution - * for more details. - * - * @param script E.g. {script: 'Get-Process outlook -ErrorAction SilentlyContinue'}. - * @return self instance for chaining. - */ - default T setPostrun(RunScript script) { - return amend(POSTRUN_OPTION, script.toMap()); - } - - /** - * Get the postrun script. - * - * @return Postrun script. - */ - default Optional getPostrun() { - //noinspection unchecked - return Optional.ofNullable(getCapability(POSTRUN_OPTION)) - .map((v) -> new RunScript((Map) v)); - } -} diff --git a/src/main/java/io/appium/java_client/windows/options/SupportsPrerunOption.java b/src/main/java/io/appium/java_client/windows/options/SupportsPrerunOption.java deleted file mode 100644 index d3722da48..000000000 --- a/src/main/java/io/appium/java_client/windows/options/SupportsPrerunOption.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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.windows.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.Map; -import java.util.Optional; - -public interface SupportsPrerunOption> extends - Capabilities, CanSetCapability { - String PRERUN_OPTION = "prerun"; - - /** - * 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 WinAppDriver session startup. - * See - * https://github.com/appium/appium-windows-driver#power-shell-commands-execution - * for more details. - * - * @param script E.g. {script: 'Get-Process outlook -ErrorAction SilentlyContinue'}. - * @return self instance for chaining. - */ - default T setPrerun(RunScript script) { - return amend(PRERUN_OPTION, script.toMap()); - } - - /** - * Get the prerun script. - * - * @return Prerun script. - */ - default Optional getPrerun() { - //noinspection unchecked - return Optional.ofNullable(getCapability(PRERUN_OPTION)) - .map((v) -> new RunScript((Map) v)); - } -} 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 0d25a1ece..8a1f0eb8f 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 @@ -20,9 +20,12 @@ 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.SupportsPostrunOption; +import io.appium.java_client.remote.options.SupportsPrerunOption; import org.openqa.selenium.Capabilities; import java.util.Map; +import java.util.Optional; /** * https://github.com/appium/appium-windows-driver#usage @@ -36,8 +39,8 @@ public class WindowsOptions extends BaseOptions implements SupportsMsWaitForAppLaunchOption, SupportsMsExperimentalWebDriverOption, SupportsSystemPortOption, - SupportsPrerunOption, - SupportsPostrunOption { + SupportsPrerunOption, + SupportsPostrunOption { public WindowsOptions() { setCommonOptions(); } @@ -56,4 +59,56 @@ private void setCommonOptions() { setPlatformName(MobilePlatform.WINDOWS); setAutomationName(AutomationName.WINDOWS); } + + /** + * 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 WinAppDriver session startup. + * See + * https://github.com/appium/appium-windows-driver#power-shell-commands-execution + * for more details. + * + * @param script E.g. {script: 'Get-Process outlook -ErrorAction SilentlyContinue'}. + * @return self instance for chaining. + */ + public WindowsOptions 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 an WinAppDriver session is finished. + * See + * https://github.com/appium/appium-windows-driver#power-shell-commands-execution + * for more details. + * + * @param script E.g. {script: 'Get-Process outlook -ErrorAction SilentlyContinue'}. + * @return self instance for chaining. + */ + public WindowsOptions 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/test/java/io/appium/java_client/drivers/options/OptionsBuildingTest.java b/src/test/java/io/appium/java_client/drivers/options/OptionsBuildingTest.java index eab85ed88..9b12ceda9 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 @@ -26,9 +26,10 @@ import io.appium.java_client.ios.options.XCUITestOptions; import io.appium.java_client.ios.options.other.CommandTimeouts; import io.appium.java_client.ios.options.simulator.Permissions; +import io.appium.java_client.mac.options.AppleScriptData; import io.appium.java_client.mac.options.Mac2Options; import io.appium.java_client.remote.AutomationName; -import io.appium.java_client.windows.options.RunScript; +import io.appium.java_client.windows.options.PowerShellData; import io.appium.java_client.windows.options.WindowsOptions; import org.junit.Test; import org.openqa.selenium.Platform; @@ -117,10 +118,8 @@ public void canBuildWindowsOptions() { assertEquals(Platform.WINDOWS, options.getPlatformName()); assertEquals(AutomationName.WINDOWS, options.getAutomationName().orElse(null)); options.setNewCommandTimeout(Duration.ofSeconds(10)) - .setPrerun(new RunScript() - .withScript("yolo prescript")) - .setPostrun(new RunScript() - .withCommand("yolo command")); + .setPrerun(new PowerShellData().withScript("yolo prescript")) + .setPostrun(new PowerShellData().withCommand("yolo command")); assertEquals(Duration.ofSeconds(10), options.getNewCommandTimeout().orElse(null)); assertEquals("yolo prescript", options.getPrerun().orElse(null).getScript().orElse(null)); assertEquals("yolo command", options.getPostrun().orElse(null).getCommand().orElse(null)); @@ -133,10 +132,8 @@ public void canBuildMac2Options() { assertEquals(AutomationName.MAC2, options.getAutomationName().orElse(null)); options.setNewCommandTimeout(Duration.ofSeconds(10)) .skipAppKill() - .setPrerun(new io.appium.java_client.mac.options.RunScript() - .withScript("yolo prescript")) - .setPostrun(new io.appium.java_client.mac.options.RunScript() - .withCommand("yolo command")); + .setPrerun(new AppleScriptData().withScript("yolo prescript")) + .setPostrun(new AppleScriptData().withCommand("yolo command")); assertEquals(Duration.ofSeconds(10), options.getNewCommandTimeout().orElse(null)); assertEquals("yolo prescript", options.getPrerun().orElse(null).getScript().orElse(null)); assertEquals("yolo command", options.getPostrun().orElse(null).getCommand().orElse(null)); From cca94d51e023a5227e0cfd0639a76c6542077079 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Sat, 30 Oct 2021 15:11:41 +0200 Subject: [PATCH 7/7] Rename the base class --- .../mac/options/AppleScriptData.java | 4 +-- .../remote/options/SupportsPostrunOption.java | 2 +- .../remote/options/SupportsPrerunOption.java | 2 +- .../{RunScript.java => SystemScript.java} | 28 ++----------------- .../windows/options/PowerShellData.java | 4 +-- 5 files changed, 9 insertions(+), 31 deletions(-) rename src/main/java/io/appium/java_client/remote/options/{RunScript.java => SystemScript.java} (62%) diff --git a/src/main/java/io/appium/java_client/mac/options/AppleScriptData.java b/src/main/java/io/appium/java_client/mac/options/AppleScriptData.java index ce2507f20..91b74aa98 100644 --- a/src/main/java/io/appium/java_client/mac/options/AppleScriptData.java +++ b/src/main/java/io/appium/java_client/mac/options/AppleScriptData.java @@ -16,12 +16,12 @@ package io.appium.java_client.mac.options; -import io.appium.java_client.remote.options.RunScript; +import io.appium.java_client.remote.options.SystemScript; import java.util.Map; import java.util.Optional; -public class AppleScriptData extends RunScript { +public class AppleScriptData extends SystemScript { public AppleScriptData() { } diff --git a/src/main/java/io/appium/java_client/remote/options/SupportsPostrunOption.java b/src/main/java/io/appium/java_client/remote/options/SupportsPostrunOption.java index 2e9618f7f..e055cb69f 100644 --- a/src/main/java/io/appium/java_client/remote/options/SupportsPostrunOption.java +++ b/src/main/java/io/appium/java_client/remote/options/SupportsPostrunOption.java @@ -20,7 +20,7 @@ import java.util.Optional; -public interface SupportsPostrunOption, S extends RunScript> +public interface SupportsPostrunOption, S extends SystemScript> extends Capabilities, CanSetCapability { String POSTRUN_OPTION = "postrun"; diff --git a/src/main/java/io/appium/java_client/remote/options/SupportsPrerunOption.java b/src/main/java/io/appium/java_client/remote/options/SupportsPrerunOption.java index cc6199da5..a44d2c53f 100644 --- a/src/main/java/io/appium/java_client/remote/options/SupportsPrerunOption.java +++ b/src/main/java/io/appium/java_client/remote/options/SupportsPrerunOption.java @@ -20,7 +20,7 @@ import java.util.Optional; -public interface SupportsPrerunOption, S extends RunScript> +public interface SupportsPrerunOption, S extends SystemScript> extends Capabilities, CanSetCapability { String PRERUN_OPTION = "prerun"; diff --git a/src/main/java/io/appium/java_client/remote/options/RunScript.java b/src/main/java/io/appium/java_client/remote/options/SystemScript.java similarity index 62% rename from src/main/java/io/appium/java_client/remote/options/RunScript.java rename to src/main/java/io/appium/java_client/remote/options/SystemScript.java index e75eeee96..901d8e220 100644 --- a/src/main/java/io/appium/java_client/remote/options/RunScript.java +++ b/src/main/java/io/appium/java_client/remote/options/SystemScript.java @@ -19,48 +19,26 @@ import java.util.Map; import java.util.Optional; -public abstract class RunScript> extends BaseMapOptionData { - public RunScript() { +public abstract class SystemScript> extends BaseMapOptionData { + public SystemScript() { } - public RunScript(Map options) { + public SystemScript(Map options) { super(options); } - /** - * Allows to provide a multiline PowerShell script. - * - * @param script A valid PowerShell script. - * @return self instance for chaining. - */ public T withScript(String script) { return assignOptionValue("script", script); } - /** - * Get a multiline PowerShell script. - * - * @return PowerShell script. - */ public Optional getScript() { return getOptionValue("script"); } - /** - * Allows to provide a single-line PowerShell script. - * - * @param command A valid PowerShell script. - * @return self instance for chaining. - */ public T withCommand(String command) { return assignOptionValue("command", command); } - /** - * Get a single-line PowerShell script. - * - * @return PowerShell script. - */ public Optional getCommand() { return getOptionValue("command"); } diff --git a/src/main/java/io/appium/java_client/windows/options/PowerShellData.java b/src/main/java/io/appium/java_client/windows/options/PowerShellData.java index 2cdd648a1..6dc97f495 100644 --- a/src/main/java/io/appium/java_client/windows/options/PowerShellData.java +++ b/src/main/java/io/appium/java_client/windows/options/PowerShellData.java @@ -16,12 +16,12 @@ package io.appium.java_client.windows.options; -import io.appium.java_client.remote.options.RunScript; +import io.appium.java_client.remote.options.SystemScript; import java.util.Map; import java.util.Optional; -public class PowerShellData extends RunScript { +public class PowerShellData extends SystemScript { public PowerShellData() { }