diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 9955fa6..df0ab23 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -2,7 +2,7 @@ trigger:
- master
pool:
- vmImage: 'macOS-latest'
+ vmImage: 'macOS-14'
jobs:
- job: sonar
@@ -44,6 +44,7 @@ jobs:
pollingTimeoutSec: '300'
- job: tests
+ timeoutInMinutes: 60
displayName: Run tests
strategy:
maxParallel: 2
@@ -55,11 +56,12 @@ jobs:
variables:
ANDROID_EMU_NAME: test
- ANDROID_SDK_ID: system-images;android-30;google_apis_playstore;x86_64
+ ANDROID_SDK_ID: system-images;android-29;google_apis_playstore;x86_64
steps:
- task: CmdLine@2
displayName: 'Configure Appium and Android SDK'
+ timeoutInMinutes: 15
inputs:
script: |
echo "Configuring Environment"
diff --git a/pom.xml b/pom.xml
index b873f89..f676780 100644
--- a/pom.xml
+++ b/pom.xml
@@ -184,7 +184,7 @@
com.github.aquality-automation
aquality-selenium-core
- 4.8.0
+ 4.9.0
diff --git a/src/main/java/aquality/appium/mobile/application/IMobileApplication.java b/src/main/java/aquality/appium/mobile/application/IMobileApplication.java
index b5f3eef..c3a3500 100644
--- a/src/main/java/aquality/appium/mobile/application/IMobileApplication.java
+++ b/src/main/java/aquality/appium/mobile/application/IMobileApplication.java
@@ -14,6 +14,7 @@
public interface IMobileApplication extends IApplication {
/**
* Provides default timeout for terminate methods.
+ *
* @return default timeout for waiting until the application is terminated.
*/
static Duration getDefaultTerminateTimeout() {
@@ -67,15 +68,19 @@ default InteractsWithApps appManagement() {
/**
* Execute application script
+ *
* @param script script
* @param params parameters
+ * @param type of the result
* @return result of the script execution.
*/
T executeScript(String script, Map params);
/**
* Execute application script
+ *
* @param script script
+ * @param type of the result
* @return result of the script execution.
*/
default T executeScript(String script) {
diff --git a/src/main/java/aquality/appium/mobile/screens/IScreen.java b/src/main/java/aquality/appium/mobile/screens/IScreen.java
index 08da550..ffdad63 100644
--- a/src/main/java/aquality/appium/mobile/screens/IScreen.java
+++ b/src/main/java/aquality/appium/mobile/screens/IScreen.java
@@ -13,16 +13,22 @@
public interface IScreen extends IForm {
/**
* Locator for specified screen
+ *
+ * @return locator
*/
By getLocator();
/**
* Name of specified screen
+ *
+ * @return name
*/
String getName();
/**
* Size of the element described by screen locator.
+ *
+ * @return size
*/
Dimension getSize();
diff --git a/src/main/java/aquality/appium/mobile/screens/Screen.java b/src/main/java/aquality/appium/mobile/screens/Screen.java
index 66466e1..3f6a1c6 100644
--- a/src/main/java/aquality/appium/mobile/screens/Screen.java
+++ b/src/main/java/aquality/appium/mobile/screens/Screen.java
@@ -30,6 +30,9 @@ public abstract class Screen extends Form implements IScreen {
/**
* Constructor with parameters
+ *
+ * @param locator Locator of the screen
+ * @param name Name of the screen
*/
protected Screen(By locator, String name) {
super(IElement.class);
@@ -50,7 +53,7 @@ public String getName() {
@Override
public Dimension getSize() {
- return screenElement.visual().getSize();
+ return screenElement.visual().getSize();
}
@Override
@@ -68,7 +71,7 @@ protected IElement getScreenElement() {
return screenElement;
}
- protected IElementFactory getElementFactory(){
+ protected IElementFactory getElementFactory() {
return AqualityServices.getElementFactory();
}
diff --git a/src/main/java/aquality/appium/mobile/screens/screenfactory/IScreenFactory.java b/src/main/java/aquality/appium/mobile/screens/screenfactory/IScreenFactory.java
index 63c69cc..165f9cf 100644
--- a/src/main/java/aquality/appium/mobile/screens/screenfactory/IScreenFactory.java
+++ b/src/main/java/aquality/appium/mobile/screens/screenfactory/IScreenFactory.java
@@ -9,7 +9,10 @@ public interface IScreenFactory {
/**
* Returns an implementation of a particular app screen.
- * @param Type of desired application screen.
+ *
+ * @param Type of desired application screen.
+ * @param clazz Class of desired application screen.
+ * @return Instance of desired application screen.
*/
T getScreen(Class clazz);
}
diff --git a/src/test/java/samples/android/nativeapp/apidemos/ApplicationActivity.java b/src/test/java/samples/android/nativeapp/apidemos/ApplicationActivity.java
index 9b2f289..907dd48 100644
--- a/src/test/java/samples/android/nativeapp/apidemos/ApplicationActivity.java
+++ b/src/test/java/samples/android/nativeapp/apidemos/ApplicationActivity.java
@@ -1,16 +1,16 @@
package samples.android.nativeapp.apidemos;
import aquality.appium.mobile.application.AqualityServices;
+import aquality.appium.mobile.elements.interfaces.IButton;
import aquality.appium.mobile.screens.Screen;
+import aquality.selenium.core.configurations.ITimeoutConfiguration;
import io.appium.java_client.android.Activity;
import org.openqa.selenium.By;
-import samples.android.nativeapp.apidemos.screens.AlertsMenuScreen;
-import samples.android.nativeapp.apidemos.screens.AndroidScreen;
-import samples.android.nativeapp.apidemos.screens.InvokeSearchScreen;
-import samples.android.nativeapp.apidemos.screens.ViewControlsScreen;
-import samples.android.nativeapp.apidemos.screens.ViewTabsScrollableScreen;
+import org.openqa.selenium.WebDriverException;
+import samples.android.nativeapp.apidemos.screens.*;
import java.lang.reflect.InvocationTargetException;
+import java.util.Collections;
public enum ApplicationActivity {
@@ -38,7 +38,8 @@ public T open() {
public T getScreen() {
try {
return (T) screen.getDeclaredConstructor().newInstance();
- } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
+ } catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
+ InvocationTargetException e) {
AqualityServices.getLogger().debug(e.getMessage());
throw new IllegalArgumentException("Something went wrong during screen getting");
}
@@ -46,6 +47,8 @@ public T getScreen() {
private static class ActivityScreen extends AndroidScreen {
private final Activity activity;
+ private final IButton btnWait = getElementFactory().getButton(By.id("android:id/aerr_wait"), "Wait");
+ private final IButton btnCloseApp = getElementFactory().getButton(By.id("android:id/aerr_close"), "Close app");
ActivityScreen(Activity activity) {
super(By.name(activity.getAppActivity()), activity.getAppActivity());
@@ -54,6 +57,21 @@ private static class ActivityScreen extends AndroidScreen {
void open() {
startActivity(activity);
+ // workaround to handle System UI isn't responding dialog
+ ITimeoutConfiguration timeoutConfiguration = AqualityServices.getConfiguration().getTimeoutConfiguration();
+ boolean result = AqualityServices.getConditionalWait().waitFor(() ->
+ {
+ if (!btnWait.state().waitForDisplayed()) {
+ return true;
+ }
+ btnWait.click();
+ return btnWait.state().waitForNotDisplayed();
+ }, timeoutConfiguration.getCommand(),
+ timeoutConfiguration.getCondition(),
+ Collections.singletonList(WebDriverException.class));
+ if (!result) {
+ btnCloseApp.click();
+ }
}
}
}
diff --git a/src/test/java/samples/android/web/WebTextBoxTest.java b/src/test/java/samples/android/web/WebTextBoxTest.java
index 7a0c215..c031f5b 100644
--- a/src/test/java/samples/android/web/WebTextBoxTest.java
+++ b/src/test/java/samples/android/web/WebTextBoxTest.java
@@ -1,7 +1,9 @@
package samples.android.web;
import aquality.appium.mobile.application.AqualityServices;
+import aquality.appium.mobile.elements.interfaces.IButton;
import aquality.appium.mobile.elements.interfaces.ITextBox;
+import aquality.selenium.core.configurations.ITimeoutConfiguration;
import io.appium.java_client.android.AndroidDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
@@ -11,18 +13,24 @@
public class WebTextBoxTest extends AndroidWebTest {
private static final String VALUE_TO_SUBMIT = "quality assurance";
+ private static final ITextBox txbSearch = AqualityServices.getElementFactory().getTextBox(By.id("searchInput"), "Search");
+ private static final IButton btnOverlayToggle = AqualityServices.getElementFactory().getButton(By.className("button-collapse"), "Toggle Overlay");
+ private static final IButton btnCloseBanner = AqualityServices.getElementFactory().getButton(By.className("overlay-banner-close"), "Close banner");
@Test
public void testTextBoxInteraction() {
AqualityServices.getApplication().getDriver().get("https://wikipedia.org");
- ITextBox txbSearch = AqualityServices.getElementFactory().getTextBox(By.id("searchInput"), "Search");
txbSearch.state().waitForClickable();
+ if (btnOverlayToggle.state().isDisplayed()) {
+ btnOverlayToggle.click();
+ btnCloseBanner.click();
+ }
txbSearch.type(VALUE_TO_SUBMIT);
Assert.assertEquals(VALUE_TO_SUBMIT, txbSearch.getValue(), "Submitted value should match to expected");
txbSearch.clear();
Assert.assertEquals("", txbSearch.getValue(), "Value should be cleared");
txbSearch.click();
- checkUnfocus(txbSearch);
+ checkUnfocus();
txbSearch.focus();
Assert.assertTrue(isKeyboardShown(true), "Keyboard should be shown when focus successful");
txbSearch.typeSecret(VALUE_TO_SUBMIT);
@@ -35,17 +43,17 @@ public void testTextBoxInteraction() {
Assert.assertTrue(txbSearch.state().waitForNotDisplayed(), "text field should disappear after the submit");
}
- private void checkUnfocus(ITextBox txbSearch) {
+ private void checkUnfocus() {
txbSearch.unfocus();
Assert.assertFalse(isKeyboardShown(false), "Keyboard should not be shown when unfocus successful");
}
- @SuppressWarnings("unchecked")
private boolean isKeyboardShown(boolean expectedStateToWait) {
+ ITimeoutConfiguration timeoutConfiguration = AqualityServices.getConfiguration().getTimeoutConfiguration();
boolean waitResult = AqualityServices.getConditionalWait()
- .waitFor(driver -> ((AndroidDriver)driver).isKeyboardShown() == expectedStateToWait,
- AqualityServices.getConfiguration().getTimeoutConfiguration().getCommand(),
- AqualityServices.getConfiguration().getTimeoutConfiguration().getPollingInterval().multipliedBy(10),
+ .waitFor(driver -> ((AndroidDriver) driver).isKeyboardShown() == expectedStateToWait,
+ timeoutConfiguration.getCommand(),
+ timeoutConfiguration.getPollingInterval().multipliedBy(10),
String.format("is keyboard shown condition should be %s", expectedStateToWait));
return expectedStateToWait == waitResult;
}
diff --git a/src/test/resources/settings.json b/src/test/resources/settings.json
index bc76c3b..3c4de1a 100644
--- a/src/test/resources/settings.json
+++ b/src/test/resources/settings.json
@@ -11,7 +11,8 @@
"platformName": "Android",
"automationName": "UIAutomator2",
"eventTimings": true,
- "uiautomator2ServerInstallTimeout": 30000
+ "uiautomator2ServerInstallTimeout": 30000,
+ "uiautomator2ServerLaunchTimeout": 60000
}
},
"ios": {