Skip to content

Ws/appium service selector performance#14980

Merged
wswebcreation merged 64 commits intomainfrom
ws/appium-service-selector-performance
Feb 10, 2026
Merged

Ws/appium service selector performance#14980
wswebcreation merged 64 commits intomainfrom
ws/appium-service-selector-performance

Conversation

@wswebcreation
Copy link
Member

@wswebcreation wswebcreation commented Jan 3, 2026

Proposed changes

This pull request introduces Mobile Selector Performance Optimization and tracking features to the wdio-appium-service package. The changes add

  • a new service
  • a reporter reporter to collect selector performance data,
  • provide automatic optimization and suggest replacement of iOS XPath selectors,
  • extend configuration options for selector performance tracking.

These improvements aim to help users identify and replace slow/brittle iOS locators and selectors in their mobile test suites.

Selector Performance Tracking and Optimization:

  • Added a new reporter (mspo-reporter.ts) and shared store (mspo-store.ts) to collect test context and selector performance data, enabling detailed tracking of element-finding times and test context information.
  • Implemented selector optimization logic (optimizer.ts) and command overwrites (overwrite.ts) to automatically find and use optimized selectors (e.g., accessibility id, ios predicate string, class chain) instead of XPath, with performance comparison and fallback to original selectors if needed.

Dependency Updates:

  • Added @wdio/reporter as a dependency to support the new selector performance reporter.
  • Added @xmldom/xmldom and xpath for XML lookups

How to use

It can be used by adding this to the wdio-appium-service configuration

    services: [
        [
            'appium',
            {
                command: './node_modules/.bin/appium',
                args: {
                  // ......
                },
                /********
                 * NEW
                 ********/
                trackSelectorPerformance: {
                    enabled: true,
                    replaceWithOptimizedSelector: true,
                    enableMarkdownReport: true,
                    enableCliReport: true,
                    pageObjectPaths: ['./tests/pageobjects', './tests/screenobjects']
                },
            },
        ],
    ],

This can result in a CLI-report or a markdown report, see example below. It has been running against the wdio-native-demo-app

═══════════════════════════════════════════════════════════════════════════════
📊 Mobile Selector Performance Optimizer Report
═══════════════════════════════════════════════════════════════════════════════

   Device: iPhone 14
   Run Time: 18:31:52 → 18:34:08 (2m 16s)
   Analyzed: 6 unique selectors (6 optimizable)
   Total Potential Savings: 10.54s per test run (7.8% of total run time)
   Average Improvement per Selector: 67.7% faster

📈 Summary
───────────────────────────────────────────────────────────────────────────────
   🔴 High (>50% gain):        6 → Fix immediately

🎯 File-Based Fixes
───────────────────────────────────────────────────────────────────────────────
   Update these specific lines for immediate impact:

   📁 /Users/wimselles/Git/wdio/appium-boilerplate/tests/screenobjects/LoginScreen.ts
            L4: $('//*[@name="Login-screen"]') → $("~Login-screen")
                ⚡ 1649.9ms/use × 2 uses = 3.30s total
            L13: $('//*[@name="button-login-container"]') → $("~button-login-container") [2102.1ms]
            L20: $('//*[@name="button-biometric"]') → $("~button-biometric") [742.0ms]
      └─ File total: 6.14s saved (3 selectors)

   📁 /Users/wimselles/Git/wdio/appium-boilerplate/tests/screenobjects/components/TabBar.ts
            L3: $('//*[@name="Home"]') → $("~Home")
                ⚡ 868.1ms/use × 2 uses = 1.74s total
            L11: $('//*[@name="Login"]') → $("~Login")
                ⚡ 654.1ms/use × 2 uses = 1.31s total
      └─ File total: 3.04s saved (2 selectors)

   📁 /Users/wimselles/Git/wdio/appium-boilerplate/tests/screenobjects/components/NativeAlert.ts
            L8: $('//XCUIElementTypeAlert') → $("-ios predicate string:type == 'XCUIElementTyp...")
                ⚡ 675.5ms/use × 2 uses = 1.35s total
      └─ File total: 1.35s saved (1 selector)

💡 Why Change?
───────────────────────────────────────────────────────────────────────────────
   • Speed: Native selectors bypass expensive XML tree traversal
   • Stability: Less affected by UI hierarchy changes
   • Priority: ~accessibilityId > -ios predicate string > -ios class chain > //xpath
   • Docs: https://webdriver.io/docs/selectors#mobile-selectors
