Full Code of appium/ruby_lib for AI

master 47ac48a3aaac cached
141 files
579.2 KB
183.9k tokens
904 symbols
1 requests
Download .txt
Showing preview only (620K chars total). Download the full file or copy to clipboard to get everything.
Repository: appium/ruby_lib
Branch: master
Commit: 47ac48a3aaac
Files: 141
Total size: 579.2 KB

Directory structure:
gitextract_9jozq5zh/

├── .github/
│   ├── CODEOWNERS
│   ├── ISSUE_TEMPLATE.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── dependabot.yml
│   └── workflows/
│       ├── functional-test.yml
│       ├── pr-title.yml
│       └── rubocop.yml
├── .gitignore
├── .rubocop.yml
├── CHANGELOG.md
├── Gemfile
├── LICENSE-2.0.txt
├── Rakefile
├── Thorfile
├── android_tests/
│   ├── Gemfile
│   ├── LICENSE-2.0.txt
│   ├── Rakefile
│   ├── appium.txt
│   ├── flaky.txt
│   ├── lib/
│   │   ├── android/
│   │   │   └── specs/
│   │   │       ├── android/
│   │   │       │   ├── element/
│   │   │       │   │   ├── alert.rb
│   │   │       │   │   ├── button.rb
│   │   │       │   │   ├── generic.rb
│   │   │       │   │   ├── text.rb
│   │   │       │   │   └── textfield.rb
│   │   │       │   ├── helper.rb
│   │   │       │   └── patch.rb
│   │   │       ├── common/
│   │   │       │   ├── device.rb
│   │   │       │   ├── device_touchaction.rb
│   │   │       │   ├── element/
│   │   │       │   │   └── window.rb
│   │   │       │   ├── helper.rb
│   │   │       │   ├── patch.rb
│   │   │       │   ├── version.rb
│   │   │       │   └── web_context.rb
│   │   │       ├── driver.rb
│   │   │       ├── install.rb
│   │   │       └── sauce_labs.rb
│   │   ├── format.rb
│   │   └── run.rb
│   └── readme.md
├── appium_lib.gemspec
├── contributing.md
├── docs/
│   ├── android_uiautomator.md
│   ├── docs.md
│   ├── ios_xcuitest.md
│   ├── parallel.md
│   └── w3c.md
├── grid/
│   ├── README.md
│   ├── appium.txt.ios.example
│   ├── config.json
│   ├── hub_config.json
│   └── hub_config_3.json
├── ios_tests/
│   ├── Gemfile
│   ├── LICENSE-2.0.txt
│   ├── Rakefile
│   ├── appium.txt
│   ├── data/
│   │   └── unicode.txt
│   ├── flaky.txt
│   ├── lib/
│   │   ├── common.rb
│   │   ├── format.rb
│   │   ├── ios/
│   │   │   └── specs/
│   │   │       ├── common/
│   │   │       │   ├── element/
│   │   │       │   │   └── window.rb
│   │   │       │   ├── helper.rb
│   │   │       │   ├── patch.rb
│   │   │       │   ├── version.rb
│   │   │       │   └── web_context.rb
│   │   │       ├── device/
│   │   │       │   ├── device.rb
│   │   │       │   └── image_comparison.rb
│   │   │       ├── driver.rb
│   │   │       └── ios/
│   │   │           ├── command/
│   │   │           │   ├── multi_app_handler.rb
│   │   │           │   ├── pasteboard.rb
│   │   │           │   └── source.rb
│   │   │           ├── element/
│   │   │           │   ├── alert.rb
│   │   │           │   ├── button.rb
│   │   │           │   ├── generic.rb
│   │   │           │   ├── text.rb
│   │   │           │   └── textfield.rb
│   │   │           ├── helper.rb
│   │   │           ├── mobile_methods.rb
│   │   │           ├── patch.rb
│   │   │           └── xcuitest_gestures.rb
│   │   └── run.rb
│   ├── parallel/
│   │   └── test.rb
│   └── readme.md
├── lib/
│   ├── appium_lib/
│   │   ├── android/
│   │   │   ├── android.rb
│   │   │   ├── common/
│   │   │   │   ├── command/
│   │   │   │   │   └── command.rb
│   │   │   │   └── helper.rb
│   │   │   ├── element/
│   │   │   │   ├── alert.rb
│   │   │   │   ├── button.rb
│   │   │   │   ├── generic.rb
│   │   │   │   ├── text.rb
│   │   │   │   └── textfield.rb
│   │   │   ├── espresso/
│   │   │   │   ├── bridge.rb
│   │   │   │   ├── element/
│   │   │   │   │   ├── button.rb
│   │   │   │   │   └── generic.rb
│   │   │   │   ├── element.rb
│   │   │   │   └── helper.rb
│   │   │   ├── espresso.rb
│   │   │   ├── uiautomator2/
│   │   │   │   ├── bridge.rb
│   │   │   │   ├── element/
│   │   │   │   │   └── button.rb
│   │   │   │   ├── element.rb
│   │   │   │   └── helper.rb
│   │   │   └── uiautomator2.rb
│   │   ├── appium.rb
│   │   ├── common/
│   │   │   ├── command.rb
│   │   │   ├── device.rb
│   │   │   ├── helper.rb
│   │   │   ├── http_client.rb
│   │   │   ├── log.rb
│   │   │   └── wait.rb
│   │   ├── driver.rb
│   │   ├── error.rb
│   │   ├── ios/
│   │   │   ├── common/
│   │   │   │   ├── errors.rb
│   │   │   │   └── helper.rb
│   │   │   ├── element/
│   │   │   │   ├── alert.rb
│   │   │   │   ├── button.rb
│   │   │   │   ├── generic.rb
│   │   │   │   ├── text.rb
│   │   │   │   └── textfield.rb
│   │   │   ├── ios.rb
│   │   │   ├── xcuitest/
│   │   │   │   ├── bridge.rb
│   │   │   │   ├── command/
│   │   │   │   │   ├── certificate.rb
│   │   │   │   │   ├── gestures.rb
│   │   │   │   │   ├── get_context.rb
│   │   │   │   │   ├── multi_app_handler.rb
│   │   │   │   │   ├── pasteboard.rb
│   │   │   │   │   └── source.rb
│   │   │   │   ├── command.rb
│   │   │   │   ├── element/
│   │   │   │   │   ├── button.rb
│   │   │   │   │   ├── generic.rb
│   │   │   │   │   ├── text.rb
│   │   │   │   │   └── textfield.rb
│   │   │   │   ├── element.rb
│   │   │   │   └── helper.rb
│   │   │   └── xcuitest.rb
│   │   ├── sauce_labs.rb
│   │   └── version.rb
│   └── appium_lib.rb
├── readme.md
├── release_notes.md
├── test/
│   └── first_test.rb
└── test_apps/
    ├── VodQA.apk
    └── api.apk

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/CODEOWNERS
================================================
* @KazuCocoa


================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
## This is a
* [ ] Bug report
* [ ] Question
* [ ] Freature Request

## Summary

## Environment
* Appium version (or git revision):
* `ruby_lib` version:
* Mobile platform/version/device under test:

## Actual behaviour and steps to reproduce

## Expected behaviour

## Link to Appium/Ruby logs

