diff --git a/azure-pipelines.yml b/azure-pipelines.yml index e374442f0..ea502ec76 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -15,43 +15,46 @@ variables: IOS_PLATFORM_VERSION: 12.2 IOS_DEVICE_NAME: iPhone X -steps: -- task: NodeTool@0 - inputs: - versionSpec: '11.x' - -- script: | - echo "Configuring Environment" - echo "y" | $ANDROID_HOME/tools/bin/sdkmanager --install 'system-images;$(ANDROID_EMU_TARGET);$(ANDROID_EMU_TAG);$(ANDROID_EMU_ABI)' - echo "no" | $ANDROID_HOME/tools/bin/avdmanager create avd -n "$(ANDROID_EMU_NAME)" -k 'system-images;$(ANDROID_EMU_TARGET);$(ANDROID_EMU_TAG);$(ANDROID_EMU_ABI)' --force - echo $ANDROID_HOME/emulator/emulator -list-avds - - echo "Starting emulator" - nohup $ANDROID_HOME/emulator/emulator -avd "$(ANDROID_EMU_NAME)" -no-snapshot > /dev/null 2>&1 & - $ANDROID_HOME/platform-tools/adb wait-for-device - while [[ $? -ne 0 ]]; do sleep 1; $ANDROID_HOME/platform-tools/adb shell pm list packages; done; - $ANDROID_HOME/platform-tools/adb devices - echo "Emulator started" - - sudo xcode-select -s /Applications/Xcode_$(XCODE_VERSION).app/Contents/Developer - xcrun simctl list - - npm config delete prefix - npm config set prefix $NVM_DIR/versions/node/`node --version` - node --version - - npm install -g appium@beta - appium --version - - java -version - -- task: Gradle@2 - inputs: - gradleWrapperFile: 'gradlew' - gradleOptions: '-Xmx3072m' - javaHomeOption: 'JDKVersion' - jdkVersionOption: '1.8' - jdkArchitectureOption: 'x64' - publishJUnitResults: true - tasks: 'build' - options: 'xcuiTest uiAutomationTest -x checkstyleTest -x test -x signMavenJavaPublication' +jobs: +- job: E2E_Tests + timeoutInMinutes: 120 + steps: + - task: NodeTool@0 + inputs: + versionSpec: '11.x' + + - script: | + echo "Configuring Environment" + echo "y" | $ANDROID_HOME/tools/bin/sdkmanager --install 'system-images;$(ANDROID_EMU_TARGET);$(ANDROID_EMU_TAG);$(ANDROID_EMU_ABI)' + echo "no" | $ANDROID_HOME/tools/bin/avdmanager create avd -n "$(ANDROID_EMU_NAME)" -k 'system-images;$(ANDROID_EMU_TARGET);$(ANDROID_EMU_TAG);$(ANDROID_EMU_ABI)' --force + echo $ANDROID_HOME/emulator/emulator -list-avds + + echo "Starting emulator" + nohup $ANDROID_HOME/emulator/emulator -avd "$(ANDROID_EMU_NAME)" -no-snapshot > /dev/null 2>&1 & + $ANDROID_HOME/platform-tools/adb wait-for-device + while [[ $? -ne 0 ]]; do sleep 1; $ANDROID_HOME/platform-tools/adb shell pm list packages; done; + $ANDROID_HOME/platform-tools/adb devices + echo "Emulator started" + + sudo xcode-select -s /Applications/Xcode_$(XCODE_VERSION).app/Contents/Developer + xcrun simctl list + + npm config delete prefix + npm config set prefix $NVM_DIR/versions/node/`node --version` + node --version + + npm install -g appium@beta + appium --version + + java -version + + - task: Gradle@2 + inputs: + gradleWrapperFile: 'gradlew' + gradleOptions: '-Xmx3072m' + javaHomeOption: 'JDKVersion' + jdkVersionOption: '1.8' + jdkArchitectureOption: 'x64' + publishJUnitResults: true + tasks: 'build' + options: 'xcuiTest uiAutomationTest -x checkstyleTest -x test -x signMavenJavaPublication' diff --git a/src/main/java/io/appium/java_client/android/AndroidStartScreenRecordingOptions.java b/src/main/java/io/appium/java_client/android/AndroidStartScreenRecordingOptions.java index f3c79a508..c8378a86b 100644 --- a/src/main/java/io/appium/java_client/android/AndroidStartScreenRecordingOptions.java +++ b/src/main/java/io/appium/java_client/android/AndroidStartScreenRecordingOptions.java @@ -21,6 +21,7 @@ import com.google.common.collect.ImmutableMap; import io.appium.java_client.screenrecording.BaseStartScreenRecordingOptions; +import io.appium.java_client.screenrecording.ScreenRecordingUploadOptions; import java.time.Duration; import java.util.Map; @@ -49,6 +50,14 @@ public AndroidStartScreenRecordingOptions withBitRate(int bitRate) { this.bitRate = bitRate; return this; } + + /** + * {@inheritDoc} + */ + @Override + public AndroidStartScreenRecordingOptions withUploadOptions(ScreenRecordingUploadOptions uploadOptions) { + return (AndroidStartScreenRecordingOptions) super.withUploadOptions(uploadOptions); + } /** * The video size of the generated media file. The format is WIDTHxHEIGHT. diff --git a/src/main/java/io/appium/java_client/ios/IOSStartScreenRecordingOptions.java b/src/main/java/io/appium/java_client/ios/IOSStartScreenRecordingOptions.java index ff45f7e08..d9b918977 100644 --- a/src/main/java/io/appium/java_client/ios/IOSStartScreenRecordingOptions.java +++ b/src/main/java/io/appium/java_client/ios/IOSStartScreenRecordingOptions.java @@ -22,6 +22,7 @@ import com.google.common.collect.ImmutableMap; import io.appium.java_client.screenrecording.BaseStartScreenRecordingOptions; +import io.appium.java_client.screenrecording.ScreenRecordingUploadOptions; import java.time.Duration; import java.util.Map; @@ -38,6 +39,14 @@ public static IOSStartScreenRecordingOptions startScreenRecordingOptions() { return new IOSStartScreenRecordingOptions(); } + /** + * {@inheritDoc} + */ + @Override + public IOSStartScreenRecordingOptions withUploadOptions(ScreenRecordingUploadOptions uploadOptions) { + return (IOSStartScreenRecordingOptions) super.withUploadOptions(uploadOptions); + } + /** * The video codec type used for encoding of the recorded screen capture. * Execute `ffmpeg -codecs` in the terminal to see the list of supported video codecs. diff --git a/src/main/java/io/appium/java_client/screenrecording/BaseScreenRecordingOptions.java b/src/main/java/io/appium/java_client/screenrecording/BaseScreenRecordingOptions.java index d194e6ab6..127cc29a9 100644 --- a/src/main/java/io/appium/java_client/screenrecording/BaseScreenRecordingOptions.java +++ b/src/main/java/io/appium/java_client/screenrecording/BaseScreenRecordingOptions.java @@ -33,7 +33,7 @@ public abstract class BaseScreenRecordingOptions build() { final ImmutableMap.Builder builder = ImmutableMap.builder(); diff --git a/src/main/java/io/appium/java_client/screenrecording/CanRecordScreen.java b/src/main/java/io/appium/java_client/screenrecording/CanRecordScreen.java index 69c1498e4..551a68bec 100644 --- a/src/main/java/io/appium/java_client/screenrecording/CanRecordScreen.java +++ b/src/main/java/io/appium/java_client/screenrecording/CanRecordScreen.java @@ -31,8 +31,6 @@ public interface CanRecordScreen extends ExecutesMethod { * * @param options see the documentation on the {@link BaseStartScreenRecordingOptions} * descendant for the particular platform. - * @return Base-64 encoded content of the recorded media file or an empty string - * if the file has been successfully uploaded to a remote location (depends on the actual options). */ default String startRecordingScreen(T options) { return CommandExecutionHelper.execute(this, startRecordingScreenCommand(options)); @@ -40,8 +38,6 @@ default String startRecordingScreen( /** * Start asynchronous screen recording process with default options. - * - * @return Base-64 encoded content of the recorded media file. */ default String startRecordingScreen() { return this.execute(START_RECORDING_SCREEN).getValue().toString(); 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 af559f12a..3c8126ac1 100644 --- a/src/main/java/io/appium/java_client/windows/WindowsDriver.java +++ b/src/main/java/io/appium/java_client/windows/WindowsDriver.java @@ -21,6 +21,7 @@ import io.appium.java_client.AppiumDriver; import io.appium.java_client.FindsByWindowsAutomation; import io.appium.java_client.HidesKeyboardWithKeyName; +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.openqa.selenium.Capabilities; @@ -32,7 +33,7 @@ public class WindowsDriver extends AppiumDriver implements PressesKeyCode, HidesKeyboardWithKeyName, - FindsByWindowsAutomation { + FindsByWindowsAutomation, CanRecordScreen { public WindowsDriver(HttpCommandExecutor executor, Capabilities capabilities) { super(executor, updateDefaultPlatformName(capabilities, WINDOWS)); diff --git a/src/main/java/io/appium/java_client/windows/WindowsStartScreenRecordingOptions.java b/src/main/java/io/appium/java_client/windows/WindowsStartScreenRecordingOptions.java new file mode 100644 index 000000000..ff90a08f2 --- /dev/null +++ b/src/main/java/io/appium/java_client/windows/WindowsStartScreenRecordingOptions.java @@ -0,0 +1,151 @@ +/* + * 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; + +import com.google.common.collect.ImmutableMap; +import io.appium.java_client.screenrecording.BaseStartScreenRecordingOptions; + +import java.time.Duration; +import java.util.Map; + +import static java.util.Optional.ofNullable; + +public class WindowsStartScreenRecordingOptions + extends BaseStartScreenRecordingOptions { + private Integer fps; + private String videoFilter; + private String preset; + private Boolean captureCursor; + private Boolean captureClicks; + private String audioInput; + + public static WindowsStartScreenRecordingOptions startScreenRecordingOptions() { + return new WindowsStartScreenRecordingOptions(); + } + + /** + * 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 WindowsStartScreenRecordingOptions 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 WindowsStartScreenRecordingOptions 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 WindowsStartScreenRecordingOptions 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 WindowsStartScreenRecordingOptions 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 WindowsStartScreenRecordingOptions 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 WindowsStartScreenRecordingOptions 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 WindowsStartScreenRecordingOptions withTimeLimit(Duration timeLimit) { + return super.withTimeLimit(timeLimit); + } + + @Override + public Map build() { + final ImmutableMap.Builder builder = ImmutableMap.builder(); + builder.putAll(super.build()); + ofNullable(fps).map(x -> builder.put("fps", x)); + ofNullable(preset).map(x -> builder.put("preset", x)); + ofNullable(videoFilter).map(x -> builder.put("videoFilter", x)); + ofNullable(captureClicks).map(x -> builder.put("captureClicks", x)); + ofNullable(captureCursor).map(x -> builder.put("captureCursor", x)); + ofNullable(audioInput).map(x -> builder.put("audioInput", x)); + return builder.build(); + } +} diff --git a/src/main/java/io/appium/java_client/windows/WindowsStopScreenRecordingOptions.java b/src/main/java/io/appium/java_client/windows/WindowsStopScreenRecordingOptions.java new file mode 100644 index 000000000..206e8c644 --- /dev/null +++ b/src/main/java/io/appium/java_client/windows/WindowsStopScreenRecordingOptions.java @@ -0,0 +1,28 @@ +/* + * 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; + +import io.appium.java_client.screenrecording.BaseStopScreenRecordingOptions; + +public class WindowsStopScreenRecordingOptions extends + BaseStopScreenRecordingOptions { + + public static WindowsStopScreenRecordingOptions stopScreenRecordingOptions() { + return new WindowsStopScreenRecordingOptions(); + } + +} diff --git a/src/test/java/io/appium/java_client/appium/element/generation/BaseElementGenerationTest.java b/src/test/java/io/appium/java_client/appium/element/generation/BaseElementGenerationTest.java index f6d8db2bd..83271f229 100644 --- a/src/test/java/io/appium/java_client/appium/element/generation/BaseElementGenerationTest.java +++ b/src/test/java/io/appium/java_client/appium/element/generation/BaseElementGenerationTest.java @@ -7,14 +7,16 @@ import org.junit.After; import org.openqa.selenium.By; import org.openqa.selenium.Capabilities; +import org.openqa.selenium.SessionNotCreatedException; import org.openqa.selenium.WebElement; +import org.openqa.selenium.remote.DesiredCapabilities; import java.util.function.BiPredicate; import java.util.function.Supplier; public class BaseElementGenerationTest { protected AppiumDriver driver; - private AppiumDriverLocalService service; + protected AppiumDriverLocalService service; protected final BiPredicate> commonPredicate = (by, aClass) -> { WebElement element = driver.findElement(by); @@ -37,12 +39,4 @@ public void tearDown() { } } - protected boolean check(Supplier capabilitiesSupplier, - BiPredicate> filter, - By by, Class clazz) { - service = AppiumDriverLocalService.buildDefaultService(); - driver = new AppiumDriver<>(service, capabilitiesSupplier.get()); - return filter.test(by, clazz); - } - } diff --git a/src/test/java/io/appium/java_client/appium/element/generation/android/AndroidElementGeneratingTest.java b/src/test/java/io/appium/java_client/appium/element/generation/android/AndroidElementGeneratingTest.java index 992cb43cf..9e139e2cd 100644 --- a/src/test/java/io/appium/java_client/appium/element/generation/android/AndroidElementGeneratingTest.java +++ b/src/test/java/io/appium/java_client/appium/element/generation/android/AndroidElementGeneratingTest.java @@ -5,16 +5,22 @@ import static org.openqa.selenium.By.name; import static org.openqa.selenium.By.tagName; +import io.appium.java_client.AppiumDriver; import io.appium.java_client.android.AndroidElement; import io.appium.java_client.appium.element.generation.BaseElementGenerationTest; import io.appium.java_client.remote.AndroidMobileCapabilityType; import io.appium.java_client.remote.MobileBrowserType; import io.appium.java_client.remote.MobileCapabilityType; import io.appium.java_client.remote.MobilePlatform; +import io.appium.java_client.service.local.AppiumDriverLocalService; import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.Capabilities; +import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.DesiredCapabilities; import java.io.File; +import java.util.function.BiPredicate; import java.util.function.Supplier; public class AndroidElementGeneratingTest extends BaseElementGenerationTest { @@ -36,8 +42,8 @@ public void whenAndroidNativeAppIsLaunched() { clientCapabilities.setCapability(MobileCapabilityType.FULL_RESET, true); clientCapabilities.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, 60); return clientCapabilities; - }, commonPredicate, AndroidUIAutomator("new UiSelector().clickable(true)"), - AndroidElement.class)); + }, commonPredicate, AndroidUIAutomator("new UiSelector().clickable(true)") + )); } @Test @@ -50,7 +56,7 @@ public void whenAndroidHybridAppIsLaunched() { }, (by, aClass) -> { driver.context("WEBVIEW_io.appium.android.apis"); return commonPredicate.test(by, aClass); - }, tagName("a"), AndroidElement.class)); + }, tagName("a"))); } @Test @@ -64,8 +70,14 @@ public void whenAndroidBrowserIsLaunched() { }, (by, aClass) -> { driver.get("https://www.google.com"); return commonPredicate.test(by, aClass); - }, name("q"), AndroidElement.class)); + }, name("q"))); } - + private boolean check(Supplier capabilitiesSupplier, + BiPredicate> filter, + By by) { + service = AppiumDriverLocalService.buildDefaultService(); + driver = new AppiumDriver<>(service, capabilitiesSupplier.get()); + return filter.test(by, AndroidElement.class); + } } diff --git a/src/test/java/io/appium/java_client/appium/element/generation/ios/IOSElementGenerationTest.java b/src/test/java/io/appium/java_client/appium/element/generation/ios/IOSElementGenerationTest.java index 0b7572be3..19f1fd32b 100644 --- a/src/test/java/io/appium/java_client/appium/element/generation/ios/IOSElementGenerationTest.java +++ b/src/test/java/io/appium/java_client/appium/element/generation/ios/IOSElementGenerationTest.java @@ -6,6 +6,7 @@ import static org.openqa.selenium.By.name; import static org.openqa.selenium.By.partialLinkText; +import io.appium.java_client.AppiumDriver; import io.appium.java_client.appium.element.generation.BaseElementGenerationTest; import io.appium.java_client.ios.BaseIOSTest; import io.appium.java_client.ios.IOSElement; @@ -13,14 +14,19 @@ import io.appium.java_client.remote.MobileBrowserType; import io.appium.java_client.remote.MobileCapabilityType; import io.appium.java_client.remote.MobilePlatform; +import io.appium.java_client.service.local.AppiumDriverLocalService; import org.junit.Ignore; import org.junit.Test; +import org.openqa.selenium.By; import org.openqa.selenium.Capabilities; +import org.openqa.selenium.SessionNotCreatedException; +import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import java.io.File; +import java.util.function.BiPredicate; import java.util.function.Function; import java.util.function.Supplier; @@ -73,8 +79,8 @@ public void whenIOSNativeAppIsLaunched() { Capabilities caps = commonAppCapabilitiesSupplier.get(); return caps.merge(appFileSupplierFunction.apply(testApp).get()); }, commonPredicate, - AccessibilityId("Answer"), - IOSElement.class)); + AccessibilityId("Answer") + )); } @Ignore @@ -102,7 +108,7 @@ public void whenIOSHybridAppIsLaunched() { } }); return commonPredicate.test(by, aClass); - }, partialLinkText("login"), IOSElement.class)); + }, partialLinkText("login"))); } @Test @@ -113,7 +119,7 @@ public void whenIOSBrowserIsLaunched() { }, (by, aClass) -> { driver.get("https://www.google.com"); return commonPredicate.test(by, aClass); - }, name("q"), IOSElement.class)); + }, name("q"))); } @Test @@ -123,7 +129,7 @@ public void whenIOSNativeAppIsLaunched2() { serverCapabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, BaseIOSTest.PLATFORM_VERSION); serverCapabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, MobilePlatform.IOS); return serverCapabilities.merge(appFileSupplierFunction.apply(testApp).get()); - }, commonPredicate, id("IntegerA"), IOSElement.class)); + }, commonPredicate, id("IntegerA"))); } @Test @@ -136,6 +142,22 @@ public void whenIOSBrowserIsLaunched2() { }, (by, aClass) -> { driver.get("https://www.google.com"); return commonPredicate.test(by, aClass); - }, name("q"), IOSElement.class)); + }, name("q"))); + } + + private boolean check(Supplier capabilitiesSupplier, + BiPredicate> filter, + By by) { + service = AppiumDriverLocalService.buildDefaultService(); + Capabilities caps = capabilitiesSupplier.get(); + DesiredCapabilities fixedCaps = new DesiredCapabilities(caps); + fixedCaps.setCapability("commandTimeouts", "120000"); + try { + driver = new AppiumDriver<>(service, fixedCaps); + } catch (SessionNotCreatedException e) { + fixedCaps.setCapability("useNewWDA", true); + driver = new AppiumDriver<>(service, fixedCaps); + } + return filter.test(by, IOSElement.class); } } diff --git a/src/test/java/io/appium/java_client/ios/AppIOSTest.java b/src/test/java/io/appium/java_client/ios/AppIOSTest.java index b4b47247c..e41e325a6 100644 --- a/src/test/java/io/appium/java_client/ios/AppIOSTest.java +++ b/src/test/java/io/appium/java_client/ios/AppIOSTest.java @@ -5,6 +5,7 @@ import io.appium.java_client.remote.MobileCapabilityType; import io.appium.java_client.service.local.AppiumServerHasNotBeenStartedLocallyException; import org.junit.BeforeClass; +import org.openqa.selenium.SessionNotCreatedException; import org.openqa.selenium.remote.DesiredCapabilities; import java.io.File; @@ -30,7 +31,13 @@ public static void beforeClass() throws Exception { capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, AutomationName.IOS_XCUI_TEST); //sometimes environment has performance problems capabilities.setCapability(IOSMobileCapabilityType.LAUNCH_TIMEOUT, 500000); + capabilities.setCapability("commandTimeouts", "120000"); capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath()); - driver = new IOSDriver<>(new URL("http://" + ip + ":" + PORT + "/wd/hub"), capabilities); + try { + driver = new IOSDriver<>(new URL("http://" + ip + ":" + PORT + "/wd/hub"), capabilities); + } catch (SessionNotCreatedException e) { + capabilities.setCapability("useNewWDA", true); + driver = new IOSDriver<>(new URL("http://" + ip + ":" + PORT + "/wd/hub"), capabilities); + } } } diff --git a/src/test/java/io/appium/java_client/ios/BaseIOSWebViewTest.java b/src/test/java/io/appium/java_client/ios/BaseIOSWebViewTest.java index ce0b115a5..647718603 100644 --- a/src/test/java/io/appium/java_client/ios/BaseIOSWebViewTest.java +++ b/src/test/java/io/appium/java_client/ios/BaseIOSWebViewTest.java @@ -20,12 +20,15 @@ import io.appium.java_client.remote.MobileCapabilityType; import io.appium.java_client.service.local.AppiumServerHasNotBeenStartedLocallyException; import org.junit.BeforeClass; +import org.openqa.selenium.SessionNotCreatedException; import org.openqa.selenium.remote.DesiredCapabilities; import java.io.File; import java.io.IOException; +import java.net.MalformedURLException; import java.net.URL; import java.time.Duration; +import java.util.function.Supplier; public class BaseIOSWebViewTest extends BaseIOSTest { private static final Duration WEB_VIEW_DETECT_INTERVAL = Duration.ofSeconds(1); @@ -41,13 +44,28 @@ public static void beforeClass() throws IOException { File appDir = new File("src/test/java/io/appium/java_client"); File app = new File(appDir, "vodqa.zip"); - DesiredCapabilities capabilities = new DesiredCapabilities(); + final DesiredCapabilities capabilities = new DesiredCapabilities(); capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, PLATFORM_VERSION); //sometimes environment has performance problems capabilities.setCapability(IOSMobileCapabilityType.LAUNCH_TIMEOUT, 500000); capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, DEVICE_NAME); + capabilities.setCapability("commandTimeouts", "120000"); capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath()); - driver = new IOSDriver<>(new URL("http://" + ip + ":" + PORT + "/wd/hub"), capabilities); + Supplier> createDriver = () -> { + try { + return new IOSDriver<>(new URL("http://" + ip + ":" + PORT + "/wd/hub"), capabilities); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + }; + try { + driver = createDriver.get(); + } catch (SessionNotCreatedException e) { + // Sometimes WDA session creation freezes unexpectedly on CI: + // https://dev.azure.com/srinivasansekar/java-client/_build/results?buildId=356&view=ms.vss-test-web.build-test-results-tab + capabilities.setCapability("useNewWDA", true); + driver = createDriver.get(); + } } protected void findAndSwitchToWebView() throws InterruptedException {