═══════════════════════════════════════════════════════════════════════════════

───────────────────────────────────────────────────────────────────────────────
📝 Mobile Selector Performance Optimizer - Markdown Report
───────────────────────────────────────────────────────────────────────────────
   📁 Markdown report written to: /Users/wimselles/Git/wdio/appium-boilerplate/logs/mobile-selector-performance-optimizer-report-iphone_14-1769276066643.md
───────────────────────────────────────────────────────────────────────────────


═══════════════════════════════════════════════════════════════════════════════
📊 Mobile Selector Performance Optimizer Report
═══════════════════════════════════════════════════════════════════════════════

   Device: iPhone Simulator
   Run Time: 18:31:53 → 18:33:53 (2m 0s)
   Analyzed: 6 unique selectors (5 optimizable, 1 not recommended)
   Total Potential Savings: 9.31s per test run (7.7% of total run time)
   Average Improvement per Selector: 71.5% faster

📈 Summary
───────────────────────────────────────────────────────────────────────────────
   🔴 High (>50% gain):        5 → Fix immediately
   ⚠️  Slower in Testing:      1 → See warnings below

🎯 File-Based Fixes
───────────────────────────────────────────────────────────────────────────────
   Update these specific lines for immediate impact:

   📁 /Users/wimselles/Git/wdio/appium-boilerplate/tests/screenobjects/components/TabBar.ts
            L3: $('//*[@name="Home"]') → $("~Home")
                ⚡ 1565.2ms/use × 2 uses = 3.13s total
            L11: $('//*[@name="Login"]') → $("~Login")
                ⚡ 787.6ms/use × 2 uses = 1.58s total
      └─ File total: 4.71s saved (2 selectors)

   📁 /Users/wimselles/Git/wdio/appium-boilerplate/tests/screenobjects/LoginScreen.ts
            L4: $('//*[@name="Login-screen"]') → $("~Login-screen")
                ⚡ 1290.6ms/use × 2 uses = 2.58s total
            L13: $('//*[@name="button-login-container"]') → $("~button-login-container") [745.2ms]
            L20: $('//*[@name="button-biometric"]') → $("~button-biometric") [1280.2ms]
      └─ File total: 4.61s saved (3 selectors)