Create a [GIST](https://gist.github.com) which is a paste of your _full_ Appium logs, and link them here. 

## Any additional comments


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
# Summary

Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context.

Closes # (issue)

# How Has This Been Tested?

Please describe the tests that you ran to verify your changes. If the change has test code, it can be alternative.

- [ ] Test A
- [ ] Test B

# Checklist

- [ ] `bundle exec rake rubocop`


================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: bundler
  directory: "/"
  schedule:
    interval: weekly
    time: "11:00"
  open-pull-requests-limit: 10
- package-ecosystem: github-actions
  directory: "/"
  schedule:
    interval: weekly
    time: "11:00"
  open-pull-requests-limit: 10


================================================
FILE: .github/workflows/functional-test.yml
================================================
name: Functional Tests

on:
  # Run by manual at this time
  workflow_dispatch:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

concurrency:
  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

jobs:
  ios_test:
    runs-on: macos-15
    timeout-minutes: 90
    env:
          XCODE_VERSION: 16.4
          IOS_VERSION: 18.5
          IOS_DEVICE_NAME: iPhone 16 Plus

    steps:
    - uses: actions/checkout@v6

    - name: Install Node.js
      uses: actions/setup-node@v6
      with:
        node-version: 'lts/*'

    - name: Select Xcode
      uses: maxim-lobanov/setup-xcode@v1
      with:
        xcode-version: ${{ env.XCODE_VERSION }}
    - run: defaults write com.apple.iphonesimulator PasteboardAutomaticSync -bool false

    - uses: futureware-tech/simulator-action@v5
      with:
      # https://github.com/actions/runner-images/blob/main/images/macos/macos-14-arm64-Readme.md
        model: ${{ env.IOS_DEVICE_NAME }}
        os_version: ${{ env.IOS_VERSION }}

    - name: Preparing other environment
      run: |
        brew install ffmpeg
        brew tap wix/brew
        brew install applesimutils

    # Start Appium
    - name: Install appium and mjpeg-consumer
      run: |
        npm install -g appium
        npm install -g mjpeg-consumer
    - run: |
        appium driver install xcuitest
        appium plugin install images
        appium plugin install execute-driver
        nohup appium --use-plugins=images,execute-driver --relaxed-security --log-timestamp --log-no-colors > appium.log &

    - run: |
        npx appium driver run xcuitest download-wda-sim --platform=ios --outdir=${{ github.workspace }}/wda
      name: Downloading prebuilt WDA

    - name: Set up Ruby
      uses: ruby/setup-ruby@v1
      with:
        ruby-version: 4.0
    - run: |
        bundle install
        bundle exec rake ios
      name: Run tests
      timeout-minutes: 60
      working-directory: ios_tests
      env:
        LOCAL_PREBUILT_WDA: ${{ github.workspace }}/wda/WebDriverAgentRunner-Runner.app

    - name: Save server output
      if: ${{ always() }}
      uses: actions/upload-artifact@master
      with:
        name: appium-ios_test_with_other_deps.log
        path: |
          appium.log
          test/report/

  android_test:
    runs-on: ubuntu-latest
    timeout-minutes: 90
    env:
      API_LEVEL: 35
      ARCH: x86_64

    steps:
    - uses: actions/checkout@v6

    - name: Set up Java
      uses: actions/setup-java@v5
      with:
        distribution: temurin
        java-version: '17'

    - name: Install Node.js
      uses: actions/setup-node@v6
      with:
        node-version: 'lts/*'

    - name: Set up Ruby
      uses: ruby/setup-ruby@v1
      with:
        ruby-version: 4.0

    - name: Install appium
      run: |
        npm install -g appium
        npm install -g mjpeg-consumer

    - name: Start appium
      run: |
        appium driver install uiautomator2
        appium plugin install images
        appium plugin install execute-driver
        nohup appium --use-plugins=images,execute-driver --relaxed-security --log-timestamp --log-no-colors > appium.log &

    - name: Enable KVM group perms
      run: |
        echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
        sudo udevadm control --reload-rules
        sudo udevadm trigger --name-match=kvm

    - name: AVD cache
      uses: actions/cache@v5
      id: avd-cache
      with:
        path: |
          ~/.android/avd/*
          ~/.android/adb*
        key: avd-${{ env.API_LEVEL }}

    - name: Create AVD snapshot for cache
      if: steps.avd-cache.outputs.cache-hit != 'true'
      uses: reactivecircus/android-emulator-runner@v2
      with:
        api-level: ${{ env.API_LEVEL }}
        arch: ${{ env.ARCH }}
        target: google_apis
        force-avd-creation: false
        emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
        disable-animations: false
        script: echo "Generated AVD snapshot for caching."

    - name: run tests
      uses: reactivecircus/android-emulator-runner@v2
      with:
        api-level: ${{ env.API_LEVEL }}
        arch: ${{ env.ARCH }}
        script: cd android_tests;bundle install;bundle exec rake --tasks;bundle exec rake android
        target: google_apis
        profile: Nexus 5X
        disable-spellchecker: true
        disable-animations: true

    - name: Save server output
      if: ${{ always() }}
      uses: actions/upload-artifact@master
      with:
        name: appium-android_test_with_other_deps.log
        path: |
          appium.log
          test/report/


================================================
FILE: .github/workflows/pr-title.yml
================================================
name: Conventional Commits
on:
  pull_request:
    types: [opened, edited, synchronize, reopened]

jobs:
  lint:
    uses: appium/appium-workflows/.github/workflows/pr-title.yml@main
    with:
      config-preset: angular


================================================
FILE: .github/workflows/rubocop.yml
================================================
name: rubocop

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  test:
    strategy:
      fail-fast: false
      matrix:
        ruby: [3.1, 3.2, 3.3]

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v6
    - name: Set up Ruby
      uses: ruby/setup-ruby@v1
      with:
        ruby-version: ${{ matrix.ruby }}
    - name: Install dependencies
      run: bundle install
    - name: Run rubocop
      run: bundle exec rake rubocop
    - name: Run tests
      run: bundle exec rake test


================================================
FILE: .gitignore
================================================
*.gem
*.lock
.DS_Store



================================================
FILE: .rubocop.yml
================================================
AllCops:
  TargetRubyVersion: 3.1
Layout/LineLength:
  Max: 128
Metrics/MethodLength:
  Enabled: false
Metrics/ModuleLength:
  Enabled: false
Metrics/ClassLength:
  Enabled: false
Metrics/CyclomaticComplexity:
  Enabled: false
Metrics/PerceivedComplexity:
  Enabled: false
Metrics/AbcSize:
  Enabled: false
Metrics/BlockLength:
  Enabled: false
Style/Documentation:
  Enabled: false
Style/RegexpLiteral:
  Enabled: false
# blocked on https://github.com/appium/ruby_lib/issues/312. Already removed from core part
Style/GlobalVars:
  Enabled: false
Style/PercentLiteralDelimiters:
  Enabled: false
Style/CommentedKeyword:
  Enabled: false
Naming/AccessorMethodName:
  Enabled: false
Naming/RescuedExceptionsVariableName:
  Enabled: false
Layout/HeredocIndentation:
  Enabled: false
Layout/RescueEnsureAlignment:
  Enabled: false
Layout/HashAlignment:
  Enabled: false
Style/ExplicitBlockArgument:
  Enabled: false
Style/OptionalBooleanParameter:
  Enabled: false
Naming/MethodParameterName:
  Enabled: false
Style/KeywordParametersOrder:
  Enabled: false
Style/AccessorGrouping:
  Enabled: false
Style/StringConcatenation:
  Enabled: false
Lint/NonDeterministicRequireOrder:
  Enabled: false
Gemspec/DeprecatedAttributeAssignment:
  Enabled: true
Layout/LineEndStringConcatenationIndentation:
  Enabled: true
Layout/SpaceBeforeBrackets:
  Enabled: true
Lint/AmbiguousAssignment:
  Enabled: true
Lint/AmbiguousOperatorPrecedence:
  Enabled: false
Lint/AmbiguousRange:
  Enabled: true
Lint/DeprecatedConstants:
  Enabled: true
Lint/DuplicateBranch:
  Enabled: true
Lint/DuplicateRegexpCharacterClassElement:
  Enabled: true
Lint/EmptyBlock:
  Enabled: true
Lint/EmptyClass:
  Enabled: false
Lint/EmptyInPattern:
  Enabled: true
Lint/IncompatibleIoSelectWithFiberScheduler:
  Enabled: true
Lint/LambdaWithoutLiteralBlock:
  Enabled: true
Lint/NoReturnInBeginEndBlocks:
  Enabled: true
Lint/NumberedParameterAssignment:
  Enabled: true
Lint/OrAssignmentToConstant:
  Enabled: true
Lint/RedundantDirGlobSort:
  Enabled: true
Lint/RequireRelativeSelfPath:
  Enabled: true
Lint/SymbolConversion:
  Enabled: true
Lint/ToEnumArguments:
  Enabled: true
Lint/TripleQuotes:
  Enabled: true
Lint/UnexpectedBlockArity:
  Enabled: true
Lint/UnmodifiedReduceAccumulator:
  Enabled: true
Security/IoMethods:
  Enabled: true
Style/ArgumentsForwarding:
  Enabled: true
Style/CollectionCompact:
  Enabled: true
Style/DocumentDynamicEvalDefinition:
  Enabled: true
Style/EndlessMethod:
  Enabled: true
Style/HashConversion:
  Enabled: false
Style/HashExcept:
  Enabled: true
Style/IfWithBooleanLiteralBranches:
  Enabled: true
Style/InPatternThen:
  Enabled: true
Style/MultilineInPatternThen:
  Enabled: true
Style/NegatedIfElseCondition:
  Enabled: true
Style/NilLambda:
  Enabled: true
Style/NumberedParameters:
  Enabled: true
Style/NumberedParametersLimit:
  Enabled: true
Style/QuotedSymbols:
  Enabled: true
Style/RedundantArgument:
  Enabled: true
Style/RedundantSelfAssignmentBranch:
  Enabled: true
Style/SelectByRegexp:
  Enabled: true
Style/StringChars:
  Enabled: true
Style/SwapValues:
  Enabled: true
Gemspec/DevelopmentDependencies: # new in 1.44
  Enabled: true
Layout/LineContinuationLeadingSpace: # new in 1.31
  Enabled: true
Layout/LineContinuationSpacing: # new in 1.31
  Enabled: true
Lint/ConstantOverwrittenInRescue: # new in 1.31
  Enabled: true
Lint/DuplicateMagicComment: # new in 1.37
  Enabled: true
Lint/NonAtomicFileOperation: # new in 1.31
  Enabled: false
Lint/RefinementImportMethods: # new in 1.27
  Enabled: true
Lint/RequireRangeParentheses: # new in 1.32
  Enabled: true
Lint/UselessRescue: # new in 1.43
  Enabled: true
Metrics/CollectionLiteralLength: # new in 1.47
  Enabled: true
Naming/BlockForwarding: # new in 1.24
  Enabled: true
Security/CompoundHash: # new in 1.28
  Enabled: true
Style/ArrayIntersect: # new in 1.40
  Enabled: true
Style/ComparableClamp: # new in 1.44
  Enabled: true
Style/ConcatArrayLiterals: # new in 1.41
  Enabled: true
Style/DirEmpty: # new in 1.48
  Enabled: true
Style/EmptyHeredoc: # new in 1.32
  Enabled: true
Style/EnvHome: # new in 1.29
  Enabled: true
Style/FetchEnvVar: # new in 1.28
  Enabled: true
Style/FileEmpty: # new in 1.48
  Enabled: true
Style/FileRead: # new in 1.24
  Enabled: true
Style/FileWrite: # new in 1.24
  Enabled: true
Style/MagicCommentFormat: # new in 1.35
  Enabled: true
Style/MapCompactWithConditionalBlock: # new in 1.30
  Enabled: true
Style/MapToHash: # new in 1.24
  Enabled: true
Style/MapToSet: # new in 1.42
  Enabled: true
Style/MinMaxComparison: # new in 1.42
  Enabled: true
Style/NestedFileDirname: # new in 1.26
  Enabled: true
Style/ObjectThen: # new in 1.28
  Enabled: true
Style/OperatorMethodCall: # new in 1.37
  Enabled: true
Style/RedundantConstantBase: # new in 1.40
  Enabled: false
Style/RedundantDoubleSplatHashBraces: # new in 1.41
  Enabled: true
Style/RedundantEach: # new in 1.38
  Enabled: true
Style/RedundantHeredocDelimiterQuotes: # new in 1.45
  Enabled: true
Style/RedundantInitialize: # new in 1.27
  Enabled: true
Style/RedundantStringEscape: # new in 1.37
  Enabled: true
Gemspec/RequireMFA: # new in 1.23
  Enabled: true
Lint/UselessRuby2Keywords: # new in 1.23
  Enabled: true
Style/OpenStructUse: # new in 1.23
  Enabled: false
Lint/RedundantStringCoercion:
  Enabled: false
Gemspec/AddRuntimeDependency: # new in 1.65
  Enabled: true
Lint/ConstantReassignment: # new in 1.70
  Enabled: true
Lint/DuplicateMatchPattern: # new in 1.50
  Enabled: true
Lint/DuplicateSetElement: # new in 1.67
  Enabled: true
Lint/HashNewWithKeywordArgumentsAsDefault: # new in 1.69
  Enabled: true
Lint/ItWithoutArgumentsInBlock: # new in 1.59
  Enabled: true
Lint/LiteralAssignmentInCondition: # new in 1.58
  Enabled: true
Lint/MixedCaseRange: # new in 1.53
  Enabled: true
Lint/NumericOperationWithConstantResult: # new in 1.69
  Enabled: true
Lint/RedundantRegexpQuantifiers: # new in 1.53
  Enabled: true
Lint/SharedMutableDefault: # new in 1.70
  Enabled: true
Lint/UnescapedBracketInRegexp: # new in 1.68
  Enabled: true
Lint/UselessDefined: # new in 1.69
  Enabled: true
Lint/UselessNumericOperation: # new in 1.66
  Enabled: true
Style/AmbiguousEndlessMethodDefinition: # new in 1.68
  Enabled: true
Style/BitwisePredicate: # new in 1.68
  Enabled: true
Style/CombinableDefined: # new in 1.68
  Enabled: true
Style/DataInheritance: # new in 1.49
  Enabled: true
Style/DigChain: # new in 1.69
  Enabled: true
Style/ExactRegexpMatch: # new in 1.51
  Enabled: true
Style/FileNull: # new in 1.69
  Enabled: true
Style/FileTouch: # new in 1.69
  Enabled: true
Style/ItAssignment: # new in 1.70
  Enabled: true
Style/KeywordArgumentsMerging: # new in 1.68
  Enabled: true
Style/MapIntoArray: # new in 1.63
  Enabled: true
Style/RedundantArrayConstructor: # new in 1.52
  Enabled: true
Style/RedundantCurrentDirectoryInPath: # new in 1.53
  Enabled: true
Style/RedundantFilterChain: # new in 1.52
  Enabled: true
Style/RedundantInterpolationUnfreeze: # new in 1.66
  Enabled: true
Style/RedundantLineContinuation: # new in 1.49
  Enabled: true
Style/RedundantRegexpArgument: # new in 1.53
  Enabled: true
Style/RedundantRegexpConstructor: # new in 1.52
  Enabled: true
Style/ReturnNilInPredicateMethodDefinition: # new in 1.53
  Enabled: true
Style/SafeNavigationChainLength: # new in 1.68
  Enabled: false
Style/SendWithLiteralMethodName: # new in 1.64
  Enabled: true
Style/SingleLineDoEndBlock: # new in 1.57
  Enabled: true
Style/SuperArguments: # new in 1.64
  Enabled: true
Style/SuperWithArgsParentheses: # new in 1.58
  Enabled: true
Style/YAMLFileRead: # new in 1.53
  Enabled: true


================================================
FILE: CHANGELOG.md
================================================
# Changelogs
Commit based release not is [release_notes.md](./release_notes.md)

Release tags are https://github.com/appium/ruby_lib/releases .

## [16.2.0] - 2026-04-19
- Define device methods (`lock`, `unlock`, `hide_keyboard`, `push_file`, `pull_file`, `background_app`, `shake`, etc.) natively on `Appium::Driver` via `def_delegators :driver`, replacing the implicit delegation previously set up by `extend ::Appium::Core::Device`. Paves the way for `ruby_lib_core` to drop its static compatibility list (appium/ruby_lib_core#97).

## 16.1.1 - 2025-12-28
- Add deprecated mark for start_logs_broadcast/stop_logs_broadcast to use BiDi instead

## 16.1.0 - 2025-03-37
- Relaxed usable the appium_lib_core deps version to `> 11`

## 16.0.1 - 2025-03-16
- Update appium_lib_core deps version condition

## 16.0.0 - 2025-02-16
- Use `http://127.0.0.1:4723` as the default url destination instead of `http://127.0.0.1:4723/wd/hub`
    - `--base-path` in appium server may need to drop the `/wd/hub` if configured

## 15.2.2 - 2024-08-06
- Fix non `app` capability behavior

## 15.2.1 - 2024-08-03
- Fix client side timeout in the default http client
- Bump appium_lib_core 9.2.1+ to apply the fix

## 15.2.0 - 2024-07-20
- Raise defined errors instead of Ruby general errors by appium_lib's own errors

## 15.1.0 - 2024-05-19
- Use appium_lib_core 9.0.0

## 15.0.1 - 2024-04-26
- Bump release module (internal only)

## 15.0.0 - 2024-04-11
- Breaking
    - Use appium_lib_core 8.0.0 and up
        - Please refer to [the diff](https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#800---2024-03-08) about the details.
        - Remove `Appium::MultiTouch` and `Appium::TouchAction`
            - `swipe` could use `mobile:swipe`, or w3c actions. Multi-touch actions such as zoom/pinch can be written in w3c actions.
            - Please use [w3c actions](https://github.com/appium/ruby_lib/blob/master/docs/w3c.md) instead. Several resources such as [test code in ruby_lib_core](https://github.com/appium/ruby_lib_core/blob/master/test/functional/common_w3c_actions.rb) also would help to check the syntax.

## 14.0.0 - 2024-01-25
- Use appium_lib_core  7.4.0 and up
    - Removed deprecated `export_session` and `export_session_path`
    - Please get the session id via `driver.session_id` instead

## 13.0.2 - 2024-01-25
- Allow up to appium_lib_core 7.3

## 13.0.1 - 2023-06-19
- Ruby 3.0+ is required

## 12.3.3 - 2023-04-27

### Bug fixes
- Fix start_driver

## 12.2.1 - 2023-04-24

### 1. Enhancements

### 2. Bug fixes
- fixed the `default_wait` value as zero (regression)
    `set_wait` will set `0` if no `appium_lib: {wait: 0}` is not given.

### 3. Deprecations


## 12.2.0 - 2022-12-25

### 1. Enhancements

### 2. Bug fixes

### 3. Deprecations
- Defaults to XCUITest modulefor iOS

## 12.1.3 - 2022-12-13

### 1. Enhancements
- Minor internal update

### 2. Bug fixes

### 3. Deprecations

## 12.1.2 - 2022-11-13

### 1. Enhancements

### 2. Bug fixes
- Fix `app` capability handling in parsing a toml file

### 3. Deprecations

## 12.1.1 - 2022-10-19

### 1. Enhancements

### 2. Bug fixes
- Fix undefined `.warning` method call

### 3. Deprecations

## 12.1.0 - 2022-10-11

### 1. Enhancements
- Bump minimal ruby_lib_core version

### 2. Bug fixes

### 3. Deprecations
- Deprecate `Appium::Driver.absolute_app_path`, instead, please set proper `app` capability
    - This aims to reduce client side validation as same as other clients.

## 12.0.1 - 2022-04-02

### 1. Enhancements

### 2. Bug fixes
- Fixes `promote_appium_methods`

### 3. Deprecations

## 12.0.0 - 2021-11-06
### 1. Enhancements

- Update ruby_lib_core version from v4 to v5. The change affects this library.
    - [Migration from v4 to v5 in ruby_lib_core client](https://github.com/appium/ruby_lib_core#migration-from-v4-to-v5)
        - Base Selenium Ruby binding is now v4
        - Support only W3C WebDriver spec (and a few Appium specific commands)
        - Support Ruby 2.6+
    - `element.id` returns the element id instead of `element.ref`
        - `element.ref` now returns an array
    - Removed `forceMjsonwp` to send only MJSONWP capabilities since Selenium cleint v4 no longer supports MJSONWP
    - No longer set default `timeouts` as `0`
        - ruby_lib_core will call `/timeouts` endpoint only when `appium_lib: { wait: 5 }` is provided explicitly
    - Raises `::Appium::Core::Error::ArgumentError` instead of `ArgumentError` for this library specific argument errors

### 2. Deprecations
- `TouchAction` and `MultiTouch` are deprecated
    - Please use W3C actions instead https://github.com/appium/ruby_lib/blob/master/docs/w3c.md
    - Other examples
        - https://github.com/appium/ruby_lib/pull/909
        - https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#deprecations-1
- `launch_app`, `close_app` and `reset` are deprecated. Please read [issues#15807](https://github.com/appium/appium/issues/15807) for more details.
    - `activate_app` or a new session request can be alternatives of `launch_app`
    - `terminate_app` or close the session request can be alternatives of `close_app`
    - Close current session and creating a new session, or `terminate_app` and `launch_app` can be alternatives of `reset`
- Global driver (`$driver`) is `false` by default. Please provide `true` as `Appium::Driver.new(opts, true)` to enable it as previously logged as a deprecation warning message.

## 11.1.0 - 2020-12-29 (11.2.0 is the same as this version)

Support Ruby 3

### 1. Enhancements

### 2. Bug fixes

### 3. Deprecations
- Rename `Appium::Ios::Xcuitest::Guesture#tap` to `Appium::Ios::Xcuitest::Guesture#one_finger_tap` to prevent conflicts with `tap` in Ruby

## 11.0.0 - 2020-12-19

Bump supported Ruby version to 2.4+

[related changes](https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#400---2020-12-19) in ruby_lib_core.

## 10.6.0
### 1. Enhancements

### 2. Bug fixes

### 3. Deprecations
- Remove auto `Pry.config.pager` off
    - Please turn it off if you needed. https://github.com/pry/pry/wiki/Customization-and-configuration#Config_pager

## v10.5.0
### 1. Enhancements
- Added `driver.log_event` to post an event
- Added `driver.log_events` to get the events

### 2. Bug fixes

### 3. Deprecations

## v10.4.1
### 1. Enhancements

### 2. Bug fixes
- Fix iOS `page` in native context

### 3. Deprecations

## v10.4.0
### 1. Enhancements
- Add `execute_driver` support

### 2. Bug fixes
- Fix wrong warning message in create session

### 3. Deprecations

## v10.3.1
### 1. Enhancements

### 2. Bug fixes
- Fix `scroll_to` and `scroll_to_exact` for Android [#859](https://github.com/appium/ruby_lib/pull/859)

### 3. Deprecations

## v10.3.0
### 1. Enhancements
- Add `tvOS` support
    - Requires Appium 1.13

### 2. Bug fixes

### 3. Deprecations

## v10.2.0
### 1. Enhancements

### 2. Bug fixes
- **Breaking changes**
    - `find_element/s_by_image` no longer need arguments except for a file path
        - `find_element/s_by_image(file_to_image)` instead of `find_element/s_by_image(file_to_image, match_threshold:, visualize:)`

### 3. Deprecations

## v10.1.0
### 1. Enhancements

### 2. Bug fixes
- `*_exact` methods handle value as case sensitive
    - This might break test cases if it calls `*_exact` as case insensitive

### 3. Deprecations

## v10.0.0

This change has a breaking change about implicit wait.

### 1. Enhancements
- **Breaking changes**
    - Set implicit wait zero by default following [WebDriver spec in Selenium](https://www.seleniumhq.org/docs/04_webdriver_advanced.jsp)
        - The change potentially break your `find_element/s`
        - You can wrap it with `wait` method to avoid the error explicitly
        - Or you also can configure `wait: 20` as `appium_lib` capability to keep the behaviour
- [Experimental]
    - Add `direct_connect` capability
        - How to use: `{ caps: {...},  appium_lib: { direct_connect: true }}`
        - Read [here](https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#enhancements-1) for more details

### 2. Bug fixes

### 3. Deprecations

## v9.18.0
### 1. Enhancements
- Enhance Espresso automation name adaptation
    - Call `xpath` locator strategy instead of `uiautomator` locator strategy in various wrapper methods like `text/s`, `button/s`, etc
    - [#884](https://github.com/appium/ruby_lib/pull/844/)

### 2. Bug fixes

### 3. Deprecations

## v9.17.0
### 1. Enhancements
- Add `action` wrapping _ruby_lib_core_ for [W3C actions](https://github.com/appium/ruby_lib_core/blob/master/lib/appium_lib_core/common/base/bridge/w3c.rb#L39)
    - Returns `TouchAction.new` if the driver works as _MJSONWP_

### 2. Bug fixes

### 3. Deprecations
- `:offset_x` and `:offset_y` in `TouchAction#swipe` is deprecated in favor of `:end_x` and `:end_y`
- [internal] Remove `check_server_version_xcuitest`

## v9.16.1
### 1. Enhancements

### 2. Bug fixes
- Fix failing Appium version comparison [#836](https://github.com/appium/ruby_lib/issues/836)

### 3. Deprecations

## v9.16.0
### 1. Enhancements
- Introduce `appium_thor` in order to automate release

### 2. Bug fixes
- `:app` can be non-path capability like [Windows](https://github.com/Microsoft/WinAppDriver)
    ```ruby
    { caps:
      { platformName: :windows,
        app: 'Microsoft.WindowsCalculator_8wekyb3d8bbwe!App'
      }
    } # `:app` is bundle id.

    { caps:
      { platformName: :windows,
        app: 'relative/path/to/app'
      }
    } # `:app` will be alsolute path to the `:app` if the path exists
    ```

### 3. Deprecations

## v9.15.2
### 1. Enhancements
- Wrap selenium-webdriver apis via `Appium::Driver` through Appium Core Bridge [#827](https://github.com/appium/ruby_lib/pull/827/files)

### 2. Bug fixes

### 3. Deprecations

## v9.15.1
### 1. Enhancements
- [Internal] Use [ruby_lib_core](https://github.com/appium/ruby_lib_core) 2.0
    - The change shouldn't affect this version since the change influence `Core.new`.

### 2. Bug fixes

### 3. Deprecations

## v9.15.0
### 1. Enhancements
- Requires `appium_lib_core` 1.9.0+
    - Requires `selenium-webdriver 3.14+`
    - Support `find_element :image, image` [appium-base-driver#235](https://github.com/appium/appium-base-driver/pull/235)
        - Requires Appium1.8.2
    - Read [changelog](https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#190---2018-08-05) for more details
- Add `distance` option in `scroll` for XCUITest [#805](https://github.com/appium/ruby_lib/pull/805). Thanks [@saim80](https://github.com/saim80)

### 2. Bug fixes

### 3. Deprecations

## v9.14.3
### 1. Enhancements
- Add Tizen
- Use [ruby_lib_core](https://github.com/appium/ruby_lib_core) 1.8.0

### 2. Bug fixes

### 3. Deprecations

## v9.14.2
### 1. Enhancements
- add `mobile: installCertificate` shortcut for XCUITest
- add `mobile: getContexts` shortcut for XCUITest
- Add `find_element_by_image` and `find_elements_by_image` to handle `ImageElement`
   - Read a [PR](https://github.com/appium/ruby_lib/pull/795/files) and [Core](https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#enhancements-1) for more details
   - Experimental feature

### 2. Bug fixes

### 3. Deprecations

## v9.14.1
### 1. Enhancements

### 2. Bug fixes
- Fix an initialisation error for iOS with `appium_lib_core 1.7.0` [#785](https://github.com/appium/ruby_lib/issues/785)

### 3. Deprecations

## v9.14.0
### 1. Enhancements
- Breaking changes for `press_keycode` and `long_press_keycode`
    - Detail: https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#170---2018-05-28

### 2. Bug fixes

### 3. Deprecations

## v9.13.0
### 1. Enhancements
- Requires `appium_lib_core` 1.6.0+
    - Breaking change for `app_state`: https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#160---2018-05-08

### 2. Bug fixes

### 3. Deprecations

## v9.12.1
### 1. Enhancements
- Support `start_logs_broadcast` and `stop_logs_broadcast` for iOS

### 2. Bug fixes
- Back compatible for `wait(number) {}` and `wait_true(number) {}`

### 3. Deprecations

## v9.12.0
### 1. Enhancements

### 2. Bug fixes

### 3. Deprecations
- Changed the name of arguments
    - `swipe(start_x:, start_y:, end_x:, end_y:)` instead of `swipe(start_x:, start_y:, offset_x:, offset_y:)`

## v9.11.1
### 1. Enhancements
- Apply `ruby_lib_core ~> 1.4.2`
   - Support image comparison features
       - http://www.rubydoc.info/gems/appium_lib_core/Appium/Core/Device/ImageComparison

### 2. Bug fixes
- Fix `wait` compatibility for `ruby_lib_core ~> 1.4.1`

### 3. Deprecations

## v9.11.0
### 1. Enhancements
- Add `start_logs_broadcast` and `stop_logs_broadcast` which use WebSocket to get logcat.
    - Include https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#140---2018-04-15

### 2. Bug fixes

### 3. Deprecations

## v9.10.0
### 1. Enhancements
- Some changes for Appium 1.8.0
    - Read also:
        - https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#131---2018-02-14
        - https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#130---2018-01-28

### 2. Bug fixes

### 3. Deprecations

## v9.9.2
### 1. Enhancements
- Fix Security Vulnerability(Nokogiri)[#761](https://github.com/appium/ruby_lib/pull/761)

### 2. Bug fixes

### 3. Deprecations

## v9.9.1
### 1. Enhancements

### 2. Bug fixes
- fix `Minitest`'s revert: [URL](http://docs.seattlerb.org/minitest/History_rdoc.html#label-5.11.2+-2F+2018-01-25)

### 3. Deprecations

## v9.9.0
### 1. Enhancements
- Bump the core library to 1.3.0
    - The change have one breaking change for `start_recording_screen`(Android)

### 2. Bug fixes

### 3. Deprecations

## v9.8.5
### 1. Enhancements

### 2. Bug fixes
- Fix _Bug: NameError: uninitialized constant Minitest::VERSION [#750](https://github.com/appium/ruby_lib/issues/750)_

### 3. Deprecations

## v9.8.4
### 1. Enhancements

### 2. Bug fixes
- Fix `TypeError: superclass mismatch for class Test` for minitest `5.11.0`+ [PR](https://github.com/appium/ruby_lib/pull/748)

### 3. Deprecations

## v9.8.3
### 1. Enhancements
- Bump the core library to 1.2.5
    - The changelog is [here](https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#124---2018-01-03)

### 2. Bug fixes

### 3. Deprecations

## v9.8.2
### 1. Enhancements
- add `shell` command wrapped `mobile: shell` for Android [#732](https://github.com/appium/ruby_lib/pull/732)
- add handling multiple apps for iOS [#729](https://github.com/appium/ruby_lib/issues/729)
- Adapt W3C commands and make sure to work Appium 1.7.2+
    - Which module, msjsonwp or w3c, used depends on server side's response.

### 2. Bug fixes

### 3. Deprecations

## v9.8.1
### 1. Enhancements

### 2. Bug fixes
- Fix creating session for the new W3C createSession
    - https://github.com/appium/appium/pull/9791

### 3. Deprecations

## v9.8.0

### 1. Enhancements
- Add start/stop recording screen [#674](https://github.com/appium/ruby_lib/issues/674)
- replace core directory to core library [#665](https://github.com/appium/ruby_lib/issues/665), [#718](https://github.com/appium/ruby_lib/pull/718)
    - No change for users

### 2. Bug fixes

### 3. Deprecations
- `ap_` prefixed logging
- `source_window`: use `get_source` instead
- `ios_version`: use `platform_version` instead
- `current_app`: use `current_activity`, for example to know current app.

## v9.7.5

### 1. Enhancements

### 2. Bug fixes
- [fix: take care capybara case #716](https://github.com/appium/ruby_lib/pull/716)

### 3. Deprecations

## v9.7.4

### 1. Enhancements
- Add unlock command: [PR](https://github.com/appium/ruby_lib/pull/710/files)
- Be able to call `source` command from any `automationName`

### 2. Bug fixes

### 3. Deprecations

## v9.7.3

### 1. Enhancements
- Get source from XCUITest with `xcuitest_source format: :json`
    - https://github.com/appium/ruby_lib/pull/699
- `:espresso` support

### 2. Bug fixes


### 3. Deprecations

## v9.7.2

### 1. Enhancements
- Raise error if capability is wrong
    - [validate `caps` and `appium_lib` #684](https://github.com/appium/ruby_lib/issues/684)

### 2. Bug fixes
- `Bug: NoMethodError: undefined method 'write_session_id' for #<Appium::Core::Driver:0x00007fa69119ce88>` [#686](https://github.com/appium/ruby_lib/issues/686)
- undefined local variable or method `patch_webdriver_element' [#687](https://github.com/appium/ruby_lib/issues/687)

### 3. Deprecations

## v9.7.1
Hot-fix for v9.7.0: [uninitialized constant Appium::VERSION #680](https://github.com/appium/ruby_lib/issues/680)

## v9.7.0

_v9.7.0_ has [a bunch of refactoring](https://github.com/appium/ruby_lib/issues/602#issuecomment-331140219) but the behaviours must be the same as well as previous versions.
I've checked the behaviour and confirmed test cases in this repository. So, please create issues if you have any issues against this version.

### 1. Enhancements
- Refactoring
```
lib/appium_lib         # root directory
              /core    # Minumul driver files for the Appium server and dependencies for Selenium Driver.
              /common  # Appium related(some methods to make ruby_lib useful)
              /android # for Android
              /ios     # for iOS
```

- The `core` directory will separate as the other gem in [separate core as core ruby gem #665](https://github.com/appium/ruby_lib/issues/665)
- Logs
    - `get_available_log_types`: To get a list of available log types
    - `get_log(type)`: To get logs associated with `type`

### 2. Bug fixes

### 3. Deprecations
- [refactor: Reduce patch_webdriver_element and some DEPRECATIONs #663](https://github.com/appium/ruby_lib/pull/663)
    - Remove deprecated methods:
        - Android
            - `client_xpath/client_xpaths`
                - Please use `xpath` or `find_element/s(:xpath, "xpaths")`
        - iOS
            - `get_page`
                - Please use `source` instead
    - Deprecated
        - iOS
            - `ios_version`, `source_window`, `page_window`
              - Please use `source` instead


## v9.6.1
### 1. Enhancements
- Refactor `XCUItest` for iOS and `uiautomator2` for Android a bit

### 2. Bug fixes
- missing extending `button` methods for `uiautomator2`, Android

### 3. Deprecations

## v9.6.0
### 1. Enhancements
- Reduce Global Driver
    - We'll stop defining global scope driver by default. So, if you'd like to continue to define global scope, please call `start_driver` as the following.
      ```ruby
      Appium::Driver.new(opts, true).start_driver # $driver is defined.
      Appium::Driver.new(opts, false).start_driver # $driver isn't defined.
      ```
        - [link](https://github.com/appium/ruby_lib/blob/master/docs/ios_docs.md#initialize)
    - We need to provide `driver` to work `TouchAction` and `MultiAction` without global driver
        - `TouchAction`
            ```ruby
            driver =  Appium::Driver.new(opts, false).start_driver
            action = TouchAction.new.press(x: 45, y: 100).wait(5).release
            action.perform(driver)
            action = TouchAction.new.swipe(....)
            action.perform(driver)
            ```

        - `MultiAction`
            ```ruby
            driver =  Appium::Driver.new(opts, false).start_driver
            pinch 200, true, driver
            ```
- Add example to run multiple iOS Simulators [doc](https://github.com/appium/ruby_lib/blob/master/docs/ios_xcuitest.md#run-tests-on-multiple-simulators-with-xcode-9)
    - Require Xcode 9 and Appium 1.6.6

### 2. Bug fixes
- `scroll_to` is failed on some Android 5.0 and 5.1 devices
    - https://github.com/appium/ruby_lib/pull/638

### 3. Deprecations

### Special Thanks
- Fixing `acroll_to`
    - [@emen](https://github.com/emen)
- Add alias `quit_driver`
    - [@DylanLacey ](https://github.com/DylanLacey)

## v9.5.0
### 1. Enhancements
- Support `selenium-webdriver3.4.1+`
    - Support new `createSession`

### 2. Bug fixes

### 3. Deprecations
- Drop `selenium-webdriver` `3.0 ~ 3.4.0` since some methods depends on `selenium-webdriver3.4.1+`

## v9.4.10
### 1. Enhancements
- some refactoring
- add some documentations

### 2. Bug fixes

### 3. Deprecations

## v9.4.9
### 1. Enhancements

### 2. Bug fixes
- fix handling a tap gesture in xcuitest [#611](https://github.com/appium/ruby_lib/pull/611)

### 3. Deprecations

## v9.4.8
### 1. Enhancements
- within_context swallowing block return value [#311](https://github.com/appium/ruby_lib/issues/311)
- get current_package for Android [#604](https://github.com/appium/ruby_lib/issues/604)
- Show visibility on iOS page command [#609](https://github.com/appium/ruby_lib/pull/609)
    - related: allow showing all elements on ios page command [#310](https://github.com/appium/ruby_lib/issues/310)

### 2. Bug fixes

### 3. Deprecations
- Android: mark deprecated for client side xpath strategy [#608](https://github.com/appium/ruby_lib/pull/608)
- iOS: get_page method [#609](https://github.com/appium/ruby_lib/pull/609)

## v9.4.7
### 1. Enhancements

### 2. Bug fixes
- fix raise 500 error by `driver.remote_status` in `appium_server_version` [#599](https://github.com/appium/ruby_lib/issues/599)

### 3. Deprecations

## v9.4.6
### 1. Enhancements

### 2. Bug fixes
- reduce gemfile size [#591](https://github.com/appium/ruby_lib/issues/591)
    - Exclude `ios_tests`, `android_tests` and `grid` from gem

### 3. Deprecations

## v9.4.5
### 1. Enhancements
- add `touch_and_hols` for `mobile:` command in XCUITest [#581](https://github.com/appium/ruby_lib/pull/581)
- Driver disables Pry pager without asking [#582](https://github.com/appium/ruby_lib/issues/582)
- add grid environments in this repository.

### 2. Bug fixes

### 3. Deprecations

## v9.4.4
### 1. Enhancements
- add mobile gesture, `mobile: alert`
    - Required over https://github.com/appium/appium-xcuitest-driver/releases/tag/v2.28.6
- add travis example for ios [#573](https://github.com/appium/ruby_lib/pull/573)
- remove some redundant code [#572](https://github.com/appium/ruby_lib/pull/572), [#571](https://github.com/appium/ruby_lib/pull/571)
- update api-demos [#569](https://github.com/appium/ruby_lib/issues/569)

### 2. Bug fixes

### 3. Deprecations

## v9.4.3
### 1. Enhancements
- Use uiautomator for uiautomator2 [#561](https://github.com/appium/ruby_lib/pull/561)
    - improve stability for some methods
- don't use selenium-webdriver 3.5+ [#559](https://github.com/appium/ruby_lib/pull/559)
- Auto link bug # from release notes [#239](https://github.com/appium/ruby_lib/issues/239)

### 2. Bug fixes

### 3. Deprecations

### Special Thanks
- Thanks for checking uiautomator2
    - [@Edouard-chin](https://github.com/Edouard-chin), [@rajdeepv](https://github.com/rajdeepv)

## v9.4.2
### 1. Enhancements

### 2. Bug fixes
- fix drag_from_to_for_duration gets server error [#552](https://github.com/appium/ruby_lib/issues/552)

### 3. Deprecations

## v9.4.1
### 1. Enhancements

### 2. Bug fixes
- fix 9.4.0 release sudden failures [#546](https://github.com/appium/ruby_lib/issues/546)
    - XPath strategy for find_element/s sudden fail than uiautomator strategy.
    - Use `:xpath` strategy only for uiautomator2

### 3. Deprecations

## v9.4.0
### 1. Enhancements
- update mobile gesture APIs for XCUITest(WDA) [#514](https://github.com/appium/ruby_lib/pull/514)
    - For XCUITest(WebDriverAgent)
    - Users can call some [`mobile:` methods](https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/ios-xctest-mobile-gestures.md) without `execute_script('mobile: tap', args)`.
    - Users can write test code without `.ref` method for elements in `execute_script`.
    - Example: https://github.com/appium/ruby_lib/pull/537
- Support UIAutomator2 strategy for Android[#505](https://github.com/appium/ruby_lib/issues/505)
    - Fix some find elemenet methods[#544](https://github.com/appium/ruby_lib/pull/544)

### 2. Bug fixes

### 3. Deprecations

## v9.3.8
### 1. Enhancements
- allow using TestObject server [#538](https://github.com/appium/ruby_lib/pull/538)

### 2. Bug fixes

### 3. Deprecations

## v9.3.7
### 1. Enhancements
- Remove appium suffix from find element [#532](https://github.com/appium/ruby_lib/pull/532)
    - rename `@driver.find_element/s_with_appium` to `@driver.find_element/s`
- fix documentations

### 2. Bug fixes

### 3. Deprecations
- `@driver.find_element/s_with_appium`
    - use `@driver.find_element/s` instead

## v9.3.6
### 1. Enhancements
- Add toggle touch id enrollment [#521](https://github.com/appium/ruby_lib/pull/521)

### 2. Bug fixes

### 3. Deprecations

## v9.3.5
### 1. Enhancements
- add some commands for Android and class chain for iOS [#513](https://github.com/appium/ruby_lib/issues/513)
    - iOS
        - `find_element :class_chain, 'XCUIElementTypeWindow/*/*/XCUIElementTypeStaticText'`
    - Android
        - `get_system_bars`
        - `get_display_density`
        - `is_keyboard_shown`
- add scrollable index parameter into scroll methods [#506](https://github.com/appium/ruby_lib/issues/506)
    - `scroll_to(text, scrollable_index = 0)`
    - `scroll_to_exact(text, scrollable_index = 0)`
- clear `@actions` in Appium::TouchAction if `perform` is called [#511](https://github.com/appium/ruby_lib/issues/511)

### 2. Bug fixes

### 3. Deprecations

## v9.3.4
### 1. Enhancements
- [remove workaround](https://github.com/appium/ruby_lib/pull/474/commits/57cc95264e83e14862f729683b93c1f020a30ce5) to pass CI
- document uiautomator events logging command [#319](https://github.com/appium/ruby_lib/issues/319)
- use predicate for XCUITest to improve performance [#493](https://github.com/appium/ruby_lib/issues/493)
    - `text/s`, `button/s`, `textfield/s`, `tags_exact`, `tags_include`
    - new: `find_ele/s_by_predicate`, `find_ele/s_by_predicate_include`

### 2. Bug fixes

### 3. Deprecations


## v9.3.3
### 1. Enhancements
- add tags_include/tags_exact to be able to find elements of arbitrary classes such as XCUIElementTypeTextView [#488](https://github.com/appium/ruby_lib/issues/488)

### 2. Bug fixes

### 3. Deprecations

## v9.3.2
### 1. Enhancements
- allow SAUCE_ENDPOINT env var to override sauce server url/path [#485](https://github.com/appium/ruby_lib/pull/485)
    - Read [readme](https://github.com/appium/ruby_lib/blob/89c7c89be058153d119d517eab22ccc318d33649/readme.md#sauce-labs-env-vars)'s `SAUCE_ENDPOINT` section.

### 2. Bug fixes

### 3. Deprecations

## v9.3.1
### 1. Enhancements
- Clarify disabling Sauce Labs. [#471](https://github.com/appium/ruby_lib/pull/471)
- add getting performance [#479](https://github.com/appium/ruby_lib/issues/479)
    - **require appium-base-driver@2.1.7**

### 2. Bug fixes
- Fix missed var rename [#481](https://github.com/appium/ruby_lib/pull/481)

### 3. Deprecations

## v9.3.0
### 1. Enhancements
- wait / wait_true need global defaults [#250](https://github.com/appium/ruby_lib/issues/250)
    - You can set default value in `appium_lib`
    - e.g.: [lib/appium_lib/driver.rb](https://github.com/appium/ruby_lib/blob/34803ef6b7b94df9ef4e147ba8fec5c1d2cfaada/lib/appium_lib/driver.rb#L341-L351)
- Problem with delta_x/delta_y in swipe method [#461](https://github.com/appium/ruby_lib/issues/461)
    - Revert _fix arguments for `move_to` in `swipe` method._ in Appium v8.2.1
    - `delta_x/delta_y` replace to `offset_*` for iOS
        - e.g.: `swipe start_x: start_x, start_y: start_y, end_offset_x: 0, offset_y: -100`
    - `delta_x/delta_y` replace to `end_*` for Android
        - e.g.: `swipe start_x: start_x, start_y: start_y, end_x: start_x, end_y: start_y - 100`
    - The reason why there are two kind of arguments is the following issue.
        - [Difference behaviour between iOS and Android regarding with `swipe` action #7702](https://github.com/appium/appium/issues/7702)
- Clarify disabling Sauce Labs. #471
  - update documentations

### 2. Bug fixes
- REQUIRED_VERSION_XCUITEST [#463](https://github.com/appium/ruby_lib/issues/463)
- find elements except for name attributes in text/s, button/s [#462](https://github.com/appium/ruby_lib/issues/462)
    - Return only **visible** elements
        - Previously, these methods return **all** elements.

### 3. Deprecations
- Problem with delta_x/delta_y in swipe method [#461](https://github.com/appium/ruby_lib/issues/461)
    - `delta_x/delta_y` are replaced to `offset_*` for iOS and `end_*` for Android.

## v9.2.0
### 1. Enhancements
- update set_wait / no_wait logic #249
    - `no_wait` just set `implicit_wait = 0`
    - `set_wait` just set `@default_wait` or arbitrary time as `implicit_wait`
    - remove `last_waits` attribute

### 2. Bug fixes
- automationName always nil if set automationName in server side #450

### 3. Deprecations

## v9.1.3

Support selenium-webdriver 3.0.4+

### 1. Enhancements
- Improve performance for button/s and text/s #442
- Should use `open_timeout` or `read_timeout` instead of `timeout` #436
- add documentation for alternative long_press method #440

### 2. Bug fixes

### 3. Deprecations

## v9.1.2
### 1. Enhancements
- add `appium_client_version`: https://github.com/appium/ruby_lib/issues/260
- add some tests and fix some rubocop syntax errors

### 2. Bug fixes
- fix `set_immediate_value`: https://github.com/appium/ruby_lib/issues/263

### 3. Deprecations

## v9.1.1
### 1. Enhancements

### 2. Bug fixes
- fix Finds exact in ios does not return an array #423

### 3. Deprecations

Thanks @slipy12

## v9.1.0
### 1. Enhancements
- update dependencies
    - Support selenium-webdriver 3.0.2+
        - If you'd like to use `selenium-webdriver2.x`, please use `appium_lib9.0.0`

### 2. Bug fixes

### 3. Deprecations
- Drop Ruby 1.9.3, 2.0, 2.1 support
    - Because these ruby versions have already stop updating.

## v9.0.0
### 1. Enhancements
- Support `XCUITest` strategy for iOS
    - Basically, `XCUITest` strategy is compatible with `Appium` strategy in this library.
    - But users who use XPath should be check [this document](https://github.com/appium/ruby_lib/blob/master/docs/ios_xcuitest.md) since XPath has performance issue
        - Users who use `find_element/s` should work fine.
        - tests for elements are [here](https://github.com/appium/ruby_lib/tree/master/ios_tests/lib/ios/specs/ios/element)

Special thanks to @montdidier

### 2. Bug fixes

### 3. Deprecations


## v8.2.1
- fix arguments for `move_to` in `swipe` method.
    - https://github.com/appium/ruby_lib/pull/405
    - Please set `:delta_x` and `:delta_y` as the distance from start to move.


================================================
FILE: Gemfile
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

source 'https://rubygems.org'
gemspec

gem 'appium_thor', '~> 2.0'
gem 'hashdiff', '~> 1.2.0'
gem 'minitest', '~> 5.0'
gem 'minitest-reporters', '~> 1.1'
gem 'pry'
gem 'rake', '~> 13.0'
gem 'rubocop', '1.86.1'
gem 'yard', '~> 0.9.11'


================================================
FILE: LICENSE-2.0.txt
================================================

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: Rakefile
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require 'bundler/gem_tasks'
require 'rubocop/rake_task'
require 'rake/testtask'

desc 'Execute RuboCop static code analysis'
RuboCop::RakeTask.new(:rubocop) do |t|
  t.patterns = %w(lib ios_tests android_tests)
  t.options = %w(-D)
  t.fail_on_error = true
end

desc('Run all unit tests in test directory')
Rake::TestTask.new(:test) do |t|
  t.libs << 'test'
  t.libs << 'lib'
  t.test_files = FileList[ENV['TESTS'] ? ENV['TESTS'].split(',') : 'test/**/*_test.rb']
end


================================================
FILE: Thorfile
================================================
require 'appium_thor'

Appium::Thor::Config.set do
  gem_name     'appium_lib'
  github_name  'ruby_lib'
  version_file 'lib/appium_lib/version.rb'
end


================================================
FILE: android_tests/Gemfile
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

source 'https://rubygems.org'
eval_gemfile File.join(File.expand_path('..', __dir__), 'Gemfile')


================================================
FILE: android_tests/LICENSE-2.0.txt
================================================

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: android_tests/Rakefile
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require 'rubygems'
require 'rake'
require 'rubocop/rake_task'

task default: :android

# Run sh and ignore exception
def run_sh(cmd)
  sh cmd
rescue StandardError
  # ignored
end

# Run cmd. On failure run install and try again.
def bash(cmd)
  sh cmd do |successful, result|
    # exitstatus 7 means bundle install failed
    # non-zero (except 7 retry path) means the test failed
    if !successful && result.exitstatus == 7
      Rake::Task['install'].execute
      sh cmd
    elsif !successful
      raise "Command failed with status #{result.exitstatus}: #{cmd}"
    end
  end
end

# rake android['single_text_name']
# rake android
def run_android(test_file = nil)
  cmd = 'bundle exec ruby ./lib/run.rb android'
  cmd = %(#{cmd} "#{test_file}") if test_file
  bash cmd
end

# Run a single test with:
# rake android['android/element/generic']
#
# Run all tests with:
# rake android
desc 'Run the Android tests'
task :android, :args, :test_file do |_args, test_file|
  run_android test_file[:args]
end

desc 'Run the Android tests without uninstalling'
task :droid, :args, :test_file do |_args, test_file|
  run_android test_file[:args]
end

desc 'Run bundle install'
task :install do
  sh 'bundle install'
end

desc 'Execute RuboCop static code analysis'
RuboCop::RakeTask.new(:rubocop) do |t|
  t.patterns = %w(**/*.rb)
  t.options = %w(-D)
  t.fail_on_error = false
end


================================================
FILE: android_tests/appium.txt
================================================
[caps]
automationName = "uiautomator2"
platformName = "android"
deviceName = "Android emulator"
app = "../test_apps/api.apk"
appPackage = "io.appium.android.apis"
appActivity = "io.appium.android.apis.ApiDemos"
some_capability = "some_capability"


[appium_lib]
sauce_username = ""
sauce_access_key = ""


================================================
FILE: android_tests/flaky.txt
================================================
android = "lib/android/specs/"

================================================
FILE: android_tests/lib/android/specs/android/element/alert.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# rake "android[android/element/alert]"
class AndroidTest
  class Element
    class Alert < Minitest::Test
      def open_alert
        # trigger the alert
        wait { button('OK Cancel dialog with a message').click }
      end

      def test_01_alert_click
        # nav to alert activity
        wait { find('app').click }
        wait { find('alert').click }

        # test
        wait { open_alert }
        wait { alert_click('OK') }
      end

      def test_02_alert_accept
        wait { open_alert }
        wait { alert_accept }
      end

      def test_03_alert_accept_text
        wait { open_alert }
        wait { assert_equal alert_accept_text, 'OK' }
        wait { alert_accept }
      end

      def test_04_alert_dismiss
        wait { open_alert }
        wait { alert_dismiss }
      end

      def test_05_alert_dismiss_text
        wait { open_alert }

        # alert dialog button placement changed:
        # 'OK Cancel dialog with a long message'
        # Android L: 'Something, Cancel, Ok'
        # Android 19: 'Cancel, Something, Ok'

        wait { assert_equal alert_dismiss_text.downcase, 'cancel' }
        wait { alert_dismiss }

        # nav to start activity
        2.times { back }
      end
    end
  end
end


================================================
FILE: android_tests/lib/android/specs/android/element/button.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# rake "android[android/element/button]"
class AndroidTest
  class Element
    class Button < Minitest::Test
      def before_first
        # nav to buttons activity
        wait { find('App').click }
        wait { find('Activity').click }
        wait { find('Animation').click }
      end

      def after_last
        # nav back to home activity
        3.times { back }
      end

      def fade_in
        'Fade in'
      end

      def test_01_before_first
        before_first
      end

      def test_02_button
        # by index
        2.times { wait { assert_equal button(1).text.upcase, fade_in.upcase } }

        # by name contains
        wait { assert_equal button('ade').text.upcase, fade_in.upcase }
      end

      def test_03_buttons
        exp = ['ZOOM IN', 'MODERN ZOOM IN', 'THUMBNAIL ZOOM']
        wait { assert_equal buttons('zoom').map(&:text).map(&:upcase), exp }
        wait { assert_equal buttons.length, 6 }
      end

      def test_04_first_button
        wait { assert_equal first_button.text.upcase, fade_in.upcase }
      end

      def test_05_last_button
        wait { assert_equal last_button.text.upcase, 'THUMBNAIL ZOOM' }
      end

      def test_06_button_exact
        wait { assert_equal button_exact(fade_in).text.upcase, fade_in.upcase }
      end

      def test_07_buttons_exact
        2.times { wait { assert_equal buttons_exact(fade_in).first.text.upcase, fade_in.upcase } }
      end

      def test_08_after_last
        after_last
      end
    end
  end
end


================================================
FILE: android_tests/lib/android/specs/android/element/generic.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# rake "android[android/element/generic]"
class AndroidTest
  class Element
    class Generic < Minitest::Test
      def content
        'Content'
      end

      def partial
        'tent'
      end

      def test_01_find_works_before_and_after_get_source
        wait { assert_equal find(partial).text, content }
        wait { assert_equal get_source.class, String }
        wait { assert_equal find(partial).text, content }
      end

      def test_01_find
        wait { assert_equal find(partial).text, content }
      end

      def test_01_finds
        wait { assert_equal finds(partial).first.text, content }
      end

      def test_01_find_exact
        wait { assert_equal find_exact(content).text, content }
      end

      def test_01_finds_exact
        wait { assert_equal finds_exact(content).first.text, content }
      end

      # scroll_to is broken
      def test_01_scroll_to
        wait { scroll_to('Views').click }
        wait { assert_equal scroll_to('scrollbars').text, 'ScrollBars' }

        wait { find('ScrollBars').click }
        wait { text('style').click }
        wait { assert scroll_to('Developers', 1).text.include? 'What would it take to build a better mobile phone?' }
        back
        back
        # back to start activity
        back
      end

      def test_01_scroll_to_exact
        wait { scroll_to('Views').click }

        wait { assert_equal scroll_to_exact('ScrollBars').text, 'ScrollBars' }
        wait { find('ScrollBars').click }
        wait { text('style').click }
        back
        back
        # back to start activity
        back
      end
    end
  end
end


================================================
FILE: android_tests/lib/android/specs/android/element/text.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# rake "android[android/element/text]"
class AndroidTest
  class Element
    class Text < Minitest::Test
      def must_raise_no_element
        assert_raises Selenium::WebDriver::Error::NoSuchElementError do
          yield
        end
      end

      def test_01_text
        wait { assert ['API Demos', "Access'ibility"].include? text(1).text }
        wait { assert_equal text('mos').text, 'API Demos' }
      end

      def test_02_texts
        wait { assert_equal texts('i').length, 7 }
        wait { assert_equal texts.length, 13 }
      end

      def test_03_first_text
        wait { assert ['API Demos', "Access'ibility"].include? first_text.text }
      end

      def test_04_last_text
        wait { assert ['API Demos', 'Views'].include? last_text.text }
      end

      def test_05_text_exact
        must_raise_no_element { text_exact 'mos' }

        # should pass
        wait { assert_equal text_exact('API Demos').text, 'API Demos' }
      end

      def test_06_texts_exact
        wait { assert_equal texts_exact('API Demos').length, 1 }
      end
    end
  end
end


================================================
FILE: android_tests/lib/android/specs/android/element/textfield.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# rake "android[android/element/textfield]"
class AndroidTest
  class Element
    class TextField < Minitest::Test
      def must_raise_no_element
        assert_raises Selenium::WebDriver::Error::NoSuchElementError do
          yield
        end
      end

      def left
        'Left is best'
      end

      def right
        'Right is always right'
      end

      def before_first
        # nav to activity
        wait { find('app').click }
        wait { find('activity').click }
        wait { find('custom title').click }
      end

      def after_last
        # back to start
        3.times { back }
      end

      def test_01_before_test
        before_first
      end

      def test_02_textfield
        wait { assert_equal textfield(1).text, left }
        wait { assert_equal textfield('right').text, right }
      end

      def test_03_textfields
        wait { assert_equal textfields('right').first.text, right }
        wait { assert_equal textfields.length, 2 }
      end

      def test_04_first_textfield
        wait { assert_equal first_textfield.text, left }
      end

      def test_05_last_textfield
        wait { assert_equal last_textfield.text, right }
      end

      def test_06_textfield_exact
        must_raise_no_element { textfield_exact 'zz' }
        wait { assert_equal textfield_exact(left).text, left }
      end

      def test_07_textfields_exact
        wait { assert_equal textfields_exact('zz'), [] }
        wait { assert_equal textfields_exact(left).first.text, left }
      end

      def test_08_hide_keyboard
        first_textfield.click
        hide_keyboard
      end

      def test_09_after_last
        after_last
      end
    end
  end
end


================================================
FILE: android_tests/lib/android/specs/android/helper.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# rake "android[android/helper]"
class AndroidTest
  class Helper < Minitest::Test
    def test_01_tags
      wait { assert_equal tags('android.widget.TextView').length, 13 }
    end

    def test_01_get_page_class
      # digit values change based on screen size
      # larger screens have more elements

      act = get_page_class
      assert act.split("\n").length >= 5

      assert act.include? '13x android.widget.TextView'
      if automation_name_is_espresso?
        # 13x android.widget.TextView
        # 1x android.widget.ActionMenuView
        # 1x android.widget.Toolbar
        # 1x com.android.internal.widget.ActionBarContainer
        # 1x com.android.internal.widget.ActionBarContextView
        # 1x android.widget.ListView
        # 1x android.widget.FrameLayout
        # 1x com.android.internal.widget.ActionBarOverlayLayout
        # 1x com.android.internal.policy.DecorView
        assert act.include? '1x android.widget.ActionMenuView'
      else
        assert act.include? '3x android.widget.FrameLayout'
        assert act.include? '2x android.view.ViewGroup'
        assert act.include? '1x android.widget.ListView'
        assert act.include? '1x hierarchy'
      end
    end

    # def test_01_page_class' do # tested by get_page_c

    def test_02_get_android_inspect
      # line count changes based on screen size
      wait { assert get_android_inspect.split("\n").length >= 40 }
    end

    # def test_01_get_inspect' do # tested by get_android_ins
    # def test_01_page' do # tested by get_android_ins

    def id_key
      'animation_2_instructions'
    end

    def id_value
      'Select an animation:'
    end

    def test_03_xml_keys
      wait do
        id_pair = xml_keys id_key
        id_pair = id_pair.to_a[0]
        assert_equal id_pair.length, 2
        assert_equal id_pair.first, id_key
        assert_equal id_pair.last, id_value
      end
    end

    def test_04_resolve_id
      wait do
        str = resolve_id id_key
        assert_equal str, id_value
      end
    end

    def test_05_xml_values
      wait do
        value = xml_values(id_value).first.last
        assert_equal value, id_value
      end
    end

    def test_06_find_by_id
      wait { find('accessibility').click }
      wait { find('accessibility node provider').click }

      if automation_name_is_uiautomator2? || automation_name_is_espresso?
        wait { text 'Accessibility/Accessibility Node Provider' }
      else
        # With string.xml
        # Only for uiautomator1
        wait { id 'accessibility_node_provider' }
      end

      2.times { back }
    end

    def test_07_ids
      wait { assert_equal ids('android:id/text1').length, 12 }
    end
  end
end


================================================
FILE: android_tests/lib/android/specs/android/patch.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# rake "android[android/patch]"
class AndroidTest
  class Patch < Minitest::Test
    def test_type
      # nav to textfield
      wait { find('app').click }
      wait { find('Search').click }
      wait { find('Invoke Search').click }

      wait { first_textfield.type 'ok' }
      wait { assert_equal first_textfield.text, 'ok' }

      # TODO: how to invoke random am start commands?
      # nav to start activity
      # io.appium.android.apis/io.appium.android.apis.ApiDemos

      # keyboard may exist, if it doesn't then an error will raise
      ignore { hide_keyboard }

      # return to app start
      back
      wait { find('Invoke Search') }
      back
      wait { find_exact('Search') }
      back
      wait { find('app') }
    end
  end
end


================================================
FILE: android_tests/lib/android/specs/common/device.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# rake "android[common/device]"
class AndroidTest
  class Common
    class Device < Minitest::Test
      def test_01_get_performance_data_types
        expected = %w(batteryinfo cpuinfo memoryinfo networkinfo)
        assert_equal get_performance_data_types.sort, expected

        assert_equal get_performance_data(
          package_name: 'io.appium.android.apis', data_type: 'cpuinfo'
        )[0], %w(user kernel)
      end

      def test_02_start_activity
        wait { assert_equal current_activity, '.ApiDemos' }
        start_activity(
          app_package: 'io.appium.android.apis',
          app_activity: '.accessibility.AccessibilityNodeProviderActivity'
        )
        wait { assert_equal current_activity.include?('Node'), true }
        start_activity(
          app_package: 'com.android.settings',
          app_activity: '.Settings',
          app_wait_package: 'com.android.settings',
          app_wait_activity: '.Settings'
        )
        wait { assert_equal current_activity.include?('Settings'), true }
      end

      def test_03_current_package
        start_activity(
          app_package: 'io.appium.android.apis',
          app_activity: '.accessibility.AccessibilityNodeProviderActivity'
        )
        wait { assert_equal current_package, 'io.appium.android.apis' }
      end

      def test_04_app_strings
        wait_true { app_strings.key? 'activity_save_restore' }
      end

      def test_05_press_keycode
        # http://developer.android.com/reference/android/view/KeyEvent.html
        press_keycode 176
      end

      def test_06_long_press_keycode
        # http://developer.android.com/reference/android/view/KeyEvent.html
        long_press_keycode 176
      end
    end
  end
end


================================================
FILE: android_tests/lib/android/specs/common/device_touchaction.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# rake "android[common/device_touchaction]"
class AndroidTest
  class Common
    class DeviceTouchAction < Minitest::Test
      def test_01_before_test
        wait { text('Accessibility') }
      end

      def test_02_action_chain_press_release
        wait do
          e = text('Accessibility')
          action.click(e).perform
        end
        wait { text('Custom View') }
        back
        wait { text_exact 'NFC' }
      end

      def test_03_action_chain_tap
        wait do
          e = text('Accessibility')
          action.click(e).perform
        end
        wait { text('Custom View') }
        back
        wait { text_exact 'NFC' }
      end

      def test_04_swipe
        wait { text('Animation').click }
        wait { text_exact('Bouncing Balls').click }

        driver.action
              .move_to_location(0.75, 0.25).pointer_down(:left)
              .move_to_location(0.75, 50)
              .release.perform

        3.times { back }
        wait { text_exact 'NFC' }
      end

      def test_05_pinch_zoom
        wait { text_exact 'NFC' }
        wait { text_exact('Graphics').click }
        wait { scroll_to('Touch Paint').click }

        # multiple action chains
        f1 = driver.action.add_pointer_input(:touch, 'finger1')
        f1.create_pointer_move(
          duration: 0.5, x: 500, y: 800,
          origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT
        )
        f1.create_pointer_down(:left)
        f1.create_pause(0.5)
        f1.create_pointer_move(
          duration: 3, x: 500, y: 700,
          origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT
        )
        f1.create_pointer_up(:left)

        f2 = driver.action.add_pointer_input(:touch, 'finger2')
        f2.create_pointer_move(
          duration: 0.5, x: 500, y: 800,
          origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT
        )
        f2.create_pointer_down(:left)
        f1.create_pause(0.5)
        f2.create_pointer_move(
          duration: 3, x: 500, y: 900,
          origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT
        )
        f2.create_pointer_up(:left)

        driver.perform_actions [f1, f2]

        wait { text('Graphics/Touch Paint') }
        2.times { back }
        wait { text_exact 'NFC' }
      end
    end
  end
end


================================================
FILE: android_tests/lib/android/specs/common/element/window.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# rake "android[common/element/window]"
class AndroidTest
  class Common
    class Element
      class Window < Minitest::Test
        def test_window_size
          wait do
            size = window_size
            assert_equal size.width.class, Integer
            assert_equal size.height.class, Integer
          end
        end
      end
    end
  end
end


================================================
FILE: android_tests/lib/android/specs/common/helper.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# rake "android[common/helper]"
class AndroidTest
  class Common
    class Helper < Minitest::Test
      def wait_opts
        { timeout: 0.2, interval: 0.2 } # max_wait, interval
      end

      # There's no `must_not_raise` as the opposite of must_raise

      # By default code is expected to not raise exceptions.
      # must_not_raise is a no-op.

      # wait is a success unless an error is raised
      # max_wait=0 is infinity to use 0.1
      def test_01_wait
        # successful wait should not raise error
        wait(wait_opts) { true }
        wait(wait_opts) { false }
        wait(wait_opts) { nil }

        # failed wait should error
        assert_raises ::Appium::Core::Wait::TimeoutError do
          wait(wait_opts) { raise }
        end

        # regular rescue will not handle exceptions outside of StandardError hierarchy
        # must rescue Exception explicitly to rescue everything
        assert_raises ::Appium::Core::Wait::TimeoutError do
          wait(wait_opts) { raise NoMemoryError }
        end

        assert_raises ::Appium::Core::Wait::TimeoutError do
          wait(timeout: 0.2, interval: 0.0) { raise NoMemoryError }
        end

        e = assert_raises ArgumentError do
          wait_true(invalidkey: 2) { true }
        end
        assert_equal 'unknown keyword: :invalidkey', e.message
      end

      def test_02_ignore
        # ignore should rescue all exceptions
        ignore { true }
        ignore { false }
        ignore { nil }
        ignore { raise }
        ignore { raise NoMemoryError }
      end

      # wait_true is a success unless the value is not true
      def test_03_wait_true
        # successful wait should not error
        wait_true(wait_opts) { true }

        # failed wait should error
        assert_raises ::Appium::Core::Wait::TimeoutError do
          wait_true(wait_opts) { false }
        end

        assert_raises ::Appium::Core::Wait::TimeoutError do
          wait_true(wait_opts) { nil }
        end

        # raise should error
        assert_raises ::Appium::Core::Wait::TimeoutError do
          wait_true(wait_opts) { raise }
        end

        # regular rescue will not handle exceptions outside of StandardError hierarchy
        # must rescue Exception explicitly to rescue everything
        assert_raises ::Appium::Core::Wait::TimeoutError do
          wait_true(wait_opts) { raise NoMemoryError }
        end

        assert_raises ::Appium::Core::Wait::TimeoutError do
          wait_true(timeout: 0.2, interval: 0.0) { raise NoMemoryError }
        end

        e = assert_raises ArgumentError do
          wait_true(invalidkey: 2) { true }
        end
        assert_equal 'unknown keyword: :invalidkey', e.message
      end

      def test_04_back
        # start page
        wait { assert_equal texts.length, 13 }
        # nav to new page.
        # ele 0 is the title and can't be clicked.
        wait { text(2).click }
        wait { assert_equal texts.length, 5 }
        # go back
        back
        # start page
        wait { find 'NFC' }
      end

      def test_05_session_id
        wait { assert_match(/\h{8}-\h{4}-\h{4}-\h{4}-\h{12}/, session_id) }
      end

      def test_06_xpath
        #  Access'ibility is for Espresso
        wait { assert ['API Demos', "Access'ibility"].include? xpath('//android.widget.TextView').text }
      end

      def test_07_xpaths
        wait { assert_equal xpaths('//android.widget.TextView').length, 13 }
      end

      def test_08_ele_index
        # Animation is for Espresso
        wait { assert %w(Accessibility Animation).include? ele_index('android.widget.TextView', 3).text }
      end

      def test_09_tags
        wait { assert_equal tags('android.widget.TextView').length, 13 }
      end

      def test_10_first_ele
        wait do
          # Access'ibility is for Espresso
          assert ['API Demos', "Access'ibility"].include? first_ele('android.widget.TextView').text
        end
      end

      def test_11_last_ele
        wait do
          # "API Demos" is for Espresso
          assert ['API Demos', 'Views'].include? last_ele('android.widget.TextView').text
        end
      end

      # def test_01_source' do # tested by get_so

      def test_12_get_source
        wait do
          assert_equal get_source.class, String
        end
      end
    end
  end
end


================================================
FILE: android_tests/lib/android/specs/common/patch.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Skip:
#   status # status patches are already tested in driver.rb
#   execute # debug output for Pry

# rake "android[common/patch]"
class AndroidTest
  class Common
    class Patch < Minitest::Test
      # Attributes are busted in Android.
      # Blocked on https://github.com/appium/appium/issues/628

      # Android supports exactly two string Attributes
      # .name and .text
      # https://github.com/appium/appium/blob/ea3450e7f78d1794bab42fa396a387e7b86fd3b3/android/bootstrap/src/io/appium/android/bootstrap/handler/GetAttribute.java#L43
      # def test_01_value' do; end # Doesn't work on And

      def test_01_element_method_name
        wait { assert_equal first_text.text, 'API Demos' }
      end

      # def test_01_tag_name' do; end # Doesn't work on And

      def test_02_element_method_location_rel
        wait do
          loc = first_text.location_rel($driver)
          assert_equal loc.x.class, String
          assert_equal loc.y.class, String
        end
      end

      # By default, the webdriver gem will return message instead of origValue
      def test_03_common_patch_id_error_message
        value = ''
        begin
          set_wait 0
          find_element(:id, 'ok')
        rescue StandardError => e
          value = e.message
        ensure
          set_wait 30
        end
        exp = 'An element could not be located on the page using the given search parameters.'
        assert value.start_with? exp
      end

      def test_04_id_common_patch_success
        if automation_name_is_uiautomator2?
          wait do
            el = text 'text' # <string name="autocomplete_3_button_7">Text</str
            assert_equal el.text, 'Text'
          end
        else
          wait do
            el = id 'autocomplete_3_button_7' # <string name="autocomplete_3_button_7">Text</string>
            assert_equal el.text, 'Text'
          end
        end
      end

      def test_05_find_many_elements_by_resource_id
        wait do
          value = find_elements(:id, 'android:id/text1').length
          assert_equal value, 12
        end
      end

      def test_06_find_single_element_by_resource_id
        wait do
          value = id('android:id/text1').text
          assert_equal value, "Access'ibility"
        end
      end
    end
  end
end


================================================
FILE: android_tests/lib/android/specs/common/version.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# rake "android[common/version]"
class AndroidTest
  class Common
    class Version < Minitest::Test
      def test_appium_version
        assert_match(/(\d+)\.(\d+).(\d+)/, ::Appium::VERSION)
      end

      def test_appium_date
        assert_match(/(\d+)-(\d+)-(\d+)/, ::Appium::DATE)
      end
    end
  end
end


================================================
FILE: android_tests/lib/android/specs/common/web_context.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Tests specifically for areas where the web_context differs in behaviour
# rake "android[common/web_context]"
class AndroidTest
  class Common
    class WebContext < Minitest::Test
      # appium's context support is broken on android

      def test_01_available_contexts
        wait_true { available_contexts.include? 'NATIVE_APP' }
      end

      def test_02_current_context
        wait { assert_equal current_context, 'NATIVE_APP' }
      end

      def undo_setcontext_nav
        back
        wait { find('WebView') }
        back
        wait { find 'Views' }
      end

      def test_03_set_context
        wait { scroll_to('Views').click }
        wait { scroll_to('WebView').click }

        wait_true { !available_contexts.detect { |e| e.start_with?('WEBVIEW') }.nil? }

        webview_context = available_contexts.detect { |e| e.start_with?('WEBVIEW') }

        if webview_context.nil?
          undo_setcontext_nav
          raise "No webview context found. contexts are: #{contexts}"
        end

        wait { set_context webview_context }
        wait { assert_equal current_context, webview_context }

        # verify inspect within webview works
        assert get_android_inspect.split("\n").length >= 3

        wait { set_context 'NATIVE_APP' }
        wait { assert_equal current_context, 'NATIVE_APP' }

        undo_setcontext_nav
      end
    end
  end
end


================================================
FILE: android_tests/lib/android/specs/driver.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require 'tmpdir'

# rake "android[driver]"
class AndroidTest
  class Driver < Minitest::Test
    def sauce?
      ENV.fetch('UPLOAD_FILE', nil) && ENV.fetch('SAUCE_USERNAME', nil)
    end

    def test_01_load_settings
      appium_txt = File.join(Dir.pwd, 'appium.txt')
      parsed   = Appium.load_settings file: appium_txt, verbose: true
      apk_name = File.basename parsed[:caps][:app]
      assert_equal apk_name, 'api.apk'
    end

    def test_02_attributes_no_wait
      no_wait
      assert_raises Selenium::WebDriver::Error::NoSuchElementError do
        button('zz')
      end
      set_wait
    end

    # attr_reader :default_wait, :app_path, :app_name,
    #            :app_package, :app_activity, :app_wait_activity,
    #            :sauce_username, :sauce_access_key, :port, :os, :debug
    def test_03_attributes_default_wait_attr
      set_wait 1
      assert_equal default_wait, 1
      set_wait # restore default
    end

    def test_04_attributes_app_path_attr
      apk_name = File.basename driver_attributes[:caps][:app]
      assert_equal apk_name, 'api.apk'
    end

    def test_05_attributes_verify_all_attributes
      actual = driver_attributes
      expected_app = File.absolute_path('../test_apps/api.apk')

      expected = {
        automation_name:     :uiautomator2,
        custom_url:          'http://127.0.0.1:4723',
        default_wait:        1,
        sauce_username:      nil,
        sauce_access_key:    nil,
        sauce_endpoint:      'ondemand.saucelabs.com:443/wd/hub',
        port:                4723,
        device:              :android,
        debug:               true,
        listener:            nil,
        wait_timeout:        30, # default
        wait_interval:       0.5 # default
      }

      # actual[:caps].to_json send to Appium server
      caps_with_json = JSON.parse(actual[:caps].to_json)
      assert_equal caps_with_json['platformName'], 'android'
      assert_equal caps_with_json['app'], expected_app
      assert_equal caps_with_json['appPackage'], 'io.appium.android.apis'
      assert_equal caps_with_json['appActivity'], 'io.appium.android.apis.ApiDemos'
      assert_equal caps_with_json['deviceName'], 'Android emulator'
      assert_equal caps_with_json['someCapability'], 'some_capability'

      assert_equal actual[:caps][:platformName], 'android'
      assert_equal actual[:caps][:app], expected_app
      assert_equal actual[:caps][:appPackage], 'io.appium.android.apis'
      assert_equal actual[:caps][:appActivity], 'io.appium.android.apis.ApiDemos'
      assert !actual[:caps][:deviceName].nil?
      assert_equal actual[:caps][:some_capability], 'some_capability'

      dup_actual = actual.dup
      dup_actual.delete(:caps)

      raise "\n\nactual:\n\n: #{dup_actual}expected:\n\n#{expected}" if dup_actual != expected
    end

    def test_06_driver_class
      assert_equal $driver.class, Appium::Driver
    end

    def absolute_app_path(path)
      $driver.class.absolute_app_path(caps: { app: path })
    end

    def validate_path(path)
      assert_equal absolute_app_path(path), path
    end

    def test_07_absolute_app_path
      validate_path 'sauce-storage:some_storage_suffix'
      validate_path 'http://www.saucelabs.com'

      Dir.mktmpdir do |tmp_dir|
        existing_path = File.join(tmp_dir, 'myapp.app')
        FileUtils.mkdir_p existing_path
        validate_path existing_path
      end

      # bundle id test
      validate_path 'my.bundle.id'

      # relative path test

      relative_path = File.join __FILE__, ('..' + File::SEPARATOR) * 5, 'test_apps/api.apk'
      expected_path = File.expand_path relative_path

      assert_equal absolute_app_path(relative_path), expected_path

      # invalid path test
      assert_equal absolute_app_path('../../does_not_exist.apk'), '../../does_not_exist.apk'
    end

    def test_08_methods_status
      appium_server_version['build'].keys.sort.include? 'version'
    end

    def test_09_methods_server_version
      server_version = appium_server_version['build']['version']
      if sauce?
        assert_match 'Sauce OnDemand', server_version
      else
        assert_match(/(\d+)\.(\d+).(\d+)/, server_version)
      end
    end

    def test_10_methods_client_version
      client_version = appium_client_version
      expected = { version: ::Appium::VERSION }
      assert_equal client_version, expected
    end

    def test_11_methods_restart
      set_wait 1 # ensure wait is 1 before we restart.
      restart
      assert_equal current_activity, '.ApiDemos'
    end

    def test_12_methods_driver
      assert_equal driver.browser, 'unknown'
    end

    # Skip:
    #   screenshot   # this is slow and already tested by Appium
    #   driver_quit  # tested by restart
    #   start_driver # tested by restart
    #   no_wait  # posts value to server, it's not stored locally
    #   set_wait # posts value to server, it's not stored locally
    #   execute_script # 'mobile: ' is deprecated and plain execute_script unsupported

    def test_13_methods_default_wait
      set_wait 1
      assert_equal default_wait, 1
    end

    # returns true unless an error is raised
    def test_14_methods_exists
      assert_equal exists(0, 0) { true }, true
      assert_equal exists(0, 0) { raise 'error' }, false
    end

    # any elements
    def test_15_methods_find_elements
      wait do
        assert_equal find_elements(:class_name, 'android.widget.TextView').length, 13
      end
    end

    # any element
    def test_16_methods_find_element
      wait do
        assert_equal find_element(:class_name, 'android.widget.TextView').class, ::Appium::Core::Element
      end
    end

    # simple integration sanity test to check for unexpected exceptions
    def test_17_methods_set_location
      set_location latitude: 55, longitude: -72, altitude: 33
    rescue Selenium::WebDriver::Error::UnknownError => e
      # on android this method is expected to raise with this message when running
      # on a regular device, or on genymotion.
      # error could be many messages, including:
      # ERROR running Appium command: port should be a number or string
      # ERROR running Appium command: port should be > 0 and < 65536
      raise unless e.message.include?('ERROR running Appium command: port should be')
    end

    # settings
    def test_18_methods_get_settings
      assert !get_settings.nil?
    end

    def test_19_methods_update_settings
      update_settings allowInvisibleElements: true
      assert_equal get_settings['allowInvisibleElements'], true
    end

    # Skip: x # x is only used in Pry
  end
end


================================================
FILE: android_tests/lib/android/specs/install.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# rake "android[install]"
class AndroidTest
  class Install < Minitest::Test
    # To Do: Blocked on https://github.com/appium/appium/issues/3032
    def pkg
      'io.appium.android.apis'
    end

    def installed
      assert_equal app_installed?(pkg), true
    end

    def not_installed
      assert_equal app_installed?(pkg), false
    end

    def test_install_uninstall
      installed
      remove_app 'io.appium.android.apis'
      not_installed
      install_app caps[:app]
      installed
    end

    # no way to launch apk after it's uninstalled/installed
    # blocked on: https://github.com/appium/appium/issues/2969
    # launch_app
  end
end


================================================
FILE: android_tests/lib/android/specs/sauce_labs.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# rake "android[sauce_labs]"
class AndroidTest
  class SauceLabs < Minitest::Test
    def test_sauce_settings
      opt = {}
      sauce_username = 'sauce_name'
      sauce_access_key = 'abcdefghijklmn'
      sauce_endpoint = 'ondemand.saucelabs.com:443/wd/hub'

      opt[:sauce_username] = sauce_username
      opt[:sauce_access_key] = sauce_access_key
      opt[:sauce_endpoint] = sauce_endpoint

      sauce = Appium::SauceLabs.new(opt)

      assert_equal sauce.username, sauce_username
      assert_equal sauce.access_key, sauce_access_key
      assert_equal sauce.endpoint, sauce_endpoint
      assert_equal sauce.sauce_server_url?, true
      assert_equal sauce.server_url, 'https://sauce_name:abcdefghijklmn@ondemand.saucelabs.com:443/wd/hub'
    end

    def test_no_sauce_settings
      opt = {}
      sauce = Appium::SauceLabs.new(opt)

      assert_equal sauce.sauce_server_url?, false
      assert_equal sauce.server_url, 'http://127.0.0.1:4723/wd/hub'
    end
  end
end


================================================
FILE: android_tests/lib/format.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# helper code useful for writing and verifying tests using Pry
list = <<-TXT
find
text
texts
name
names
scroll_to
TXT

list.split("\n").each do |method|
  puts "t '#{method}' do"
  puts
  puts 'end'
  puts
end

# --

# Format AndroidElementClassMap from
# https://github.com/appium/appium/blob/master/android/bootstrap/src/io/appium/android/bootstrap/AndroidElementClassMap.java
# for ruby_lib android/helper.rb tag_name_to_android
list = <<TXT
    map.put("abslist", "AbsListView");
    map.put("button", "Button");
TXT

list.split("\n").each do |method|
  pair  = method.match(/"([^"]+)"[^"]+"([^"]+)"/)
  tag   = pair[1]
  klass = pair[2]

  indent = 6
  puts "#{' ' * indent}when '#{tag}'"
  line2 = "#{' ' * (indent + 2)}prefix '#{klass}'"
  # button must translate to both button and image button
  # for ruby_lib to find all buttons
  line2.concat(", 'ImageButton'") if klass == 'Button'
  puts line2
end

# for Pry
# class Object
#   def must_equal b
#     raise 'not equal' unless self == b
#   end
# end


================================================
FILE: android_tests/lib/run.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require 'rubygems'
require 'minitest/autorun'
require 'minitest/reporters'
require 'minitest'
require 'hashdiff'
require_relative '../../lib/appium_lib'

Appium::Logger.level = ::Logger::ERROR # Show Logger logs only they are error

Minitest::Test.i_suck_and_my_tests_are_order_dependent!

begin
  Minitest::Reporters.use! [Minitest::Reporters::ProgressReporter.new]
rescue Errno::ENOENT
  # Ignore since Minitest::Reporters::JUnitReporter.new fails in deleting files, sometimes
end

# Run all Android tests:
#   ruby run.rb android

# Run only the view album test:
#   ruby run.rb ios view_album

def start_driver(caps)
  driver = Appium::Driver.new(caps, true)
  # Tests expect methods defined on the minispec object
  Appium.promote_appium_methods Minitest::Test, driver

  # Use bounded HTTP timeouts in tests to avoid CI hangs on stuck requests.
  open_timeout = Integer(ENV.fetch('APPIUM_TEST_OPEN_TIMEOUT', '120'))
  read_timeout = Integer(ENV.fetch('APPIUM_TEST_READ_TIMEOUT', '300'))

  driver.start_driver(open_timeout: open_timeout, read_timeout: read_timeout)
end

dir = File.expand_path(File.join(Dir.pwd, 'lib'))
appium_txt = File.join(Dir.pwd, 'appium.txt')
device = ARGV[0].downcase.strip
devices = %w(android ios)
raise 'Expected android or ios as first argument' unless devices.include? device

one_test = ARGV[1]
test_dir = "/#{device}/"

caps = Appium.load_settings file: appium_txt, verbose: true
caps = if caps[:appium_lib]
         appium_lib = caps[:appium_lib]
         appium_lib = appium_lib.merge(debug: true) unless appium_lib[:debug]
         appium_lib = appium_lib.merge(wait: 1) unless appium_lib[:wait]
         caps.merge(appium_lib: appium_lib)
       else
         caps.merge(appium_lib: { debug: true, wait: 1 })
       end

if ENV['LOCAL_PREBUILT_WDA']
  caps[:caps][:usePreinstalledWDA] = true
  caps[:caps][:prebuiltWDAPath] = ENV['LOCAL_PREBUILT_WDA']
end

trace_files = []

if one_test
  if File.exist? one_test
    one_test = File.expand_path one_test
  else
    # ensure ext is .rb
    one_test = File.join(File.dirname(one_test),
                         "#{File.basename(one_test, '.*')}.rb")
    one_test = File.join(dir, "#{test_dir}specs/#{one_test}")
  end

  raise "\nTest #{one_test} does not exist.\n" unless File.exist?(one_test)

  start_driver(caps)

  # Ruby 3.0 sorts the Dir.glob order
  # require support (common.rb)
  file_name = File.join dir, "#{test_dir}/*.rb"
  Dir.glob(file_name) do |test|
    require test
    trace_files << test
  end
  puts "Loading one test: #{one_test}"
  require one_test
  trace_files << one_test
else
  # require all
  file_names = File.join(dir, "#{test_dir}**/*.rb")
  Dir.glob(file_names) do |test|
    # load all tests
    trace_files << test
    puts "  #{File.basename(test, '.*')}"
    require test
  end

  start_driver(caps)
end

trace_files.map! do |f|
  f = File.expand_path f
  # ensure all traced files end in .rb
  f = File.join(File.dirname(f), "#{File.basename(f, '.*')}.rb")
  f
end

# Exit after tests.
Minitest.after_run { $driver&.x }


================================================
FILE: android_tests/readme.md
================================================
ruby_lib_android
=====================

ruby_lib's Android tests. Requires `Ruby 2.2+` or better.

- `rake install` Install gems required to run the tests.
- `rake android` Run all tests.
- `rake android['android/element/generic']` Run a single test.
- `arc` Opens the Appium Ruby Console (arc). Enables interactive testing.
  - `gem install appium_console` if it's not installed already.

api.apk is from [appium/android-apidemos](https://github.com/appium/android-apidemos)
The way to generate api.apk is described in the repository.

---

```ruby
Finished in 2 mins 57 secs

106 runs, 144 assertions, 0 failures, 0 errors, 0 skips
```

#### Coverage

- apk
    - [emma-build](https://github.com/appium/android-apidemos/blob/a20597cb97238bf43c073500444b9428fab53f50/README.md#emma-build-for-testing-code-coverage)
- `appium.txt`
    ```
    [caps]
    platformName = "android"
    deviceName = "Nexus 7"
    app = "../test_apps/api.apk"
    appPackage = "io.appium.android.apis"
    appActivity = "io.appium.android.apis.ApiDemos"
    some_capability = "some_capability"
    androidCoverage = 'io.appium.android.apis/io.appium.android.apis.app.LocalSampleInstrumentation'
    
    [appium_lib]
    sauce_username = ""
    sauce_access_key = ""
    ```


================================================
FILE: appium_lib.gemspec
================================================
require_relative 'lib/appium_lib/version'

Gem::Specification.new do |s|
  s.required_ruby_version = '>= 3.1'

  s.name          = 'appium_lib'
  s.version       = Appium::VERSION
  s.license       = 'Apache-2.0'
  s.description   = 'Ruby library for Appium.'
  s.summary       = 'Ruby library for Appium'
  s.authors       = ['code@bootstraponline.com', 'Kazuaki Matsuo']
  s.email         = %w(code@bootstraponline.com fly.49.89.over@gmail.com)
  s.homepage      = 'https://github.com/appium/ruby_lib' # published as appium_lib
  s.require_paths = ['lib']

  s.add_dependency 'appium_lib_core', '>= 9.2.1', '< 13.0'
  s.add_dependency 'nokogiri', '~> 1.8', '>= 1.8.1'
  s.add_dependency 'tomlrb', '>= 1.1', '< 3.0'

  s.files = `git ls-files`.split("\n").reject { |v| v.match(/\A^(ios_tests|android_tests|grid|test_apps)\/.+/) }
  s.metadata['rubygems_mfa_required'] = 'true'
end


================================================
FILE: contributing.md
================================================
# Contributing

For features or bug fixes, please submit a pull request. Ideally there would be a test as well. The remainder of this doc details how to run the tests.

If you'd like to adding new driver commands, please refer to https://github.com/appium/ruby_lib_core

## Tests

- Tests are run against [appium's master branch](https://github.com/appium/appium/blob/master/docs/en/contributing-to-appium/appium-from-source.md)
- The tests are run using the [flaky gem](https://github.com/appium/flaky) on OS X
- The `arc` command can be run from within the `ios_tests` or `android_tests` folder to open an interactive console

### Run iOS tests

iOS tests are run on the iPhone 6 / iOS 9.3 simulator.

- `cd ios_tests`
- `flake 3 ios` - Run all the iOS tests up to 3 times

### Run Android tests

Android tests require running on physical hardware with Android 5.0 (API 21). The emulator is unreliable.

- `cd android_tests`
- `flake 3 android` - Run all the Android tests up to 3 times

## Publishing

0. Ensure you have `~/.gem/credentials` If not run [the following command](http://guides.rubygems.org/make-your-own-gem/) (replace username with your rubygems user)
> $ curl -u username https://rubygems.org/api/v1/api_key.yaml >
~/.gem/credentials; chmod 0600 ~/.gem/credentials

1. Bump the version number: `thor bump` (`bumpy`, `bumpz`)
2. Update `CHANGELOG.md`
3. Generate release note, publish release gem and push the tag to this repository: `thor release`


================================================
FILE: docs/android_uiautomator.md
================================================
# Help debugging

- `adb shell uiautomator events` 
    - Prints out accessibility events to the console until the connection to the device is terminated
    - [URL](https://stuff.mit.edu/afs/sipb/project/android/docs/tools/help/uiautomator/index.html)
    - **notice**
        - If Appium is started then it terminates the other `uiautomator` processes

# uiautomator2
## difference between uiautomator1 and uiautomator2
- `find_element/s :id, "ids"`
    - uiautomator1
        - Find elements with `resource_id`
        - Find elements with string id resource(string.xml based)
    - uiautomator2
        - Find elements with `resource_id`
    - from: Does not appium-uiautomator2-server support finding string ids with "id" strategy? [issue](https://github.com/appium/appium/issues/8349)


================================================
FILE: docs/docs.md
================================================
# Documentation
## API Doc of Ruby Client
- This library: http://www.rubydoc.info/github/appium/ruby_lib
- Core: http://www.rubydoc.info/github/appium/ruby_lib_core
- [Ruby selenium-webdriver](https://github.com/SeleniumHQ/selenium/wiki/Ruby-Bindings)

### General
- [Appium](https://github.com/appium/appium/blob/master/README.md)
- [Supported platforms](https://github.com/appium/appium/blob/master/docs/en/about-appium/platform-support.md)
- [All methods supported by Appium](https://github.com/appium/appium-base-driver/blob/master/docs/mjsonwp/protocol-methods.md)
    - Fundamental Commands: http://appium.io/docs/en/commands/status/ etc
- [MiniTest Expectations](http://docs.seattlerb.org/minitest/Minitest/Expectations.html)

### Driver types in Ruby Client

```ruby
# Appium specific driver with helpers available extending Standard Appium Driver.
@appium_driver = Appium::Driver.new @options, false

# Standard Appium Driver extends Selenium WebDriver.
@selenium_driver = @appium_driver.start_driver
```

### Example

Example of automating the built in Android settings.

```ruby
# run Pry, and paste the following
apk = { 
        platformName: 'android',
        deviceName: :nexus,
        appPackage: 'com.android.settings',
        appActivity: '.Settings',
        appWaitActivity: '.Settings'
      }
Appium::Driver.new({caps: apk}, false).start_driver
```

Example use of Appium's mobile gesture.


Long click on an ImageView in Android.

```
last_image = find_elements(:class, 'ImageView').last
long_press(element: last_image)
```

Rotate examples. The behaviour is depends on devices.

```ruby
driver.rotate :landscape
driver.rotate :portrait
```

- `appium_server_version` Discover the Appium rev running on the server.
- `element.send_keys "msg"` Sends keys to currently active element


### APIs

```ruby
e.name # button, text
e.value # secure, textfield
e.type 'some text' # type text into textfield
e.clear # clear textfield
e.tag_name # calls .type (patch.rb)
e.text
e.size
e.location
e.location_rel
e.click
e.send_keys 'keys to send'
e.displayed? # true or false depending if the element is visible
e.selected? # is the tab selected?
e.attribute('checked') # is the checkbox checked?


# alert example without helper methods
alert = @driver.switch_to.alert
alert.text
alert.accept
alert.dismiss

# Secure textfield example.
#
# Find using default value
s = textfield 'Password'
# Enter password
s.send_keys 'hello'
# Check value
s.value == ios_password('hello'.length)
```

--

#### Driver
- `start_driver` will restart the driver.
- `x` will quit the driver and exit Pry.
- `execute_script` calls `@driver.execute_script`
- `find_element` calls `@driver.find_element`
- `find_elements` calls `@driver.find_elements`
- `no_wait` will set implicit wait to 0. `@driver.manage.timeouts.implicit_wait = 0`
- `set_wait` will set implicit wait to default seconds. `@driver.manage.timeouts.implicit_wait = default`
- `set_wait(timeout_seconds)` will set implicit wait to desired timeout. `@driver.manage.timeouts.implicit_wait = timeout`
- `.click` to tap an element.
- `.send_keys` or `.type` to type on an element.

#### Cucumber Sauce Integration

Reset after each test and when done report the result to Sauce after quiting the driver.

```ruby
require 'rest_client' # https://github.com/archiloque/rest-client
require 'json' # for .to_json
require 'sauce_whisk'

After do |scenario|
  # end the test session, ignoring any exceptions.
  ignore { $driver.driver_quit }
  
  user   = ENV['SAUCE_USERNAME']
  key    = ENV['SAUCE_ACCESS_KEY']
  if user && !user.empty? && key && !key.empty?
    passed = ! scenario.failed?
    SauceWhisk::Jobs.change_status $driver.driver.session_id, passed
  end
end
```


================================================
FILE: docs/ios_xcuitest.md
================================================
## XCUITest
- Over Appium1.6.0 provides `XCUITest` automation name based on WebDriverAgent.
    - [appium-xcuitest-driver](https://github.com/appium/appium-xcuitest-driver)
    - [WebDriverAgent](https://github.com/facebook/WebDriverAgent)
- How to migrate XCUITest from UIAutomation
    - [Migrating your iOS tests from UIAutomation](https://github.com/appium/appium/blob/v1.6.2/docs/en/advanced-concepts/migrating-to-xcuitest.md)
- Mobile gestures for XCUITest
    - [ios-xctest-mobile-gestures](https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/ios/ios-xctest-mobile-gestures.md)
    - Required Appium1.6.4+

## find elements
- supported elements by find_element are:
    - [appium-xcuitest-driver](https://github.com/appium/appium-xcuitest-driver/blob/master/lib/commands/find.js#L17)
        - [locatorStrategies](https://github.com/appium/appium-xcuitest-driver/blob/95886f1118d71fe950768f8262179d3608b40fc7/lib/driver.js#L81)
    - [WebDriverAgent](https://github.com/facebook/WebDriverAgent/blob/8346199212bffceab24192e81bc0118d65132466/WebDriverAgentLib/Commands/FBFindElementCommands.m#L111)
- Mapping
    - https://github.com/facebook/WebDriverAgent/blob/master/WebDriverAgentLib/Utilities/FBElementTypeTransformer.m#L19

### with except for XPath and Predicate
#### examples
- [button_class](https://github.com/appium/ruby_lib/blob/master/lib/appium_lib/ios/element/button.rb#L8), [static_text_class](https://github.com/appium/ruby_lib/blob/master/lib/appium_lib/ios/element/text.rb#L8), [text_field_class](https://github.com/appium/ruby_lib/blob/master/lib/appium_lib/ios/element/textfield.rb#L10) and [secure_text_field_class](https://github.com/appium/ruby_lib/blob/master/lib/appium_lib/ios/element/textfield.rb#L15) provide class name.
    - If `automationName` is `Appium` or `nil`, then they provide `UIAxxxx`
    - If `automationName` is `XCUITest`, then they provide `XCUIElementTypexxx`

```ruby
find_element(:class, button_class) # Return a element of XCUIElementTypeButton for XCUITest
```

- [tag/s](https://github.com/appium/ruby_lib/blob/ac03116756a72fbd624fa32ea886123b955d7089/lib/appium_lib/android/helper.rb#L238) is alias of `find_element :class, element`

- `accessibility_id`

```ruby
find_element(:accessibility_id, element) # Return a element which has accessibilityIdentifier, `element`.
```

- `button/s(value)`, `button_exact/buttons_exact`, `text/s(value)`, `text_exact/texts_exact` 
```ruby
buttons(value) # Return button elements include `value` as its name attributes.
```

### with Predicate
- We recommend to use predicate strategy instead of XPath strategy.
    - e.g. `find_ele_by_predicate/find_eles_by_predicate`,  `find_ele_by_predicate_include/find_eles_by_predicate_include`
- A helpful cheatsheet for predicate
    - https://realm.io/news/nspredicate-cheatsheet/
- For XCUITest(WebDriverAgent), without 'wd' prefixes are supported.
    - https://github.com/facebook/WebDriverAgent/wiki/Queries
    - For example, `%(name ==[c] "#{value}" || label ==[c] "#{value}" || value ==[c] "#{value}")` is equal to `%(wdName ==[c] "#{value}" || wdLabel ==[c] "#{value}" || wdValue ==[c] "#{value}")` in WebDriverAgent.

#### examples
- `textfield/s(value)`, `find/s`, `find_exact/finds_exact`, `find_ele_by_predicate/find_eles_by_predicate` and `find_ele_by_predicate_include/find_eles_by_predicate_include` use predicate strategy in their method.

```ruby
textfield(value) # Return a XCUIElementTypeSecureTextField or XCUIElementTypeTextField element which has `value` text.
finds_exact(value) # Return any elements include `value` as its name attributes.
```

### with Class Chain
- require Appium 1.6.4+
    - https://github.com/appium/appium-xcuitest-driver/pull/391
    - https://github.com/appium/java-client/pull/599/files
- WebDriverAgent
    - https://github.com/facebook/WebDriverAgent/wiki/Queries

### with XPath
- It is better to avoid XPath strategy.
    - https://github.com/appium/appium/blob/v1.6.2/docs/en/advanced-concepts/migrating-to-xcuitest.md#xpath-locator-strategy
        - > Try not to use XPath locators unless there are absolutely no other alternatives. In general, XPath locators might be times slower, than other types of locators like accessibility id, class name and predicate (up to 100 times slower in some special cases). They are so slow because XPath location is not natively supported by Apple's XCTest framework.
    - Improved performance a bit
        - https://github.com/appium/appium/issues/6842
        - https://github.com/facebook/WebDriverAgent/issues/306
- XPath in WebDriverAgent
    - https://github.com/facebook/WebDriverAgent/blob/2158a8d0f305549532f1338fe1e4628cfbd53cd9/WebDriverAgentLib/Categories/XCElementSnapshot%2BFBHelpers.m#L57

#### examples

```ruby
xpaths("//some xpaths")
```

## Gesture
- `mobile:` commands are provided by WDA.
- Documentations
    - https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/ios/ios-xctest-mobile-gestures.md
- Specs by test code
    - https://github.com/appium/appium-xcuitest-driver/blob/master/test/functional/basic/gesture-e2e-specs.js

### Workaround
- `mobile:` commands depends on WDA and Apple's framework and the behaviour depends on them.
- Sometimes issues occur such as "doubleTap isn't tapping #548"
    - workaround for it:
        - with `selenium-webdriver >= 3.4.0`
            ```ruby
            def double_tap(element)
              rect = element.rect
              execute_script 'mobile: doubleTap', x: rect.x + rect.width / 2, y: rect.y + rect.height / 2
            end
            ```        
        - with `selenium-webdriver < 3.4.0`
            ```ruby
              def double_tap(element)
                size = element.size
                location = element.location
                execute_script 'mobile: doubleTap', x: location.x + size.width / 2, y: location.y + size.height / 2
              end
            ```

## Other actions
Basically, other actions such as `type` are compatible with `automationName = Appium`.

## Pasteboard
- Simulator only
    - https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/ios-xctest-pasteboard.md


================================================
FILE: docs/parallel.md
================================================
Appium 1.7.0+ supports single server and multiple sessions, and it requires Xcode 9 for iOS.

# Example
## Run tests on Multiple Simulators with Xcode 9
- https://github.com/appium/appium-xcuitest-driver/tree/master/test/functional/parallel
- https://github.com/appium/ruby_lib/tree/master/ios_tests/parallel
    - Thread programming: TestParallelRunThread
    - Process programming: TestParallelRunProcess


================================================
FILE: docs/w3c.md
================================================
Perform touch actions for W3C module. Generate `touch` pointer action here and users can use this via `driver.action`

[Documentation](http://www.rubydoc.info/github/appium/ruby_lib_core/Appium%2FCore%2FBase%2FCoreBridgeW3C:action)

# Example

```ruby
dialect #=> :w3c

# then
el = find_element(:name, 'Pickers')
driver.action.click(el).perform #=> work


# Scroll/Swipe
driver.action
      .move_to_location(500, 500).pointer_down(:left)
      .move_to_location(0, 700)
      .release.perform


# Zoom in
# multiple action chains
f1 = driver.action.add_pointer_input(:touch, 'finger1')
f1.create_pointer_move(duration: 1, x: 200, y: 500,
                   origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)
f1.create_pointer_down(:left)
f1.create_pause(0.5)
f1.create_pointer_move(duration: 1, x: 200, y: 200,
                   origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)
f1.create_pointer_up(:left)

f2 = driver.action.add_pointer_input(:touch, 'finger2')
f2.create_pointer_move(duration: 1, x: 200, y: 500,
                   origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)
f2.create_pointer_down(:left)
f2.create_pause(0.5)
f2.create_pointer_move(duration: 1, x: 200, y: 800,
                   origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)
f2.create_pointer_up(:left)

driver.perform_actions [f1, f2]
```

# Note
## Coordinate points
- jsonwp
    - Relative action coordinates are counted relatively to the **top left point** of element's rectangle
- W3C
    - Relative action coordinates are counted relatively to the **center** of element's rectangle

## Limitations
- WebDriverAgent support only `touch` as a `pointer type`.
    - By default, [ruby_lib_core](https://github.com/appium/ruby_lib_core/blob/ab5d7c5ed31f318a9395e5aeafe1d0d655d3cff4/lib/appium_lib_core/common/base/w3c_bridge.rb#L26) generate `touch` based actions.
    - About `pointer type` => [W3C](https://www.w3.org/TR/webdriver/#perform-actions) and [Simple WD Spec](https://github.com/jlipps/simple-wd-spec#perform-actions)


================================================
FILE: grid/README.md
================================================
# Run Grid

```bash
$ java -jar selenium-server-standalone-2.53.1.jar -role hub -hubConfig hub_config.json
```

**note**
Selenium Grid 3.4.0 is failed to establish sessions: 

# Run Appium

```bash
$ node . --nodeconfig ~/GitHub/ruby_lib/grid/config.json

# or

$ appium --nodeconfig ~/GitHub/ruby_lib/grid/config.json
```

# Run Ruby Script

```bash
$ rake ios # for example
```


================================================
FILE: grid/appium.txt.ios.example
================================================
[caps]
platformName = "ios"
platformVersion = "11.4"
deviceName ="iPhone 11"
automationName = 'XCUITest'
app = "/absolute/path/to/UICatalog.app.zip"
some_capability = "some_capability"

[appium_lib]
server_url = "http://localhost:4444/wd/hub"
sauce_username = ""
sauce_access_key = ""
sauce_endpoint = ""
wait = 30
wait_timeout = 20
wait_interval = 1


================================================
FILE: grid/config.json
================================================
{
  "capabilities":
  [
    {
      "browserName": "iPhone 11",
      "version":"11.4",
      "platform":"ios",
      "maxInstances": 1
    }
  ],
  "configuration":
  {
    "cleanUpCycle": 2000,
    "timeout": 60000,
    "proxy": "org.openqa.grid.selenium.proxy.DefaultRemoteProxy",
    "url": "http://localhost:4723",
    "host": "localhost",
    "port": 4723,
    "maxSession": 1,
    "register": true,
    "registerCycle": 5000,
    "hubPort": 4444,
    "hubHost": "localhost"
  }
}


================================================
FILE: grid/hub_config.json
================================================
{
  "port": 4444,
  "newSessionWaitTimeout": -1,
  "servlets" : [],
  "withoutServlets": [],
  "custom": {},
  "capabilityMatcher": "org.openqa.grid.internal.utils.DefaultCapabilityMatcher",
  "throwOnCapabilityNotPresent": true,
  "cleanUpCycle": 5000,
  "role": "hub",
  "debug": false,
  "browserTimeout": 0,
  "timeout": 1800
}


================================================
FILE: grid/hub_config_3.json
================================================
{
  "capabilities":
  [
    {
      "browserName": "iPhone 11",
      "version":"11.4",
      "maxInstances": 1,
      "seleniumProtocol": "WebDriver"
    }
  ],
  "proxy": "org.openqa.grid.selenium.proxy.DefaultRemoteProxy",
  "maxSession": 5,
  "port": 4444,
  "register": true,
  "registerCycle": 5000,
  "hub": "http://localhost:4444",
  "nodeStatusCheckTimeout": 5000,
  "nodePolling": 5000,
  "role": "hub",
  "unregisterIfStillDownAfter": 60000,
  "downPollingLimit": 2,
  "debug": true,
  "servlets" : [],
  "withoutServlets": [],
  "custom": {}
}


================================================
FILE: ios_tests/Gemfile
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

source 'https://rubygems.org'
eval_gemfile File.join(File.expand_path('..', __dir__), 'Gemfile')

gem 'parallel_tests'


================================================
FILE: ios_tests/LICENSE-2.0.txt
================================================

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: ios_tests/Rakefile
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require 'rubygems'
require 'rake'
require 'rubocop/rake_task'

task default: :ios

# Run sh and ignore exception
def run_sh(cmd)
  sh cmd
rescue StandardError
  # Ignored
end

# Run cmd. On failure run install and try again.
def bash(cmd)
  sh cmd do |successful, result|
    # exitstatus 7 means bundle install failed
    # non-zero (except 7 retry path) means the test failed
    if !successful && result.exitstatus == 7
      Rake::Task['install'].execute
      sh cmd
    elsif !successful
      raise "Command failed with status #{result.exitstatus}: #{cmd}"
    end
  end
end

# Run a single test with:
# rake ios['ios/element/generic']
#
# rake ios['driver']
#
# Run all tests with:
# rake ios
desc 'Run the iOS tests'
task :ios, :args, :test_file do |_args, test_file|
  # rake android['ok']
  # args = android
  # test_file = {:args=>"ok"}
  test_file = test_file[:args]
  cmd = 'bundle exec ruby ./lib/run.rb ios'
  cmd = %(#{cmd} "#{test_file}") if test_file
  bash cmd
end

desc 'Run bundle install'
task :install do
  sh 'bundle install'
end

desc 'Execute RuboCop static code analysis'
RuboCop::RakeTask.new(:rubocop) do |t|
  t.patterns = %w(**/*.rb)
  t.options = %w(-D)
  t.fail_on_error = false
end

class Device
  def self.one
    {
      automationName: 'xcuitest',
      platformName: 'ios',
      platformVersion: '11.0',
      deviceName: 'iPhone 6',
      app: "#{Dir.pwd}/../test_apps/UICatalog.app.zip",
      wdaLocalPort: 8100,
      isCommandsQueueEnabled: false
    }
  end

  def self.two
    {
      automationName: 'xcuitest',
      platformName: 'ios',
      platformVersion: '11.0',
      deviceName: 'iPhone 6s',
      app: "#{Dir.pwd}/../test_apps/UICatalog.app.zip",
      wdaLocalPort: 8200,
      isCommandsQueueEnabled: false
    }
  end
end

desc 'Run tests with parallel thread'
task :run_parallel_t do
  require_relative 'parallel/test'

  threads = []
  [Device.one, Device.two].map do |capability|
    threads << Thread.new do
      TestParallelRunThread.new(capability).test_run
    end
  end

  threads.each(&:join)
end

desc 'Run tests with parallel processes'
task :run_parallel_p do
  require_relative 'parallel/test'

  [Device.one, Device.two].each do |capability|
    fork do
      TestParallelRunProcess.new(capability).test_run
    end
  end

  Process.waitall
end


================================================
FILE: ios_tests/appium.txt
================================================
[caps]
platformName = "ios"
platformVersion = "18.5"
deviceName ="iPhone 16 Plus"
automationName = 'XCUITest'
app = "../test_apps/UICatalog.app.zip"
someCapability = "some_capability"
simulatorStartupTimeout = 600000
wdaLaunchTimeout = 600000

[appium_lib]
wait = 30
wait_timeout = 20
wait_interval = 1


================================================
FILE: ios_tests/data/unicode.txt
================================================
®

================================================
FILE: ios_tests/flaky.txt
================================================
ios = "lib/ios/specs/"

================================================
FILE: ios_tests/lib/common.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# common methods
def back_click
  back
end

def leave_textfields
  back_click
  assert screen == catalog
end

def go_to_textfields
  assert screen == catalog
  wait_true do
    find_element(:name, 'Text Fields').click
    screen == 'Text Fields' # wait for screen transition
  end
end

def screen
  $driver.find_element(:class, ui_ios.navbar).name
end

def catalog
  'UICatalog'
end

def target_bundle_id
  'com.example.apple-samplecode.UICatalog'
end

def ui_ios
  UI.new($driver)
end

class UI
  def initialize(driver)
    @driver = driver
  end

  def navbar
    'XCUIElementTypeNavigationBar'
  end

  def button
    'XCUIElementTypeButton'
  end

  def static_text
    'XCUIElementTypeStaticText'
  end

  def text_field
    'XCUIElementTypeTextField'
  end

  def secure_text_field
    'XCUIElementTypeSecureTextField'
  end

  def picker
    'XCUIElementTypePicker'
  end

  def picker_wheel
    'XCUIElementTypePickerWheel'
  end

  def action_sheet
    'XCUIElementTypeActionSheet'
  end

  def table
    'XCUIElementTypeTable'
  end

  def table_cell
    'XCUIElementTypeCell'
  end

  def other
    'XCUIElementTypeOther'
  end

  def status_bar
    'XCUIElementTypeStatusBar'
  end
end


================================================
FILE: ios_tests/lib/format.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# helper code useful for writing and verifying tests using Pry
list = <<TXT
alert_click
alert_text
alert_accept
alert_accept_text
alert_dismiss
alert_dismiss_text
TXT

list.split("\n").each do |method|
  puts "t '#{method}' do"
  puts
  puts 'end'
  puts
end

# for Pry
# class Object
#   def must_equal b
#     raise 'not equal' unless self == b
#   end
# end


================================================
FILE: ios_tests/lib/ios/specs/common/element/window.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# rake "ios[common/element/window]"

class IosTest
  class Common
    class Element
      class Window < Minitest::Test
        def before_first
          driver.terminate_app target_bundle_id
          driver.activate_app target_bundle_id
          assert_equal screen, catalog
        end

        def test_01_before_first
          before_first
        end

        def test_02_window_size
          size = window_size
          assert_equal  size.width.class, Integer
          assert_equal  size.height.class, Integer
        end
      end
    end
  end
end


================================================
FILE: ios_tests/lib/ios/specs/common/helper.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# rake "ios[common/helper]"
class IosTest
  class Common
    class Helper < Minitest::Test
      def setup
        @wait_opts = { timeout: 0.2, interval: 0.2 } # max_wait, interval
      end

      def test_01_before_first
        driver.terminate_app target_bundle_id
        driver.activate_app target_bundle_id
        assert_equal screen, catalog
      end

      # There's no `must_not_raise` as the opposite of must_raise
      #
      # By default code is expected to not raise exceptions.
      # must_not_raise is a no-op.

      # wait is a success unless an error is raised
      # max_wait=0 is infinity to use 0.1
      def test_02_wait
        # successful wait should not raise error
        wait(@wait_opts) { true }
        wait(@wait_opts) { false }
        wait(@wait_opts) { nil }

        # failed wait should error
        assert_raises ::Appium::Core::Wait::TimeoutError do
          wait(@wait_opts) { raise }
        end

        # regular rescue will not handle exceptions outside of StandardError hierarchy
        # must rescue Exception explicitly to rescue everything
        assert_raises ::Appium::Core::Wait::TimeoutError do
          wait(@wait_opts) { raise NoMemoryError }
        end

        assert_raises ::Appium::Core::Wait::TimeoutError do
          wait(timeout: 0.2, interval: 0.0) { raise NoMemoryError }
        end
        e = assert_raises ArgumentError do
          wait(invalidkey: 2) { true }
        end
        assert_equal 'unknown keyword: :invalidkey', e.message
      end

      def test_03_ignore
        # ignore should rescue all exceptions
        ignore { true }
        ignore { false }
        ignore { nil }
        ignore { raise }
        ignore { raise NoMemoryError }
      end

      # wait_true is a success unless the value is not true
      def test_04_wait_true
        # successful wait should not error
        wait_true(@wait_opts) { true }

        # failed wait should error
        assert_raises ::Appium::Core::Wait::TimeoutError do
          wait_true(@wait_opts) { false }
        end
        assert_raises ::Appium::Core::Wait::TimeoutError do
          wait_true(@wait_opts) { nil }
        end

        # raise should error
        assert_raises ::Appium::Core::Wait::TimeoutError do
          wait_true(@wait_opts) { raise }
        end

        # regular rescue will not handle exceptions outside of StandardError hierarchy
        # must rescue Exception explicitly to rescue everything
        assert_raises ::Appium::Core::Wait::TimeoutError do
          wait_true(@wait_opts) { raise NoMemoryError }
        end
        assert_raises ::Appium::Core::Wait::TimeoutError do
          wait_true(timeout: 0.2, interval: 0.0) { raise NoMemoryError }
        end

        e = assert_raises ArgumentError do
          wait_true(invalidkey: 2) { true }
        end
        assert_equal 'unknown keyword: :invalidkey', e.message
      end

      def test_06_back
        # start page
        assert_equal tag(ui_ios.navbar).name, 'UICatalog'
        # nav to new page.
        wait_true do
          text('buttons').click
          tag(ui_ios.navbar).name == 'Buttons'
        end

        assert_equal tag(ui_ios.navbar).name, 'Buttons'
        # go back
        back_click
        # start page
        assert_equal tag(ui_ios.navbar).name, 'UICatalog'
      end

      def test_07_session_id
        # Sauce doesn't return '-' so make them optional.
        assert_match(/\h{8}-?\h{4}-?\h{4}-?\h{4}-?\h{12}/, session_id)
      end

      def test_08_xpath
        assert_equal xpath("//#{ui_ios.static_text}").name, 'UICatalog'
      end

      def test_09_xpaths
        assert_equal xpaths("//#{ui_ios.static_text}").length, 35
      end

      def uibutton_text
        'Buttons'
      end

      def action_sheets
        'Action Sheets'
      end

      def test_10_ele_index
        assert_equal ele_index(ui_ios.static_text, 2).name, action_sheets
      end

      # TODO: 'string_attr_exact'

      def test_11_find_ele_by_attr
        el_id = find_ele_by_attr(ui_ios.static_text, 'name', uibutton_text).instance_variable_get :@id
        assert_match(/\d+/, el_id)
      end

      def test_12_find_eles_by_attr
        # '!' clears the input buffer in Pry so make sure there's
        # no space after the !
        set_wait 1
        # empty array returned when no match
        found = !find_eles_by_attr(ui_ios.static_text, 'name', uibutton_text).empty?
        assert_equal found, true

        found = !find_eles_by_attr(ui_ios.static_text, 'name', 'zz').empty?
        assert_equal found, false
        set_wait
      end

      def test_13_find_ele_by_predicate
        el_text = find_ele_by_predicate(value: uibutton_text).text
        assert_equal el_text, uibutton_text

        el_name = find_ele_by_predicate(value: uibutton_text).name
        assert_equal el_name, uibutton_text
      end

      def test_14_find_eles_by_predicate
        ele_count = find_eles_by_predicate(value: uibutton_text).length
        assert_equal ele_count, 1

        ele_count = find_eles_by_predicate(value: 'zz').length
        assert_equal ele_count, 0
      end

      # TODO: 'string_attr_include'

      def test_15_find_ele_by_attr_include
        el_text = find_ele_by_attr_include(ui_ios.static_text, :name, 'button').text
        assert_equal el_text, uibutton_text

        el_name = find_ele_by_attr_include(ui_ios.static_text, :name, 'button').name
        assert_equal el_name, uibutton_text
      end

      def test_16_find_eles_by_attr_include
        ele_count = find_eles_by_attr_include(ui_ios.static_text, :name, 'e').length
        assert_equal ele_count, 31
      end

      def test_17_find_ele_by_predicate_include
        el_text = find_ele_by_predicate_include(value: 'button').text
        assert_equal el_text, uibutton_text

        el_name = find_ele_by_predicate_include(value: 'button').name
        assert_equal el_name, uibutton_text
      end

      def test_18_find_eles_by_predicate_include
        assert_equal find_eles_by_predicate_include(value: 'e').length, 51
      end

      def test_19_first_ele
        assert_equal first_ele(ui_ios.static_text).name, 'UICatalog'
      end

      def test_20_last_ele
        expected = 'Steppers'

        el = last_ele(ui_ios.static_text)
        assert_equal el.text, expected
        assert_equal el.name, expected
      end

      # t 'source' do # tested by get_source

      def test_21_get_source
        assert_equal get_source.class, String
      end

      def test_22_invalid_id_should_error
        assert_raises Selenium::WebDriver::Error::NoSuchElementError do
          id 'does not exist'
        end

        assert_raises Selenium::WebDriver::Error::NoSuchElementError do
          id 'android:id/text1'
        end
      end

      def test_23_tag
        assert_equal tag(ui_ios.navbar).name, 'UICatalog'
      end

      def test_24_tags
        assert_equal tags(ui_ios.table_cell).length, 12
      end

      def test_25_find_eles_by_attr_include_length
        assert_equal find_eles_by_attr_include(ui_ios.static_text, 'name', 'AAPL').length, 16
      end

      def test_26_get_page_class
        act = get_page_class

        assert(act.split("\n").length >= 7)
        assert_includes act, '25x XCUIElementTypeOther'
        assert_includes act, '24x XCUIElementTypeStaticText'
        assert_includes act, '12x XCUIElementTypeCell'
        assert_includes act, '1x XCUIElementTypeTable'
        assert_includes act, '1x XCUIElementTypeNavigationBar'
        assert_includes act, '1x XCUIElementTypeWindow'
        assert_includes act, '1x XCUIElementTypeApplication'
      end

      # TODO: write tests
      # page_class
      # px_to_window_rel
      # lazy_load_strings
      # xml_keys
      # xml_values
      # resolve_id
      # string_visible_contains
      # xpath_visible_contains
      # xpaths_visible_contains
      # string_visible_exact
      # xpath_visible_exact
      # xpaths_visible_exact
      # raise_no_element_error
    end
  end
end


================================================
FILE: ios_tests/lib/ios/specs/common/patch.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

#  Skip:
#    status # status patches are already tested in driver.rb
#    execute # debug output for Pry
#

# bundle exec rake "ios[common/patch]"
class IosTest
  class Common
    class Patch < Minitest::Test
      def test_01_before_first
        driver.terminate_app target_bundle_id
        driver.activate_app target_bundle_id
        assert_equal screen, catalog
      end

      def test_02_appium_core_element_method_name
        assert_equal first_text.name, 'UICatalog'
      end

      def test_03_appium_core_element_method_location_rel
        loc = first_text.location_rel($driver)
        assert_equal loc.x.class, String
        assert_equal loc.y.class, String
      end
    end
  end
end


================================================
FILE: ios_tests/lib/ios/specs/common/version.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

class IosTest
  class Common
    class Version < Minitest::Test
      def test_01_before_first
        assert_equal screen, catalog
      end

      def test_02_appium_version
        assert_match(/(\d+)\.(\d+).(\d+)/, ::Appium::VERSION)
      end

      def test_03_appium_date
        assert_match(/(\d+)-(\d+)-(\d+)/, ::Appium::DATE)
      end
    end
  end
end


================================================
FILE: ios_tests/lib/ios/specs/common/web_context.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Tests specifically for areas where the web_context differs in behaviour
# rake "ios[common/web_context]"

class IosTest
  class Common
    class WebContext < Minitest::Test
      def test_01_before_first
        driver.terminate_app target_bundle_id
        driver.activate_app target_bundle_id
        assert_equal screen, catalog
      end

      def test_02_get_ios_inspect
        find_eles_by_predicate_include(value: 'Web').first.click

        wait_true { available_contexts.size >= 2 }
        web_view_context = available_contexts.find { |c| c.start_with? 'WEBVIEW' } # Get WEBVIEW_59153.1 for example.

        set_context web_view_context
        assert_equal current_context, web_view_context
        sleep 1 # Give a chance to load
        assert_equal page.start_with?("\nhtml\n"), true
      end

      def test_03_xcuitest_get_contexts
        context = xcuitest_get_contexts
        assert_equal({ 'id' => 'NATIVE_APP' }, context.first)
        assert context[1]['id'].include?('WEBVIEW_')
      end

      def test_04_after_last
        set_context 'NATIVE_APP'
        back_click
      end
    end
  end
end


================================================
FILE: ios_tests/lib/ios/specs/device/device.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# $ rake "ios[device/device]"

class IosTest
  class Device
    class Device < Minitest::Test
      # go back to the main page
      def go_back
        back
        wait { find_ele_by_predicate_include(class_name: ui_ios.navbar, value: 'UICatalog') }
      end

      def test_01_before_first
        driver.terminate_app target_bundle_id
        driver.activate_app target_bundle_id
        assert_equal screen, catalog
      end

      def test_02_app_installed
        installed = app_installed? 'Derrp'
        assert_equal installed, false
      end

      def test_03_background_app_homescreen
        bundle_id = 'com.example.apple-samplecode.UICatalog'

        background_app(-1) # background_app(nil) should work as same.

        # The app goes to background and never come back
        wait do
          assert_equal driver.app_state(bundle_id), :running_in_background_suspended
        end

        driver.activate_app bundle_id
      end

      def test_04_app_strings
        assert_includes app_strings, 'A Short Title Is Best'
        assert_includes app_strings('en'), 'A Short Title Is Best'
      end

      def test_05_action_chain
        element = text('Buttons')
        one_finger_tap x: 0, y: 0, element: element

        wait { button 'UICatalog' } # successfully transitioned to buttons page
        go_back
      end

      def test_06_swipe
        action.move_to_location(75, 500).pointer_down(:left)
              .move_to_location(75, 20).release.perform
      end
    end
  end
end


================================================
FILE: ios_tests/lib/ios/specs/device/image_comparison.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# $ rake ios[device/image_comparison]

class IosTest
  class Device
    class ImageComparison < Minitest::Test
      def test_image_comparison
        image1 = File.read './data/test_normal.png'
        image2 = File.read './data/test_has_blue.png'

        # Equal to `$driver.driver.find_image_occurrence`
        # Equal to `driver.find_image_occurrence`
        find_result = find_image_occurrence full_image: image1, partial_image: image2
        rect = find_result['rect']
        assert_equal({ 'x' => 0, 'y' => 0, 'width' => 750, 'height' => 1334 }, rect)
      end
    end
  end
end


================================================
FILE: ios_tests/lib/ios/specs/driver.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# bundle exec rake "ios[driver]"
class IosTest
  class Driver < Minitest::Test
    def test_01_before_first
      driver.terminate_app target_bundle_id
      driver.activate_app target_bundle_id
      assert_equal screen, catalog
    end

    def test_02_unicode_defaults
      data = File.read File.expand_path('../../../data/unicode.txt', __dir__)
      assert_equal data.strip, 174.chr('UTF-8')
    end

    def test_03_load_settings
      appium_txt = File.join(Dir.pwd, 'appium.txt')
      opts       = Appium.load_settings file: appium_txt, verbose: true

      actual   = ''
      actual   = File.basename opts[:caps][:app] if opts && opts[:caps]
      expected = 'UICatalog.app.zip'
      assert_equal expected, actual
    end

    def test_04_verify_all_attributes
      actual                = driver_attributes
      caps_app_for_teardown = actual[:caps][:app]
      expected_app = File.absolute_path('../test_apps/UICatalog.app.zip')

      # actual[:caps].to_json send to Appium server
      caps_with_json = JSON.parse(actual[:caps].to_json)
      assert_equal caps_with_json['platformName'], 'ios'
      assert !caps_with_json['platformVersion'].nil?
      assert_equal caps_with_json['app'], expected_app
      assert_equal caps_with_json['automationName'], 'XCUITest'
      assert !caps_with_json['deviceName'].nil?
      assert_equal caps_with_json['someCapability'], 'some_capability'

      assert_equal actual[:caps][:platformName], 'ios'
      assert !actual[:caps][:platformVersion].nil?
      assert_equal actual[:caps][:app], expected_app
      assert_equal actual[:caps][:automationName], 'XCUITest'
      assert !actual[:caps][:deviceName].nil?
      assert_equal actual[:caps][:someCapability], 'some_capability'

      actual_selenium_caps = actual[:caps][:automationName]
      assert_equal actual_selenium_caps, 'XCUITest'
      actual[:caps][:app] = caps_app_for_teardown
    end

    def test_05_verify_attributes_are_immutable
      assert_equal driver_attributes[:custom_url], 'http://127.0.0.1:4723'
      driver_attributes[:custom_url] = true
      assert_equal driver_attributes[:custom_url], 'http://127.0.0.1:4723'
    end

    def test_06_verify_attribute_of_caps_are_not_immutable_because_it_depends_on_selenium
      # immutability depends on Selenium
      for_clean_up                   = driver_attributes[:caps][:app].dup
      driver_attributes[:caps][:app] = 'fake'
      expected                       = 'fake'
      assert_equal driver_attributes[:caps][:app], expected

      # clean up
      driver_attributes[:caps][:app] = for_clean_up
    end

    def test_07_no_wait
      no_wait
      assert_raises Selenium::WebDriver::Error::NoSuchElementError do
        find_element(:accessibility_id, 'zz')
      end
      set_wait
    end

    def test_08_app_path_attr
      apk_name = File.basename driver_attributes[:caps][:app]
      assert_equal apk_name, 'UICatalog.app.zip'
    end

    def test_09_driver_class
      assert_equal $driver.class, Appium::Driver
    end

    def test_10_status
      assert appium_server_version['build'].keys.member?('version')
    end

    def test_11_server_version
      server_version = appium_server_version['build']['version']
      assert_match(/(\d+)\.(\d+).(\d+)/, server_version)
    end

    def test_12_client_version
      client_version = appium_client_version
      expected = { version: ::Appium::VERSION }
      assert_equal client_version, expected
    end

    def test_13_restart
      restart
      text 'buttons'
    end

    def test_14_driver
      assert driver.browser.empty?
    end

    def test_15_automation_name_is_xcuitest?
      assert_equal automation_name_is_xcuitest?, true
    end

    #
    # Skip:
    #    screenshot   # this is slow and already tested by Appium
    #    driver_quit  # tested by restart
    #    start_driver # tested by restart
    #

    def test_16_set_wait
      # fill the @last_waits array with: [30, 30]
      assert_equal set_wait(30), 30
      assert_equal set_wait(30), 30

      # verify set_wait with no args works correctly
      assert_equal set_wait, 30
      assert_equal set_wait(30), 30
      assert_equal set_wait, 30

      assert_equal set_wait(2), 2
      assert_equal set_wait, 30
      assert_equal set_wait(3), 3
      assert_equal set_wait, 30

      assert_equal set_wait(2), 2
      assert_equal set_wait(3), 3
      assert_equal set_wait, 30
    end

    def test_17_default_wait
      set_wait 30
      assert_equal default_wait, 30 # set in run.rb
    end

    # returns true unless an error is raised
    def test_18_exists
      assert_equal exists(0, 0) { true }, true
      assert_equal exists(0, 0) { raise 'error' }, false
    end

    # simple integration sanity test to check for unexpected exceptions
    def test_19_set_location
      set_location latitude: 55, longitude: -72, altitude: 33
    end

    # any elements
    def test_20_find_elements
      assert_equal find_elements(:class, ui_ios.table_cell).length, 18
    end

    # any element
    def test_21_find_element
      assert_equal find_element(:class, ui_ios.static_text).class, ::Appium::Core::Element
    end

    # settings
    def test_22_get_settings
      assert !get_settings.nil?
    end

    def test_23_update_settings
      update_settings allowInvisibleElements: true
      assert_equal get_settings['allowInvisibleElements'], true
    end

    def test_24_events
      log_event vendor: 'appium', event: 'funEvent'
      log_events
    end

    def test_25_device_is_ios
      assert_equal device_is_ios?, true
    end
  end
end


================================================
FILE: ios_tests/lib/ios/specs/ios/command/multi_app_handler.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# rake "ios[ios/command/multi_app_handler]"
class IosTest
  class Ios
    class Command
      class MultiAppHandler < Minitest::Test
        # Only for Xcode 9+
        def test_multip_app_handler
          driver.terminate_app target_bundle_id
          driver.activate_app target_bundle_id

          test_app_bundle = target_bundle_id

          assert_equal xcuitest_query_app_status(bundle_id: test_app_bundle), :running_in_foreground

          assert_equal xcuitest_terminate_app(bundle_id: test_app_bundle), true
          assert_equal xcuitest_query_app_status(bundle_id: test_app_bundle), :not_running

          assert xcuitest_activate_app(bundle_id: test_app_bundle).nil?
          assert_equal xcuitest_query_app_status(bundle_id: test_app_bundle), :running_in_foreground

          assert xcuitest_activate_app(bundle_id: 'com.apple.Preferences').nil?
          wait(timeout: 5) do
            assert_equal xcuitest_query_app_status(bundle_id: test_app_bundle), :running_in_background_suspended
          end

          assert xcuitest_activate_app(bundle_id: test_app_bundle).nil?
          wait(timeout: 5) do
            assert_equal xcuitest_query_app_status(bundle_id: test_app_bundle), :running_in_foreground
          end
        end
      end
    end
  end
end


================================================
FILE: ios_tests/lib/ios/specs/ios/command/pasteboard.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# rake "ios[ios/command/pasteboard]"
class IosTest
  class Ios
    class Command
      class Pasteboard < Minitest::Test
        def test_pasteboard
          driver.terminate_app target_bundle_id
          driver.activate_app target_bundle_id

          # set blank before testing because pasteboard is remaining during launching simulators
          set_pasteboard content: 'before'
          assert_equal get_pasteboard, 'before'

          set_pasteboard content: 'sample content'

          assert_equal get_pasteboard, 'sample content'
        end
      end
    end
  end
end


================================================
FILE: ios_tests/lib/ios/specs/ios/command/source.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# rake ios[ios/command/source]
class IosTest
  class Ios
    class Command
      class Source < Minitest::Test
        def test_source
          assert_equal xcuitest_source(format: :json).is_a?(Hash), true
          assert_equal xcuitest_source(format: :xml).is_a?(String), true
        end
      end
    end
  end
end


================================================
FILE: ios_tests/lib/ios/specs/ios/element/alert.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# rake "ios[ios/element/alert]"
class IosTest
  class Ios
    class Element
      class Alert < Minitest::Test
        def open_alert
          wait_true do
            find_element(:name, 'Okay / Cancel').click
            find_element(:name, 'A Short Title Is Best').displayed?
          end
        end

        def test_01_before
          driver.terminate_app target_bundle_id
          driver.activate_app target_bundle_id

          assert_equal screen, catalog
          wait_true do
            find_element(:name, 'Alert Views').click
            tag(ui_ios.navbar).name == 'Alert Views' # wait for true
          end
        end

        def test_02_alert_accept
          open_alert
          alert_accept
        end

        def test_03_alert_dismiss
          open_alert
          alert_dismiss
        end

        def test_04_after_last
          back_click
          assert screen == catalog
          sleep 1
        end
      end
    end
  end
end


================================================
FILE: ios_tests/lib/ios/specs/ios/element/button.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# FIXME: The order is broken in Ruby 3.
# rake "ios[ios/element/button]"

class IosTest
  class Ios
    class Element
      class Button < Minitest::Test
        def before_first
          assert_equal screen, catalog
          # nav to buttons activity
          wait { find_element(:name, 'Buttons').click }
        end

        def after_last
          # nav back to start
          back_click
        end

        def test_01_before_first
          driver.terminate_app target_bundle_id
          driver.activate_app target_bundle_id

          before_first
        end

        def test_02_button
          # by index
          assert_equal button(3).name, 'UIAccessoryButtonPlus'

          # by name contains
          assert_equal button('Plus').name, 'UIAccessoryButtonPlus'
        end

        def test_03_buttons
          exp = %w(UICatalog UIAccessoryButtonPlus)

          target_buttons = buttons('a')
          assert_equal target_buttons.map(&:name), exp
          assert_equal target_buttons.length, exp.length
        end

        def test_04_first_button
          assert_equal first_button.name, 'UICatalog'
        end

        def test_05_last_button
          expected = 'Button'
          assert_equal last_button.name, expected
        end

        def test_06_button_exact
          assert_equal button_exact('UIAccessoryButtonPlus').name, 'UIAccessoryButtonPlus'
        end

        def test_07_buttons_exact
          assert_equal buttons_exact('UIAccessoryButtonPlus').first.name, 'UIAccessoryButtonPlus'
        end

        def test_08_after_last
          after_last
        end
      end
    end
  end
end


================================================
FILE: ios_tests/lib/ios/specs/ios/element/generic.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# rake "ios[ios/element/generic]"
class IosTest
  class Ios
    class Element
      class Generic < Minitest::Test
        def uibutton_text
          'Buttons'
        end

        def verify(element)
          element = element.first if element.is_a? Array
          assert_equal element.name, uibutton_text
        end

        def test_01_before_first
          driver.terminate_app target_bundle_id
          driver.activate_app target_bundle_id

          assert_equal screen, catalog
        end

        def test_02_find
          verify find 'tons'
        end

        def test_03_finds
          verify finds 'tons'
        end

        def test_04_find_exact
          verify find_exact uibutton_text
        end

        def test_05_finds_exact
          elements = finds_exact uibutton_text
          assert_equal elements.is_a?(Array), true
          verify elements
        end
      end
    end
  end
end


================================================
FILE: ios_tests/lib/ios/specs/ios/element/text.rb
================================================
# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# rake "ios[ios/element/text]"
class IosTest
  class Ios
    class Element
      class Text < Minitest::Test
        def ui_catalog
          'UICatalog'
        end

        def uiview_steppers
          'Steppers'
        end

        def test_01_before_first
          driver.terminate_app target_bundle_id
          driver.activate_app target_bundle_id

          assert_equal screen, catalog
        end

        def test_02_first_text
          assert_equal first_text.text, ui_catalog
        end

        def test_03_last_text
          expected = 'Steppers'

          assert_equal last_text.text, expected
          assert_equal last_text.name, expected
        end

        def test_04_
Download .txt
gitextract_9jozq5zh/

├── .github/
│   ├── CODEOWNERS
│   ├── ISSUE_TEMPLATE.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── dependabot.yml
│   └── workflows/
│       ├── functional-test.yml
│       ├── pr-title.yml
│       └── rubocop.yml
├── .gitignore
├── .rubocop.yml
├── CHANGELOG.md
├── Gemfile
├── LICENSE-2.0.txt
├── Rakefile
├── Thorfile
├── android_tests/
│   ├── Gemfile
│   ├── LICENSE-2.0.txt
│   ├── Rakefile
│   ├── appium.txt
│   ├── flaky.txt
│   ├── lib/
│   │   ├── android/
│   │   │   └── specs/
│   │   │       ├── android/
│   │   │       │   ├── element/
│   │   │       │   │   ├── alert.rb
│   │   │       │   │   ├── button.rb
│   │   │       │   │   ├── generic.rb
│   │   │       │   │   ├── text.rb
│   │   │       │   │   └── textfield.rb
│   │   │       │   ├── helper.rb
│   │   │       │   └── patch.rb
│   │   │       ├── common/
│   │   │       │   ├── device.rb
│   │   │       │   ├── device_touchaction.rb
│   │   │       │   ├── element/
│   │   │       │   │   └── window.rb
│   │   │       │   ├── helper.rb
│   │   │       │   ├── patch.rb
│   │   │       │   ├── version.rb
│   │   │       │   └── web_context.rb
│   │   │       ├── driver.rb
│   │   │       ├── install.rb
│   │   │       └── sauce_labs.rb
│   │   ├── format.rb
│   │   └── run.rb
│   └── readme.md
├── appium_lib.gemspec
├── contributing.md
├── docs/
│   ├── android_uiautomator.md
│   ├── docs.md
│   ├── ios_xcuitest.md
│   ├── parallel.md
│   └── w3c.md
├── grid/
│   ├── README.md
│   ├── appium.txt.ios.example
│   ├── config.json
│   ├── hub_config.json
│   └── hub_config_3.json
├── ios_tests/
│   ├── Gemfile
│   ├── LICENSE-2.0.txt
│   ├── Rakefile
│   ├── appium.txt
│   ├── data/
│   │   └── unicode.txt
│   ├── flaky.txt
│   ├── lib/
│   │   ├── common.rb
│   │   ├── format.rb
│   │   ├── ios/
│   │   │   └── specs/
│   │   │       ├── common/
│   │   │       │   ├── element/
│   │   │       │   │   └── window.rb
│   │   │       │   ├── helper.rb
│   │   │       │   ├── patch.rb
│   │   │       │   ├── version.rb
│   │   │       │   └── web_context.rb
│   │   │       ├── device/
│   │   │       │   ├── device.rb
│   │   │       │   └── image_comparison.rb
│   │   │       ├── driver.rb
│   │   │       └── ios/
│   │   │           ├── command/
│   │   │           │   ├── multi_app_handler.rb
│   │   │           │   ├── pasteboard.rb
│   │   │           │   └── source.rb
│   │   │           ├── element/
│   │   │           │   ├── alert.rb
│   │   │           │   ├── button.rb
│   │   │           │   ├── generic.rb
│   │   │           │   ├── text.rb
│   │   │           │   └── textfield.rb
│   │   │           ├── helper.rb
│   │   │           ├── mobile_methods.rb
│   │   │           ├── patch.rb
│   │   │           └── xcuitest_gestures.rb
│   │   └── run.rb
│   ├── parallel/
│   │   └── test.rb
│   └── readme.md
├── lib/
│   ├── appium_lib/
│   │   ├── android/
│   │   │   ├── android.rb
│   │   │   ├── common/
│   │   │   │   ├── command/
│   │   │   │   │   └── command.rb
│   │   │   │   └── helper.rb
│   │   │   ├── element/
│   │   │   │   ├── alert.rb
│   │   │   │   ├── button.rb
│   │   │   │   ├── generic.rb
│   │   │   │   ├── text.rb
│   │   │   │   └── textfield.rb
│   │   │   ├── espresso/
│   │   │   │   ├── bridge.rb
│   │   │   │   ├── element/
│   │   │   │   │   ├── button.rb
│   │   │   │   │   └── generic.rb
│   │   │   │   ├── element.rb
│   │   │   │   └── helper.rb
│   │   │   ├── espresso.rb
│   │   │   ├── uiautomator2/
│   │   │   │   ├── bridge.rb
│   │   │   │   ├── element/
│   │   │   │   │   └── button.rb
│   │   │   │   ├── element.rb
│   │   │   │   └── helper.rb
│   │   │   └── uiautomator2.rb
│   │   ├── appium.rb
│   │   ├── common/
│   │   │   ├── command.rb
│   │   │   ├── device.rb
│   │   │   ├── helper.rb
│   │   │   ├── http_client.rb
│   │   │   ├── log.rb
│   │   │   └── wait.rb
│   │   ├── driver.rb
│   │   ├── error.rb
│   │   ├── ios/
│   │   │   ├── common/
│   │   │   │   ├── errors.rb
│   │   │   │   └── helper.rb
│   │   │   ├── element/
│   │   │   │   ├── alert.rb
│   │   │   │   ├── button.rb
│   │   │   │   ├── generic.rb
│   │   │   │   ├── text.rb
│   │   │   │   └── textfield.rb
│   │   │   ├── ios.rb
│   │   │   ├── xcuitest/
│   │   │   │   ├── bridge.rb
│   │   │   │   ├── command/
│   │   │   │   │   ├── certificate.rb
│   │   │   │   │   ├── gestures.rb
│   │   │   │   │   ├── get_context.rb
│   │   │   │   │   ├── multi_app_handler.rb
│   │   │   │   │   ├── pasteboard.rb
│   │   │   │   │   └── source.rb
│   │   │   │   ├── command.rb
│   │   │   │   ├── element/
│   │   │   │   │   ├── button.rb
│   │   │   │   │   ├── generic.rb
│   │   │   │   │   ├── text.rb
│   │   │   │   │   └── textfield.rb
│   │   │   │   ├── element.rb
│   │   │   │   └── helper.rb
│   │   │   └── xcuitest.rb
│   │   ├── sauce_labs.rb
│   │   └── version.rb
│   └── appium_lib.rb
├── readme.md
├── release_notes.md
├── test/
│   └── first_test.rb
└── test_apps/
    ├── VodQA.apk
    └── api.apk
Download .txt
SYMBOL INDEX (904 symbols across 93 files)

FILE: android_tests/lib/android/specs/android/element/alert.rb
  class AndroidTest (line 16) | class AndroidTest
    class Element (line 17) | class Element
      class Alert (line 18) | class Alert < Minitest::Test
        method open_alert (line 19) | def open_alert
        method test_01_alert_click (line 24) | def test_01_alert_click
        method test_02_alert_accept (line 34) | def test_02_alert_accept
        method test_03_alert_accept_text (line 39) | def test_03_alert_accept_text
        method test_04_alert_dismiss (line 45) | def test_04_alert_dismiss
        method test_05_alert_dismiss_text (line 50) | def test_05_alert_dismiss_text

FILE: android_tests/lib/android/specs/android/element/button.rb
  class AndroidTest (line 16) | class AndroidTest
    class Element (line 17) | class Element
      class Button (line 18) | class Button < Minitest::Test
        method before_first (line 19) | def before_first
        method after_last (line 26) | def after_last
        method fade_in (line 31) | def fade_in
        method test_01_before_first (line 35) | def test_01_before_first
        method test_02_button (line 39) | def test_02_button
        method test_03_buttons (line 47) | def test_03_buttons
        method test_04_first_button (line 53) | def test_04_first_button
        method test_05_last_button (line 57) | def test_05_last_button
        method test_06_button_exact (line 61) | def test_06_button_exact
        method test_07_buttons_exact (line 65) | def test_07_buttons_exact
        method test_08_after_last (line 69) | def test_08_after_last

FILE: android_tests/lib/android/specs/android/element/generic.rb
  class AndroidTest (line 16) | class AndroidTest
    class Element (line 17) | class Element
      class Generic (line 18) | class Generic < Minitest::Test
        method content (line 19) | def content
        method partial (line 23) | def partial
        method test_01_find_works_before_and_after_get_source (line 27) | def test_01_find_works_before_and_after_get_source
        method test_01_find (line 33) | def test_01_find
        method test_01_finds (line 37) | def test_01_finds
        method test_01_find_exact (line 41) | def test_01_find_exact
        method test_01_finds_exact (line 45) | def test_01_finds_exact
        method test_01_scroll_to (line 50) | def test_01_scroll_to
        method test_01_scroll_to_exact (line 63) | def test_01_scroll_to_exact

FILE: android_tests/lib/android/specs/android/element/text.rb
  class AndroidTest (line 16) | class AndroidTest
    class Element (line 17) | class Element
      class Text (line 18) | class Text < Minitest::Test
        method must_raise_no_element (line 19) | def must_raise_no_element
        method test_01_text (line 25) | def test_01_text
        method test_02_texts (line 30) | def test_02_texts
        method test_03_first_text (line 35) | def test_03_first_text
        method test_04_last_text (line 39) | def test_04_last_text
        method test_05_text_exact (line 43) | def test_05_text_exact
        method test_06_texts_exact (line 50) | def test_06_texts_exact

FILE: android_tests/lib/android/specs/android/element/textfield.rb
  class AndroidTest (line 16) | class AndroidTest
    class Element (line 17) | class Element
      class TextField (line 18) | class TextField < Minitest::Test
        method must_raise_no_element (line 19) | def must_raise_no_element
        method left (line 25) | def left
        method right (line 29) | def right
        method before_first (line 33) | def before_first
        method after_last (line 40) | def after_last
        method test_01_before_test (line 45) | def test_01_before_test
        method test_02_textfield (line 49) | def test_02_textfield
        method test_03_textfields (line 54) | def test_03_textfields
        method test_04_first_textfield (line 59) | def test_04_first_textfield
        method test_05_last_textfield (line 63) | def test_05_last_textfield
        method test_06_textfield_exact (line 67) | def test_06_textfield_exact
        method test_07_textfields_exact (line 72) | def test_07_textfields_exact
        method test_08_hide_keyboard (line 77) | def test_08_hide_keyboard
        method test_09_after_last (line 82) | def test_09_after_last

FILE: android_tests/lib/android/specs/android/helper.rb
  class AndroidTest (line 16) | class AndroidTest
    class Helper (line 17) | class Helper < Minitest::Test
      method test_01_tags (line 18) | def test_01_tags
      method test_01_get_page_class (line 22) | def test_01_get_page_class
      method test_02_get_android_inspect (line 51) | def test_02_get_android_inspect
      method id_key (line 59) | def id_key
      method id_value (line 63) | def id_value
      method test_03_xml_keys (line 67) | def test_03_xml_keys
      method test_04_resolve_id (line 77) | def test_04_resolve_id
      method test_05_xml_values (line 84) | def test_05_xml_values
      method test_06_find_by_id (line 91) | def test_06_find_by_id
      method test_07_ids (line 106) | def test_07_ids

FILE: android_tests/lib/android/specs/android/patch.rb
  class AndroidTest (line 16) | class AndroidTest
    class Patch (line 17) | class Patch < Minitest::Test
      method test_type (line 18) | def test_type

FILE: android_tests/lib/android/specs/common/device.rb
  class AndroidTest (line 16) | class AndroidTest
    class Common (line 17) | class Common
      class Device (line 18) | class Device < Minitest::Test
        method test_01_get_performance_data_types (line 19) | def test_01_get_performance_data_types
        method test_02_start_activity (line 28) | def test_02_start_activity
        method test_03_current_package (line 44) | def test_03_current_package
        method test_04_app_strings (line 52) | def test_04_app_strings
        method test_05_press_keycode (line 56) | def test_05_press_keycode
        method test_06_long_press_keycode (line 61) | def test_06_long_press_keycode

FILE: android_tests/lib/android/specs/common/device_touchaction.rb
  class AndroidTest (line 16) | class AndroidTest
    class Common (line 17) | class Common
      class DeviceTouchAction (line 18) | class DeviceTouchAction < Minitest::Test
        method test_01_before_test (line 19) | def test_01_before_test
        method test_02_action_chain_press_release (line 23) | def test_02_action_chain_press_release
        method test_03_action_chain_tap (line 33) | def test_03_action_chain_tap
        method test_04_swipe (line 43) | def test_04_swipe
        method test_05_pinch_zoom (line 56) | def test_05_pinch_zoom

FILE: android_tests/lib/android/specs/common/element/window.rb
  class AndroidTest (line 16) | class AndroidTest
    class Common (line 17) | class Common
      class Element (line 18) | class Element
        class Window (line 19) | class Window < Minitest::Test
          method test_window_size (line 20) | def test_window_size

FILE: android_tests/lib/android/specs/common/helper.rb
  class AndroidTest (line 16) | class AndroidTest
    class Common (line 17) | class Common
      class Helper (line 18) | class Helper < Minitest::Test
        method wait_opts (line 19) | def wait_opts
        method test_01_wait (line 30) | def test_01_wait
        method test_02_ignore (line 57) | def test_02_ignore
        method test_03_wait_true (line 67) | def test_03_wait_true
        method test_04_back (line 101) | def test_04_back
        method test_05_session_id (line 114) | def test_05_session_id
        method test_06_xpath (line 118) | def test_06_xpath
        method test_07_xpaths (line 123) | def test_07_xpaths
        method test_08_ele_index (line 127) | def test_08_ele_index
        method test_09_tags (line 132) | def test_09_tags
        method test_10_first_ele (line 136) | def test_10_first_ele
        method test_11_last_ele (line 143) | def test_11_last_ele
        method test_12_get_source (line 152) | def test_12_get_source

FILE: android_tests/lib/android/specs/common/patch.rb
  class AndroidTest (line 20) | class AndroidTest
    class Common (line 21) | class Common
      class Patch (line 22) | class Patch < Minitest::Test
        method test_01_element_method_name (line 31) | def test_01_element_method_name
        method test_02_element_method_location_rel (line 37) | def test_02_element_method_location_rel
        method test_03_common_patch_id_error_message (line 46) | def test_03_common_patch_id_error_message
        method test_04_id_common_patch_success (line 60) | def test_04_id_common_patch_success
        method test_05_find_many_elements_by_resource_id (line 74) | def test_05_find_many_elements_by_resource_id
        method test_06_find_single_element_by_resource_id (line 81) | def test_06_find_single_element_by_resource_id

FILE: android_tests/lib/android/specs/common/version.rb
  class AndroidTest (line 16) | class AndroidTest
    class Common (line 17) | class Common
      class Version (line 18) | class Version < Minitest::Test
        method test_appium_version (line 19) | def test_appium_version
        method test_appium_date (line 23) | def test_appium_date

FILE: android_tests/lib/android/specs/common/web_context.rb
  class AndroidTest (line 17) | class AndroidTest
    class Common (line 18) | class Common
      class WebContext (line 19) | class WebContext < Minitest::Test
        method test_01_available_contexts (line 22) | def test_01_available_contexts
        method test_02_current_context (line 26) | def test_02_current_context
        method undo_setcontext_nav (line 30) | def undo_setcontext_nav
        method test_03_set_context (line 37) | def test_03_set_context

FILE: android_tests/lib/android/specs/driver.rb
  class AndroidTest (line 18) | class AndroidTest
    class Driver (line 19) | class Driver < Minitest::Test
      method sauce? (line 20) | def sauce?
      method test_01_load_settings (line 24) | def test_01_load_settings
      method test_02_attributes_no_wait (line 31) | def test_02_attributes_no_wait
      method test_03_attributes_default_wait_attr (line 42) | def test_03_attributes_default_wait_attr
      method test_04_attributes_app_path_attr (line 48) | def test_04_attributes_app_path_attr
      method test_05_attributes_verify_all_attributes (line 53) | def test_05_attributes_verify_all_attributes
      method test_06_driver_class (line 94) | def test_06_driver_class
      method absolute_app_path (line 98) | def absolute_app_path(path)
      method validate_path (line 102) | def validate_path(path)
      method test_07_absolute_app_path (line 106) | def test_07_absolute_app_path
      method test_08_methods_status (line 130) | def test_08_methods_status
      method test_09_methods_server_version (line 134) | def test_09_methods_server_version
      method test_10_methods_client_version (line 143) | def test_10_methods_client_version
      method test_11_methods_restart (line 149) | def test_11_methods_restart
      method test_12_methods_driver (line 155) | def test_12_methods_driver
      method test_13_methods_default_wait (line 167) | def test_13_methods_default_wait
      method test_14_methods_exists (line 173) | def test_14_methods_exists
      method test_15_methods_find_elements (line 179) | def test_15_methods_find_elements
      method test_16_methods_find_element (line 186) | def test_16_methods_find_element
      method test_17_methods_set_location (line 193) | def test_17_methods_set_location
      method test_18_methods_get_settings (line 205) | def test_18_methods_get_settings
      method test_19_methods_update_settings (line 209) | def test_19_methods_update_settings

FILE: android_tests/lib/android/specs/install.rb
  class AndroidTest (line 16) | class AndroidTest
    class Install (line 17) | class Install < Minitest::Test
      method pkg (line 19) | def pkg
      method installed (line 23) | def installed
      method not_installed (line 27) | def not_installed
      method test_install_uninstall (line 31) | def test_install_uninstall

FILE: android_tests/lib/android/specs/sauce_labs.rb
  class AndroidTest (line 16) | class AndroidTest
    class SauceLabs (line 17) | class SauceLabs < Minitest::Test
      method test_sauce_settings (line 18) | def test_sauce_settings
      method test_no_sauce_settings (line 37) | def test_no_sauce_settings

FILE: android_tests/lib/run.rb
  function start_driver (line 38) | def start_driver(caps)

FILE: ios_tests/lib/common.rb
  function back_click (line 16) | def back_click
  function leave_textfields (line 20) | def leave_textfields
  function go_to_textfields (line 25) | def go_to_textfields
  function screen (line 33) | def screen
  function catalog (line 37) | def catalog
  function target_bundle_id (line 41) | def target_bundle_id
  function ui_ios (line 45) | def ui_ios
  class UI (line 49) | class UI
    method initialize (line 50) | def initialize(driver)
    method navbar (line 54) | def navbar
    method button (line 58) | def button
    method static_text (line 62) | def static_text
    method text_field (line 66) | def text_field
    method secure_text_field (line 70) | def secure_text_field
    method picker (line 74) | def picker
    method picker_wheel (line 78) | def picker_wheel
    method action_sheet (line 82) | def action_sheet
    method table (line 86) | def table
    method table_cell (line 90) | def table_cell
    method other (line 94) | def other
    method status_bar (line 98) | def status_bar

FILE: ios_tests/lib/ios/specs/common/element/window.rb
  class IosTest (line 17) | class IosTest
    class Common (line 18) | class Common
      class Element (line 19) | class Element
        class Window (line 20) | class Window < Minitest::Test
          method before_first (line 21) | def before_first
          method test_01_before_first (line 27) | def test_01_before_first
          method test_02_window_size (line 31) | def test_02_window_size

FILE: ios_tests/lib/ios/specs/common/helper.rb
  class IosTest (line 16) | class IosTest
    class Common (line 17) | class Common
      class Helper (line 18) | class Helper < Minitest::Test
        method setup (line 19) | def setup
        method test_01_before_first (line 23) | def test_01_before_first
        method test_02_wait (line 36) | def test_02_wait
        method test_03_ignore (line 62) | def test_03_ignore
        method test_04_wait_true (line 72) | def test_04_wait_true
        method test_06_back (line 104) | def test_06_back
        method test_07_session_id (line 120) | def test_07_session_id
        method test_08_xpath (line 125) | def test_08_xpath
        method test_09_xpaths (line 129) | def test_09_xpaths
        method uibutton_text (line 133) | def uibutton_text
        method action_sheets (line 137) | def action_sheets
        method test_10_ele_index (line 141) | def test_10_ele_index
        method test_11_find_ele_by_attr (line 147) | def test_11_find_ele_by_attr
        method test_12_find_eles_by_attr (line 152) | def test_12_find_eles_by_attr
        method test_13_find_ele_by_predicate (line 165) | def test_13_find_ele_by_predicate
        method test_14_find_eles_by_predicate (line 173) | def test_14_find_eles_by_predicate
        method test_15_find_ele_by_attr_include (line 183) | def test_15_find_ele_by_attr_include
        method test_16_find_eles_by_attr_include (line 191) | def test_16_find_eles_by_attr_include
        method test_17_find_ele_by_predicate_include (line 196) | def test_17_find_ele_by_predicate_include
        method test_18_find_eles_by_predicate_include (line 204) | def test_18_find_eles_by_predicate_include
        method test_19_first_ele (line 208) | def test_19_first_ele
        method test_20_last_ele (line 212) | def test_20_last_ele
        method test_21_get_source (line 222) | def test_21_get_source
        method test_22_invalid_id_should_error (line 226) | def test_22_invalid_id_should_error
        method test_23_tag (line 236) | def test_23_tag
        method test_24_tags (line 240) | def test_24_tags
        method test_25_find_eles_by_attr_include_length (line 244) | def test_25_find_eles_by_attr_include_length
        method test_26_get_page_class (line 248) | def test_26_get_page_class

FILE: ios_tests/lib/ios/specs/common/patch.rb
  class IosTest (line 21) | class IosTest
    class Common (line 22) | class Common
      class Patch (line 23) | class Patch < Minitest::Test
        method test_01_before_first (line 24) | def test_01_before_first
        method test_02_appium_core_element_method_name (line 30) | def test_02_appium_core_element_method_name
        method test_03_appium_core_element_method_location_rel (line 34) | def test_03_appium_core_element_method_location_rel

FILE: ios_tests/lib/ios/specs/common/version.rb
  class IosTest (line 15) | class IosTest
    class Common (line 16) | class Common
      class Version (line 17) | class Version < Minitest::Test
        method test_01_before_first (line 18) | def test_01_before_first
        method test_02_appium_version (line 22) | def test_02_appium_version
        method test_03_appium_date (line 26) | def test_03_appium_date

FILE: ios_tests/lib/ios/specs/common/web_context.rb
  class IosTest (line 18) | class IosTest
    class Common (line 19) | class Common
      class WebContext (line 20) | class WebContext < Minitest::Test
        method test_01_before_first (line 21) | def test_01_before_first
        method test_02_get_ios_inspect (line 27) | def test_02_get_ios_inspect
        method test_03_xcuitest_get_contexts (line 39) | def test_03_xcuitest_get_contexts
        method test_04_after_last (line 45) | def test_04_after_last

FILE: ios_tests/lib/ios/specs/device/device.rb
  class IosTest (line 17) | class IosTest
    class Device (line 18) | class Device
      class Device (line 19) | class Device < Minitest::Test
        method go_back (line 21) | def go_back
        method test_01_before_first (line 26) | def test_01_before_first
        method test_02_app_installed (line 32) | def test_02_app_installed
        method test_03_background_app_homescreen (line 37) | def test_03_background_app_homescreen
        method test_04_app_strings (line 50) | def test_04_app_strings
        method test_05_action_chain (line 55) | def test_05_action_chain
        method test_06_swipe (line 63) | def test_06_swipe

FILE: ios_tests/lib/ios/specs/device/image_comparison.rb
  class IosTest (line 17) | class IosTest
    class Device (line 18) | class Device
      class ImageComparison (line 19) | class ImageComparison < Minitest::Test
        method test_image_comparison (line 20) | def test_image_comparison

FILE: ios_tests/lib/ios/specs/driver.rb
  class IosTest (line 16) | class IosTest
    class Driver (line 17) | class Driver < Minitest::Test
      method test_01_before_first (line 18) | def test_01_before_first
      method test_02_unicode_defaults (line 24) | def test_02_unicode_defaults
      method test_03_load_settings (line 29) | def test_03_load_settings
      method test_04_verify_all_attributes (line 39) | def test_04_verify_all_attributes
      method test_05_verify_attributes_are_immutable (line 65) | def test_05_verify_attributes_are_immutable
      method test_06_verify_attribute_of_caps_are_not_immutable_because_it_depends_on_selenium (line 71) | def test_06_verify_attribute_of_caps_are_not_immutable_because_it_de...
      method test_07_no_wait (line 82) | def test_07_no_wait
      method test_08_app_path_attr (line 90) | def test_08_app_path_attr
      method test_09_driver_class (line 95) | def test_09_driver_class
      method test_10_status (line 99) | def test_10_status
      method test_11_server_version (line 103) | def test_11_server_version
      method test_12_client_version (line 108) | def test_12_client_version
      method test_13_restart (line 114) | def test_13_restart
      method test_14_driver (line 119) | def test_14_driver
      method test_15_automation_name_is_xcuitest? (line 123) | def test_15_automation_name_is_xcuitest?
      method test_16_set_wait (line 134) | def test_16_set_wait
      method test_17_default_wait (line 154) | def test_17_default_wait
      method test_18_exists (line 160) | def test_18_exists
      method test_19_set_location (line 166) | def test_19_set_location
      method test_20_find_elements (line 171) | def test_20_find_elements
      method test_21_find_element (line 176) | def test_21_find_element
      method test_22_get_settings (line 181) | def test_22_get_settings
      method test_23_update_settings (line 185) | def test_23_update_settings
      method test_24_events (line 190) | def test_24_events
      method test_25_device_is_ios (line 195) | def test_25_device_is_ios

FILE: ios_tests/lib/ios/specs/ios/command/multi_app_handler.rb
  class IosTest (line 16) | class IosTest
    class Ios (line 17) | class Ios
      class Command (line 18) | class Command
        class MultiAppHandler (line 19) | class MultiAppHandler < Minitest::Test
          method test_multip_app_handler (line 21) | def test_multip_app_handler

FILE: ios_tests/lib/ios/specs/ios/command/pasteboard.rb
  class IosTest (line 16) | class IosTest
    class Ios (line 17) | class Ios
      class Command (line 18) | class Command
        class Pasteboard (line 19) | class Pasteboard < Minitest::Test
          method test_pasteboard (line 20) | def test_pasteboard

FILE: ios_tests/lib/ios/specs/ios/command/source.rb
  class IosTest (line 16) | class IosTest
    class Ios (line 17) | class Ios
      class Command (line 18) | class Command
        class Source (line 19) | class Source < Minitest::Test
          method test_source (line 20) | def test_source

FILE: ios_tests/lib/ios/specs/ios/element/alert.rb
  class IosTest (line 16) | class IosTest
    class Ios (line 17) | class Ios
      class Element (line 18) | class Element
        class Alert (line 19) | class Alert < Minitest::Test
          method open_alert (line 20) | def open_alert
          method test_01_before (line 27) | def test_01_before
          method test_02_alert_accept (line 38) | def test_02_alert_accept
          method test_03_alert_dismiss (line 43) | def test_03_alert_dismiss
          method test_04_after_last (line 48) | def test_04_after_last

FILE: ios_tests/lib/ios/specs/ios/element/button.rb
  class IosTest (line 18) | class IosTest
    class Ios (line 19) | class Ios
      class Element (line 20) | class Element
        class Button (line 21) | class Button < Minitest::Test
          method before_first (line 22) | def before_first
          method after_last (line 28) | def after_last
          method test_01_before_first (line 33) | def test_01_before_first
          method test_02_button (line 40) | def test_02_button
          method test_03_buttons (line 48) | def test_03_buttons
          method test_04_first_button (line 56) | def test_04_first_button
          method test_05_last_button (line 60) | def test_05_last_button
          method test_06_button_exact (line 65) | def test_06_button_exact
          method test_07_buttons_exact (line 69) | def test_07_buttons_exact
          method test_08_after_last (line 73) | def test_08_after_last

FILE: ios_tests/lib/ios/specs/ios/element/generic.rb
  class IosTest (line 16) | class IosTest
    class Ios (line 17) | class Ios
      class Element (line 18) | class Element
        class Generic (line 19) | class Generic < Minitest::Test
          method uibutton_text (line 20) | def uibutton_text
          method verify (line 24) | def verify(element)
          method test_01_before_first (line 29) | def test_01_before_first
          method test_02_find (line 36) | def test_02_find
          method test_03_finds (line 40) | def test_03_finds
          method test_04_find_exact (line 44) | def test_04_find_exact
          method test_05_finds_exact (line 48) | def test_05_finds_exact

FILE: ios_tests/lib/ios/specs/ios/element/text.rb
  class IosTest (line 16) | class IosTest
    class Ios (line 17) | class Ios
      class Element (line 18) | class Element
        class Text (line 19) | class Text < Minitest::Test
          method ui_catalog (line 20) | def ui_catalog
          method uiview_steppers (line 24) | def uiview_steppers
          method test_01_before_first (line 28) | def test_01_before_first
          method test_02_first_text (line 35) | def test_02_first_text
          method test_03_last_text (line 39) | def test_03_last_text
          method test_04_text (line 46) | def test_04_text
          method test_05_texts (line 52) | def test_05_texts
          method test_06_text_exact (line 59) | def test_06_text_exact
          method test_07_texts_exact (line 74) | def test_07_texts_exact

FILE: ios_tests/lib/ios/specs/ios/element/textfield.rb
  class IosTest (line 16) | class IosTest
    class Element (line 17) | class Element
      class Textfield (line 18) | class Textfield < Minitest::Test
        method enter_text (line 19) | def enter_text
        method enter_password (line 23) | def enter_password
        method test_01_before_first (line 27) | def test_01_before_first
        method test_02_textfield (line 34) | def test_02_textfield
        method test_03_textfields (line 40) | def test_03_textfields
        method test_04_predicate_textfields (line 47) | def test_04_predicate_textfields
        method test_05_first_textfield (line 52) | def test_05_first_textfield
        method test_06_last_textfield (line 56) | def test_06_last_textfield
        method test_07_textfield_exact (line 60) | def test_07_textfield_exact
        method test_08_textfields_exact (line 64) | def test_08_textfields_exact
        method test_09_textfield_type (line 68) | def test_09_textfield_type
        method test_10_hide_keyboard (line 74) | def test_10_hide_keyboard
        method test_11_leave_textfields (line 81) | def test_11_leave_textfields
        method test_12_no_textfield (line 86) | def test_12_no_textfield
        method test_13_no_textfields (line 91) | def test_13_no_textfields
        method test_14_no_first_textfield (line 95) | def test_14_no_first_textfield
        method test_15_no_last_textfield (line 99) | def test_15_no_last_textfield
        method test_16_no_textfield_exact (line 103) | def test_16_no_textfield_exact
        method test_17_no_textfields_exact (line 107) | def test_17_no_textfields_exact
        method test_18_after_last (line 111) | def test_18_after_last

FILE: ios_tests/lib/ios/specs/ios/helper.rb
  class IosTest (line 16) | class IosTest
    class Ios (line 17) | class Ios
      class Helper (line 18) | class Helper < Minitest::Test
        method test_01_before_first (line 19) | def test_01_before_first
        method test_02_ios_password (line 26) | def test_02_ios_password
        method test_03_page (line 31) | def test_03_page
        method test_04_id (line 35) | def test_04_id
        method test_05_platform_version (line 39) | def test_05_platform_version
        method test_06_tags_include (line 43) | def test_06_tags_include
        method test_07_tags_exact (line 54) | def test_07_tags_exact

FILE: ios_tests/lib/ios/specs/ios/mobile_methods.rb
  class IosTest (line 16) | class IosTest
    class Ios (line 17) | class Ios
      class MobileMethods (line 18) | class MobileMethods < Minitest::Test
        method test_01_before_first (line 19) | def test_01_before_first
        method test_02_an_element_with_class_chain (line 25) | def test_02_an_element_with_class_chain
        method test_03_elements_with_class_chain (line 31) | def test_03_elements_with_class_chain

FILE: ios_tests/lib/ios/specs/ios/patch.rb
  class IosTest (line 16) | class IosTest
    class Ios (line 17) | class Ios
      class Patch (line 18) | class Patch < Minitest::Test
        method test_01_before_first (line 19) | def test_01_before_first
        method test_02_label (line 26) | def test_02_label
        method test_03_type (line 30) | def test_03_type
        method test_04_after_last (line 40) | def test_04_after_last

FILE: ios_tests/lib/ios/specs/ios/xcuitest_gestures.rb
  class IosTest (line 16) | class IosTest
    class Ios (line 17) | class Ios
      class XcuitestGestures (line 18) | class XcuitestGestures < Minitest::Test
        method open_alert_ok_cancel (line 19) | def open_alert_ok_cancel
        method open_alert_custom (line 26) | def open_alert_custom
        method test_01_before_first (line 33) | def test_01_before_first
        method test_02_tap (line 39) | def test_02_tap
        method test_03_double_tap (line 50) | def test_03_double_tap
        method test_04_touch_and_hold (line 55) | def test_04_touch_and_hold
        method test_05_swipe (line 61) | def test_05_swipe
        method test_06_drag_from_to_for_duration (line 70) | def test_06_drag_from_to_for_duration
        method test_07_pinch (line 74) | def test_07_pinch
        method test_08_back_to_top (line 78) | def test_08_back_to_top
        method test_09_select_picker_wheel (line 82) | def test_09_select_picker_wheel
        method test_10_back_to_top (line 95) | def test_10_back_to_top
        method test_11_alert (line 99) | def test_11_alert
        method test_12_back_to_top (line 117) | def test_12_back_to_top
        method test_13_after_last (line 121) | def test_13_after_last

FILE: ios_tests/parallel/test.rb
  function des_server_caps (line 17) | def des_server_caps
  class TestParallelRunThread (line 27) | class TestParallelRunThread
    method initialize (line 28) | def initialize(capability)
    method setup (line 32) | def setup
    method teardown (line 37) | def teardown
    method test_run (line 42) | def test_run
  class TestParallelRunProcess (line 65) | class TestParallelRunProcess
    method initialize (line 66) | def initialize(capability)
    method setup (line 70) | def setup
    method teardown (line 76) | def teardown
    method test_run (line 81) | def test_run

FILE: lib/appium_lib/android/android.rb
  type Appium (line 30) | module Appium
    type Android (line 31) | module Android
      class Bridge (line 32) | class Bridge
        method for (line 33) | def self.for(target)

FILE: lib/appium_lib/android/common/command/command.rb
  type Appium (line 15) | module Appium
    type Android (line 16) | module Android
      type Command (line 17) | module Command
        function shell (line 28) | def shell(command, arguments)

FILE: lib/appium_lib/android/common/helper.rb
  type Appium (line 15) | module Appium
    type Android (line 16) | module Android
      class AndroidElements (line 19) | class AndroidElements < Nokogiri::XML::SAX::Document
        method filter= (line 23) | def filter=(value)
        method initialize (line 30) | def initialize # rubocop:disable Lint/MissingSuper
        method reset (line 35) | def reset
        method start_element (line 41) | def start_element(name, attrs = [], driver = $driver)
      function get_android_inspect (line 95) | def get_android_inspect(class_name = false)
      function page (line 121) | def page(opts = {})
      function id (line 130) | def id(id)
      function ids (line 138) | def ids(id)
      function ele_index (line 147) | def ele_index(class_name, index)
      function first_ele (line 166) | def first_ele(class_name)
      function last_ele (line 173) | def last_ele(class_name)
      function tag (line 181) | def tag(class_name)
      function tags (line 189) | def tags(class_name)
      function resource_id (line 202) | def resource_id(string, on_match)
      function string_visible_contains_xpath (line 232) | def string_visible_contains_xpath(class_name, value)
      function string_visible_contains (line 252) | def string_visible_contains(class_name, value)
      function complex_find_contains (line 270) | def complex_find_contains(class_name, value)
      function complex_finds_contains (line 278) | def complex_finds_contains(class_name, value)
      function string_visible_exact_xpath (line 288) | def string_visible_exact_xpath(class_name, value)
      function string_visible_exact (line 301) | def string_visible_exact(class_name, value)
      function complex_find_exact (line 320) | def complex_find_exact(class_name, value)
      function complex_finds_exact (line 328) | def complex_finds_exact(class_name, value)

FILE: lib/appium_lib/android/element/alert.rb
  type Appium (line 15) | module Appium
    type Android (line 16) | module Android
      function alert_click (line 20) | def alert_click(value)
      function alert_accept (line 27) | def alert_accept
      function alert_accept_text (line 34) | def alert_accept_text
      function alert_dismiss (line 41) | def alert_dismiss
      function alert_dismiss_text (line 48) | def alert_dismiss_text

FILE: lib/appium_lib/android/element/button.rb
  type Appium (line 15) | module Appium
    type Android (line 16) | module Android
      function button (line 27) | def button(value)
      function buttons (line 45) | def buttons(value = false)
      function first_button (line 53) | def first_button
      function last_button (line 59) | def last_button
      function button_exact (line 75) | def button_exact(value)
      function buttons_exact (line 82) | def buttons_exact(value)
      function raise_no_such_element_if_empty (line 89) | def raise_no_such_element_if_empty(elements)
      function _button_visible_selectors (line 95) | def _button_visible_selectors(opts = {})
      function _button_exact_string (line 108) | def _button_exact_string(value)
      function _button_contains_string (line 114) | def _button_contains_string(value)

FILE: lib/appium_lib/android/element/generic.rb
  type Appium (line 15) | module Appium
    type Android (line 16) | module Android
      function find (line 20) | def find(value)
      function finds (line 27) | def finds(value)
      function find_exact (line 34) | def find_exact(value)
      function finds_exact (line 41) | def finds_exact(value)
      function scroll_uiselector (line 46) | def scroll_uiselector(content, index = 0)
      function scroll_to (line 54) | def scroll_to(text, scrollable_index = 0)
      function scroll_to_exact (line 70) | def scroll_to_exact(text, scrollable_index = 0)

FILE: lib/appium_lib/android/element/text.rb
  type Appium (line 16) | module Appium
    type Android (line 17) | module Android
      function text (line 25) | def text(value)
      function texts (line 35) | def texts(value = false)
      function first_text (line 43) | def first_text
      function last_text (line 49) | def last_text
      function text_exact (line 56) | def text_exact(value)
      function texts_exact (line 63) | def texts_exact(value)

FILE: lib/appium_lib/android/element/textfield.rb
  type Appium (line 15) | module Appium
    type Android (line 16) | module Android
      function textfield (line 24) | def textfield(value)
      function textfields (line 34) | def textfields(value = false)
      function first_textfield (line 42) | def first_textfield
      function last_textfield (line 48) | def last_textfield
      function textfield_exact (line 55) | def textfield_exact(value)
      function textfields_exact (line 62) | def textfields_exact(value)

FILE: lib/appium_lib/android/espresso.rb
  type Appium (line 19) | module Appium
    type Android (line 20) | module Android
      type Espresso (line 21) | module Espresso

FILE: lib/appium_lib/android/espresso/bridge.rb
  type Appium (line 17) | module Appium
    type Android (line 18) | module Android
      type Espresso (line 19) | module Espresso
        class Bridge (line 20) | class Bridge
          method for (line 21) | def self.for(target)

FILE: lib/appium_lib/android/espresso/element.rb
  type Appium (line 18) | module Appium
    type Android (line 19) | module Android
      type Espresso (line 20) | module Espresso
        type Element (line 21) | module Element

FILE: lib/appium_lib/android/espresso/element/button.rb
  type Appium (line 15) | module Appium
    type Android (line 16) | module Android
      type Espresso (line 17) | module Espresso
        type Element (line 18) | module Element
          function button (line 23) | def button(value)
          function buttons (line 46) | def buttons(value = false)
          function first_button (line 56) | def first_button
          function last_button (line 62) | def last_button
          function button_exact (line 77) | def button_exact(value)
          function buttons_exact (line 89) | def buttons_exact(value)
          function raise_no_such_element_if_empty (line 98) | def raise_no_such_element_if_empty(elements)
          function _button_visible_selectors_xpath (line 104) | def _button_visible_selectors_xpath(opts = {})
          function _button_exact_string_xpath (line 125) | def _button_exact_string_xpath(class_name, value)
          function _button_contains_string_xpath (line 130) | def _button_contains_string_xpath(class_name, value)

FILE: lib/appium_lib/android/espresso/element/generic.rb
  type Appium (line 15) | module Appium
    type Android (line 16) | module Android
      type Espresso (line 17) | module Espresso
        type Element (line 18) | module Element
          function scroll_to (line 23) | def scroll_to(text)
          function scroll_to_exact (line 48) | def scroll_to_exact(text)

FILE: lib/appium_lib/android/espresso/helper.rb
  type Appium (line 15) | module Appium
    type Android (line 16) | module Android
      type Espresso (line 17) | module Espresso
        type Helper (line 18) | module Helper
          function complex_find_contains (line 23) | def complex_find_contains(class_name, value)
          function complex_finds_contains (line 31) | def complex_finds_contains(class_name, value)
          function complex_find_exact (line 39) | def complex_find_exact(class_name, value)
          function complex_finds_exact (line 47) | def complex_finds_exact(class_name, value)

FILE: lib/appium_lib/android/uiautomator2.rb
  type Appium (line 19) | module Appium
    type Android (line 20) | module Android
      type Uiautomator2 (line 21) | module Uiautomator2

FILE: lib/appium_lib/android/uiautomator2/bridge.rb
  type Appium (line 17) | module Appium
    type Android (line 18) | module Android
      type Uiautomator2 (line 19) | module Uiautomator2
        class Bridge (line 20) | class Bridge
          method for (line 21) | def self.for(target)

FILE: lib/appium_lib/android/uiautomator2/element.rb
  type Appium (line 17) | module Appium
    type Android (line 18) | module Android
      type Uiautomator2 (line 19) | module Uiautomator2
        type Element (line 20) | module Element

FILE: lib/appium_lib/android/uiautomator2/element/button.rb
  type Appium (line 15) | module Appium
    type Android (line 16) | module Android
      type Uiautomator2 (line 17) | module Uiautomator2
        type Element (line 18) | module Element
          function button (line 23) | def button(value)
          function buttons (line 44) | def buttons(value = false)
          function first_button (line 52) | def first_button
          function last_button (line 59) | def last_button
          function button_exact (line 76) | def button_exact(value)
          function buttons_exact (line 84) | def buttons_exact(value)
          function raise_no_such_element_if_empty (line 91) | def raise_no_such_element_if_empty(elements)
          function _button_visible_selectors (line 98) | def _button_visible_selectors(opts = {})
          function _button_exact_string (line 112) | def _button_exact_string(value)
          function _button_contains_string (line 119) | def _button_contains_string(value)

FILE: lib/appium_lib/android/uiautomator2/helper.rb
  type Appium (line 15) | module Appium
    type Android (line 16) | module Android
      type Uiautomator2 (line 17) | module Uiautomator2
        type Helper (line 18) | module Helper
          function string_visible_contains (line 27) | def string_visible_contains(class_name, value)
          function complex_find_contains (line 45) | def complex_find_contains(class_name, value)
          function complex_finds_contains (line 56) | def complex_finds_contains(class_name, value)
          function string_visible_exact (line 65) | def string_visible_exact(class_name, value)
          function complex_find_exact (line 84) | def complex_find_exact(class_name, value)
          function complex_finds_exact (line 95) | def complex_finds_exact(class_name, value)

FILE: lib/appium_lib/appium.rb
  type Appium (line 39) | module Appium
    function load_settings (line 58) | def load_settings(opts = {})
    function expand_required_files (line 111) | def expand_required_files(base_dir, file_paths)
    function promote_singleton_appium_methods (line 153) | def promote_singleton_appium_methods(modules, driver = $driver)
    function promote_appium_methods (line 207) | def promote_appium_methods(class_array, driver = $driver)

FILE: lib/appium_lib/common/command.rb
  type Appium (line 15) | module Appium
    type Common (line 16) | module Common
      type Command (line 17) | module Command

FILE: lib/appium_lib/common/device.rb
  type Appium (line 15) | module Appium
    type Device (line 16) | module Device

FILE: lib/appium_lib/common/helper.rb
  type Appium (line 16) | module Appium
    type Common (line 17) | module Common
      function ignore (line 30) | def ignore
      function back (line 38) | def back
      function session_id (line 49) | def session_id
      function xpath (line 57) | def xpath(xpath_str)
      function xpaths (line 65) | def xpaths(xpath_str)
      class CountElements (line 74) | class CountElements < Nokogiri::XML::SAX::Document
        method initialize (line 77) | def initialize(platform) # rubocop:disable Lint/MissingSuper
        method reset (line 82) | def reset
        method start_element (line 87) | def start_element(name, attrs = [])
        method formatted_result (line 98) | def formatted_result
      function get_page_class (line 116) | def get_page_class
      function page_class (line 141) | def page_class
      function source (line 148) | def source
      function get_source (line 155) | def get_source
      function px_to_window_rel (line 165) | def px_to_window_rel(opts = {}, driver = $driver)
      function lazy_load_strings (line 175) | def lazy_load_strings
      function xml_keys (line 184) | def xml_keys(target)
      function xml_values (line 192) | def xml_values(target)
      function resolve_id (line 200) | def resolve_id(id)
      class HTMLElements (line 206) | class HTMLElements < Nokogiri::XML::SAX::Document
        method filter= (line 210) | def filter=(value)
        method initialize (line 217) | def initialize # rubocop:disable Lint/MissingSuper
        method reset (line 222) | def reset
        method result (line 228) | def result
        method start_element (line 242) | def start_element(name, attrs = [])
        method end_element (line 252) | def end_element(name)
        method characters (line 259) | def characters(chars)
      function _no_such_element (line 268) | def _no_such_element
      function _print_source (line 274) | def _print_source(source)

FILE: lib/appium_lib/common/http_client.rb
  type Appium (line 18) | module Appium
    type Http (line 19) | module Http
      class Default (line 20) | class Default < ::Appium::Core::Base::Http::Default

FILE: lib/appium_lib/common/log.rb
  type Appium (line 15) | module Appium
    type Common (line 16) | module Common
      function get_log (line 25) | def get_log(type)
      function get_available_log_types (line 37) | def get_available_log_types

FILE: lib/appium_lib/common/wait.rb
  type Appium (line 17) | module Appium
    type Common (line 18) | module Common
      class Wait (line 19) | class Wait
      function wait_true (line 44) | def wait_true(opts = {})
      function wait (line 73) | def wait(opts = {})

FILE: lib/appium_lib/driver.rb
  type Minitest (line 18) | module Minitest
    class Runnable (line 20) | class Runnable
    class Test (line 24) | class Test < Runnable
    class Test (line 32) | class Test < Result
  type Appium (line 41) | module Appium
    class Driver (line 42) | class Driver
      method convert_to_symbol (line 72) | def convert_to_symbol(value)
      method get_cap (line 81) | def get_cap(caps, name)
      method initialize (line 200) | def initialize(opts = {}, global_driver = false)
      method extend_for (line 255) | def extend_for(device:, automation_name:)
      method set_app_path (line 294) | def set_app_path(opts)
      method set_sauce_related_values (line 306) | def set_sauce_related_values(appium_lib_opts)
      method driver_attributes (line 316) | def driver_attributes
      method device_is_android? (line 334) | def device_is_android?
      method device_is_ios? (line 338) | def device_is_ios?
      method device_is_windows? (line 342) | def device_is_windows?
      method automation_name_is_uiautomator2? (line 348) | def automation_name_is_uiautomator2?
      method automation_name_is_espresso? (line 354) | def automation_name_is_espresso?
      method automation_name_is_xcuitest? (line 360) | def automation_name_is_xcuitest?
      method action (line 374) | def action
      method appium_server_version (line 389) | def appium_server_version
      method platform_version (line 401) | def platform_version
      method appium_client_version (line 417) | def appium_client_version
      method absolute_app_path (line 429) | def self.absolute_app_path(opts)
      method server_url (line 453) | def server_url
      method restart (line 462) | def restart
      method screenshot (line 475) | def screenshot(png_save_path)
      method element_screenshot (line 489) | def element_screenshot(element, png_save_path)
      method driver_quit (line 496) | def driver_quit
      method window_size (line 513) | def window_size
      method window_rect (line 531) | def window_rect
      method start_driver (line 566) | def start_driver(http_client_ops = { http_client: nil, open_timeout:...
      method set_implicit_wait (line 601) | def set_implicit_wait(wait)
      method no_wait (line 612) | def no_wait
      method set_wait (line 626) | def set_wait(timeout = nil)
      method exists (line 643) | def exists(pre_check = 0, post_check = @default_wait)
      method execute_script (line 667) | def execute_script(script, *args)
      method execute_async_script (line 677) | def execute_async_script(script, *args)
      method execute_driver (line 711) | def execute_driver(script: '', type: 'webdriverio', timeout_ms: nil)
      method window_handles (line 717) | def window_handles
      method window_handle (line 724) | def window_handle
      method navigate (line 730) | def navigate
      method manage (line 736) | def manage
      method get (line 742) | def get(url)
      method current_url (line 748) | def current_url
      method title (line 754) | def title
      method switch_to (line 762) | def switch_to
      method find_elements (line 791) | def find_elements(*args)
      method find_element (line 809) | def find_element(*args)
      method find_element_by_image (line 826) | def find_element_by_image(png_img_path)
      method find_elements_by_image (line 843) | def find_elements_by_image(png_img_paths)
      method set_location (line 858) | def set_location(opts = {})
      method log_event (line 883) | def log_event(vendor:, event:)
      method log_event= (line 889) | def log_event=(log_event)
      method log_events (line 909) | def log_events(type = nil)
      method x (line 918) | def x

FILE: lib/appium_lib/error.rb
  type Appium (line 15) | module Appium
    class Error (line 16) | class Error < StandardError; end
    class NoDriverInstanceError (line 19) | class NoDriverInstanceError < Appium::Error; end
    class ArgumentError (line 21) | class ArgumentError < ArgumentError; end

FILE: lib/appium_lib/ios/common/errors.rb
  type Appium (line 15) | module Appium
    type Ios (line 16) | module Ios
      class CommandError (line 17) | class CommandError < RuntimeError

FILE: lib/appium_lib/ios/common/helper.rb
  type Appium (line 15) | module Appium
    type Ios (line 16) | module Ios
      class UITestElementsPrinter (line 18) | class UITestElementsPrinter < Nokogiri::XML::SAX::Document
        method start_element (line 21) | def start_element(type, attrs = [])
        method _print_attr (line 32) | def _print_attr(type, name, label, value, hint, visible) # rubocop...
      function ios_password (line 58) | def ios_password(length = 1)
      function page (line 74) | def page(opts = {})
      function id (line 101) | def id(id)
      function ele_index (line 109) | def ele_index(class_name, index)
      function string_attr_exact (line 128) | def string_attr_exact(class_name, attr, value)
      function find_ele_by_attr (line 139) | def find_ele_by_attr(class_name, attr, value)
      function find_eles_by_attr (line 150) | def find_eles_by_attr(class_name, attr, value)
      function string_attr_include (line 155) | def string_attr_include(class_name, attr, value)
      function find_ele_by_predicate (line 163) | def find_ele_by_predicate(class_name: '*', value:)
      function find_eles_by_predicate (line 175) | def find_eles_by_predicate(class_name: '*', value:)
      function find_ele_by_attr_include (line 191) | def find_ele_by_attr_include(class_name, attr, value)
      function find_eles_by_attr_include (line 201) | def find_eles_by_attr_include(class_name, attr, value)
      function find_ele_by_predicate_include (line 209) | def find_ele_by_predicate_include(class_name: '*', value:)
      function find_eles_by_predicate_include (line 221) | def find_eles_by_predicate_include(class_name: '*', value:)
      function first_ele (line 234) | def first_ele(class_name)
      function last_ele (line 241) | def last_ele(class_name)
      function tag (line 249) | def tag(class_name)
      function tags (line 257) | def tags(class_name)
      function tags_include (line 268) | def tags_include(class_names:, value: nil)
      function tags_exact (line 283) | def tags_exact(class_names:, value: nil)
      function string_visible_contains (line 299) | def string_visible_contains(element, value)
      function ele_by_json_visible_contains (line 320) | def ele_by_json_visible_contains(element, value)
      function eles_by_json_visible_contains (line 329) | def eles_by_json_visible_contains(element, value)
      function string_visible_exact (line 338) | def string_visible_exact(element, value)
      function ele_by_json_visible_exact (line 359) | def ele_by_json_visible_exact(element, value)
      function eles_by_json_visible_exact (line 368) | def eles_by_json_visible_exact(element, value)
      function _all_pred (line 377) | def _all_pred(opts)
      function ele_with_pred (line 391) | def ele_with_pred(opts)
      function eles_with_pred (line 402) | def eles_with_pred(opts)
      function _validate_object (line 406) | def _validate_object(*objects)
      function _by_json (line 456) | def _by_json(opts)
      function eles_by_json (line 506) | def eles_by_json(opts)
      function ele_by_json (line 512) | def ele_by_json(opts)

FILE: lib/appium_lib/ios/element/alert.rb
  type Appium (line 15) | module Appium
    type Ios (line 16) | module Ios
      function alert_accept (line 19) | def alert_accept
      function alert_dismiss (line 27) | def alert_dismiss

FILE: lib/appium_lib/ios/element/button.rb
  type Appium (line 16) | module Appium
    type Ios (line 17) | module Ios
      function button_class (line 25) | def button_class
      function button (line 33) | def button(value)
      function buttons (line 44) | def buttons(value = false)
      function first_button (line 52) | def first_button
      function last_button (line 60) | def last_button
      function button_exact (line 67) | def button_exact(value)
      function buttons_exact (line 74) | def buttons_exact(value)

FILE: lib/appium_lib/ios/element/generic.rb
  type Appium (line 15) | module Appium
    type Ios (line 16) | module Ios
      function find (line 20) | def find(value)
      function finds (line 27) | def finds(value)
      function find_exact (line 34) | def find_exact(value)
      function finds_exact (line 41) | def finds_exact(value)
      function raise_error_if_no_element (line 47) | def raise_error_if_no_element(element)
      function select_visible_elements (line 55) | def select_visible_elements(elements)

FILE: lib/appium_lib/ios/element/text.rb
  type Appium (line 16) | module Appium
    type Ios (line 17) | module Ios
      function static_text_class (line 25) | def static_text_class
      function text (line 33) | def text(value)
      function texts (line 43) | def texts(value = false)
      function first_text (line 51) | def first_text
      function last_text (line 57) | def last_text
      function text_exact (line 64) | def text_exact(value)
      function texts_exact (line 71) | def texts_exact(value)

FILE: lib/appium_lib/ios/element/textfield.rb
  type Appium (line 15) | module Appium
    type Ios (line 16) | module Ios
      function text_field_class (line 28) | def text_field_class
      function secure_text_field_class (line 33) | def secure_text_field_class
      function textfield (line 42) | def textfield(value)
      function textfields (line 61) | def textfields(value = false)
      function first_textfield (line 69) | def first_textfield
      function last_textfield (line 75) | def last_textfield
      function textfield_exact (line 85) | def textfield_exact(value)
      function textfields_exact (line 92) | def textfields_exact(value)
      function _textfield_visible (line 99) | def _textfield_visible
      function _textfield_exact_string (line 104) | def _textfield_exact_string(value)
      function _textfield_contains_string (line 111) | def _textfield_contains_string(value)

FILE: lib/appium_lib/ios/ios.rb
  type Appium (line 26) | module Appium
    type Ios (line 27) | module Ios
      class Bridge (line 28) | class Bridge
        method for (line 29) | def self.for(target)

FILE: lib/appium_lib/ios/xcuitest.rb
  type Appium (line 20) | module Appium
    type Ios (line 21) | module Ios
      type Xcuitest (line 22) | module Xcuitest

FILE: lib/appium_lib/ios/xcuitest/bridge.rb
  type Appium (line 17) | module Appium
    type Ios (line 18) | module Ios
      type Xcuitest (line 19) | module Xcuitest
        class Bridge (line 20) | class Bridge
          method for (line 21) | def self.for(target)

FILE: lib/appium_lib/ios/xcuitest/command/certificate.rb
  type Appium (line 17) | module Appium
    type Ios (line 18) | module Ios
      type Xcuitest (line 19) | module Xcuitest
        type Certificate (line 20) | module Certificate
          function install_certificate (line 32) | def install_certificate(cer_file:)

FILE: lib/appium_lib/ios/xcuitest/command/gestures.rb
  type Appium (line 15) | module Appium
    type Ios (line 16) | module Ios
      type Xcuitest (line 17) | module Xcuitest
        type Gesture (line 18) | module Gesture
          function swipe (line 25) | def swipe(direction:, element: nil)
          function scroll (line 46) | def scroll(direction:, distance: nil, name: nil, element: nil, t...
          function pinch (line 67) | def pinch(scale:, velocity: 1.0, element: nil)
          function double_tap (line 82) | def double_tap(x: nil, y: nil, element: nil)
          function touch_and_hold (line 99) | def touch_and_hold(x: nil, y: nil, element: nil, duration: 1.0)
          function two_finger_tap (line 112) | def two_finger_tap(element:)
          function one_finger_tap (line 127) | def one_finger_tap(x:, y:, element: nil)
          function drag_from_to_for_duration (line 147) | def drag_from_to_for_duration(from_x:, from_y:, to_x:, to_y:, du...
          function select_picker_wheel (line 164) | def select_picker_wheel(element:, order:, offset: nil)
          function alert (line 182) | def alert(action:, button_label: nil)

FILE: lib/appium_lib/ios/xcuitest/command/get_context.rb
  type Appium (line 15) | module Appium
    type Ios (line 16) | module Ios
      type Xcuitest (line 17) | module Xcuitest
        type GetContext (line 19) | module GetContext
          function xcuitest_get_contexts (line 28) | def xcuitest_get_contexts

FILE: lib/appium_lib/ios/xcuitest/command/multi_app_handler.rb
  type Appium (line 15) | module Appium
    type Ios (line 16) | module Ios
      type Xcuitest (line 17) | module Xcuitest
        type MultiAppHandler (line 21) | module MultiAppHandler
          function xcuitest_install_app (line 35) | def xcuitest_install_app(app:)
          function xcuitest_app_installed? (line 48) | def xcuitest_app_installed?(bundle_id:)
          function xcuitest_remove_app (line 62) | def xcuitest_remove_app(bundle_id:)
          function xcuitest_launch_app (line 76) | def xcuitest_launch_app(bundle_id:)
          function xcuitest_terminate_app (line 91) | def xcuitest_terminate_app(bundle_id:)
          function xcuitest_query_app_status (line 112) | def xcuitest_query_app_status(bundle_id:)
          function xcuitest_activate_app (line 127) | def xcuitest_activate_app(bundle_id:)

FILE: lib/appium_lib/ios/xcuitest/command/pasteboard.rb
  type Appium (line 15) | module Appium
    type Ios (line 16) | module Ios
      type Xcuitest (line 17) | module Xcuitest
        type PasteBoard (line 18) | module PasteBoard
          function set_pasteboard (line 26) | def set_pasteboard(content:, encoding: nil)
          function get_pasteboard (line 38) | def get_pasteboard(encoding: nil)

FILE: lib/appium_lib/ios/xcuitest/command/source.rb
  type Appium (line 15) | module Appium
    type Ios (line 16) | module Ios
      type Xcuitest (line 17) | module Xcuitest
        type Source (line 19) | module Source
          function xcuitest_source (line 25) | def xcuitest_source(format: :xml)

FILE: lib/appium_lib/ios/xcuitest/element.rb
  type Appium (line 20) | module Appium
    type Ios (line 21) | module Ios
      type Xcuitest (line 22) | module Xcuitest
        type Element (line 23) | module Element

FILE: lib/appium_lib/ios/xcuitest/element/button.rb
  type Appium (line 16) | module Appium
    type Ios (line 17) | module Ios
      type Xcuitest (line 18) | module Xcuitest
        type Element (line 19) | module Element
          function button_class (line 23) | def button_class
          function button (line 31) | def button(value)
          function buttons (line 42) | def buttons(value = false)
          function first_button (line 51) | def first_button
          function last_button (line 59) | def last_button
          function button_exact (line 66) | def button_exact(value)
          function buttons_exact (line 73) | def buttons_exact(value)

FILE: lib/appium_lib/ios/xcuitest/element/generic.rb
  type Appium (line 15) | module Appium
    type Ios (line 16) | module Ios
      type Xcuitest (line 17) | module Xcuitest
        type Element (line 18) | module Element
          function find (line 22) | def find(value)
          function finds (line 29) | def finds(value)
          function find_exact (line 37) | def find_exact(value)
          function finds_exact (line 44) | def finds_exact(value)
          function raise_error_if_no_element (line 51) | def raise_error_if_no_element(element)
          function select_visible_elements (line 59) | def select_visible_elements(elements)

FILE: lib/appium_lib/ios/xcuitest/element/text.rb
  type Appium (line 16) | module Appium
    type Ios (line 17) | module Ios
      type Xcuitest (line 18) | module Xcuitest
        type Element (line 19) | module Element
          function static_text_class (line 23) | def static_text_class
          function text (line 31) | def text(value)
          function texts (line 41) | def texts(value = false)
          function first_text (line 50) | def first_text
          function last_text (line 56) | def last_text
          function text_exact (line 63) | def text_exact(value)
          function texts_exact (line 70) | def texts_exact(value)

FILE: lib/appium_lib/ios/xcuitest/element/textfield.rb
  type Appium (line 15) | module Appium
    type Ios (line 16) | module Ios
      type Xcuitest (line 17) | module Xcuitest
        type Element (line 18) | module Element
          function text_field_class (line 23) | def text_field_class
          function secure_text_field_class (line 28) | def secure_text_field_class
          function textfield (line 37) | def textfield(value)
          function textfields (line 57) | def textfields(value = false)
          function first_textfield (line 66) | def first_textfield
          function last_textfield (line 72) | def last_textfield
          function textfield_exact (line 82) | def textfield_exact(value)
          function textfields_exact (line 89) | def textfields_exact(value)
          function _textfield_with_predicate (line 98) | def _textfield_with_predicate
          function _textfields_with_predicate (line 104) | def _textfields_with_predicate

FILE: lib/appium_lib/ios/xcuitest/helper.rb
  type Appium (line 15) | module Appium
    type Ios (line 16) | module Ios
      type Xcuitest (line 17) | module Xcuitest
        type Helper (line 18) | module Helper
          function string_attr_exact (line 20) | def string_attr_exact(class_name, attr, value)
          function string_attr_include (line 29) | def string_attr_include(class_name, attr, value)
          function last_ele (line 40) | def last_ele(class_name)
          function tag (line 51) | def tag(class_name)
          function tags (line 59) | def tags(class_name)
          function tags_include (line 71) | def tags_include(class_names:, value: nil)
          function tags_exact (line 93) | def tags_exact(class_names:, value: nil)

FILE: lib/appium_lib/sauce_labs.rb
  type Appium (line 15) | module Appium
    class SauceLabs (line 16) | class SauceLabs
      method initialize (line 47) | def initialize(appium_lib_opts)
      method sauce_server_url? (line 67) | def sauce_server_url?
      method server_url (line 80) | def server_url

FILE: lib/appium_lib/version.rb
  type Appium (line 15) | module Appium

FILE: test/first_test.rb
  class SampleTest (line 25) | class SampleTest < Minitest::Test
    method test_test (line 26) | def test_test
Condensed preview — 141 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (617K chars).
[
  {
    "path": ".github/CODEOWNERS",
    "chars": 13,
    "preview": "* @KazuCocoa\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "chars": 431,
    "preview": "## This is a\n* [ ] Bug report\n* [ ] Question\n* [ ] Freature Request\n\n## Summary\n\n## Environment\n* Appium version (or git"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 366,
    "preview": "# Summary\n\nPlease include a summary of the change and which issue is fixed.\nPlease also include relevant motivation and "
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 283,
    "preview": "version: 2\nupdates:\n- package-ecosystem: bundler\n  directory: \"/\"\n  schedule:\n    interval: weekly\n    time: \"11:00\"\n  o"
  },
  {
    "path": ".github/workflows/functional-test.yml",
    "chars": 4772,
    "preview": "name: Functional Tests\n\non:\n  # Run by manual at this time\n  workflow_dispatch:\n  push:\n    branches: [ master ]\n  pull_"
  },
  {
    "path": ".github/workflows/pr-title.yml",
    "chars": 222,
    "preview": "name: Conventional Commits\non:\n  pull_request:\n    types: [opened, edited, synchronize, reopened]\n\njobs:\n  lint:\n    use"
  },
  {
    "path": ".github/workflows/rubocop.yml",
    "chars": 543,
    "preview": "name: rubocop\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\njobs:\n  test:\n    strategy"
  },
  {
    "path": ".gitignore",
    "chars": 24,
    "preview": "*.gem\n*.lock\n.DS_Store\n\n"
  },
  {
    "path": ".rubocop.yml",
    "chars": 7599,
    "preview": "AllCops:\n  TargetRubyVersion: 3.1\nLayout/LineLength:\n  Max: 128\nMetrics/MethodLength:\n  Enabled: false\nMetrics/ModuleLen"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 30478,
    "preview": "# Changelogs\nCommit based release not is [release_notes.md](./release_notes.md)\n\nRelease tags are https://github.com/app"
  },
  {
    "path": "Gemfile",
    "chars": 810,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "LICENSE-2.0.txt",
    "chars": 11358,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "Rakefile",
    "chars": 1045,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "Thorfile",
    "chars": 152,
    "preview": "require 'appium_thor'\n\nAppium::Thor::Config.set do\n  gem_name     'appium_lib'\n  github_name  'ruby_lib'\n  version_file "
  },
  {
    "path": "android_tests/Gemfile",
    "chars": 673,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "android_tests/LICENSE-2.0.txt",
    "chars": 11358,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "android_tests/Rakefile",
    "chars": 1953,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "android_tests/appium.txt",
    "chars": 304,
    "preview": "[caps]\nautomationName = \"uiautomator2\"\nplatformName = \"android\"\ndeviceName = \"Android emulator\"\napp = \"../test_apps/api."
  },
  {
    "path": "android_tests/flaky.txt",
    "chars": 30,
    "preview": "android = \"lib/android/specs/\""
  },
  {
    "path": "android_tests/lib/android/specs/android/element/alert.rb",
    "chars": 1834,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "android_tests/lib/android/specs/android/element/button.rb",
    "chars": 2097,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "android_tests/lib/android/specs/android/element/generic.rb",
    "chars": 2212,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "android_tests/lib/android/specs/android/element/text.rb",
    "chars": 1669,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "android_tests/lib/android/specs/android/element/textfield.rb",
    "chars": 2287,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "android_tests/lib/android/specs/android/helper.rb",
    "chars": 3288,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "android_tests/lib/android/specs/android/patch.rb",
    "chars": 1336,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "android_tests/lib/android/specs/common/device.rb",
    "chars": 2318,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "android_tests/lib/android/specs/common/device_touchaction.rb",
    "chars": 2929,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "android_tests/lib/android/specs/common/element/window.rb",
    "chars": 938,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "android_tests/lib/android/specs/common/helper.rb",
    "chars": 4945,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "android_tests/lib/android/specs/common/patch.rb",
    "chars": 2884,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "android_tests/lib/android/specs/common/version.rb",
    "chars": 893,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "android_tests/lib/android/specs/common/web_context.rb",
    "chars": 1969,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "android_tests/lib/android/specs/driver.rb",
    "chars": 7209,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "android_tests/lib/android/specs/install.rb",
    "chars": 1236,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "android_tests/lib/android/specs/sauce_labs.rb",
    "chars": 1561,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "android_tests/lib/format.rb",
    "chars": 1590,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "android_tests/lib/run.rb",
    "chars": 3624,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "android_tests/readme.md",
    "chars": 1254,
    "preview": "ruby_lib_android\n=====================\n\nruby_lib's Android tests. Requires `Ruby 2.2+` or better.\n\n- `rake install` Inst"
  },
  {
    "path": "appium_lib.gemspec",
    "chars": 882,
    "preview": "require_relative 'lib/appium_lib/version'\n\nGem::Specification.new do |s|\n  s.required_ruby_version = '>= 3.1'\n\n  s.name "
  },
  {
    "path": "contributing.md",
    "chars": 1467,
    "preview": "# Contributing\n\nFor features or bug fixes, please submit a pull request. Ideally there would be a test as well. The rema"
  },
  {
    "path": "docs/android_uiautomator.md",
    "chars": 791,
    "preview": "# Help debugging\n\n- `adb shell uiautomator events` \n    - Prints out accessibility events to the console until the conne"
  },
  {
    "path": "docs/docs.md",
    "chars": 3726,
    "preview": "# Documentation\n## API Doc of Ruby Client\n- This library: http://www.rubydoc.info/github/appium/ruby_lib\n- Core: http://"
  },
  {
    "path": "docs/ios_xcuitest.md",
    "chars": 6184,
    "preview": "## XCUITest\n- Over Appium1.6.0 provides `XCUITest` automation name based on WebDriverAgent.\n    - [appium-xcuitest-drive"
  },
  {
    "path": "docs/parallel.md",
    "chars": 407,
    "preview": "Appium 1.7.0+ supports single server and multiple sessions, and it requires Xcode 9 for iOS.\n\n# Example\n## Run tests on "
  },
  {
    "path": "docs/w3c.md",
    "chars": 2086,
    "preview": "Perform touch actions for W3C module. Generate `touch` pointer action here and users can use this via `driver.action`\n\n["
  },
  {
    "path": "grid/README.md",
    "chars": 380,
    "preview": "# Run Grid\n\n```bash\n$ java -jar selenium-server-standalone-2.53.1.jar -role hub -hubConfig hub_config.json\n```\n\n**note**"
  },
  {
    "path": "grid/appium.txt.ios.example",
    "chars": 351,
    "preview": "[caps]\nplatformName = \"ios\"\nplatformVersion = \"11.4\"\ndeviceName =\"iPhone 11\"\nautomationName = 'XCUITest'\napp = \"/absolut"
  },
  {
    "path": "grid/config.json",
    "chars": 487,
    "preview": "{\n  \"capabilities\":\n  [\n    {\n      \"browserName\": \"iPhone 11\",\n      \"version\":\"11.4\",\n      \"platform\":\"ios\",\n      \"m"
  },
  {
    "path": "grid/hub_config.json",
    "chars": 332,
    "preview": "{\n  \"port\": 4444,\n  \"newSessionWaitTimeout\": -1,\n  \"servlets\" : [],\n  \"withoutServlets\": [],\n  \"custom\": {},\n  \"capabili"
  },
  {
    "path": "grid/hub_config_3.json",
    "chars": 556,
    "preview": "{\n  \"capabilities\":\n  [\n    {\n      \"browserName\": \"iPhone 11\",\n      \"version\":\"11.4\",\n      \"maxInstances\": 1,\n      \""
  },
  {
    "path": "ios_tests/Gemfile",
    "chars": 695,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/LICENSE-2.0.txt",
    "chars": 11358,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "ios_tests/Rakefile",
    "chars": 2897,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/appium.txt",
    "chars": 303,
    "preview": "[caps]\nplatformName = \"ios\"\nplatformVersion = \"18.5\"\ndeviceName =\"iPhone 16 Plus\"\nautomationName = 'XCUITest'\napp = \"../"
  },
  {
    "path": "ios_tests/data/unicode.txt",
    "chars": 1,
    "preview": "®"
  },
  {
    "path": "ios_tests/flaky.txt",
    "chars": 22,
    "preview": "ios = \"lib/ios/specs/\""
  },
  {
    "path": "ios_tests/lib/common.rb",
    "chars": 1774,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/lib/format.rb",
    "chars": 937,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/lib/ios/specs/common/element/window.rb",
    "chars": 1139,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/lib/ios/specs/common/helper.rb",
    "chars": 8634,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/lib/ios/specs/common/patch.rb",
    "chars": 1282,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/lib/ios/specs/common/version.rb",
    "chars": 941,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/lib/ios/specs/common/web_context.rb",
    "chars": 1705,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/lib/ios/specs/device/device.rb",
    "chars": 2093,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/lib/ios/specs/device/image_comparison.rb",
    "chars": 1168,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/lib/ios/specs/driver.rb",
    "chars": 6169,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/command/multi_app_handler.rb",
    "chars": 1860,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/command/pasteboard.rb",
    "chars": 1158,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/command/source.rb",
    "chars": 896,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/element/alert.rb",
    "chars": 1544,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/element/button.rb",
    "chars": 2218,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/element/generic.rb",
    "chars": 1498,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/element/text.rb",
    "chars": 2204,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/element/textfield.rb",
    "chars": 3411,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/helper.rb",
    "chars": 2278,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/mobile_methods.rb",
    "chars": 1291,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/patch.rb",
    "chars": 1192,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/xcuitest_gestures.rb",
    "chars": 3437,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/lib/run.rb",
    "chars": 730,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/parallel/test.rb",
    "chars": 2390,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "ios_tests/readme.md",
    "chars": 1243,
    "preview": "ruby_lib_ios\n=====================\n\nruby_lib's iOS tests. Requires `Ruby 2.2+` or better.\n\n- `rake install` Install gems"
  },
  {
    "path": "lib/appium_lib/android/android.rb",
    "chars": 1120,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/android/common/command/command.rb",
    "chars": 1185,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/android/common/helper.rb",
    "chars": 12290,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/android/element/alert.rb",
    "chars": 1548,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/android/element/button.rb",
    "chars": 4161,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/android/element/generic.rb",
    "chars": 3232,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/android/element/text.rb",
    "chars": 2034,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/android/element/textfield.rb",
    "chars": 2058,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/android/espresso/bridge.rb",
    "chars": 1002,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/android/espresso/element/button.rb",
    "chars": 5124,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/android/espresso/element/generic.rb",
    "chars": 2465,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/android/espresso/element.rb",
    "chars": 814,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/android/espresso/helper.rb",
    "chars": 2137,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/android/espresso.rb",
    "chars": 818,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/android/uiautomator2/bridge.rb",
    "chars": 1018,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/android/uiautomator2/element/button.rb",
    "chars": 4982,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/android/uiautomator2/element.rb",
    "chars": 787,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/android/uiautomator2/helper.rb",
    "chars": 4282,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/android/uiautomator2.rb",
    "chars": 838,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/appium.rb",
    "chars": 8451,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/common/command.rb",
    "chars": 658,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/common/device.rb",
    "chars": 671,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/common/helper.rb",
    "chars": 8408,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/common/http_client.rb",
    "chars": 956,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/common/log.rb",
    "chars": 1310,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/common/wait.rb",
    "chars": 3577,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/driver.rb",
    "chars": 29176,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/error.rb",
    "chars": 770,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/ios/common/errors.rb",
    "chars": 659,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/ios/common/helper.rb",
    "chars": 18665,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/ios/element/alert.rb",
    "chars": 1087,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/ios/element/button.rb",
    "chars": 2843,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/ios/element/generic.rb",
    "chars": 1849,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/ios/element/text.rb",
    "chars": 2840,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/ios/element/textfield.rb",
    "chars": 3738,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/ios/ios.rb",
    "chars": 977,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/bridge.rb",
    "chars": 1217,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/command/certificate.rb",
    "chars": 1479,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/command/gestures.rb",
    "chars": 9532,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/command/get_context.rb",
    "chars": 1209,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/command/multi_app_handler.rb",
    "chars": 5472,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/command/pasteboard.rb",
    "chars": 1689,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/command/source.rb",
    "chars": 1187,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/command.rb",
    "chars": 768,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/element/button.rb",
    "chars": 3190,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/element/generic.rb",
    "chars": 2207,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/element/text.rb",
    "chars": 3139,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/element/textfield.rb",
    "chars": 3825,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/element.rb",
    "chars": 888,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/helper.rb",
    "chars": 4201,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/ios/xcuitest.rb",
    "chars": 846,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/sauce_labs.rb",
    "chars": 3368,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib/version.rb",
    "chars": 783,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "lib/appium_lib.rb",
    "chars": 814,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "readme.md",
    "chars": 4103,
    "preview": "# appium_lib\n\n[![Gem Version](https://badge.fury.io/rb/appium_lib.svg)](http://badge.fury.io/rb/appium_lib)\n\n[![Download"
  },
  {
    "path": "release_notes.md",
    "chars": 197110,
    "preview": "#### v16.2.0 2026-04-19\n\n- [939a204](https://github.com/appium/ruby_lib/commit/939a20461738c80f9a19bb9ee8fe41030ab6c91e)"
  },
  {
    "path": "test/first_test.rb",
    "chars": 923,
    "preview": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  }
]

// ... and 2 more files (download for full content)

About this extraction

This page contains the full source code of the appium/ruby_lib GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 141 files (579.2 KB), approximately 183.9k tokens, and a symbol index with 904 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!