├── src ├── main │ └── java │ │ └── io │ │ └── github │ │ └── ashwith │ │ └── flutter │ │ ├── finders │ │ ├── PageBack.java │ │ ├── ByText.java │ │ ├── ByType.java │ │ ├── ByToolTip.java │ │ ├── ByValueKey.java │ │ ├── ByAncestor.java │ │ ├── ByDescendant.java │ │ └── BySemanticsLabel.java │ │ ├── FlutterElement.java │ │ └── FlutterFinder.java └── test │ └── java │ └── io │ └── github │ └── ashwith │ └── flutter │ └── example │ └── FlutterFinderExampleTest.java ├── .github └── workflows │ ├── mavenbuild.yml │ ├── maven-publish.yml │ └── github-release.yml ├── .gitignore ├── LICENSE ├── README.md └── pom.xml /src/main/java/io/github/ashwith/flutter/finders/PageBack.java: -------------------------------------------------------------------------------- 1 | package io.github.ashwith.flutter.finders; 2 | 3 | import io.github.ashwith.flutter.FlutterElement; 4 | 5 | /** 6 | * To navigate back to previous page 7 | * 8 | * @author ashwith 9 | * @version 1.0.0 10 | */ 11 | public interface PageBack { 12 | 13 | FlutterElement pageBack(); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/io/github/ashwith/flutter/finders/ByText.java: -------------------------------------------------------------------------------- 1 | package io.github.ashwith.flutter.finders; 2 | 3 | import io.github.ashwith.flutter.FlutterElement; 4 | 5 | /** 6 | * To identify the element using Text 7 | * 8 | * @author ashwith 9 | * @version 1.0.0 10 | */ 11 | public interface ByText { 12 | 13 | FlutterElement byText(String input); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/io/github/ashwith/flutter/finders/ByType.java: -------------------------------------------------------------------------------- 1 | package io.github.ashwith.flutter.finders; 2 | 3 | import io.github.ashwith.flutter.FlutterElement; 4 | 5 | /** 6 | * To identify the element using Type 7 | * 8 | * @author ashwith 9 | * @version 1.0.0 10 | */ 11 | public interface ByType { 12 | 13 | FlutterElement byType(String type); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/io/github/ashwith/flutter/finders/ByToolTip.java: -------------------------------------------------------------------------------- 1 | package io.github.ashwith.flutter.finders; 2 | 3 | import io.github.ashwith.flutter.FlutterElement; 4 | 5 | /** 6 | * To identify the element using ToolTip 7 | * 8 | * @author ashwith 9 | * @version 1.0.0 10 | */ 11 | public interface ByToolTip { 12 | 13 | FlutterElement byToolTip(String toolTipText); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/io/github/ashwith/flutter/finders/ByValueKey.java: -------------------------------------------------------------------------------- 1 | package io.github.ashwith.flutter.finders; 2 | 3 | import io.github.ashwith.flutter.FlutterElement; 4 | 5 | /** 6 | * To identify the element using Value key 7 | * 8 | * @author ashwith 9 | * @version 1.0.0 10 | */ 11 | public interface ByValueKey { 12 | 13 | 14 | FlutterElement byValueKey(String key); 15 | 16 | FlutterElement byValueKey(int key); 17 | } -------------------------------------------------------------------------------- /.github/workflows/mavenbuild.yml: -------------------------------------------------------------------------------- 1 | name: Java CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v3 11 | - name: Set up JDK 17 12 | uses: actions/setup-java@v3 13 | with: 14 | java-version: '17' 15 | distribution: 'temurin' 16 | - name: Build with Maven 17 | run: mvn --batch-mode --update-snapshots package -------------------------------------------------------------------------------- /src/main/java/io/github/ashwith/flutter/finders/ByAncestor.java: -------------------------------------------------------------------------------- 1 | package io.github.ashwith.flutter.finders; 2 | 3 | import io.github.ashwith.flutter.FlutterElement; 4 | 5 | /** 6 | * To identify the element using Ancestor 7 | * 8 | * @author ashwith 9 | * @version 1.0.0 10 | */ 11 | public interface ByAncestor { 12 | 13 | FlutterElement byAncestor(FlutterElement of, FlutterElement matching, boolean matchRoot, boolean firstMatchOnly); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/io/github/ashwith/flutter/finders/ByDescendant.java: -------------------------------------------------------------------------------- 1 | package io.github.ashwith.flutter.finders; 2 | 3 | import io.github.ashwith.flutter.FlutterElement; 4 | 5 | /** 6 | * To identify the element using Descendant 7 | * 8 | * @author ashwith 9 | * @version 1.0.0 10 | */ 11 | public interface ByDescendant { 12 | 13 | FlutterElement byDescendant(FlutterElement of, FlutterElement matching, boolean matchRoot, boolean firstMatchOnly); 14 | 15 | } -------------------------------------------------------------------------------- /src/main/java/io/github/ashwith/flutter/finders/BySemanticsLabel.java: -------------------------------------------------------------------------------- 1 | package io.github.ashwith.flutter.finders; 2 | 3 | import io.github.ashwith.flutter.FlutterElement; 4 | 5 | import java.util.regex.Pattern; 6 | 7 | /** 8 | * To identify the element using SemanticsLabel 9 | * @author ashwith 10 | * @version 1.0.0 11 | */ 12 | public interface BySemanticsLabel { 13 | 14 | FlutterElement bySemanticsLabel(String label); 15 | 16 | FlutterElement bySemanticsLabel(Pattern label); 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | #inteliji 26 | .idea 27 | 28 | #maven file 29 | target/ 30 | pom.xml.tag 31 | pom.xml.releaseBackup 32 | pom.xml.versionsBackup 33 | pom.xml.next 34 | release.properties 35 | dependency-reduced-pom.xml 36 | buildNumber.properties 37 | .mvn/timing.properties 38 | # https://github.com/takari/maven-wrapper#usage-without-binary-jar 39 | .mvn/wrapper/maven-wrapper.jar 40 | *.iml 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 ashwithpoojary98 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/maven-publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish to Maven Central 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | workflow_dispatch: 8 | 9 | jobs: 10 | publish: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: 1. Checkout repository 15 | uses: actions/checkout@v4 16 | with: 17 | fetch-depth: 0 18 | 19 | - name: 2. Set up JDK 11 20 | uses: actions/setup-java@v4 21 | with: 22 | java-version: '11' 23 | distribution: 'temurin' 24 | 25 | - name: 3. Configure GPG 26 | run: | 27 | echo "${{ secrets.GPG_PRIVATE_KEY }}" | gpg --batch --import 28 | echo "allow-loopback-pinentry" >> ~/.gnupg/gpg-agent.conf 29 | echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf 30 | gpg-connect-agent reloadagent /bye 31 | export GPG_TTY=$(tty) 32 | 33 | - name: 4. Create Maven settings.xml 34 | run: | 35 | mkdir -p ~/.m2 36 | cat > ~/.m2/settings.xml << EOF 37 | 38 | 39 | 40 | central 41 | ${{ secrets.MAVEN_USERNAME }} 42 | ${{ secrets.MAVEN_PASSWORD }} 43 | 44 | 45 | 46 | EOF 47 | 48 | - name: 5. Deploy to Maven Central Portal 49 | run: mvn clean deploy -P release --batch-mode -Dgpg.passphrase="${{ secrets.GPG_PASSPHRASE }}" -Dgpg.pinentry-mode=loopback -------------------------------------------------------------------------------- /src/test/java/io/github/ashwith/flutter/example/FlutterFinderExampleTest.java: -------------------------------------------------------------------------------- 1 | package io.github.ashwith.flutter.example; 2 | 3 | import io.github.ashwith.flutter.FlutterFinder; 4 | import io.appium.java_client.android.AndroidDriver; 5 | import org.openqa.selenium.WebElement; 6 | import org.openqa.selenium.remote.DesiredCapabilities; 7 | import org.openqa.selenium.remote.RemoteWebDriver; 8 | import org.testng.annotations.AfterMethod; 9 | import org.testng.annotations.BeforeMethod; 10 | import org.testng.annotations.Test; 11 | 12 | import java.net.MalformedURLException; 13 | import java.net.URL; 14 | import java.time.Duration; 15 | 16 | 17 | public class FlutterFinderExampleTest { 18 | RemoteWebDriver driver; 19 | 20 | @BeforeMethod 21 | public void openApp() throws MalformedURLException { 22 | DesiredCapabilities capabilities = new DesiredCapabilities(); 23 | capabilities.setCapability("deviceName", "emulator-5554"); 24 | capabilities.setCapability("platformName", "Android"); 25 | capabilities.setCapability("noReset", true); 26 | capabilities.setCapability("app", ""); 27 | capabilities.setCapability("automationName", "Flutter"); 28 | driver = new AndroidDriver(new URL("http://0.0.0.0:4723/wd/hub"), capabilities); 29 | driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(30)); 30 | } 31 | 32 | @Test 33 | public void appiumFlutterTest() { 34 | FlutterFinder finder = new FlutterFinder(driver); 35 | WebElement element = finder.byToolTip("increment"); 36 | element.click(); 37 | } 38 | 39 | @AfterMethod 40 | public void tearDown() { 41 | if (driver != null) { 42 | driver.quit(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/io/github/ashwith/flutter/FlutterElement.java: -------------------------------------------------------------------------------- 1 | package io.github.ashwith.flutter; 2 | 3 | 4 | import com.google.gson.Gson; 5 | import com.google.gson.JsonElement; 6 | import com.google.gson.JsonPrimitive; 7 | import org.openqa.selenium.remote.RemoteWebElement; 8 | 9 | import java.util.Base64; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | import java.util.Objects; 13 | 14 | /** 15 | * Implement FlutterElement extending RemoteWebElement to enable common Mobile element operations such as click, enter e.t.c on FlutterElement objects 16 | * 17 | * @author ashwith 18 | * @version 1.0.0 19 | */ 20 | public class FlutterElement extends RemoteWebElement { 21 | 22 | private final Map rawMap; 23 | private final Gson gson = new Gson(); 24 | 25 | protected FlutterElement(final Map rawMap) { 26 | this.rawMap = rawMap; 27 | id = serialize(rawMap); 28 | } 29 | 30 | /** 31 | * To return the raw data map 32 | * 33 | * @return raw data map 34 | */ 35 | protected Map getRawMap() { 36 | return rawMap; 37 | } 38 | 39 | /** 40 | * To serialize raw data map 41 | * 42 | * @param rawMap serializing map 43 | * @return Stringify map 44 | */ 45 | private String serialize(final Map rawMap) { 46 | final JsonPrimitive localInstance = new JsonPrimitive(String.valueOf(false)); 47 | Map tempMap = new HashMap<>(); 48 | rawMap.forEach( 49 | (key, value) -> { 50 | if (value instanceof String || value instanceof Integer || value instanceof Boolean) { 51 | tempMap.put(key, new JsonPrimitive(String.valueOf(value))); 52 | } else if (value instanceof JsonElement) { 53 | tempMap.put(key, value); 54 | } else if (value instanceof Map) { 55 | tempMap.put(key, gson.toJson(value)); 56 | } else { 57 | tempMap.put(key, localInstance); 58 | } 59 | }); 60 | String mapJsonStringify = gson.toJson(tempMap); 61 | return Base64.getEncoder().encodeToString(mapJsonStringify.getBytes()); 62 | } 63 | 64 | @Override 65 | public boolean equals(Object o) { 66 | if (this == o) return true; 67 | if (o == null || getClass() != o.getClass()) return false; 68 | if (!super.equals(o)) return false; 69 | FlutterElement that = (FlutterElement) o; 70 | return Objects.equals(rawMap, that.rawMap) && Objects.equals(gson, that.gson); 71 | } 72 | 73 | @Override 74 | public int hashCode() { 75 | return Objects.hash(super.hashCode(), rawMap, gson); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /.github/workflows/github-release.yml: -------------------------------------------------------------------------------- 1 | name: Create Release with Automated Notes 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*.*.*' # Triggers on semantic version tags like v1.0.0, v2.1.3 7 | 8 | permissions: 9 | contents: write 10 | 11 | jobs: 12 | release: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout code 17 | uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 # Fetch all history for changelog generation 20 | 21 | - name: Get previous tag 22 | id: previoustag 23 | run: | 24 | PREVIOUS_TAG=$(git tag --sort=-creatordate | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sed -n '2p') 25 | if [ -z "$PREVIOUS_TAG" ]; then 26 | echo "No previous tag found, using first commit" 27 | PREVIOUS_TAG=$(git rev-list --max-parents=0 HEAD) 28 | fi 29 | echo "tag=$PREVIOUS_TAG" >> $GITHUB_OUTPUT 30 | echo "Previous tag: $PREVIOUS_TAG" 31 | 32 | - name: Generate changelog 33 | id: changelog 34 | run: | 35 | echo "# What's Changed" > changelog.md 36 | echo "" >> changelog.md 37 | 38 | # Get commits between tags 39 | COMMITS=$(git log ${{ steps.previoustag.outputs.tag }}..HEAD --pretty=format:"%s|%h" --no-merges) 40 | 41 | # Categorize commits 42 | echo "## ✨ Features" >> changelog.md 43 | echo "$COMMITS" | grep -iE "^feat|^feature" | sed 's/\(.*\)|\(.*\)/- \1 (\2)/' >> changelog.md || echo "- No new features" >> changelog.md 44 | echo "" >> changelog.md 45 | 46 | echo "## 🐛 Bug Fixes" >> changelog.md 47 | echo "$COMMITS" | grep -iE "^fix|^bugfix" | sed 's/\(.*\)|\(.*\)/- \1 (\2)/' >> changelog.md || echo "- No bug fixes" >> changelog.md 48 | echo "" >> changelog.md 49 | 50 | echo "## 📚 Documentation" >> changelog.md 51 | echo "$COMMITS" | grep -iE "^docs|^doc" | sed 's/\(.*\)|\(.*\)/- \1 (\2)/' >> changelog.md || echo "- No documentation updates" >> changelog.md 52 | echo "" >> changelog.md 53 | 54 | echo "## 🔧 Other Changes" >> changelog.md 55 | echo "$COMMITS" | grep -viE "^feat|^feature|^fix|^bugfix|^docs|^doc" | sed 's/\(.*\)|\(.*\)/- \1 (\2)/' >> changelog.md || echo "- No other changes" >> changelog.md 56 | 57 | # Output for GitHub 58 | echo "notes<> $GITHUB_OUTPUT 59 | cat changelog.md >> $GITHUB_OUTPUT 60 | echo "EOF" >> $GITHUB_OUTPUT 61 | 62 | - name: Display changelog 63 | run: cat changelog.md 64 | 65 | - name: Create Release 66 | uses: softprops/action-gh-release@v1 67 | with: 68 | body: ${{ steps.changelog.outputs.notes }} 69 | draft: false 70 | prerelease: false 71 | generate_release_notes: true # Also includes GitHub's auto-generated notes 72 | env: 73 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 74 | 75 | - name: Notify release created 76 | run: | 77 | echo "✅ Release ${{ github.ref_name }} created successfully!" 78 | echo "📝 View it at: ${{ github.server_url }}/${{ github.repository }}/releases/tag/${{ github.ref_name }}" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Appium Flutter Finder Java 2 | Flutter appium driver is automation tool with java implementation. 3 | 4 | [![Open Source Love](https://badges.frapsoft.com/os/v1/open-source.svg?v=103)](https://github.com/ashwithpoojary98/javaflutterfinder) 5 | [![GitHub stars](https://img.shields.io/github/stars/ashwithpoojary98/javaflutterfinder.svg?style=flat)](https://github.com/ashwithpoojary98/javaflutterfinder/stargazers) 6 | [![PRs Welcome](https://img.shields.io/badge/PRs-Welcome-brightgreen.svg?style=flat )](https://github.com/ashwithpoojary98/javaflutterfinder/pulls) 7 | [![GitHub forks](https://img.shields.io/github/forks/ashwithpoojary98/javaflutterfinder.svg?style=social&label=Fork)](https://github.com/ashwithpoojary98/javaflutterfinder/network) 8 | 9 | # maven-plugin 10 | [![Build Status](https://github.com/ashwithpoojary98/javaflutterfinder/actions/workflows/mavenbuild.yml/badge.svg)](https://github.com/ashwithpoojary98/javaflutterfinder/actions/workflows/mavenbuild.yml) 11 | ## Setup 12 | Add maven dependency to pom.xml 13 | 14 | ```xml 15 | 16 | io.github.ashwithpoojary98 17 | appium_flutterfinder_java 18 | 1.0.12 19 | 20 | ``` 21 | 22 | ## Maven Center Repo link 23 | 24 | https://mvnrepository.com/artifact/io.github.ashwithpoojary98/appium_flutterfinder_java 25 | ## Usage 26 | 27 | ```java 28 | 29 | import io.appium.java_client.AppiumDriver; 30 | 31 | public class FlutterFinderExampleTest { 32 | RemoteWebDriver driver; 33 | 34 | @BeforeMethod 35 | public void openApp() throws MalformedURLException { 36 | DesiredCapabilities capabilities = new DesiredCapabilities(); 37 | capabilities.setCapability("deviceName", "emulator-5554"); 38 | capabilities.setCapability("platformName", "Android"); 39 | capabilities.setCapability("noReset", true); 40 | capabilities.setCapability("app", ""); 41 | capabilities.setCapability("automationName", "Flutter"); 42 | driver = new AppiumDriver(new URL("http://0.0.0.0:4723/wd/hub"), capabilities); 43 | driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(30)); 44 | } 45 | 46 | @Test 47 | public void appiumFlutterTest() { 48 | FlutterFinder finder = new FlutterFinder(driver); 49 | WebElement element = finder.byValueKey("increment"); 50 | element.click(); 51 | } 52 | 53 | @AfterMethod 54 | public void tearDown() { 55 | if (driver != null) { 56 | driver.quit(); 57 | } 58 | } 59 | } 60 | ``` 61 | ### Automation setup 62 | https://dev.to/ashwithpoojary98/automating-flutter-app-using-flutter-appium-driver-1cmb 63 | 64 | ### list of finder 65 | 1. byValueKey(String key) 66 | 2. byValueKey(int key) 67 | 3. byToolTip(String toolTipText) 68 | 4. byType(String type) 69 | 5. byText(String input) 70 | 6. byAncestor(FlutterElement of, FlutterElement matching, boolean matchRoot, boolean firstMatchOnly) 71 | 7. byDescendant(FlutterElement of, FlutterElement matching, boolean matchRoot, boolean firstMatchOnly) 72 | 8. bySemanticsLabel(String label) 73 | 9. bySemanticsLabel(Pattern label) 74 | 75 | 76 | ### Flutter Common Finders 77 | https://api.flutter.dev/flutter/flutter_test/CommonFinders-class.html 78 | 79 | ### More about flutter finder 80 | https://github.com/appium-userland/appium-flutter-driver 81 | 82 | ## License 83 | 84 | appium_flutterfinder_java is released under [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 85 | 86 | Copyright (c) 2025 appium_flutterfinder_java -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | io.github.ashwithpoojary98 7 | appium_flutterfinder_java 8 | 1.0.14 9 | 10 | 11 | 12 | org.apache.maven.plugins 13 | maven-compiler-plugin 14 | 15 | 11 16 | 11 17 | 18 | 19 | 20 | org.sonatype.central 21 | central-publishing-maven-plugin 22 | 0.9.0 23 | true 24 | 25 | central 26 | true 27 | 28 | 29 | 30 | 31 | jar 32 | ${project.groupId}:${project.artifactId} 33 | Flutter finder plugin for Appium in java 34 | https://github.com/ashwithpoojary98/javaflutterfinder 35 | 36 | 37 | MIT License 38 | http://www.opensource.org/licenses/mit-license.php 39 | 40 | 41 | 42 | 43 | 44 | 45 | ashwith 46 | ashwithpoojary98@gmail.com 47 | ashwithpoojary98 48 | https://github.com/ashwithpoojary98/javaflutterfinder 49 | 50 | 51 | 52 | scm:git:git://github.com/ashwithpoojary98/javaflutterfinder.git 53 | scm:git:ssh://github.com:ashwithpoojary98/javaflutterfinder.git 54 | https://github.com/ashwithpoojary98/javaflutterfinder 55 | 56 | 57 | 58 | 59 | 11 60 | 11 61 | 10.0.0 62 | 2.13.1 63 | 7.11.0 64 | true 65 | 66 | 67 | 68 | 69 | io.appium 70 | java-client 71 | ${appium.version} 72 | 73 | 74 | com.google.code.gson 75 | gson 76 | ${google.gson.version} 77 | 78 | 79 | org.testng 80 | testng 81 | ${testng.version} 82 | 83 | 84 | 85 | 86 | release 87 | 88 | 89 | 90 | org.apache.maven.plugins 91 | maven-source-plugin 92 | 2.2.1 93 | 94 | 95 | attach-sources 96 | 97 | jar-no-fork 98 | 99 | 100 | 101 | 102 | 103 | org.apache.maven.plugins 104 | maven-javadoc-plugin 105 | 2.9.1 106 | 107 | 108 | attach-javadocs 109 | 110 | jar 111 | 112 | 113 | 114 | 115 | 116 | org.apache.maven.plugins 117 | maven-gpg-plugin 118 | 1.5 119 | 120 | 121 | sign-artifacts 122 | verify 123 | 124 | sign 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /src/main/java/io/github/ashwith/flutter/FlutterFinder.java: -------------------------------------------------------------------------------- 1 | package io.github.ashwith.flutter; 2 | 3 | 4 | import io.github.ashwith.flutter.finders.ByAncestor; 5 | import io.github.ashwith.flutter.finders.ByDescendant; 6 | import io.github.ashwith.flutter.finders.BySemanticsLabel; 7 | import io.github.ashwith.flutter.finders.ByText; 8 | import io.github.ashwith.flutter.finders.ByToolTip; 9 | import io.github.ashwith.flutter.finders.ByType; 10 | import io.github.ashwith.flutter.finders.ByValueKey; 11 | import io.github.ashwith.flutter.finders.PageBack; 12 | import org.openqa.selenium.remote.FileDetector; 13 | import org.openqa.selenium.remote.RemoteWebDriver; 14 | 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | import java.util.regex.Pattern; 18 | 19 | /** 20 | * Flutter finder implementation of different type of flutter element finder 21 | * 22 | * @author ashwith 23 | * @version 1.0.0 24 | */ 25 | public class FlutterFinder implements ByValueKey, ByType, ByToolTip, ByText, ByAncestor, ByDescendant, 26 | BySemanticsLabel, PageBack { 27 | RemoteWebDriver driver; 28 | FileDetector fileDetector; 29 | private static final String FINDER_TYPE = "finderType"; 30 | 31 | public FlutterFinder(RemoteWebDriver driver) { 32 | this.driver = driver; 33 | this.fileDetector = keys -> null; 34 | } 35 | 36 | @Override 37 | public FlutterElement byValueKey(String key) { 38 | FlutterElement flutterElement = new FlutterElement(Map 39 | .of(FINDER_TYPE, "ByValueKey", 40 | "keyValueType", "String", 41 | "keyValueString", key)); 42 | flutterElement.setParent(driver); 43 | flutterElement.setFileDetector(fileDetector); 44 | return flutterElement; 45 | } 46 | 47 | @Override 48 | public FlutterElement byValueKey(int key) { 49 | FlutterElement flutterElement = new FlutterElement(Map 50 | .of(FINDER_TYPE, "ByValueKey", 51 | "keyValueType", "int", 52 | "keyValueString", key)); 53 | flutterElement.setParent(driver); 54 | flutterElement.setFileDetector(fileDetector); 55 | return flutterElement; 56 | } 57 | 58 | @Override 59 | public FlutterElement byType(String type) { 60 | FlutterElement flutterElement = new FlutterElement(Map.of( 61 | FINDER_TYPE, "ByType", 62 | "type", type 63 | )); 64 | flutterElement.setParent(driver); 65 | flutterElement.setFileDetector(fileDetector); 66 | return flutterElement; 67 | } 68 | 69 | @Override 70 | public FlutterElement byToolTip(String toolTipText) { 71 | FlutterElement flutterElement = new FlutterElement(Map.of( 72 | FINDER_TYPE, "ByTooltipMessage", 73 | "text", toolTipText 74 | )); 75 | flutterElement.setParent(driver); 76 | flutterElement.setFileDetector(fileDetector); 77 | return flutterElement; 78 | } 79 | 80 | @Override 81 | public FlutterElement byText(String input) { 82 | FlutterElement flutterElement = new FlutterElement(Map.of( 83 | FINDER_TYPE, "ByText", 84 | "text", input 85 | )); 86 | flutterElement.setParent(driver); 87 | flutterElement.setFileDetector(fileDetector); 88 | return flutterElement; 89 | } 90 | 91 | @Override 92 | public FlutterElement byAncestor(FlutterElement of, FlutterElement matching, 93 | boolean matchRoot, boolean firstMatchOnly) { 94 | Map matchIdentifier = new HashMap<>(Map.of( 95 | FINDER_TYPE, "Ancestor", 96 | "matchRoot", matchRoot, 97 | "firstMatchOnly", firstMatchOnly 98 | )); 99 | matchIdentifier.put("of", of.getRawMap()); 100 | matchIdentifier.put("matching", matching.getRawMap()); 101 | FlutterElement flutterElement = new FlutterElement(matchIdentifier); 102 | flutterElement.setParent(driver); 103 | flutterElement.setFileDetector(fileDetector); 104 | return flutterElement; 105 | } 106 | 107 | @Override 108 | public FlutterElement byDescendant(FlutterElement of, FlutterElement matching, 109 | boolean matchRoot, boolean firstMatchOnly) { 110 | Map matchIdentifier = new HashMap<>(Map.of( 111 | FINDER_TYPE, "Descendant", 112 | "matchRoot", matchRoot, 113 | "firstMatchOnly", firstMatchOnly 114 | )); 115 | matchIdentifier.put("of", of.getRawMap()); 116 | matchIdentifier.put("matching", matching.getRawMap()); 117 | FlutterElement flutterElement = new FlutterElement(matchIdentifier); 118 | flutterElement.setParent(driver); 119 | flutterElement.setFileDetector(fileDetector); 120 | return flutterElement; 121 | } 122 | 123 | @Override 124 | public FlutterElement bySemanticsLabel(String label) { 125 | FlutterElement flutterElement = new FlutterElement(Map.of( 126 | FINDER_TYPE, "BySemanticsLabel", 127 | "isRegExp", false, 128 | "label", label 129 | )); 130 | flutterElement.setParent(driver); 131 | flutterElement.setFileDetector(fileDetector); 132 | return flutterElement; 133 | } 134 | 135 | @Override 136 | public FlutterElement bySemanticsLabel(Pattern label) { 137 | FlutterElement flutterElement = new FlutterElement(Map.of( 138 | FINDER_TYPE, "BySemanticsLabel", 139 | "isRegExp", true, 140 | "label", label.toString() 141 | )); 142 | flutterElement.setParent(driver); 143 | flutterElement.setFileDetector(fileDetector); 144 | return flutterElement; 145 | } 146 | 147 | @Override 148 | public FlutterElement pageBack() { 149 | return new FlutterElement(Map.of(FINDER_TYPE, "PageBack")); 150 | } 151 | } --------------------------------------------------------------------------------