⚠️  Performance Warnings
───────────────────────────────────────────────────────────────────────────────
   Native selectors were SLOWER than XPath for these cases.
   This can happen due to app-specific optimizations, element hierarchy,
   caching effects, or Appium/driver version differences.
   Recommendation: Keep using XPath for these selectors.

   📍 /Users/wimselles/Git/wdio/appium-boilerplate/tests/screenobjects/components/NativeAlert.ts:8
            XPath:  $('//XCUIElementTypeAlert') → 788ms
            Native: $('-ios predicate string:type == 'XCUIEleme...') → 1391ms
                    ❌ Native was 603ms slower (77%)

💡 Why Change?
───────────────────────────────────────────────────────────────────────────────
   • Speed: Native selectors bypass expensive XML tree traversal
   • Stability: Less affected by UI hierarchy changes
   • Priority: ~accessibilityId > -ios predicate string > -ios class chain > //xpath
   • Docs: https://webdriver.io/docs/selectors#mobile-selectors
═══════════════════════════════════════════════════════════════════════════════

───────────────────────────────────────────────────────────────────────────────
📝 Mobile Selector Performance Optimizer - Markdown Report
───────────────────────────────────────────────────────────────────────────────
   📁 Markdown report written to: /Users/wimselles/Git/wdio/appium-boilerplate/logs/mobile-selector-performance-optimizer-report-iphone_simulator-1769276066643.md
───────────────────────────────────────────────────────────────────────────────

Markdown report examples

mobile-selector-performance-optimizer-report-iphone_14-1769276066643.md
mobile-selector-performance-optimizer-report-iphone_simulator-1769276066643.md

TODO:

  • refactor code, this is a mess ATM
  • Check Android
  • Be able to run this with a cloud vendor, now it's only focussed on local excecution
  • Create a Markdown file report
  • Add docs

Types of changes

  • Polish (an improvement for an existing feature)
  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update (improvements to the project's docs)
  • Specification changes (updates to WebDriver command specifications)
  • Internal updates (everything related to internal scripts, governance documentation and CI files)

Checklist

  • I have read the CONTRIBUTING doc
  • I have added tests that prove my fix is effective or that my feature works
  • I have added the necessary documentation (if appropriate)
  • I have added proper type definitions for new commands (if appropriate)

Further comments

Reviewers: @webdriverio/project-committers

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 3, 2026

Open in StackBlitz

create-wdio

npm i https://pkg.pr.new/webdriverio/webdriverio/create-wdio@14980

eslint-plugin-wdio

npm i https://pkg.pr.new/webdriverio/webdriverio/eslint-plugin-wdio@14980

@wdio/allure-reporter

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/allure-reporter@14980

@wdio/appium-service

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/appium-service@14980

@wdio/browser-runner

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/browser-runner@14980

@wdio/browserstack-service

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/browserstack-service@14980

@wdio/cli

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/cli@14980

@wdio/concise-reporter

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/concise-reporter@14980

@wdio/config

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/config@14980

@wdio/cucumber-framework

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/cucumber-framework@14980

@wdio/dot-reporter

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/dot-reporter@14980

@wdio/firefox-profile-service

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/firefox-profile-service@14980

@wdio/globals

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/globals@14980

@wdio/jasmine-framework

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/jasmine-framework@14980

@wdio/json-reporter

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/json-reporter@14980

@wdio/junit-reporter

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/junit-reporter@14980

@wdio/lighthouse-service

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/lighthouse-service@14980

@wdio/local-runner

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/local-runner@14980

@wdio/logger

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/logger@14980

@wdio/mocha-framework

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/mocha-framework@14980

@wdio/protocols

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/protocols@14980

@wdio/repl

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/repl@14980

@wdio/reporter

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/reporter@14980

@wdio/runner

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/runner@14980

@wdio/sauce-service

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/sauce-service@14980

@wdio/shared-store-service

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/shared-store-service@14980

@wdio/smoke-test-cjs-service

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/smoke-test-cjs-service@14980

@wdio/smoke-test-reporter

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/smoke-test-reporter@14980

@wdio/smoke-test-service

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/smoke-test-service@14980

@wdio/spec-reporter

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/spec-reporter@14980

@wdio/static-server-service

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/static-server-service@14980

@wdio/sumologic-reporter

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/sumologic-reporter@14980

@wdio/testingbot-service

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/testingbot-service@14980

@wdio/types

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/types@14980

@wdio/utils

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/utils@14980

@wdio/webdriver-mock-service

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/webdriver-mock-service@14980

@wdio/xvfb

npm i https://pkg.pr.new/webdriverio/webdriverio/@wdio/xvfb@14980

webdriver

npm i https://pkg.pr.new/webdriverio/webdriverio/webdriver@14980

webdriverio

npm i https://pkg.pr.new/webdriverio/webdriverio@14980

commit: bd2c019

@Winify
Copy link
Contributor

Winify commented Jan 31, 2026

@wswebcreation Would it not be possible to include a pre-curated .snapshot() as a webdriverio API?

You are already doing optimisation, so its a safe guess from me that you "already know" the better selectors of a element, that is why you could determine an "optimal" list of elements

EDIT: This may not be this PR's responsibility, as I would image the same process could be used for browser instances as well

@wswebcreation wswebcreation marked this pull request as ready for review February 1, 2026 05:41
- add more logs for debugging
- add logs for the action that is executed
- improve element selection
- different logging for silent or else
- add indentation to make it "more readable"
- removed element action logic, will implement that later
- add new options called :
  - enableReporter
  - reportPath
  - maxLineLength
- throw proper error when the options are not correct/set
- removed reporter logic from the service, it's now fully handled by the reporter file itself
- properly handle how a reporter should log data
- optimize code a bit
- some small refactors
- before and afterCommand will be tested separately
- optimize code a bit
@wswebcreation wswebcreation force-pushed the ws/appium-service-selector-performance branch from ae1be35 to ef5a135 Compare February 1, 2026 06:06
@Winify Winify mentioned this pull request Feb 5, 2026
2 tasks
@wswebcreation wswebcreation merged commit 3d65e98 into main Feb 10, 2026
60 of 61 checks passed
@wswebcreation wswebcreation deleted the ws/appium-service-selector-performance branch February 10, 2026 05:55
@wswebcreation wswebcreation added PR: New Feature 🚀 PRs that contain new features PR: Polish 💅 PRs that contain improvements on existing features labels Feb 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

PR: New Feature 🚀 PRs that contain new features PR: Polish 💅 PRs that contain improvements on existing features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants