Skip to content

Runtime Element Inspector for Appium Android Tests - Automatically displays element locators and attributes when NoSuchElementException occurs, similar to Appium Inspector but in your terminal.

Notifications You must be signed in to change notification settings

resatkvc/Appium_Runtime_Inspector

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

2 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Appium Runtime Inspector

A Java-based Appium test automation project with a built-in Runtime Element Inspector that automatically displays element information when NoSuchElementException occurs - similar to Appium Inspector but directly in your terminal!

image

Features

  • Automatic Element Inspector: When an element is not found, the inspector automatically:

    • Captures the current page source (XML hierarchy)
    • Finds the closest matching element using a smart scoring algorithm
    • Displays multiple locator suggestions (accessibility id, id, uiautomator, xpath)
    • Shows all element attributes in a formatted table
    • Prints the parent XML block for context
  • Colorful Terminal Output: Uses ANSI colors for easy reading

  • Enable/Disable Toggle: Turn inspector on/off as needed

  • TestNG Integration: Ready-to-use test framework

Requirements

Tool Version Description
JDK 17+ Java Development Kit
Maven 3.8+ Build and dependency management
Appium 2.x Mobile automation server
Android SDK Latest Android platform tools
Node.js 18+ Required for Appium
Android Emulator/Device Any Test target device

Project Structure

Appium_Runtime_Inspector/
β”œβ”€β”€ pom.xml                          # Maven configuration
β”œβ”€β”€ testng.xml                       # TestNG suite configuration
β”œβ”€β”€ README.md                        # This file
└── src/
    β”œβ”€β”€ main/java/
    β”‚   β”œβ”€β”€ base/
    β”‚   β”‚   └── BaseTest.java        # Base test class with Inspector integration
    β”‚   └── utilities/
    β”‚       └── AndroidElementInspector.java  # The main Inspector class
    └── test/java/
        └── tests/
            └── ApiDemosTest.java    # Example test cases

Dependencies

<!-- Appium Java Client 8.6.0 (includes Selenium) -->
<dependency>
    <groupId>io.appium</groupId>
    <artifactId>java-client</artifactId>
    <version>8.6.0</version>
</dependency>

<!-- TestNG 7.10.2 -->
<dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>7.10.2</version>
</dependency>

Setup Instructions

1. Install Prerequisites

# Install Node.js (macOS)
brew install node

# Install Appium
npm install -g appium

# Install UiAutomator2 driver
appium driver install uiautomator2

# Verify installation
appium --version

2. Android Setup

# Set ANDROID_HOME environment variable
export ANDROID_HOME=$HOME/Library/Android/sdk
export PATH=$PATH:$ANDROID_HOME/platform-tools
export PATH=$PATH:$ANDROID_HOME/tools

# Verify ADB
adb devices

3. Install ApiDemos App

Download and install the ApiDemos-debug.apk on your emulator/device:

adb install ApiDemos-debug.apk

4. Start Appium Server

appium --base-path /wd/hub

5. Run Tests

# Run all tests
mvn test

# Run specific test class
mvn test -Dtest=ApiDemosTest

AndroidElementInspector

How It Works

The AndroidElementInspector is the core feature of this project. When a NoSuchElementException occurs during test execution, it automatically:

  1. Captures Page Source: Gets the current XML hierarchy from the Android driver
  2. Parses XML: Converts the page source to a DOM Document
  3. Extracts Search Term: Parses the failed locator to extract the search term
  4. Finds Best Match: Uses a scoring algorithm to find the closest matching element
  5. Prints Results: Displays formatted output with locator suggestions and attributes

Scoring Algorithm

The inspector uses a weighted scoring system to find the best match:

Match Type Points
Exact match (text/content-desc/resource-id) 1000
Resource-id ends with :id/search 900
Resource-id ends with /search 800
Text/content-desc contains search 500
Resource-id contains search 400
Class name contains search 300
Prefix similarity 5 per char

Sample Output

When an element is not found, you'll see output like this:

╔══════════════════════════════════════════════════════════════════════════════════════════════════╗
β•‘ πŸ” ANDROID ELEMENT INSPECTOR                                                                    β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•

⚠️  EXCEPTION: NoSuchElementException
πŸ“ TARGET LOCATOR: By.xpath: //*[@text='Aksesibiliti']
βœ… CLOSEST MATCHING ELEMENT FOUND

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Find By                              Selector                                                    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ -android uiautomator                 new UiSelector().text("Accessibility")                      β”‚
β”‚ xpath                                //TextView[@text="Accessibility"]                           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Attribute                            Value                                                       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ index                                0                                                           β”‚
β”‚ package                              io.appium.android.apis                                      β”‚
β”‚ class                                android.widget.TextView                                     β”‚
β”‚ text                                 Accessibility                                               β”‚
β”‚ content-desc                         -                                                           β”‚
β”‚ resource-id                          -                                                           β”‚
β”‚ enabled                              true                                                        β”‚
β”‚ bounds                               [0,210][1080,273]                                           β”‚
β”‚ displayed                            true                                                        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ πŸ“¦ XML Block (Parent: ListView)                                                                  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ <ListView>                                                                                       β”‚
β”‚   <TextView text="Accessibility"/>                                                               β”‚
β”‚   <TextView text="Animation"/>                                                                   β”‚
β”‚   <TextView text="App"/>                                                                         β”‚
β”‚   ...                                                                                            β”‚
β”‚ </ListView>                                                                                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Enable/Disable Inspector

You can control the inspector programmatically:

// Disable inspector output
AndroidElementInspector.setEnabled(false);

// Enable inspector output (default)
AndroidElementInspector.setEnabled(true);

// Check current status
boolean isEnabled = AndroidElementInspector.isEnabled();

Integration with BaseTest

The BaseTest class automatically integrates the inspector with all element finding methods:

// These methods automatically trigger Inspector on NoSuchElementException
findElement(By locator)       // Single element
findElements(By locator)      // Multiple elements (triggers on empty list)
waitAndFind(By locator)       // Wait + find (triggers on timeout)
findByText(String text)       // Find by text attribute
findById(String resourceId)   // Find by resource-id

Test Cases

The project includes 5 test cases:

Successful Tests

Test Description
testAccessibilityNavigation Navigate to Accessibility category
testViewsButtonsNavigation Navigate to Views > Buttons

Inspector Tests (NoSuchElementException)

Test Description
testInspector_NoSuchElement_1 Search with wrong resource-id
testInspector_NoSuchElement_2 Search with typo in text
testInspector_NoSuchElement_3 Search with wrong XPath

Configuration

Appium Server URL

Default: http://127.0.0.1:4723/wd/hub

To change, edit BaseTest.java:

private static final String APPIUM_SERVER_URL = "http://YOUR_IP:PORT/wd/hub";

App Configuration

Edit BaseTest.java to change the target app:

.setAppPackage("your.app.package")
.setAppActivity("your.app.MainActivity")

Troubleshooting

Common Issues

Error Solution
Connection refused Start Appium server: appium --base-path /wd/hub
Response code 404 Add /wd/hub to server URL
No device found Check adb devices and start emulator
App not installed Install ApiDemos-debug.apk on device

Verify Setup

# Check Appium
appium --version

# Check connected devices
adb devices

# Check Java
java -version

# Check Maven
mvn -version

License

MIT License

Author

Created for Android test automation with runtime element inspection capability.

About

Runtime Element Inspector for Appium Android Tests - Automatically displays element locators and attributes when NoSuchElementException occurs, similar to Appium Inspector but in your terminal.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages