Spy Tool Usage Guide
Interactive element inspection and locator capture for web and mobile testing.
Table of Contents
- Introduction
- Web Spy
- Mobile Spy
- Captured Element Format
- Using Captured Elements
- Best Practices
- Troubleshooting
Introduction
The Orbs Spy is an interactive tool for inspecting and capturing element locators from web pages and mobile apps. It helps you:
- Inspect elements interactively without writing code
- Capture multiple locator strategies (ID, XPath, CSS, etc.)
- Generate test-ready code snippets automatically
- Build object repositories for reusable elements
- Speed up test development by avoiding manual locator creation
Web Spy
Starting Web Spy
orbs spy --web --url=https://example.com
With protocol auto-detection:
# Automatically adds https://
orbs spy --web --url=google.com
How It Works
- Launches Chrome browser with spy listeners injected
- Navigate and interact with the page normally
- Press
Ctrl +` (backtick) while hovering over any element - Element details are captured and saved automatically
- Press
Ctrl + Cin terminal to stop spy session
Capturing Elements
Step-by-Step
-
Start spy session:
bash orbs spy --web --url=https://google.com -
Browser opens with the target URL
-
Hover over element you want to capture (e.g., search box)
-
Press
Ctrl +` (backtick key, usually below ESC) -
Console shows capture:
[SPY] Element captured: input[name='q'] [SPY] Saved to: object_repository/SearchBox.xml -
Repeat for more elements
-
Stop when done: Press
Ctrl + Cin the terminal
Captured Locator Strategies
The spy automatically captures multiple locator strategies:
- ID - Element's id attribute
- Name - Element's name attribute
- CSS Selector - Generated CSS selector
- XPath - Generated XPath expression
- Class Name - Element's class attribute
- Tag Name - HTML tag
- Link Text - For
<a>elements - Attributes - All element attributes
Example Captured Element
After capturing Google's search box, you get:
<!-- object_repository/SearchBox.xml -->
<WebElementEntity>
<name>SearchBox</name>
<tag>input</tag>
<selectorCollection>
<entry>
<key>ID</key>
<value>APjFqb</value>
</entry>
<entry>
<key>NAME</key>
<value>q</value>
</entry>
<entry>
<key>CSS</key>
<value>input[name='q']</value>
</entry>
<entry>
<key>XPATH</key>
<value>//input[@name='q']</value>
</entry>
<entry>
<key>CLASS</key>
<value>gLFyf</value>
</entry>
</selectorCollection>
<attributes>
<name>q</name>
<type>text</type>
<autocomplete>off</autocomplete>
<title>Search</title>
</attributes>
</WebElementEntity>
Dynamic Page Handling
The spy automatically re-injects listeners when:
- You navigate to a new page
- Page content is dynamically updated
- Listeners are removed by JavaScript
This ensures continuous capture across single-page apps (SPAs) and multi-page workflows.
Configuration
Default output directory: object_repository/
To change output location:
from orbs.spy.web import WebSpyRunner
spy = WebSpyRunner(
url="https://example.com",
output_dir="custom_elements"
)
spy.start()
Mobile Spy
Starting Mobile Spy
orbs spy --mobile
Prerequisites
-
Appium installed:
bash orbs setup android -
Device connected:
bash adb devices -
Device selected:
bash orbs select-device -
App configured in
settings/appium.properties
How It Works
- Launches Appium session with your app
- Displays app on screen (or emulator)
- Interactive element inspection (implementation-specific)
- Captures locator strategies for Android elements
- Saves to object repository
Captured Mobile Locators
For Android elements:
- Resource ID -
com.example.app:id/element_id - XPath - Generated XPath
- Accessibility ID - Content description
- Class Name - Android widget class
- Text - Visible text
- UIAutomator - UiSelector expression
Example Mobile Element
<!-- object_repository/LoginButton.xml -->
<MobileElementEntity>
<name>LoginButton</name>
<platform>Android</platform>
<selectorCollection>
<entry>
<key>RESOURCE_ID</key>
<value>com.example.app:id/login_button</value>
</entry>
<entry>
<key>XPATH</key>
<value>//android.widget.Button[@text='Login']</value>
</entry>
<entry>
<key>ACCESSIBILITY_ID</key>
<value>Login Button</value>
</entry>
<entry>
<key>CLASS</key>
<value>android.widget.Button</value>
</entry>
<entry>
<key>TEXT</key>
<value>Login</value>
</entry>
</selectorCollection>
</MobileElementEntity>
Captured Element Format
XML Structure
<WebElementEntity>
<name>ElementName</name>
<tag>html_tag</tag>
<selectorCollection>
<entry>
<key>STRATEGY_NAME</key>
<value>locator_value</value>
</entry>
<!-- More strategies... -->
</selectorCollection>
<attributes>
<attribute_name>attribute_value</attribute_name>
</attributes>
</WebElementEntity>
Loading Captured Elements
Create a helper to parse XML:
import xml.etree.ElementTree as ET
def load_element(name):
"""Load element from object repository"""
path = f"object_repository/{name}.xml"
tree = ET.parse(path)
root = tree.getroot()
selectors = {}
for entry in root.find("selectorCollection").findall("entry"):
key = entry.find("key").text
value = entry.find("value").text
selectors[key] = value
return selectors
# Usage
login_btn = load_element("LoginButton")
print(login_btn["CSS"]) # Get CSS selector
print(login_btn["XPATH"]) # Get XPath
Using Captured Elements
Direct Usage in Tests
After capturing elements, use them in your tests:
from orbs.keyword.web import Web
def test_google_search():
"""Test using spy-captured elements"""
Web.open("https://google.com")
# Use captured locators
Web.type_text("name=q", "Orbs automation")
Web.press_enter("name=q")
# Verify results
Web.wait_for_element("id=search", timeout=10)
Object Repository Pattern
Create a page object using captured elements:
# pages/google_page.py
class GooglePage:
# Locators from spy capture
SEARCH_BOX = "name=q"
SEARCH_BUTTON = "css=input[value='Google Search']"
RESULTS_DIV = "id=search"
@staticmethod
def search(query):
from orbs.keyword.web import Web
Web.type_text(GooglePage.SEARCH_BOX, query)
Web.press_enter(GooglePage.SEARCH_BOX)
@staticmethod
def wait_for_results():
from orbs.keyword.web import Web
Web.wait_for_element(GooglePage.RESULTS_DIV, timeout=10)
Use in test:
from pages.google_page import GooglePage
def test_search():
GooglePage.search("automation framework")
GooglePage.wait_for_results()
Centralized Element Repository
# repositories/elements.py
class Elements:
"""Central element repository"""
# Login page
LOGIN_EMAIL = "id=email"
LOGIN_PASSWORD = "id=password"
LOGIN_BUTTON = "id=login-btn"
# Dashboard
DASHBOARD_WELCOME = "css=.welcome-message"
DASHBOARD_MENU = "id=main-menu"
# Forms
FORM_NAME = "name=fullname"
FORM_SUBMIT = "css=button[type='submit']"
Best Practices
1. Name Elements Descriptively
✅ Good:
LoginButton.xml
SearchInputField.xml
UserProfileDropdown.xml
❌ Avoid:
Element1.xml
Button.xml
Input.xml
2. Prefer Stable Locators
From spy results, choose in this order:
- ID (most stable)
- Name (good for forms)
- CSS Selector (flexible, readable)
- XPath (powerful but fragile)
- Class (avoid if not unique)
3. Organize by Page/Module
object_repository/
├── login/
│ ├── EmailField.xml
│ ├── PasswordField.xml
│ └── LoginButton.xml
├── dashboard/
│ ├── WelcomeMessage.xml
│ └── UserMenu.xml
└── forms/
└── SubmitButton.xml
4. Verify Captured Locators
Always test captured locators in your automation:
def verify_locator():
Web.open("https://example.com")
# Test each strategy
assert Web.is_visible("id=login-btn")
assert Web.is_visible("css=.login-button")
print("✅ Locators verified")
5. Update When UI Changes
When UI updates:
- Re-capture affected elements
- Update your object repository
- Re-run tests to verify
6. Document Custom Attributes
Add notes to captured XML:
<WebElementEntity>
<name>SubmitButton</name>
<!-- Note: This button is disabled until form is valid -->
<selectorCollection>
...
</selectorCollection>
</WebElementEntity>
Troubleshooting
Web Spy Not Capturing
Symptom: Pressing Ctrl + ` does nothing
Solutions: * Check browser console for JavaScript errors * Ensure page has fully loaded * Try refreshing the page * Check if browser blocked script injection * Verify Chrome version compatibility
Listeners Not Working After Navigation
Symptom: Capture works on first page but not after clicking links
Solutions: * Spy should auto-reinject listeners (check console) * If not working, restart spy session * For SPAs, ensure listeners are re-injected after route changes
Mobile Spy Not Starting
Symptom: orbs spy --mobile fails
Solutions:
* Verify Appium installation: appium --version
* Check device connection: adb devices
* Verify settings/appium.properties configuration
* Ensure app is installed on device
* Check Appium logs for errors
Element Not Found in XML
Symptom: Captured XML missing expected attributes
Solutions: * Element may have been dynamically generated * Try re-capturing with element fully loaded * Check browser DevTools to verify attributes exist * Some attributes may be set by JavaScript after page load
Output Directory Not Created
Symptom: object_repository/ folder missing
Solutions:
* Ensure write permissions in current directory
* Manually create directory: mkdir object_repository
* Check disk space
* Verify path in spy configuration
Advanced Usage
Custom Element Naming
Automatically rename captured elements:
from orbs.spy.web import WebSpyRunner
class CustomSpyRunner(WebSpyRunner):
def save_element(self, element_data):
# Custom naming logic
tag = element_data.get('tag')
name = element_data.get('name', 'Unknown')
filename = f"{tag}_{name}.xml"
# Save logic...
Batch Element Capture
Capture multiple elements in sequence:
# Create a list of elements to capture
elements_to_capture = [
"Login email field",
"Login password field",
"Login submit button",
"Remember me checkbox"
]
# Start spy and capture each one
# (Manual process - hover and press Ctrl+` for each)
Integration with CI/CD
Spy is primarily for local development. For CI/CD:
- Capture elements locally during test development
- Commit object repository to version control
- Use captured locators in automated tests
- Re-capture when UI changes
Next Steps
- Object Repository - Use captured element using object repository
- Web Testing Guide - Use captured elements in web tests
- Mobile Testing Guide - Use captured elements in mobile tests
- CLI Reference - All spy command options
- Best Practices - Framework philosophy and patterns