-
-
Notifications
You must be signed in to change notification settings - Fork 766
feat: add support for FlutterAndroidDriver #2203
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2f2d77b
980cca0
d68dc13
ccb7110
61cb9e6
4346896
cffadc9
5d03cbc
9c3b659
fb6ce55
bc30965
0ab722c
9ec42c7
dbe13a4
aaf96ef
7d7aa6f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package io.appium.java_client.android; | ||
|
||
import io.appium.java_client.AppiumBy; | ||
import io.appium.java_client.android.options.UiAutomator2Options; | ||
import io.appium.java_client.flutter.android.FlutterAndroidDriver; | ||
import io.appium.java_client.flutter.commands.ScrollParameter; | ||
import io.appium.java_client.remote.AutomationName; | ||
import io.appium.java_client.service.local.AppiumDriverLocalService; | ||
import io.appium.java_client.service.local.AppiumServiceBuilder; | ||
import org.junit.jupiter.api.AfterAll; | ||
import org.junit.jupiter.api.AfterEach; | ||
import org.junit.jupiter.api.BeforeAll; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.openqa.selenium.By; | ||
import org.openqa.selenium.InvalidArgumentException; | ||
import org.openqa.selenium.WebElement; | ||
|
||
import java.net.MalformedURLException; | ||
import java.util.Optional; | ||
|
||
class BaseFlutterTest { | ||
|
||
private static final boolean IS_ANDROID = Optional | ||
.ofNullable(System.getProperty("platform")) | ||
.orElse("android") | ||
.equalsIgnoreCase("android"); | ||
private static final String APP_ID = IS_ANDROID | ||
? "com.example.appium_testing_app" : "com.example.appiumTestingApp"; | ||
protected static final int PORT = 4723; | ||
|
||
private static AppiumDriverLocalService service; | ||
protected static FlutterAndroidDriver driver; | ||
protected static final By LOGIN_BUTTON = AppiumBy.flutterText("Login"); | ||
|
||
/** | ||
* initialization. | ||
*/ | ||
@BeforeAll | ||
public static void beforeClass() { | ||
service = new AppiumServiceBuilder() | ||
.withIPAddress("127.0.0.1") | ||
.usingPort(PORT) | ||
.build(); | ||
service.start(); | ||
} | ||
|
||
@BeforeEach | ||
public void startSession() throws MalformedURLException { | ||
if (IS_ANDROID) { | ||
// TODO: update it with FlutterDriverOptions once implemented | ||
UiAutomator2Options options = new UiAutomator2Options() | ||
.setAutomationName(AutomationName.FLUTTER_INTEGRATION) | ||
.setApp(System.getProperty("flutterApp")) | ||
.eventTimings(); | ||
driver = new FlutterAndroidDriver(service.getUrl(), options); | ||
} else { | ||
throw new InvalidArgumentException( | ||
"Currently flutter driver implementation only supports android platform"); | ||
} | ||
} | ||
|
||
@AfterEach | ||
public void stopSession() { | ||
if (driver != null) { | ||
driver.quit(); | ||
} | ||
} | ||
|
||
@AfterAll | ||
public static void afterClass() { | ||
if (service.isRunning()) { | ||
service.stop(); | ||
} | ||
} | ||
|
||
public void openScreen(String screenTitle) { | ||
ScrollParameter scrollOptions = new ScrollParameter( | ||
AppiumBy.flutterText(screenTitle), ScrollParameter.ScrollDirection.DOWN); | ||
WebElement element = driver.scrollTillVisible(scrollOptions); | ||
element.click(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package io.appium.java_client.android; | ||
|
||
import io.appium.java_client.AppiumBy; | ||
import io.appium.java_client.flutter.commands.ScrollParameter; | ||
import io.appium.java_client.flutter.commands.WaitParameter; | ||
import org.junit.jupiter.api.Test; | ||
import org.openqa.selenium.WebElement; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertFalse; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
||
class CommandTest extends BaseFlutterTest { | ||
|
||
private static final AppiumBy.FlutterBy MESSAGE_FIELD = AppiumBy.flutterKey("message_field"); | ||
private static final AppiumBy.FlutterBy TOGGLE_BUTTON = AppiumBy.flutterKey("toggle_button"); | ||
|
||
@Test | ||
public void testWaitCommand() { | ||
WebElement loginButton = driver.findElement(BaseFlutterTest.LOGIN_BUTTON); | ||
loginButton.click(); | ||
openScreen("Lazy Loading"); | ||
|
||
WebElement messageField = driver.findElement(MESSAGE_FIELD); | ||
WebElement toggleButton = driver.findElement(TOGGLE_BUTTON); | ||
|
||
assertEquals(messageField.getText(), "Hello world"); | ||
toggleButton.click(); | ||
assertEquals(messageField.getText(), "Hello world"); | ||
|
||
WaitParameter waitParameter = new WaitParameter().setLocator(MESSAGE_FIELD); | ||
|
||
driver.waitForInVisible(waitParameter); | ||
assertEquals(0, driver.findElements(MESSAGE_FIELD).size()); | ||
toggleButton.click(); | ||
driver.waitForVisible(waitParameter); | ||
assertEquals(1, driver.findElements(MESSAGE_FIELD).size()); | ||
assertEquals(messageField.getText(), "Hello world"); | ||
} | ||
|
||
@Test | ||
public void testScrollTillVisibleCommand() { | ||
WebElement loginButton = driver.findElement(BaseFlutterTest.LOGIN_BUTTON); | ||
loginButton.click(); | ||
openScreen("Vertical Swiping"); | ||
|
||
WebElement firstElement = driver.scrollTillVisible(new ScrollParameter(AppiumBy.flutterText("Java"))); | ||
assertTrue(Boolean.parseBoolean(firstElement.getAttribute("displayed"))); | ||
|
||
WebElement lastElement = driver.scrollTillVisible(new ScrollParameter(AppiumBy.flutterText("Protractor"))); | ||
assertTrue(Boolean.parseBoolean(lastElement.getAttribute("displayed"))); | ||
assertFalse(Boolean.parseBoolean(firstElement.getAttribute("displayed"))); | ||
|
||
firstElement = driver.scrollTillVisible( | ||
new ScrollParameter(AppiumBy.flutterText("Java"), | ||
ScrollParameter.ScrollDirection.UP) | ||
); | ||
assertTrue(Boolean.parseBoolean(firstElement.getAttribute("displayed"))); | ||
assertFalse(Boolean.parseBoolean(lastElement.getAttribute("displayed"))); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package io.appium.java_client.android; | ||
|
||
import io.appium.java_client.AppiumBy; | ||
import org.junit.jupiter.api.Test; | ||
import org.openqa.selenium.WebElement; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
||
|
||
class FinderTests extends BaseFlutterTest { | ||
|
||
@Test | ||
public void testFlutterByKey() { | ||
WebElement userNameField = driver.findElement(AppiumBy.flutterKey("username_text_field")); | ||
assertEquals("admin", userNameField.getText()); | ||
userNameField.clear(); | ||
driver.findElement(AppiumBy.flutterKey("username_text_field")).sendKeys("admin123"); | ||
assertEquals("admin123", userNameField.getText()); | ||
} | ||
|
||
@Test | ||
public void testFlutterByType() { | ||
WebElement loginButton = driver.findElement(AppiumBy.flutterType("ElevatedButton")); | ||
assertEquals(loginButton.findElement(AppiumBy.flutterType("Text")).getText(), "Login"); | ||
} | ||
|
||
@Test | ||
public void testFlutterText() { | ||
WebElement loginButton = driver.findElement(AppiumBy.flutterText("Login")); | ||
assertEquals(loginButton.getText(), "Login"); | ||
loginButton.click(); | ||
|
||
assertEquals(1, driver.findElements(AppiumBy.flutterText("Slider")).size()); | ||
} | ||
|
||
@Test | ||
public void testFlutterTextContaining() { | ||
WebElement loginButton = driver.findElement(BaseFlutterTest.LOGIN_BUTTON); | ||
loginButton.click(); | ||
assertEquals(driver.findElement(AppiumBy.flutterTextContaining("Vertical")).getText(), | ||
"Vertical Swiping"); | ||
} | ||
|
||
@Test | ||
public void testFlutterSemanticsLabel() { | ||
WebElement loginButton = driver.findElement(BaseFlutterTest.LOGIN_BUTTON); | ||
loginButton.click(); | ||
openScreen("Lazy Loading"); | ||
|
||
WebElement messageField = driver.findElement(AppiumBy.flutterSemanticsLabel("message_field")); | ||
assertEquals(messageField.getText(), | ||
"Hello world"); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -206,7 +206,7 @@ public static By iOSNsPredicateString(final String iOSNsPredicateString) { | |
* @param selector is the value defined to the key attribute of the flutter element | ||
* @return an instance of {@link AppiumBy.ByFlutterKey} | ||
*/ | ||
public static By flutterKey(final String selector) { | ||
public static FlutterBy flutterKey(final String selector) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why are these changes needed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Currenlty all flutter script can only work with locators supported by flutter driver. This change is specifically introduced the simplify the API consumption and to prevent the manual type casting when calling the commands. driver.waitForInVisible(new WaitParameter().setLocator(AppiumBy.flutterKey("message_field"))); Instead of driver.waitForInVisible(new WaitParameter().setLocator((AppiumBy.FlutterBy)AppiumBy.flutterKey("message_field"))); |
||
return new ByFlutterKey(selector); | ||
} | ||
|
||
|
@@ -216,7 +216,7 @@ public static By flutterKey(final String selector) { | |
* @param selector is the Type of widget mounted in the app tree | ||
* @return an instance of {@link AppiumBy.ByFlutterType} | ||
*/ | ||
public static By flutterType(final String selector) { | ||
public static FlutterBy flutterType(final String selector) { | ||
return new ByFlutterType(selector); | ||
} | ||
|
||
|
@@ -226,7 +226,7 @@ public static By flutterType(final String selector) { | |
* @param selector is the text that is present on the widget | ||
* @return an instance of {@link AppiumBy.ByFlutterText} | ||
*/ | ||
public static By flutterText(final String selector) { | ||
public static FlutterBy flutterText(final String selector) { | ||
return new ByFlutterText(selector); | ||
} | ||
|
||
|
@@ -236,7 +236,7 @@ public static By flutterText(final String selector) { | |
* @param selector is the text that is partially present on the widget | ||
* @return an instance of {@link AppiumBy.ByFlutterTextContaining} | ||
*/ | ||
public static By flutterTextContaining(final String selector) { | ||
public static FlutterBy flutterTextContaining(final String selector) { | ||
return new ByFlutterTextContaining(selector); | ||
} | ||
|
||
|
@@ -246,7 +246,7 @@ public static By flutterTextContaining(final String selector) { | |
* @param semanticsLabel represents the value assigned to the label attribute of semantics element | ||
* @return an instance of {@link AppiumBy.ByFlutterSemanticsLabel} | ||
*/ | ||
public static By flutterSemanticsLabel(final String semanticsLabel) { | ||
public static FlutterBy flutterSemanticsLabel(final String semanticsLabel) { | ||
return new ByFlutterSemanticsLabel(semanticsLabel); | ||
} | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.