[
  {
    "path": ".github/CODEOWNERS",
    "content": "* @KazuCocoa\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "## This is a\n* [ ] Bug report\n* [ ] Question\n* [ ] Freature Request\n\n## Summary\n\n## Environment\n* Appium version (or git revision):\n* `ruby_lib` version:\n* Mobile platform/version/device under test:\n\n## Actual behaviour and steps to reproduce\n\n## Expected behaviour\n\n## Link to Appium/Ruby logs\n\nCreate a [GIST](https://gist.github.com) which is a paste of your _full_ Appium logs, and link them here. \n\n## Any additional comments\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "# Summary\n\nPlease include a summary of the change and which issue is fixed.\nPlease also include relevant motivation and context.\n\nCloses # (issue)\n\n# How Has This Been Tested?\n\nPlease describe the tests that you ran to verify your changes. If the change has test code, it can be alternative.\n\n- [ ] Test A\n- [ ] Test B\n\n# Checklist\n\n- [ ] `bundle exec rake rubocop`\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n- package-ecosystem: bundler\n  directory: \"/\"\n  schedule:\n    interval: weekly\n    time: \"11:00\"\n  open-pull-requests-limit: 10\n- package-ecosystem: github-actions\n  directory: \"/\"\n  schedule:\n    interval: weekly\n    time: \"11:00\"\n  open-pull-requests-limit: 10\n"
  },
  {
    "path": ".github/workflows/functional-test.yml",
    "content": "name: Functional Tests\n\non:\n  # Run by manual at this time\n  workflow_dispatch:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}\n  cancel-in-progress: true\n\njobs:\n  ios_test:\n    runs-on: macos-15\n    timeout-minutes: 90\n    env:\n          XCODE_VERSION: 16.4\n          IOS_VERSION: 18.5\n          IOS_DEVICE_NAME: iPhone 16 Plus\n\n    steps:\n    - uses: actions/checkout@v6\n\n    - name: Install Node.js\n      uses: actions/setup-node@v6\n      with:\n        node-version: 'lts/*'\n\n    - name: Select Xcode\n      uses: maxim-lobanov/setup-xcode@v1\n      with:\n        xcode-version: ${{ env.XCODE_VERSION }}\n    - run: defaults write com.apple.iphonesimulator PasteboardAutomaticSync -bool false\n\n    - uses: futureware-tech/simulator-action@v5\n      with:\n      # https://github.com/actions/runner-images/blob/main/images/macos/macos-14-arm64-Readme.md\n        model: ${{ env.IOS_DEVICE_NAME }}\n        os_version: ${{ env.IOS_VERSION }}\n\n    - name: Preparing other environment\n      run: |\n        brew install ffmpeg\n        brew tap wix/brew\n        brew install applesimutils\n\n    # Start Appium\n    - name: Install appium and mjpeg-consumer\n      run: |\n        npm install -g appium\n        npm install -g mjpeg-consumer\n    - run: |\n        appium driver install xcuitest\n        appium plugin install images\n        appium plugin install execute-driver\n        nohup appium --use-plugins=images,execute-driver --relaxed-security --log-timestamp --log-no-colors > appium.log &\n\n    - run: |\n        npx appium driver run xcuitest download-wda-sim --platform=ios --outdir=${{ github.workspace }}/wda\n      name: Downloading prebuilt WDA\n\n    - name: Set up Ruby\n      uses: ruby/setup-ruby@v1\n      with:\n        ruby-version: 4.0\n    - run: |\n        bundle install\n        bundle exec rake ios\n      name: Run tests\n      timeout-minutes: 60\n      working-directory: ios_tests\n      env:\n        LOCAL_PREBUILT_WDA: ${{ github.workspace }}/wda/WebDriverAgentRunner-Runner.app\n\n    - name: Save server output\n      if: ${{ always() }}\n      uses: actions/upload-artifact@master\n      with:\n        name: appium-ios_test_with_other_deps.log\n        path: |\n          appium.log\n          test/report/\n\n  android_test:\n    runs-on: ubuntu-latest\n    timeout-minutes: 90\n    env:\n      API_LEVEL: 35\n      ARCH: x86_64\n\n    steps:\n    - uses: actions/checkout@v6\n\n    - name: Set up Java\n      uses: actions/setup-java@v5\n      with:\n        distribution: temurin\n        java-version: '17'\n\n    - name: Install Node.js\n      uses: actions/setup-node@v6\n      with:\n        node-version: 'lts/*'\n\n    - name: Set up Ruby\n      uses: ruby/setup-ruby@v1\n      with:\n        ruby-version: 4.0\n\n    - name: Install appium\n      run: |\n        npm install -g appium\n        npm install -g mjpeg-consumer\n\n    - name: Start appium\n      run: |\n        appium driver install uiautomator2\n        appium plugin install images\n        appium plugin install execute-driver\n        nohup appium --use-plugins=images,execute-driver --relaxed-security --log-timestamp --log-no-colors > appium.log &\n\n    - name: Enable KVM group perms\n      run: |\n        echo 'KERNEL==\"kvm\", GROUP=\"kvm\", MODE=\"0666\", OPTIONS+=\"static_node=kvm\"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules\n        sudo udevadm control --reload-rules\n        sudo udevadm trigger --name-match=kvm\n\n    - name: AVD cache\n      uses: actions/cache@v5\n      id: avd-cache\n      with:\n        path: |\n          ~/.android/avd/*\n          ~/.android/adb*\n        key: avd-${{ env.API_LEVEL }}\n\n    - name: Create AVD snapshot for cache\n      if: steps.avd-cache.outputs.cache-hit != 'true'\n      uses: reactivecircus/android-emulator-runner@v2\n      with:\n        api-level: ${{ env.API_LEVEL }}\n        arch: ${{ env.ARCH }}\n        target: google_apis\n        force-avd-creation: false\n        emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none\n        disable-animations: false\n        script: echo \"Generated AVD snapshot for caching.\"\n\n    - name: run tests\n      uses: reactivecircus/android-emulator-runner@v2\n      with:\n        api-level: ${{ env.API_LEVEL }}\n        arch: ${{ env.ARCH }}\n        script: cd android_tests;bundle install;bundle exec rake --tasks;bundle exec rake android\n        target: google_apis\n        profile: Nexus 5X\n        disable-spellchecker: true\n        disable-animations: true\n\n    - name: Save server output\n      if: ${{ always() }}\n      uses: actions/upload-artifact@master\n      with:\n        name: appium-android_test_with_other_deps.log\n        path: |\n          appium.log\n          test/report/\n"
  },
  {
    "path": ".github/workflows/pr-title.yml",
    "content": "name: Conventional Commits\non:\n  pull_request:\n    types: [opened, edited, synchronize, reopened]\n\njobs:\n  lint:\n    uses: appium/appium-workflows/.github/workflows/pr-title.yml@main\n    with:\n      config-preset: angular\n"
  },
  {
    "path": ".github/workflows/rubocop.yml",
    "content": "name: rubocop\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\njobs:\n  test:\n    strategy:\n      fail-fast: false\n      matrix:\n        ruby: [3.1, 3.2, 3.3]\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v6\n    - name: Set up Ruby\n      uses: ruby/setup-ruby@v1\n      with:\n        ruby-version: ${{ matrix.ruby }}\n    - name: Install dependencies\n      run: bundle install\n    - name: Run rubocop\n      run: bundle exec rake rubocop\n    - name: Run tests\n      run: bundle exec rake test\n"
  },
  {
    "path": ".gitignore",
    "content": "*.gem\n*.lock\n.DS_Store\n\n"
  },
  {
    "path": ".rubocop.yml",
    "content": "AllCops:\n  TargetRubyVersion: 3.1\nLayout/LineLength:\n  Max: 128\nMetrics/MethodLength:\n  Enabled: false\nMetrics/ModuleLength:\n  Enabled: false\nMetrics/ClassLength:\n  Enabled: false\nMetrics/CyclomaticComplexity:\n  Enabled: false\nMetrics/PerceivedComplexity:\n  Enabled: false\nMetrics/AbcSize:\n  Enabled: false\nMetrics/BlockLength:\n  Enabled: false\nStyle/Documentation:\n  Enabled: false\nStyle/RegexpLiteral:\n  Enabled: false\n# blocked on https://github.com/appium/ruby_lib/issues/312. Already removed from core part\nStyle/GlobalVars:\n  Enabled: false\nStyle/PercentLiteralDelimiters:\n  Enabled: false\nStyle/CommentedKeyword:\n  Enabled: false\nNaming/AccessorMethodName:\n  Enabled: false\nNaming/RescuedExceptionsVariableName:\n  Enabled: false\nLayout/HeredocIndentation:\n  Enabled: false\nLayout/RescueEnsureAlignment:\n  Enabled: false\nLayout/HashAlignment:\n  Enabled: false\nStyle/ExplicitBlockArgument:\n  Enabled: false\nStyle/OptionalBooleanParameter:\n  Enabled: false\nNaming/MethodParameterName:\n  Enabled: false\nStyle/KeywordParametersOrder:\n  Enabled: false\nStyle/AccessorGrouping:\n  Enabled: false\nStyle/StringConcatenation:\n  Enabled: false\nLint/NonDeterministicRequireOrder:\n  Enabled: false\nGemspec/DeprecatedAttributeAssignment:\n  Enabled: true\nLayout/LineEndStringConcatenationIndentation:\n  Enabled: true\nLayout/SpaceBeforeBrackets:\n  Enabled: true\nLint/AmbiguousAssignment:\n  Enabled: true\nLint/AmbiguousOperatorPrecedence:\n  Enabled: false\nLint/AmbiguousRange:\n  Enabled: true\nLint/DeprecatedConstants:\n  Enabled: true\nLint/DuplicateBranch:\n  Enabled: true\nLint/DuplicateRegexpCharacterClassElement:\n  Enabled: true\nLint/EmptyBlock:\n  Enabled: true\nLint/EmptyClass:\n  Enabled: false\nLint/EmptyInPattern:\n  Enabled: true\nLint/IncompatibleIoSelectWithFiberScheduler:\n  Enabled: true\nLint/LambdaWithoutLiteralBlock:\n  Enabled: true\nLint/NoReturnInBeginEndBlocks:\n  Enabled: true\nLint/NumberedParameterAssignment:\n  Enabled: true\nLint/OrAssignmentToConstant:\n  Enabled: true\nLint/RedundantDirGlobSort:\n  Enabled: true\nLint/RequireRelativeSelfPath:\n  Enabled: true\nLint/SymbolConversion:\n  Enabled: true\nLint/ToEnumArguments:\n  Enabled: true\nLint/TripleQuotes:\n  Enabled: true\nLint/UnexpectedBlockArity:\n  Enabled: true\nLint/UnmodifiedReduceAccumulator:\n  Enabled: true\nSecurity/IoMethods:\n  Enabled: true\nStyle/ArgumentsForwarding:\n  Enabled: true\nStyle/CollectionCompact:\n  Enabled: true\nStyle/DocumentDynamicEvalDefinition:\n  Enabled: true\nStyle/EndlessMethod:\n  Enabled: true\nStyle/HashConversion:\n  Enabled: false\nStyle/HashExcept:\n  Enabled: true\nStyle/IfWithBooleanLiteralBranches:\n  Enabled: true\nStyle/InPatternThen:\n  Enabled: true\nStyle/MultilineInPatternThen:\n  Enabled: true\nStyle/NegatedIfElseCondition:\n  Enabled: true\nStyle/NilLambda:\n  Enabled: true\nStyle/NumberedParameters:\n  Enabled: true\nStyle/NumberedParametersLimit:\n  Enabled: true\nStyle/QuotedSymbols:\n  Enabled: true\nStyle/RedundantArgument:\n  Enabled: true\nStyle/RedundantSelfAssignmentBranch:\n  Enabled: true\nStyle/SelectByRegexp:\n  Enabled: true\nStyle/StringChars:\n  Enabled: true\nStyle/SwapValues:\n  Enabled: true\nGemspec/DevelopmentDependencies: # new in 1.44\n  Enabled: true\nLayout/LineContinuationLeadingSpace: # new in 1.31\n  Enabled: true\nLayout/LineContinuationSpacing: # new in 1.31\n  Enabled: true\nLint/ConstantOverwrittenInRescue: # new in 1.31\n  Enabled: true\nLint/DuplicateMagicComment: # new in 1.37\n  Enabled: true\nLint/NonAtomicFileOperation: # new in 1.31\n  Enabled: false\nLint/RefinementImportMethods: # new in 1.27\n  Enabled: true\nLint/RequireRangeParentheses: # new in 1.32\n  Enabled: true\nLint/UselessRescue: # new in 1.43\n  Enabled: true\nMetrics/CollectionLiteralLength: # new in 1.47\n  Enabled: true\nNaming/BlockForwarding: # new in 1.24\n  Enabled: true\nSecurity/CompoundHash: # new in 1.28\n  Enabled: true\nStyle/ArrayIntersect: # new in 1.40\n  Enabled: true\nStyle/ComparableClamp: # new in 1.44\n  Enabled: true\nStyle/ConcatArrayLiterals: # new in 1.41\n  Enabled: true\nStyle/DirEmpty: # new in 1.48\n  Enabled: true\nStyle/EmptyHeredoc: # new in 1.32\n  Enabled: true\nStyle/EnvHome: # new in 1.29\n  Enabled: true\nStyle/FetchEnvVar: # new in 1.28\n  Enabled: true\nStyle/FileEmpty: # new in 1.48\n  Enabled: true\nStyle/FileRead: # new in 1.24\n  Enabled: true\nStyle/FileWrite: # new in 1.24\n  Enabled: true\nStyle/MagicCommentFormat: # new in 1.35\n  Enabled: true\nStyle/MapCompactWithConditionalBlock: # new in 1.30\n  Enabled: true\nStyle/MapToHash: # new in 1.24\n  Enabled: true\nStyle/MapToSet: # new in 1.42\n  Enabled: true\nStyle/MinMaxComparison: # new in 1.42\n  Enabled: true\nStyle/NestedFileDirname: # new in 1.26\n  Enabled: true\nStyle/ObjectThen: # new in 1.28\n  Enabled: true\nStyle/OperatorMethodCall: # new in 1.37\n  Enabled: true\nStyle/RedundantConstantBase: # new in 1.40\n  Enabled: false\nStyle/RedundantDoubleSplatHashBraces: # new in 1.41\n  Enabled: true\nStyle/RedundantEach: # new in 1.38\n  Enabled: true\nStyle/RedundantHeredocDelimiterQuotes: # new in 1.45\n  Enabled: true\nStyle/RedundantInitialize: # new in 1.27\n  Enabled: true\nStyle/RedundantStringEscape: # new in 1.37\n  Enabled: true\nGemspec/RequireMFA: # new in 1.23\n  Enabled: true\nLint/UselessRuby2Keywords: # new in 1.23\n  Enabled: true\nStyle/OpenStructUse: # new in 1.23\n  Enabled: false\nLint/RedundantStringCoercion:\n  Enabled: false\nGemspec/AddRuntimeDependency: # new in 1.65\n  Enabled: true\nLint/ConstantReassignment: # new in 1.70\n  Enabled: true\nLint/DuplicateMatchPattern: # new in 1.50\n  Enabled: true\nLint/DuplicateSetElement: # new in 1.67\n  Enabled: true\nLint/HashNewWithKeywordArgumentsAsDefault: # new in 1.69\n  Enabled: true\nLint/ItWithoutArgumentsInBlock: # new in 1.59\n  Enabled: true\nLint/LiteralAssignmentInCondition: # new in 1.58\n  Enabled: true\nLint/MixedCaseRange: # new in 1.53\n  Enabled: true\nLint/NumericOperationWithConstantResult: # new in 1.69\n  Enabled: true\nLint/RedundantRegexpQuantifiers: # new in 1.53\n  Enabled: true\nLint/SharedMutableDefault: # new in 1.70\n  Enabled: true\nLint/UnescapedBracketInRegexp: # new in 1.68\n  Enabled: true\nLint/UselessDefined: # new in 1.69\n  Enabled: true\nLint/UselessNumericOperation: # new in 1.66\n  Enabled: true\nStyle/AmbiguousEndlessMethodDefinition: # new in 1.68\n  Enabled: true\nStyle/BitwisePredicate: # new in 1.68\n  Enabled: true\nStyle/CombinableDefined: # new in 1.68\n  Enabled: true\nStyle/DataInheritance: # new in 1.49\n  Enabled: true\nStyle/DigChain: # new in 1.69\n  Enabled: true\nStyle/ExactRegexpMatch: # new in 1.51\n  Enabled: true\nStyle/FileNull: # new in 1.69\n  Enabled: true\nStyle/FileTouch: # new in 1.69\n  Enabled: true\nStyle/ItAssignment: # new in 1.70\n  Enabled: true\nStyle/KeywordArgumentsMerging: # new in 1.68\n  Enabled: true\nStyle/MapIntoArray: # new in 1.63\n  Enabled: true\nStyle/RedundantArrayConstructor: # new in 1.52\n  Enabled: true\nStyle/RedundantCurrentDirectoryInPath: # new in 1.53\n  Enabled: true\nStyle/RedundantFilterChain: # new in 1.52\n  Enabled: true\nStyle/RedundantInterpolationUnfreeze: # new in 1.66\n  Enabled: true\nStyle/RedundantLineContinuation: # new in 1.49\n  Enabled: true\nStyle/RedundantRegexpArgument: # new in 1.53\n  Enabled: true\nStyle/RedundantRegexpConstructor: # new in 1.52\n  Enabled: true\nStyle/ReturnNilInPredicateMethodDefinition: # new in 1.53\n  Enabled: true\nStyle/SafeNavigationChainLength: # new in 1.68\n  Enabled: false\nStyle/SendWithLiteralMethodName: # new in 1.64\n  Enabled: true\nStyle/SingleLineDoEndBlock: # new in 1.57\n  Enabled: true\nStyle/SuperArguments: # new in 1.64\n  Enabled: true\nStyle/SuperWithArgsParentheses: # new in 1.58\n  Enabled: true\nStyle/YAMLFileRead: # new in 1.53\n  Enabled: true\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelogs\nCommit based release not is [release_notes.md](./release_notes.md)\n\nRelease tags are https://github.com/appium/ruby_lib/releases .\n\n## [16.2.0] - 2026-04-19\n- 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).\n\n## 16.1.1 - 2025-12-28\n- Add deprecated mark for start_logs_broadcast/stop_logs_broadcast to use BiDi instead\n\n## 16.1.0 - 2025-03-37\n- Relaxed usable the appium_lib_core deps version to `> 11`\n\n## 16.0.1 - 2025-03-16\n- Update appium_lib_core deps version condition\n\n## 16.0.0 - 2025-02-16\n- Use `http://127.0.0.1:4723` as the default url destination instead of `http://127.0.0.1:4723/wd/hub`\n    - `--base-path` in appium server may need to drop the `/wd/hub` if configured\n\n## 15.2.2 - 2024-08-06\n- Fix non `app` capability behavior\n\n## 15.2.1 - 2024-08-03\n- Fix client side timeout in the default http client\n- Bump appium_lib_core 9.2.1+ to apply the fix\n\n## 15.2.0 - 2024-07-20\n- Raise defined errors instead of Ruby general errors by appium_lib's own errors\n\n## 15.1.0 - 2024-05-19\n- Use appium_lib_core 9.0.0\n\n## 15.0.1 - 2024-04-26\n- Bump release module (internal only)\n\n## 15.0.0 - 2024-04-11\n- Breaking\n    - Use appium_lib_core 8.0.0 and up\n        - Please refer to [the diff](https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#800---2024-03-08) about the details.\n        - Remove `Appium::MultiTouch` and `Appium::TouchAction`\n            - `swipe` could use `mobile:swipe`, or w3c actions. Multi-touch actions such as zoom/pinch can be written in w3c actions.\n            - 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.\n\n## 14.0.0 - 2024-01-25\n- Use appium_lib_core  7.4.0 and up\n    - Removed deprecated `export_session` and `export_session_path`\n    - Please get the session id via `driver.session_id` instead\n\n## 13.0.2 - 2024-01-25\n- Allow up to appium_lib_core 7.3\n\n## 13.0.1 - 2023-06-19\n- Ruby 3.0+ is required\n\n## 12.3.3 - 2023-04-27\n\n### Bug fixes\n- Fix start_driver\n\n## 12.2.1 - 2023-04-24\n\n### 1. Enhancements\n\n### 2. Bug fixes\n- fixed the `default_wait` value as zero (regression)\n    `set_wait` will set `0` if no `appium_lib: {wait: 0}` is not given.\n\n### 3. Deprecations\n\n\n## 12.2.0 - 2022-12-25\n\n### 1. Enhancements\n\n### 2. Bug fixes\n\n### 3. Deprecations\n- Defaults to XCUITest modulefor iOS\n\n## 12.1.3 - 2022-12-13\n\n### 1. Enhancements\n- Minor internal update\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## 12.1.2 - 2022-11-13\n\n### 1. Enhancements\n\n### 2. Bug fixes\n- Fix `app` capability handling in parsing a toml file\n\n### 3. Deprecations\n\n## 12.1.1 - 2022-10-19\n\n### 1. Enhancements\n\n### 2. Bug fixes\n- Fix undefined `.warning` method call\n\n### 3. Deprecations\n\n## 12.1.0 - 2022-10-11\n\n### 1. Enhancements\n- Bump minimal ruby_lib_core version\n\n### 2. Bug fixes\n\n### 3. Deprecations\n- Deprecate `Appium::Driver.absolute_app_path`, instead, please set proper `app` capability\n    - This aims to reduce client side validation as same as other clients.\n\n## 12.0.1 - 2022-04-02\n\n### 1. Enhancements\n\n### 2. Bug fixes\n- Fixes `promote_appium_methods`\n\n### 3. Deprecations\n\n## 12.0.0 - 2021-11-06\n### 1. Enhancements\n\n- Update ruby_lib_core version from v4 to v5. The change affects this library.\n    - [Migration from v4 to v5 in ruby_lib_core client](https://github.com/appium/ruby_lib_core#migration-from-v4-to-v5)\n        - Base Selenium Ruby binding is now v4\n        - Support only W3C WebDriver spec (and a few Appium specific commands)\n        - Support Ruby 2.6+\n    - `element.id` returns the element id instead of `element.ref`\n        - `element.ref` now returns an array\n    - Removed `forceMjsonwp` to send only MJSONWP capabilities since Selenium cleint v4 no longer supports MJSONWP\n    - No longer set default `timeouts` as `0`\n        - ruby_lib_core will call `/timeouts` endpoint only when `appium_lib: { wait: 5 }` is provided explicitly\n    - Raises `::Appium::Core::Error::ArgumentError` instead of `ArgumentError` for this library specific argument errors\n\n### 2. Deprecations\n- `TouchAction` and `MultiTouch` are deprecated\n    - Please use W3C actions instead https://github.com/appium/ruby_lib/blob/master/docs/w3c.md\n    - Other examples\n        - https://github.com/appium/ruby_lib/pull/909\n        - https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#deprecations-1\n- `launch_app`, `close_app` and `reset` are deprecated. Please read [issues#15807](https://github.com/appium/appium/issues/15807) for more details.\n    - `activate_app` or a new session request can be alternatives of `launch_app`\n    - `terminate_app` or close the session request can be alternatives of `close_app`\n    - Close current session and creating a new session, or `terminate_app` and `launch_app` can be alternatives of `reset`\n- 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.\n\n## 11.1.0 - 2020-12-29 (11.2.0 is the same as this version)\n\nSupport Ruby 3\n\n### 1. Enhancements\n\n### 2. Bug fixes\n\n### 3. Deprecations\n- Rename `Appium::Ios::Xcuitest::Guesture#tap` to `Appium::Ios::Xcuitest::Guesture#one_finger_tap` to prevent conflicts with `tap` in Ruby\n\n## 11.0.0 - 2020-12-19\n\nBump supported Ruby version to 2.4+\n\n[related changes](https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#400---2020-12-19) in ruby_lib_core.\n\n## 10.6.0\n### 1. Enhancements\n\n### 2. Bug fixes\n\n### 3. Deprecations\n- Remove auto `Pry.config.pager` off\n    - Please turn it off if you needed. https://github.com/pry/pry/wiki/Customization-and-configuration#Config_pager\n\n## v10.5.0\n### 1. Enhancements\n- Added `driver.log_event` to post an event\n- Added `driver.log_events` to get the events\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v10.4.1\n### 1. Enhancements\n\n### 2. Bug fixes\n- Fix iOS `page` in native context\n\n### 3. Deprecations\n\n## v10.4.0\n### 1. Enhancements\n- Add `execute_driver` support\n\n### 2. Bug fixes\n- Fix wrong warning message in create session\n\n### 3. Deprecations\n\n## v10.3.1\n### 1. Enhancements\n\n### 2. Bug fixes\n- Fix `scroll_to` and `scroll_to_exact` for Android [#859](https://github.com/appium/ruby_lib/pull/859)\n\n### 3. Deprecations\n\n## v10.3.0\n### 1. Enhancements\n- Add `tvOS` support\n    - Requires Appium 1.13\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v10.2.0\n### 1. Enhancements\n\n### 2. Bug fixes\n- **Breaking changes**\n    - `find_element/s_by_image` no longer need arguments except for a file path\n        - `find_element/s_by_image(file_to_image)` instead of `find_element/s_by_image(file_to_image, match_threshold:, visualize:)`\n\n### 3. Deprecations\n\n## v10.1.0\n### 1. Enhancements\n\n### 2. Bug fixes\n- `*_exact` methods handle value as case sensitive\n    - This might break test cases if it calls `*_exact` as case insensitive\n\n### 3. Deprecations\n\n## v10.0.0\n\nThis change has a breaking change about implicit wait.\n\n### 1. Enhancements\n- **Breaking changes**\n    - Set implicit wait zero by default following [WebDriver spec in Selenium](https://www.seleniumhq.org/docs/04_webdriver_advanced.jsp)\n        - The change potentially break your `find_element/s`\n        - You can wrap it with `wait` method to avoid the error explicitly\n        - Or you also can configure `wait: 20` as `appium_lib` capability to keep the behaviour\n- [Experimental]\n    - Add `direct_connect` capability\n        - How to use: `{ caps: {...},  appium_lib: { direct_connect: true }}`\n        - Read [here](https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#enhancements-1) for more details\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.18.0\n### 1. Enhancements\n- Enhance Espresso automation name adaptation\n    - Call `xpath` locator strategy instead of `uiautomator` locator strategy in various wrapper methods like `text/s`, `button/s`, etc\n    - [#884](https://github.com/appium/ruby_lib/pull/844/)\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.17.0\n### 1. Enhancements\n- 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)\n    - Returns `TouchAction.new` if the driver works as _MJSONWP_\n\n### 2. Bug fixes\n\n### 3. Deprecations\n- `:offset_x` and `:offset_y` in `TouchAction#swipe` is deprecated in favor of `:end_x` and `:end_y`\n- [internal] Remove `check_server_version_xcuitest`\n\n## v9.16.1\n### 1. Enhancements\n\n### 2. Bug fixes\n- Fix failing Appium version comparison [#836](https://github.com/appium/ruby_lib/issues/836)\n\n### 3. Deprecations\n\n## v9.16.0\n### 1. Enhancements\n- Introduce `appium_thor` in order to automate release\n\n### 2. Bug fixes\n- `:app` can be non-path capability like [Windows](https://github.com/Microsoft/WinAppDriver)\n    ```ruby\n    { caps:\n      { platformName: :windows,\n        app: 'Microsoft.WindowsCalculator_8wekyb3d8bbwe!App'\n      }\n    } # `:app` is bundle id.\n\n    { caps:\n      { platformName: :windows,\n        app: 'relative/path/to/app'\n      }\n    } # `:app` will be alsolute path to the `:app` if the path exists\n    ```\n\n### 3. Deprecations\n\n## v9.15.2\n### 1. Enhancements\n- Wrap selenium-webdriver apis via `Appium::Driver` through Appium Core Bridge [#827](https://github.com/appium/ruby_lib/pull/827/files)\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.15.1\n### 1. Enhancements\n- [Internal] Use [ruby_lib_core](https://github.com/appium/ruby_lib_core) 2.0\n    - The change shouldn't affect this version since the change influence `Core.new`.\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.15.0\n### 1. Enhancements\n- Requires `appium_lib_core` 1.9.0+\n    - Requires `selenium-webdriver 3.14+`\n    - Support `find_element :image, image` [appium-base-driver#235](https://github.com/appium/appium-base-driver/pull/235)\n        - Requires Appium1.8.2\n    - Read [changelog](https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#190---2018-08-05) for more details\n- Add `distance` option in `scroll` for XCUITest [#805](https://github.com/appium/ruby_lib/pull/805). Thanks [@saim80](https://github.com/saim80)\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.14.3\n### 1. Enhancements\n- Add Tizen\n- Use [ruby_lib_core](https://github.com/appium/ruby_lib_core) 1.8.0\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.14.2\n### 1. Enhancements\n- add `mobile: installCertificate` shortcut for XCUITest\n- add `mobile: getContexts` shortcut for XCUITest\n- Add `find_element_by_image` and `find_elements_by_image` to handle `ImageElement`\n   - 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\n   - Experimental feature\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.14.1\n### 1. Enhancements\n\n### 2. Bug fixes\n- Fix an initialisation error for iOS with `appium_lib_core 1.7.0` [#785](https://github.com/appium/ruby_lib/issues/785)\n\n### 3. Deprecations\n\n## v9.14.0\n### 1. Enhancements\n- Breaking changes for `press_keycode` and `long_press_keycode`\n    - Detail: https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#170---2018-05-28\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.13.0\n### 1. Enhancements\n- Requires `appium_lib_core` 1.6.0+\n    - Breaking change for `app_state`: https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#160---2018-05-08\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.12.1\n### 1. Enhancements\n- Support `start_logs_broadcast` and `stop_logs_broadcast` for iOS\n\n### 2. Bug fixes\n- Back compatible for `wait(number) {}` and `wait_true(number) {}`\n\n### 3. Deprecations\n\n## v9.12.0\n### 1. Enhancements\n\n### 2. Bug fixes\n\n### 3. Deprecations\n- Changed the name of arguments\n    - `swipe(start_x:, start_y:, end_x:, end_y:)` instead of `swipe(start_x:, start_y:, offset_x:, offset_y:)`\n\n## v9.11.1\n### 1. Enhancements\n- Apply `ruby_lib_core ~> 1.4.2`\n   - Support image comparison features\n       - http://www.rubydoc.info/gems/appium_lib_core/Appium/Core/Device/ImageComparison\n\n### 2. Bug fixes\n- Fix `wait` compatibility for `ruby_lib_core ~> 1.4.1`\n\n### 3. Deprecations\n\n## v9.11.0\n### 1. Enhancements\n- Add `start_logs_broadcast` and `stop_logs_broadcast` which use WebSocket to get logcat.\n    - Include https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#140---2018-04-15\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.10.0\n### 1. Enhancements\n- Some changes for Appium 1.8.0\n    - Read also:\n        - https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#131---2018-02-14\n        - https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#130---2018-01-28\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.9.2\n### 1. Enhancements\n- Fix Security Vulnerability(Nokogiri)[#761](https://github.com/appium/ruby_lib/pull/761)\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.9.1\n### 1. Enhancements\n\n### 2. Bug fixes\n- fix `Minitest`'s revert: [URL](http://docs.seattlerb.org/minitest/History_rdoc.html#label-5.11.2+-2F+2018-01-25)\n\n### 3. Deprecations\n\n## v9.9.0\n### 1. Enhancements\n- Bump the core library to 1.3.0\n    - The change have one breaking change for `start_recording_screen`(Android)\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.8.5\n### 1. Enhancements\n\n### 2. Bug fixes\n- Fix _Bug: NameError: uninitialized constant Minitest::VERSION [#750](https://github.com/appium/ruby_lib/issues/750)_\n\n### 3. Deprecations\n\n## v9.8.4\n### 1. Enhancements\n\n### 2. Bug fixes\n- Fix `TypeError: superclass mismatch for class Test` for minitest `5.11.0`+ [PR](https://github.com/appium/ruby_lib/pull/748)\n\n### 3. Deprecations\n\n## v9.8.3\n### 1. Enhancements\n- Bump the core library to 1.2.5\n    - The changelog is [here](https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#124---2018-01-03)\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.8.2\n### 1. Enhancements\n- add `shell` command wrapped `mobile: shell` for Android [#732](https://github.com/appium/ruby_lib/pull/732)\n- add handling multiple apps for iOS [#729](https://github.com/appium/ruby_lib/issues/729)\n- Adapt W3C commands and make sure to work Appium 1.7.2+\n    - Which module, msjsonwp or w3c, used depends on server side's response.\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.8.1\n### 1. Enhancements\n\n### 2. Bug fixes\n- Fix creating session for the new W3C createSession\n    - https://github.com/appium/appium/pull/9791\n\n### 3. Deprecations\n\n## v9.8.0\n\n### 1. Enhancements\n- Add start/stop recording screen [#674](https://github.com/appium/ruby_lib/issues/674)\n- replace core directory to core library [#665](https://github.com/appium/ruby_lib/issues/665), [#718](https://github.com/appium/ruby_lib/pull/718)\n    - No change for users\n\n### 2. Bug fixes\n\n### 3. Deprecations\n- `ap_` prefixed logging\n- `source_window`: use `get_source` instead\n- `ios_version`: use `platform_version` instead\n- `current_app`: use `current_activity`, for example to know current app.\n\n## v9.7.5\n\n### 1. Enhancements\n\n### 2. Bug fixes\n- [fix: take care capybara case #716](https://github.com/appium/ruby_lib/pull/716)\n\n### 3. Deprecations\n\n## v9.7.4\n\n### 1. Enhancements\n- Add unlock command: [PR](https://github.com/appium/ruby_lib/pull/710/files)\n- Be able to call `source` command from any `automationName`\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.7.3\n\n### 1. Enhancements\n- Get source from XCUITest with `xcuitest_source format: :json`\n    - https://github.com/appium/ruby_lib/pull/699\n- `:espresso` support\n\n### 2. Bug fixes\n\n\n### 3. Deprecations\n\n## v9.7.2\n\n### 1. Enhancements\n- Raise error if capability is wrong\n    - [validate `caps` and `appium_lib` #684](https://github.com/appium/ruby_lib/issues/684)\n\n### 2. Bug fixes\n- `Bug: NoMethodError: undefined method 'write_session_id' for #<Appium::Core::Driver:0x00007fa69119ce88>` [#686](https://github.com/appium/ruby_lib/issues/686)\n- undefined local variable or method `patch_webdriver_element' [#687](https://github.com/appium/ruby_lib/issues/687)\n\n### 3. Deprecations\n\n## v9.7.1\nHot-fix for v9.7.0: [uninitialized constant Appium::VERSION #680](https://github.com/appium/ruby_lib/issues/680)\n\n## v9.7.0\n\n_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.\nI've checked the behaviour and confirmed test cases in this repository. So, please create issues if you have any issues against this version.\n\n### 1. Enhancements\n- Refactoring\n```\nlib/appium_lib         # root directory\n              /core    # Minumul driver files for the Appium server and dependencies for Selenium Driver.\n              /common  # Appium related(some methods to make ruby_lib useful)\n              /android # for Android\n              /ios     # for iOS\n```\n\n- 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)\n- Logs\n    - `get_available_log_types`: To get a list of available log types\n    - `get_log(type)`: To get logs associated with `type`\n\n### 2. Bug fixes\n\n### 3. Deprecations\n- [refactor: Reduce patch_webdriver_element and some DEPRECATIONs #663](https://github.com/appium/ruby_lib/pull/663)\n    - Remove deprecated methods:\n        - Android\n            - `client_xpath/client_xpaths`\n                - Please use `xpath` or `find_element/s(:xpath, \"xpaths\")`\n        - iOS\n            - `get_page`\n                - Please use `source` instead\n    - Deprecated\n        - iOS\n            - `ios_version`, `source_window`, `page_window`\n              - Please use `source` instead\n\n\n## v9.6.1\n### 1. Enhancements\n- Refactor `XCUItest` for iOS and `uiautomator2` for Android a bit\n\n### 2. Bug fixes\n- missing extending `button` methods for `uiautomator2`, Android\n\n### 3. Deprecations\n\n## v9.6.0\n### 1. Enhancements\n- Reduce Global Driver\n    - 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.\n      ```ruby\n      Appium::Driver.new(opts, true).start_driver # $driver is defined.\n      Appium::Driver.new(opts, false).start_driver # $driver isn't defined.\n      ```\n        - [link](https://github.com/appium/ruby_lib/blob/master/docs/ios_docs.md#initialize)\n    - We need to provide `driver` to work `TouchAction` and `MultiAction` without global driver\n        - `TouchAction`\n            ```ruby\n            driver =  Appium::Driver.new(opts, false).start_driver\n            action = TouchAction.new.press(x: 45, y: 100).wait(5).release\n            action.perform(driver)\n            action = TouchAction.new.swipe(....)\n            action.perform(driver)\n            ```\n\n        - `MultiAction`\n            ```ruby\n            driver =  Appium::Driver.new(opts, false).start_driver\n            pinch 200, true, driver\n            ```\n- 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)\n    - Require Xcode 9 and Appium 1.6.6\n\n### 2. Bug fixes\n- `scroll_to` is failed on some Android 5.0 and 5.1 devices\n    - https://github.com/appium/ruby_lib/pull/638\n\n### 3. Deprecations\n\n### Special Thanks\n- Fixing `acroll_to`\n    - [@emen](https://github.com/emen)\n- Add alias `quit_driver`\n    - [@DylanLacey ](https://github.com/DylanLacey)\n\n## v9.5.0\n### 1. Enhancements\n- Support `selenium-webdriver3.4.1+`\n    - Support new `createSession`\n\n### 2. Bug fixes\n\n### 3. Deprecations\n- Drop `selenium-webdriver` `3.0 ~ 3.4.0` since some methods depends on `selenium-webdriver3.4.1+`\n\n## v9.4.10\n### 1. Enhancements\n- some refactoring\n- add some documentations\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.4.9\n### 1. Enhancements\n\n### 2. Bug fixes\n- fix handling a tap gesture in xcuitest [#611](https://github.com/appium/ruby_lib/pull/611)\n\n### 3. Deprecations\n\n## v9.4.8\n### 1. Enhancements\n- within_context swallowing block return value [#311](https://github.com/appium/ruby_lib/issues/311)\n- get current_package for Android [#604](https://github.com/appium/ruby_lib/issues/604)\n- Show visibility on iOS page command [#609](https://github.com/appium/ruby_lib/pull/609)\n    - related: allow showing all elements on ios page command [#310](https://github.com/appium/ruby_lib/issues/310)\n\n### 2. Bug fixes\n\n### 3. Deprecations\n- Android: mark deprecated for client side xpath strategy [#608](https://github.com/appium/ruby_lib/pull/608)\n- iOS: get_page method [#609](https://github.com/appium/ruby_lib/pull/609)\n\n## v9.4.7\n### 1. Enhancements\n\n### 2. Bug fixes\n- fix raise 500 error by `driver.remote_status` in `appium_server_version` [#599](https://github.com/appium/ruby_lib/issues/599)\n\n### 3. Deprecations\n\n## v9.4.6\n### 1. Enhancements\n\n### 2. Bug fixes\n- reduce gemfile size [#591](https://github.com/appium/ruby_lib/issues/591)\n    - Exclude `ios_tests`, `android_tests` and `grid` from gem\n\n### 3. Deprecations\n\n## v9.4.5\n### 1. Enhancements\n- add `touch_and_hols` for `mobile:` command in XCUITest [#581](https://github.com/appium/ruby_lib/pull/581)\n- Driver disables Pry pager without asking [#582](https://github.com/appium/ruby_lib/issues/582)\n- add grid environments in this repository.\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.4.4\n### 1. Enhancements\n- add mobile gesture, `mobile: alert`\n    - Required over https://github.com/appium/appium-xcuitest-driver/releases/tag/v2.28.6\n- add travis example for ios [#573](https://github.com/appium/ruby_lib/pull/573)\n- remove some redundant code [#572](https://github.com/appium/ruby_lib/pull/572), [#571](https://github.com/appium/ruby_lib/pull/571)\n- update api-demos [#569](https://github.com/appium/ruby_lib/issues/569)\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.4.3\n### 1. Enhancements\n- Use uiautomator for uiautomator2 [#561](https://github.com/appium/ruby_lib/pull/561)\n    - improve stability for some methods\n- don't use selenium-webdriver 3.5+ [#559](https://github.com/appium/ruby_lib/pull/559)\n- Auto link bug # from release notes [#239](https://github.com/appium/ruby_lib/issues/239)\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n### Special Thanks\n- Thanks for checking uiautomator2\n    - [@Edouard-chin](https://github.com/Edouard-chin), [@rajdeepv](https://github.com/rajdeepv)\n\n## v9.4.2\n### 1. Enhancements\n\n### 2. Bug fixes\n- fix drag_from_to_for_duration gets server error [#552](https://github.com/appium/ruby_lib/issues/552)\n\n### 3. Deprecations\n\n## v9.4.1\n### 1. Enhancements\n\n### 2. Bug fixes\n- fix 9.4.0 release sudden failures [#546](https://github.com/appium/ruby_lib/issues/546)\n    - XPath strategy for find_element/s sudden fail than uiautomator strategy.\n    - Use `:xpath` strategy only for uiautomator2\n\n### 3. Deprecations\n\n## v9.4.0\n### 1. Enhancements\n- update mobile gesture APIs for XCUITest(WDA) [#514](https://github.com/appium/ruby_lib/pull/514)\n    - For XCUITest(WebDriverAgent)\n    - 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)`.\n    - Users can write test code without `.ref` method for elements in `execute_script`.\n    - Example: https://github.com/appium/ruby_lib/pull/537\n- Support UIAutomator2 strategy for Android[#505](https://github.com/appium/ruby_lib/issues/505)\n    - Fix some find elemenet methods[#544](https://github.com/appium/ruby_lib/pull/544)\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.3.8\n### 1. Enhancements\n- allow using TestObject server [#538](https://github.com/appium/ruby_lib/pull/538)\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.3.7\n### 1. Enhancements\n- Remove appium suffix from find element [#532](https://github.com/appium/ruby_lib/pull/532)\n    - rename `@driver.find_element/s_with_appium` to `@driver.find_element/s`\n- fix documentations\n\n### 2. Bug fixes\n\n### 3. Deprecations\n- `@driver.find_element/s_with_appium`\n    - use `@driver.find_element/s` instead\n\n## v9.3.6\n### 1. Enhancements\n- Add toggle touch id enrollment [#521](https://github.com/appium/ruby_lib/pull/521)\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.3.5\n### 1. Enhancements\n- add some commands for Android and class chain for iOS [#513](https://github.com/appium/ruby_lib/issues/513)\n    - iOS\n        - `find_element :class_chain, 'XCUIElementTypeWindow/*/*/XCUIElementTypeStaticText'`\n    - Android\n        - `get_system_bars`\n        - `get_display_density`\n        - `is_keyboard_shown`\n- add scrollable index parameter into scroll methods [#506](https://github.com/appium/ruby_lib/issues/506)\n    - `scroll_to(text, scrollable_index = 0)`\n    - `scroll_to_exact(text, scrollable_index = 0)`\n- clear `@actions` in Appium::TouchAction if `perform` is called [#511](https://github.com/appium/ruby_lib/issues/511)\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.3.4\n### 1. Enhancements\n- [remove workaround](https://github.com/appium/ruby_lib/pull/474/commits/57cc95264e83e14862f729683b93c1f020a30ce5) to pass CI\n- document uiautomator events logging command [#319](https://github.com/appium/ruby_lib/issues/319)\n- use predicate for XCUITest to improve performance [#493](https://github.com/appium/ruby_lib/issues/493)\n    - `text/s`, `button/s`, `textfield/s`, `tags_exact`, `tags_include`\n    - new: `find_ele/s_by_predicate`, `find_ele/s_by_predicate_include`\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n\n## v9.3.3\n### 1. Enhancements\n- 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)\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.3.2\n### 1. Enhancements\n- allow SAUCE_ENDPOINT env var to override sauce server url/path [#485](https://github.com/appium/ruby_lib/pull/485)\n    - Read [readme](https://github.com/appium/ruby_lib/blob/89c7c89be058153d119d517eab22ccc318d33649/readme.md#sauce-labs-env-vars)'s `SAUCE_ENDPOINT` section.\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.3.1\n### 1. Enhancements\n- Clarify disabling Sauce Labs. [#471](https://github.com/appium/ruby_lib/pull/471)\n- add getting performance [#479](https://github.com/appium/ruby_lib/issues/479)\n    - **require appium-base-driver@2.1.7**\n\n### 2. Bug fixes\n- Fix missed var rename [#481](https://github.com/appium/ruby_lib/pull/481)\n\n### 3. Deprecations\n\n## v9.3.0\n### 1. Enhancements\n- wait / wait_true need global defaults [#250](https://github.com/appium/ruby_lib/issues/250)\n    - You can set default value in `appium_lib`\n    - e.g.: [lib/appium_lib/driver.rb](https://github.com/appium/ruby_lib/blob/34803ef6b7b94df9ef4e147ba8fec5c1d2cfaada/lib/appium_lib/driver.rb#L341-L351)\n- Problem with delta_x/delta_y in swipe method [#461](https://github.com/appium/ruby_lib/issues/461)\n    - Revert _fix arguments for `move_to` in `swipe` method._ in Appium v8.2.1\n    - `delta_x/delta_y` replace to `offset_*` for iOS\n        - e.g.: `swipe start_x: start_x, start_y: start_y, end_offset_x: 0, offset_y: -100`\n    - `delta_x/delta_y` replace to `end_*` for Android\n        - e.g.: `swipe start_x: start_x, start_y: start_y, end_x: start_x, end_y: start_y - 100`\n    - The reason why there are two kind of arguments is the following issue.\n        - [Difference behaviour between iOS and Android regarding with `swipe` action #7702](https://github.com/appium/appium/issues/7702)\n- Clarify disabling Sauce Labs. #471\n  - update documentations\n\n### 2. Bug fixes\n- REQUIRED_VERSION_XCUITEST [#463](https://github.com/appium/ruby_lib/issues/463)\n- find elements except for name attributes in text/s, button/s [#462](https://github.com/appium/ruby_lib/issues/462)\n    - Return only **visible** elements\n        - Previously, these methods return **all** elements.\n\n### 3. Deprecations\n- Problem with delta_x/delta_y in swipe method [#461](https://github.com/appium/ruby_lib/issues/461)\n    - `delta_x/delta_y` are replaced to `offset_*` for iOS and `end_*` for Android.\n\n## v9.2.0\n### 1. Enhancements\n- update set_wait / no_wait logic #249\n    - `no_wait` just set `implicit_wait = 0`\n    - `set_wait` just set `@default_wait` or arbitrary time as `implicit_wait`\n    - remove `last_waits` attribute\n\n### 2. Bug fixes\n- automationName always nil if set automationName in server side #450\n\n### 3. Deprecations\n\n## v9.1.3\n\nSupport selenium-webdriver 3.0.4+\n\n### 1. Enhancements\n- Improve performance for button/s and text/s #442\n- Should use `open_timeout` or `read_timeout` instead of `timeout` #436\n- add documentation for alternative long_press method #440\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n## v9.1.2\n### 1. Enhancements\n- add `appium_client_version`: https://github.com/appium/ruby_lib/issues/260\n- add some tests and fix some rubocop syntax errors\n\n### 2. Bug fixes\n- fix `set_immediate_value`: https://github.com/appium/ruby_lib/issues/263\n\n### 3. Deprecations\n\n## v9.1.1\n### 1. Enhancements\n\n### 2. Bug fixes\n- fix Finds exact in ios does not return an array #423\n\n### 3. Deprecations\n\nThanks @slipy12\n\n## v9.1.0\n### 1. Enhancements\n- update dependencies\n    - Support selenium-webdriver 3.0.2+\n        - If you'd like to use `selenium-webdriver2.x`, please use `appium_lib9.0.0`\n\n### 2. Bug fixes\n\n### 3. Deprecations\n- Drop Ruby 1.9.3, 2.0, 2.1 support\n    - Because these ruby versions have already stop updating.\n\n## v9.0.0\n### 1. Enhancements\n- Support `XCUITest` strategy for iOS\n    - Basically, `XCUITest` strategy is compatible with `Appium` strategy in this library.\n    - 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\n        - Users who use `find_element/s` should work fine.\n        - tests for elements are [here](https://github.com/appium/ruby_lib/tree/master/ios_tests/lib/ios/specs/ios/element)\n\nSpecial thanks to @montdidier\n\n### 2. Bug fixes\n\n### 3. Deprecations\n\n\n## v8.2.1\n- fix arguments for `move_to` in `swipe` method.\n    - https://github.com/appium/ruby_lib/pull/405\n    - Please set `:delta_x` and `:delta_y` as the distance from start to move.\n"
  },
  {
    "path": "Gemfile",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nsource 'https://rubygems.org'\ngemspec\n\ngem 'appium_thor', '~> 2.0'\ngem 'hashdiff', '~> 1.2.0'\ngem 'minitest', '~> 5.0'\ngem 'minitest-reporters', '~> 1.1'\ngem 'pry'\ngem 'rake', '~> 13.0'\ngem 'rubocop', '1.86.1'\ngem 'yard', '~> 0.9.11'\n"
  },
  {
    "path": "LICENSE-2.0.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "Rakefile",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nrequire 'bundler/gem_tasks'\nrequire 'rubocop/rake_task'\nrequire 'rake/testtask'\n\ndesc 'Execute RuboCop static code analysis'\nRuboCop::RakeTask.new(:rubocop) do |t|\n  t.patterns = %w(lib ios_tests android_tests)\n  t.options = %w(-D)\n  t.fail_on_error = true\nend\n\ndesc('Run all unit tests in test directory')\nRake::TestTask.new(:test) do |t|\n  t.libs << 'test'\n  t.libs << 'lib'\n  t.test_files = FileList[ENV['TESTS'] ? ENV['TESTS'].split(',') : 'test/**/*_test.rb']\nend\n"
  },
  {
    "path": "Thorfile",
    "content": "require 'appium_thor'\n\nAppium::Thor::Config.set do\n  gem_name     'appium_lib'\n  github_name  'ruby_lib'\n  version_file 'lib/appium_lib/version.rb'\nend\n"
  },
  {
    "path": "android_tests/Gemfile",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nsource 'https://rubygems.org'\neval_gemfile File.join(File.expand_path('..', __dir__), 'Gemfile')\n"
  },
  {
    "path": "android_tests/LICENSE-2.0.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "android_tests/Rakefile",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nrequire 'rubygems'\nrequire 'rake'\nrequire 'rubocop/rake_task'\n\ntask default: :android\n\n# Run sh and ignore exception\ndef run_sh(cmd)\n  sh cmd\nrescue StandardError\n  # ignored\nend\n\n# Run cmd. On failure run install and try again.\ndef bash(cmd)\n  sh cmd do |successful, result|\n    # exitstatus 7 means bundle install failed\n    # non-zero (except 7 retry path) means the test failed\n    if !successful && result.exitstatus == 7\n      Rake::Task['install'].execute\n      sh cmd\n    elsif !successful\n      raise \"Command failed with status #{result.exitstatus}: #{cmd}\"\n    end\n  end\nend\n\n# rake android['single_text_name']\n# rake android\ndef run_android(test_file = nil)\n  cmd = 'bundle exec ruby ./lib/run.rb android'\n  cmd = %(#{cmd} \"#{test_file}\") if test_file\n  bash cmd\nend\n\n# Run a single test with:\n# rake android['android/element/generic']\n#\n# Run all tests with:\n# rake android\ndesc 'Run the Android tests'\ntask :android, :args, :test_file do |_args, test_file|\n  run_android test_file[:args]\nend\n\ndesc 'Run the Android tests without uninstalling'\ntask :droid, :args, :test_file do |_args, test_file|\n  run_android test_file[:args]\nend\n\ndesc 'Run bundle install'\ntask :install do\n  sh 'bundle install'\nend\n\ndesc 'Execute RuboCop static code analysis'\nRuboCop::RakeTask.new(:rubocop) do |t|\n  t.patterns = %w(**/*.rb)\n  t.options = %w(-D)\n  t.fail_on_error = false\nend\n"
  },
  {
    "path": "android_tests/appium.txt",
    "content": "[caps]\nautomationName = \"uiautomator2\"\nplatformName = \"android\"\ndeviceName = \"Android emulator\"\napp = \"../test_apps/api.apk\"\nappPackage = \"io.appium.android.apis\"\nappActivity = \"io.appium.android.apis.ApiDemos\"\nsome_capability = \"some_capability\"\n\n\n[appium_lib]\nsauce_username = \"\"\nsauce_access_key = \"\"\n"
  },
  {
    "path": "android_tests/flaky.txt",
    "content": "android = \"lib/android/specs/\""
  },
  {
    "path": "android_tests/lib/android/specs/android/element/alert.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"android[android/element/alert]\"\nclass AndroidTest\n  class Element\n    class Alert < Minitest::Test\n      def open_alert\n        # trigger the alert\n        wait { button('OK Cancel dialog with a message').click }\n      end\n\n      def test_01_alert_click\n        # nav to alert activity\n        wait { find('app').click }\n        wait { find('alert').click }\n\n        # test\n        wait { open_alert }\n        wait { alert_click('OK') }\n      end\n\n      def test_02_alert_accept\n        wait { open_alert }\n        wait { alert_accept }\n      end\n\n      def test_03_alert_accept_text\n        wait { open_alert }\n        wait { assert_equal alert_accept_text, 'OK' }\n        wait { alert_accept }\n      end\n\n      def test_04_alert_dismiss\n        wait { open_alert }\n        wait { alert_dismiss }\n      end\n\n      def test_05_alert_dismiss_text\n        wait { open_alert }\n\n        # alert dialog button placement changed:\n        # 'OK Cancel dialog with a long message'\n        # Android L: 'Something, Cancel, Ok'\n        # Android 19: 'Cancel, Something, Ok'\n\n        wait { assert_equal alert_dismiss_text.downcase, 'cancel' }\n        wait { alert_dismiss }\n\n        # nav to start activity\n        2.times { back }\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "android_tests/lib/android/specs/android/element/button.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"android[android/element/button]\"\nclass AndroidTest\n  class Element\n    class Button < Minitest::Test\n      def before_first\n        # nav to buttons activity\n        wait { find('App').click }\n        wait { find('Activity').click }\n        wait { find('Animation').click }\n      end\n\n      def after_last\n        # nav back to home activity\n        3.times { back }\n      end\n\n      def fade_in\n        'Fade in'\n      end\n\n      def test_01_before_first\n        before_first\n      end\n\n      def test_02_button\n        # by index\n        2.times { wait { assert_equal button(1).text.upcase, fade_in.upcase } }\n\n        # by name contains\n        wait { assert_equal button('ade').text.upcase, fade_in.upcase }\n      end\n\n      def test_03_buttons\n        exp = ['ZOOM IN', 'MODERN ZOOM IN', 'THUMBNAIL ZOOM']\n        wait { assert_equal buttons('zoom').map(&:text).map(&:upcase), exp }\n        wait { assert_equal buttons.length, 6 }\n      end\n\n      def test_04_first_button\n        wait { assert_equal first_button.text.upcase, fade_in.upcase }\n      end\n\n      def test_05_last_button\n        wait { assert_equal last_button.text.upcase, 'THUMBNAIL ZOOM' }\n      end\n\n      def test_06_button_exact\n        wait { assert_equal button_exact(fade_in).text.upcase, fade_in.upcase }\n      end\n\n      def test_07_buttons_exact\n        2.times { wait { assert_equal buttons_exact(fade_in).first.text.upcase, fade_in.upcase } }\n      end\n\n      def test_08_after_last\n        after_last\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "android_tests/lib/android/specs/android/element/generic.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"android[android/element/generic]\"\nclass AndroidTest\n  class Element\n    class Generic < Minitest::Test\n      def content\n        'Content'\n      end\n\n      def partial\n        'tent'\n      end\n\n      def test_01_find_works_before_and_after_get_source\n        wait { assert_equal find(partial).text, content }\n        wait { assert_equal get_source.class, String }\n        wait { assert_equal find(partial).text, content }\n      end\n\n      def test_01_find\n        wait { assert_equal find(partial).text, content }\n      end\n\n      def test_01_finds\n        wait { assert_equal finds(partial).first.text, content }\n      end\n\n      def test_01_find_exact\n        wait { assert_equal find_exact(content).text, content }\n      end\n\n      def test_01_finds_exact\n        wait { assert_equal finds_exact(content).first.text, content }\n      end\n\n      # scroll_to is broken\n      def test_01_scroll_to\n        wait { scroll_to('Views').click }\n        wait { assert_equal scroll_to('scrollbars').text, 'ScrollBars' }\n\n        wait { find('ScrollBars').click }\n        wait { text('style').click }\n        wait { assert scroll_to('Developers', 1).text.include? 'What would it take to build a better mobile phone?' }\n        back\n        back\n        # back to start activity\n        back\n      end\n\n      def test_01_scroll_to_exact\n        wait { scroll_to('Views').click }\n\n        wait { assert_equal scroll_to_exact('ScrollBars').text, 'ScrollBars' }\n        wait { find('ScrollBars').click }\n        wait { text('style').click }\n        back\n        back\n        # back to start activity\n        back\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "android_tests/lib/android/specs/android/element/text.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"android[android/element/text]\"\nclass AndroidTest\n  class Element\n    class Text < Minitest::Test\n      def must_raise_no_element\n        assert_raises Selenium::WebDriver::Error::NoSuchElementError do\n          yield\n        end\n      end\n\n      def test_01_text\n        wait { assert ['API Demos', \"Access'ibility\"].include? text(1).text }\n        wait { assert_equal text('mos').text, 'API Demos' }\n      end\n\n      def test_02_texts\n        wait { assert_equal texts('i').length, 7 }\n        wait { assert_equal texts.length, 13 }\n      end\n\n      def test_03_first_text\n        wait { assert ['API Demos', \"Access'ibility\"].include? first_text.text }\n      end\n\n      def test_04_last_text\n        wait { assert ['API Demos', 'Views'].include? last_text.text }\n      end\n\n      def test_05_text_exact\n        must_raise_no_element { text_exact 'mos' }\n\n        # should pass\n        wait { assert_equal text_exact('API Demos').text, 'API Demos' }\n      end\n\n      def test_06_texts_exact\n        wait { assert_equal texts_exact('API Demos').length, 1 }\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "android_tests/lib/android/specs/android/element/textfield.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"android[android/element/textfield]\"\nclass AndroidTest\n  class Element\n    class TextField < Minitest::Test\n      def must_raise_no_element\n        assert_raises Selenium::WebDriver::Error::NoSuchElementError do\n          yield\n        end\n      end\n\n      def left\n        'Left is best'\n      end\n\n      def right\n        'Right is always right'\n      end\n\n      def before_first\n        # nav to activity\n        wait { find('app').click }\n        wait { find('activity').click }\n        wait { find('custom title').click }\n      end\n\n      def after_last\n        # back to start\n        3.times { back }\n      end\n\n      def test_01_before_test\n        before_first\n      end\n\n      def test_02_textfield\n        wait { assert_equal textfield(1).text, left }\n        wait { assert_equal textfield('right').text, right }\n      end\n\n      def test_03_textfields\n        wait { assert_equal textfields('right').first.text, right }\n        wait { assert_equal textfields.length, 2 }\n      end\n\n      def test_04_first_textfield\n        wait { assert_equal first_textfield.text, left }\n      end\n\n      def test_05_last_textfield\n        wait { assert_equal last_textfield.text, right }\n      end\n\n      def test_06_textfield_exact\n        must_raise_no_element { textfield_exact 'zz' }\n        wait { assert_equal textfield_exact(left).text, left }\n      end\n\n      def test_07_textfields_exact\n        wait { assert_equal textfields_exact('zz'), [] }\n        wait { assert_equal textfields_exact(left).first.text, left }\n      end\n\n      def test_08_hide_keyboard\n        first_textfield.click\n        hide_keyboard\n      end\n\n      def test_09_after_last\n        after_last\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "android_tests/lib/android/specs/android/helper.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"android[android/helper]\"\nclass AndroidTest\n  class Helper < Minitest::Test\n    def test_01_tags\n      wait { assert_equal tags('android.widget.TextView').length, 13 }\n    end\n\n    def test_01_get_page_class\n      # digit values change based on screen size\n      # larger screens have more elements\n\n      act = get_page_class\n      assert act.split(\"\\n\").length >= 5\n\n      assert act.include? '13x android.widget.TextView'\n      if automation_name_is_espresso?\n        # 13x android.widget.TextView\n        # 1x android.widget.ActionMenuView\n        # 1x android.widget.Toolbar\n        # 1x com.android.internal.widget.ActionBarContainer\n        # 1x com.android.internal.widget.ActionBarContextView\n        # 1x android.widget.ListView\n        # 1x android.widget.FrameLayout\n        # 1x com.android.internal.widget.ActionBarOverlayLayout\n        # 1x com.android.internal.policy.DecorView\n        assert act.include? '1x android.widget.ActionMenuView'\n      else\n        assert act.include? '3x android.widget.FrameLayout'\n        assert act.include? '2x android.view.ViewGroup'\n        assert act.include? '1x android.widget.ListView'\n        assert act.include? '1x hierarchy'\n      end\n    end\n\n    # def test_01_page_class' do # tested by get_page_c\n\n    def test_02_get_android_inspect\n      # line count changes based on screen size\n      wait { assert get_android_inspect.split(\"\\n\").length >= 40 }\n    end\n\n    # def test_01_get_inspect' do # tested by get_android_ins\n    # def test_01_page' do # tested by get_android_ins\n\n    def id_key\n      'animation_2_instructions'\n    end\n\n    def id_value\n      'Select an animation:'\n    end\n\n    def test_03_xml_keys\n      wait do\n        id_pair = xml_keys id_key\n        id_pair = id_pair.to_a[0]\n        assert_equal id_pair.length, 2\n        assert_equal id_pair.first, id_key\n        assert_equal id_pair.last, id_value\n      end\n    end\n\n    def test_04_resolve_id\n      wait do\n        str = resolve_id id_key\n        assert_equal str, id_value\n      end\n    end\n\n    def test_05_xml_values\n      wait do\n        value = xml_values(id_value).first.last\n        assert_equal value, id_value\n      end\n    end\n\n    def test_06_find_by_id\n      wait { find('accessibility').click }\n      wait { find('accessibility node provider').click }\n\n      if automation_name_is_uiautomator2? || automation_name_is_espresso?\n        wait { text 'Accessibility/Accessibility Node Provider' }\n      else\n        # With string.xml\n        # Only for uiautomator1\n        wait { id 'accessibility_node_provider' }\n      end\n\n      2.times { back }\n    end\n\n    def test_07_ids\n      wait { assert_equal ids('android:id/text1').length, 12 }\n    end\n  end\nend\n"
  },
  {
    "path": "android_tests/lib/android/specs/android/patch.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"android[android/patch]\"\nclass AndroidTest\n  class Patch < Minitest::Test\n    def test_type\n      # nav to textfield\n      wait { find('app').click }\n      wait { find('Search').click }\n      wait { find('Invoke Search').click }\n\n      wait { first_textfield.type 'ok' }\n      wait { assert_equal first_textfield.text, 'ok' }\n\n      # TODO: how to invoke random am start commands?\n      # nav to start activity\n      # io.appium.android.apis/io.appium.android.apis.ApiDemos\n\n      # keyboard may exist, if it doesn't then an error will raise\n      ignore { hide_keyboard }\n\n      # return to app start\n      back\n      wait { find('Invoke Search') }\n      back\n      wait { find_exact('Search') }\n      back\n      wait { find('app') }\n    end\n  end\nend\n"
  },
  {
    "path": "android_tests/lib/android/specs/common/device.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"android[common/device]\"\nclass AndroidTest\n  class Common\n    class Device < Minitest::Test\n      def test_01_get_performance_data_types\n        expected = %w(batteryinfo cpuinfo memoryinfo networkinfo)\n        assert_equal get_performance_data_types.sort, expected\n\n        assert_equal get_performance_data(\n          package_name: 'io.appium.android.apis', data_type: 'cpuinfo'\n        )[0], %w(user kernel)\n      end\n\n      def test_02_start_activity\n        wait { assert_equal current_activity, '.ApiDemos' }\n        start_activity(\n          app_package: 'io.appium.android.apis',\n          app_activity: '.accessibility.AccessibilityNodeProviderActivity'\n        )\n        wait { assert_equal current_activity.include?('Node'), true }\n        start_activity(\n          app_package: 'com.android.settings',\n          app_activity: '.Settings',\n          app_wait_package: 'com.android.settings',\n          app_wait_activity: '.Settings'\n        )\n        wait { assert_equal current_activity.include?('Settings'), true }\n      end\n\n      def test_03_current_package\n        start_activity(\n          app_package: 'io.appium.android.apis',\n          app_activity: '.accessibility.AccessibilityNodeProviderActivity'\n        )\n        wait { assert_equal current_package, 'io.appium.android.apis' }\n      end\n\n      def test_04_app_strings\n        wait_true { app_strings.key? 'activity_save_restore' }\n      end\n\n      def test_05_press_keycode\n        # http://developer.android.com/reference/android/view/KeyEvent.html\n        press_keycode 176\n      end\n\n      def test_06_long_press_keycode\n        # http://developer.android.com/reference/android/view/KeyEvent.html\n        long_press_keycode 176\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "android_tests/lib/android/specs/common/device_touchaction.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"android[common/device_touchaction]\"\nclass AndroidTest\n  class Common\n    class DeviceTouchAction < Minitest::Test\n      def test_01_before_test\n        wait { text('Accessibility') }\n      end\n\n      def test_02_action_chain_press_release\n        wait do\n          e = text('Accessibility')\n          action.click(e).perform\n        end\n        wait { text('Custom View') }\n        back\n        wait { text_exact 'NFC' }\n      end\n\n      def test_03_action_chain_tap\n        wait do\n          e = text('Accessibility')\n          action.click(e).perform\n        end\n        wait { text('Custom View') }\n        back\n        wait { text_exact 'NFC' }\n      end\n\n      def test_04_swipe\n        wait { text('Animation').click }\n        wait { text_exact('Bouncing Balls').click }\n\n        driver.action\n              .move_to_location(0.75, 0.25).pointer_down(:left)\n              .move_to_location(0.75, 50)\n              .release.perform\n\n        3.times { back }\n        wait { text_exact 'NFC' }\n      end\n\n      def test_05_pinch_zoom\n        wait { text_exact 'NFC' }\n        wait { text_exact('Graphics').click }\n        wait { scroll_to('Touch Paint').click }\n\n        # multiple action chains\n        f1 = driver.action.add_pointer_input(:touch, 'finger1')\n        f1.create_pointer_move(\n          duration: 0.5, x: 500, y: 800,\n          origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT\n        )\n        f1.create_pointer_down(:left)\n        f1.create_pause(0.5)\n        f1.create_pointer_move(\n          duration: 3, x: 500, y: 700,\n          origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT\n        )\n        f1.create_pointer_up(:left)\n\n        f2 = driver.action.add_pointer_input(:touch, 'finger2')\n        f2.create_pointer_move(\n          duration: 0.5, x: 500, y: 800,\n          origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT\n        )\n        f2.create_pointer_down(:left)\n        f1.create_pause(0.5)\n        f2.create_pointer_move(\n          duration: 3, x: 500, y: 900,\n          origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT\n        )\n        f2.create_pointer_up(:left)\n\n        driver.perform_actions [f1, f2]\n\n        wait { text('Graphics/Touch Paint') }\n        2.times { back }\n        wait { text_exact 'NFC' }\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "android_tests/lib/android/specs/common/element/window.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"android[common/element/window]\"\nclass AndroidTest\n  class Common\n    class Element\n      class Window < Minitest::Test\n        def test_window_size\n          wait do\n            size = window_size\n            assert_equal size.width.class, Integer\n            assert_equal size.height.class, Integer\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "android_tests/lib/android/specs/common/helper.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"android[common/helper]\"\nclass AndroidTest\n  class Common\n    class Helper < Minitest::Test\n      def wait_opts\n        { timeout: 0.2, interval: 0.2 } # max_wait, interval\n      end\n\n      # There's no `must_not_raise` as the opposite of must_raise\n\n      # By default code is expected to not raise exceptions.\n      # must_not_raise is a no-op.\n\n      # wait is a success unless an error is raised\n      # max_wait=0 is infinity to use 0.1\n      def test_01_wait\n        # successful wait should not raise error\n        wait(wait_opts) { true }\n        wait(wait_opts) { false }\n        wait(wait_opts) { nil }\n\n        # failed wait should error\n        assert_raises ::Appium::Core::Wait::TimeoutError do\n          wait(wait_opts) { raise }\n        end\n\n        # regular rescue will not handle exceptions outside of StandardError hierarchy\n        # must rescue Exception explicitly to rescue everything\n        assert_raises ::Appium::Core::Wait::TimeoutError do\n          wait(wait_opts) { raise NoMemoryError }\n        end\n\n        assert_raises ::Appium::Core::Wait::TimeoutError do\n          wait(timeout: 0.2, interval: 0.0) { raise NoMemoryError }\n        end\n\n        e = assert_raises ArgumentError do\n          wait_true(invalidkey: 2) { true }\n        end\n        assert_equal 'unknown keyword: :invalidkey', e.message\n      end\n\n      def test_02_ignore\n        # ignore should rescue all exceptions\n        ignore { true }\n        ignore { false }\n        ignore { nil }\n        ignore { raise }\n        ignore { raise NoMemoryError }\n      end\n\n      # wait_true is a success unless the value is not true\n      def test_03_wait_true\n        # successful wait should not error\n        wait_true(wait_opts) { true }\n\n        # failed wait should error\n        assert_raises ::Appium::Core::Wait::TimeoutError do\n          wait_true(wait_opts) { false }\n        end\n\n        assert_raises ::Appium::Core::Wait::TimeoutError do\n          wait_true(wait_opts) { nil }\n        end\n\n        # raise should error\n        assert_raises ::Appium::Core::Wait::TimeoutError do\n          wait_true(wait_opts) { raise }\n        end\n\n        # regular rescue will not handle exceptions outside of StandardError hierarchy\n        # must rescue Exception explicitly to rescue everything\n        assert_raises ::Appium::Core::Wait::TimeoutError do\n          wait_true(wait_opts) { raise NoMemoryError }\n        end\n\n        assert_raises ::Appium::Core::Wait::TimeoutError do\n          wait_true(timeout: 0.2, interval: 0.0) { raise NoMemoryError }\n        end\n\n        e = assert_raises ArgumentError do\n          wait_true(invalidkey: 2) { true }\n        end\n        assert_equal 'unknown keyword: :invalidkey', e.message\n      end\n\n      def test_04_back\n        # start page\n        wait { assert_equal texts.length, 13 }\n        # nav to new page.\n        # ele 0 is the title and can't be clicked.\n        wait { text(2).click }\n        wait { assert_equal texts.length, 5 }\n        # go back\n        back\n        # start page\n        wait { find 'NFC' }\n      end\n\n      def test_05_session_id\n        wait { assert_match(/\\h{8}-\\h{4}-\\h{4}-\\h{4}-\\h{12}/, session_id) }\n      end\n\n      def test_06_xpath\n        #  Access'ibility is for Espresso\n        wait { assert ['API Demos', \"Access'ibility\"].include? xpath('//android.widget.TextView').text }\n      end\n\n      def test_07_xpaths\n        wait { assert_equal xpaths('//android.widget.TextView').length, 13 }\n      end\n\n      def test_08_ele_index\n        # Animation is for Espresso\n        wait { assert %w(Accessibility Animation).include? ele_index('android.widget.TextView', 3).text }\n      end\n\n      def test_09_tags\n        wait { assert_equal tags('android.widget.TextView').length, 13 }\n      end\n\n      def test_10_first_ele\n        wait do\n          # Access'ibility is for Espresso\n          assert ['API Demos', \"Access'ibility\"].include? first_ele('android.widget.TextView').text\n        end\n      end\n\n      def test_11_last_ele\n        wait do\n          # \"API Demos\" is for Espresso\n          assert ['API Demos', 'Views'].include? last_ele('android.widget.TextView').text\n        end\n      end\n\n      # def test_01_source' do # tested by get_so\n\n      def test_12_get_source\n        wait do\n          assert_equal get_source.class, String\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "android_tests/lib/android/specs/common/patch.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# Skip:\n#   status # status patches are already tested in driver.rb\n#   execute # debug output for Pry\n\n# rake \"android[common/patch]\"\nclass AndroidTest\n  class Common\n    class Patch < Minitest::Test\n      # Attributes are busted in Android.\n      # Blocked on https://github.com/appium/appium/issues/628\n\n      # Android supports exactly two string Attributes\n      # .name and .text\n      # https://github.com/appium/appium/blob/ea3450e7f78d1794bab42fa396a387e7b86fd3b3/android/bootstrap/src/io/appium/android/bootstrap/handler/GetAttribute.java#L43\n      # def test_01_value' do; end # Doesn't work on And\n\n      def test_01_element_method_name\n        wait { assert_equal first_text.text, 'API Demos' }\n      end\n\n      # def test_01_tag_name' do; end # Doesn't work on And\n\n      def test_02_element_method_location_rel\n        wait do\n          loc = first_text.location_rel($driver)\n          assert_equal loc.x.class, String\n          assert_equal loc.y.class, String\n        end\n      end\n\n      # By default, the webdriver gem will return message instead of origValue\n      def test_03_common_patch_id_error_message\n        value = ''\n        begin\n          set_wait 0\n          find_element(:id, 'ok')\n        rescue StandardError => e\n          value = e.message\n        ensure\n          set_wait 30\n        end\n        exp = 'An element could not be located on the page using the given search parameters.'\n        assert value.start_with? exp\n      end\n\n      def test_04_id_common_patch_success\n        if automation_name_is_uiautomator2?\n          wait do\n            el = text 'text' # <string name=\"autocomplete_3_button_7\">Text</str\n            assert_equal el.text, 'Text'\n          end\n        else\n          wait do\n            el = id 'autocomplete_3_button_7' # <string name=\"autocomplete_3_button_7\">Text</string>\n            assert_equal el.text, 'Text'\n          end\n        end\n      end\n\n      def test_05_find_many_elements_by_resource_id\n        wait do\n          value = find_elements(:id, 'android:id/text1').length\n          assert_equal value, 12\n        end\n      end\n\n      def test_06_find_single_element_by_resource_id\n        wait do\n          value = id('android:id/text1').text\n          assert_equal value, \"Access'ibility\"\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "android_tests/lib/android/specs/common/version.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"android[common/version]\"\nclass AndroidTest\n  class Common\n    class Version < Minitest::Test\n      def test_appium_version\n        assert_match(/(\\d+)\\.(\\d+).(\\d+)/, ::Appium::VERSION)\n      end\n\n      def test_appium_date\n        assert_match(/(\\d+)-(\\d+)-(\\d+)/, ::Appium::DATE)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "android_tests/lib/android/specs/common/web_context.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# Tests specifically for areas where the web_context differs in behaviour\n# rake \"android[common/web_context]\"\nclass AndroidTest\n  class Common\n    class WebContext < Minitest::Test\n      # appium's context support is broken on android\n\n      def test_01_available_contexts\n        wait_true { available_contexts.include? 'NATIVE_APP' }\n      end\n\n      def test_02_current_context\n        wait { assert_equal current_context, 'NATIVE_APP' }\n      end\n\n      def undo_setcontext_nav\n        back\n        wait { find('WebView') }\n        back\n        wait { find 'Views' }\n      end\n\n      def test_03_set_context\n        wait { scroll_to('Views').click }\n        wait { scroll_to('WebView').click }\n\n        wait_true { !available_contexts.detect { |e| e.start_with?('WEBVIEW') }.nil? }\n\n        webview_context = available_contexts.detect { |e| e.start_with?('WEBVIEW') }\n\n        if webview_context.nil?\n          undo_setcontext_nav\n          raise \"No webview context found. contexts are: #{contexts}\"\n        end\n\n        wait { set_context webview_context }\n        wait { assert_equal current_context, webview_context }\n\n        # verify inspect within webview works\n        assert get_android_inspect.split(\"\\n\").length >= 3\n\n        wait { set_context 'NATIVE_APP' }\n        wait { assert_equal current_context, 'NATIVE_APP' }\n\n        undo_setcontext_nav\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "android_tests/lib/android/specs/driver.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nrequire 'tmpdir'\n\n# rake \"android[driver]\"\nclass AndroidTest\n  class Driver < Minitest::Test\n    def sauce?\n      ENV.fetch('UPLOAD_FILE', nil) && ENV.fetch('SAUCE_USERNAME', nil)\n    end\n\n    def test_01_load_settings\n      appium_txt = File.join(Dir.pwd, 'appium.txt')\n      parsed   = Appium.load_settings file: appium_txt, verbose: true\n      apk_name = File.basename parsed[:caps][:app]\n      assert_equal apk_name, 'api.apk'\n    end\n\n    def test_02_attributes_no_wait\n      no_wait\n      assert_raises Selenium::WebDriver::Error::NoSuchElementError do\n        button('zz')\n      end\n      set_wait\n    end\n\n    # attr_reader :default_wait, :app_path, :app_name,\n    #            :app_package, :app_activity, :app_wait_activity,\n    #            :sauce_username, :sauce_access_key, :port, :os, :debug\n    def test_03_attributes_default_wait_attr\n      set_wait 1\n      assert_equal default_wait, 1\n      set_wait # restore default\n    end\n\n    def test_04_attributes_app_path_attr\n      apk_name = File.basename driver_attributes[:caps][:app]\n      assert_equal apk_name, 'api.apk'\n    end\n\n    def test_05_attributes_verify_all_attributes\n      actual = driver_attributes\n      expected_app = File.absolute_path('../test_apps/api.apk')\n\n      expected = {\n        automation_name:     :uiautomator2,\n        custom_url:          'http://127.0.0.1:4723',\n        default_wait:        1,\n        sauce_username:      nil,\n        sauce_access_key:    nil,\n        sauce_endpoint:      'ondemand.saucelabs.com:443/wd/hub',\n        port:                4723,\n        device:              :android,\n        debug:               true,\n        listener:            nil,\n        wait_timeout:        30, # default\n        wait_interval:       0.5 # default\n      }\n\n      # actual[:caps].to_json send to Appium server\n      caps_with_json = JSON.parse(actual[:caps].to_json)\n      assert_equal caps_with_json['platformName'], 'android'\n      assert_equal caps_with_json['app'], expected_app\n      assert_equal caps_with_json['appPackage'], 'io.appium.android.apis'\n      assert_equal caps_with_json['appActivity'], 'io.appium.android.apis.ApiDemos'\n      assert_equal caps_with_json['deviceName'], 'Android emulator'\n      assert_equal caps_with_json['someCapability'], 'some_capability'\n\n      assert_equal actual[:caps][:platformName], 'android'\n      assert_equal actual[:caps][:app], expected_app\n      assert_equal actual[:caps][:appPackage], 'io.appium.android.apis'\n      assert_equal actual[:caps][:appActivity], 'io.appium.android.apis.ApiDemos'\n      assert !actual[:caps][:deviceName].nil?\n      assert_equal actual[:caps][:some_capability], 'some_capability'\n\n      dup_actual = actual.dup\n      dup_actual.delete(:caps)\n\n      raise \"\\n\\nactual:\\n\\n: #{dup_actual}expected:\\n\\n#{expected}\" if dup_actual != expected\n    end\n\n    def test_06_driver_class\n      assert_equal $driver.class, Appium::Driver\n    end\n\n    def absolute_app_path(path)\n      $driver.class.absolute_app_path(caps: { app: path })\n    end\n\n    def validate_path(path)\n      assert_equal absolute_app_path(path), path\n    end\n\n    def test_07_absolute_app_path\n      validate_path 'sauce-storage:some_storage_suffix'\n      validate_path 'http://www.saucelabs.com'\n\n      Dir.mktmpdir do |tmp_dir|\n        existing_path = File.join(tmp_dir, 'myapp.app')\n        FileUtils.mkdir_p existing_path\n        validate_path existing_path\n      end\n\n      # bundle id test\n      validate_path 'my.bundle.id'\n\n      # relative path test\n\n      relative_path = File.join __FILE__, ('..' + File::SEPARATOR) * 5, 'test_apps/api.apk'\n      expected_path = File.expand_path relative_path\n\n      assert_equal absolute_app_path(relative_path), expected_path\n\n      # invalid path test\n      assert_equal absolute_app_path('../../does_not_exist.apk'), '../../does_not_exist.apk'\n    end\n\n    def test_08_methods_status\n      appium_server_version['build'].keys.sort.include? 'version'\n    end\n\n    def test_09_methods_server_version\n      server_version = appium_server_version['build']['version']\n      if sauce?\n        assert_match 'Sauce OnDemand', server_version\n      else\n        assert_match(/(\\d+)\\.(\\d+).(\\d+)/, server_version)\n      end\n    end\n\n    def test_10_methods_client_version\n      client_version = appium_client_version\n      expected = { version: ::Appium::VERSION }\n      assert_equal client_version, expected\n    end\n\n    def test_11_methods_restart\n      set_wait 1 # ensure wait is 1 before we restart.\n      restart\n      assert_equal current_activity, '.ApiDemos'\n    end\n\n    def test_12_methods_driver\n      assert_equal driver.browser, 'unknown'\n    end\n\n    # Skip:\n    #   screenshot   # this is slow and already tested by Appium\n    #   driver_quit  # tested by restart\n    #   start_driver # tested by restart\n    #   no_wait  # posts value to server, it's not stored locally\n    #   set_wait # posts value to server, it's not stored locally\n    #   execute_script # 'mobile: ' is deprecated and plain execute_script unsupported\n\n    def test_13_methods_default_wait\n      set_wait 1\n      assert_equal default_wait, 1\n    end\n\n    # returns true unless an error is raised\n    def test_14_methods_exists\n      assert_equal exists(0, 0) { true }, true\n      assert_equal exists(0, 0) { raise 'error' }, false\n    end\n\n    # any elements\n    def test_15_methods_find_elements\n      wait do\n        assert_equal find_elements(:class_name, 'android.widget.TextView').length, 13\n      end\n    end\n\n    # any element\n    def test_16_methods_find_element\n      wait do\n        assert_equal find_element(:class_name, 'android.widget.TextView').class, ::Appium::Core::Element\n      end\n    end\n\n    # simple integration sanity test to check for unexpected exceptions\n    def test_17_methods_set_location\n      set_location latitude: 55, longitude: -72, altitude: 33\n    rescue Selenium::WebDriver::Error::UnknownError => e\n      # on android this method is expected to raise with this message when running\n      # on a regular device, or on genymotion.\n      # error could be many messages, including:\n      # ERROR running Appium command: port should be a number or string\n      # ERROR running Appium command: port should be > 0 and < 65536\n      raise unless e.message.include?('ERROR running Appium command: port should be')\n    end\n\n    # settings\n    def test_18_methods_get_settings\n      assert !get_settings.nil?\n    end\n\n    def test_19_methods_update_settings\n      update_settings allowInvisibleElements: true\n      assert_equal get_settings['allowInvisibleElements'], true\n    end\n\n    # Skip: x # x is only used in Pry\n  end\nend\n"
  },
  {
    "path": "android_tests/lib/android/specs/install.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"android[install]\"\nclass AndroidTest\n  class Install < Minitest::Test\n    # To Do: Blocked on https://github.com/appium/appium/issues/3032\n    def pkg\n      'io.appium.android.apis'\n    end\n\n    def installed\n      assert_equal app_installed?(pkg), true\n    end\n\n    def not_installed\n      assert_equal app_installed?(pkg), false\n    end\n\n    def test_install_uninstall\n      installed\n      remove_app 'io.appium.android.apis'\n      not_installed\n      install_app caps[:app]\n      installed\n    end\n\n    # no way to launch apk after it's uninstalled/installed\n    # blocked on: https://github.com/appium/appium/issues/2969\n    # launch_app\n  end\nend\n"
  },
  {
    "path": "android_tests/lib/android/specs/sauce_labs.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"android[sauce_labs]\"\nclass AndroidTest\n  class SauceLabs < Minitest::Test\n    def test_sauce_settings\n      opt = {}\n      sauce_username = 'sauce_name'\n      sauce_access_key = 'abcdefghijklmn'\n      sauce_endpoint = 'ondemand.saucelabs.com:443/wd/hub'\n\n      opt[:sauce_username] = sauce_username\n      opt[:sauce_access_key] = sauce_access_key\n      opt[:sauce_endpoint] = sauce_endpoint\n\n      sauce = Appium::SauceLabs.new(opt)\n\n      assert_equal sauce.username, sauce_username\n      assert_equal sauce.access_key, sauce_access_key\n      assert_equal sauce.endpoint, sauce_endpoint\n      assert_equal sauce.sauce_server_url?, true\n      assert_equal sauce.server_url, 'https://sauce_name:abcdefghijklmn@ondemand.saucelabs.com:443/wd/hub'\n    end\n\n    def test_no_sauce_settings\n      opt = {}\n      sauce = Appium::SauceLabs.new(opt)\n\n      assert_equal sauce.sauce_server_url?, false\n      assert_equal sauce.server_url, 'http://127.0.0.1:4723/wd/hub'\n    end\n  end\nend\n"
  },
  {
    "path": "android_tests/lib/format.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# helper code useful for writing and verifying tests using Pry\nlist = <<-TXT\nfind\ntext\ntexts\nname\nnames\nscroll_to\nTXT\n\nlist.split(\"\\n\").each do |method|\n  puts \"t '#{method}' do\"\n  puts\n  puts 'end'\n  puts\nend\n\n# --\n\n# Format AndroidElementClassMap from\n# https://github.com/appium/appium/blob/master/android/bootstrap/src/io/appium/android/bootstrap/AndroidElementClassMap.java\n# for ruby_lib android/helper.rb tag_name_to_android\nlist = <<TXT\n    map.put(\"abslist\", \"AbsListView\");\n    map.put(\"button\", \"Button\");\nTXT\n\nlist.split(\"\\n\").each do |method|\n  pair  = method.match(/\"([^\"]+)\"[^\"]+\"([^\"]+)\"/)\n  tag   = pair[1]\n  klass = pair[2]\n\n  indent = 6\n  puts \"#{' ' * indent}when '#{tag}'\"\n  line2 = \"#{' ' * (indent + 2)}prefix '#{klass}'\"\n  # button must translate to both button and image button\n  # for ruby_lib to find all buttons\n  line2.concat(\", 'ImageButton'\") if klass == 'Button'\n  puts line2\nend\n\n# for Pry\n# class Object\n#   def must_equal b\n#     raise 'not equal' unless self == b\n#   end\n# end\n"
  },
  {
    "path": "android_tests/lib/run.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nrequire 'rubygems'\nrequire 'minitest/autorun'\nrequire 'minitest/reporters'\nrequire 'minitest'\nrequire 'hashdiff'\nrequire_relative '../../lib/appium_lib'\n\nAppium::Logger.level = ::Logger::ERROR # Show Logger logs only they are error\n\nMinitest::Test.i_suck_and_my_tests_are_order_dependent!\n\nbegin\n  Minitest::Reporters.use! [Minitest::Reporters::ProgressReporter.new]\nrescue Errno::ENOENT\n  # Ignore since Minitest::Reporters::JUnitReporter.new fails in deleting files, sometimes\nend\n\n# Run all Android tests:\n#   ruby run.rb android\n\n# Run only the view album test:\n#   ruby run.rb ios view_album\n\ndef start_driver(caps)\n  driver = Appium::Driver.new(caps, true)\n  # Tests expect methods defined on the minispec object\n  Appium.promote_appium_methods Minitest::Test, driver\n\n  # Use bounded HTTP timeouts in tests to avoid CI hangs on stuck requests.\n  open_timeout = Integer(ENV.fetch('APPIUM_TEST_OPEN_TIMEOUT', '120'))\n  read_timeout = Integer(ENV.fetch('APPIUM_TEST_READ_TIMEOUT', '300'))\n\n  driver.start_driver(open_timeout: open_timeout, read_timeout: read_timeout)\nend\n\ndir = File.expand_path(File.join(Dir.pwd, 'lib'))\nappium_txt = File.join(Dir.pwd, 'appium.txt')\ndevice = ARGV[0].downcase.strip\ndevices = %w(android ios)\nraise 'Expected android or ios as first argument' unless devices.include? device\n\none_test = ARGV[1]\ntest_dir = \"/#{device}/\"\n\ncaps = Appium.load_settings file: appium_txt, verbose: true\ncaps = if caps[:appium_lib]\n         appium_lib = caps[:appium_lib]\n         appium_lib = appium_lib.merge(debug: true) unless appium_lib[:debug]\n         appium_lib = appium_lib.merge(wait: 1) unless appium_lib[:wait]\n         caps.merge(appium_lib: appium_lib)\n       else\n         caps.merge(appium_lib: { debug: true, wait: 1 })\n       end\n\nif ENV['LOCAL_PREBUILT_WDA']\n  caps[:caps][:usePreinstalledWDA] = true\n  caps[:caps][:prebuiltWDAPath] = ENV['LOCAL_PREBUILT_WDA']\nend\n\ntrace_files = []\n\nif one_test\n  if File.exist? one_test\n    one_test = File.expand_path one_test\n  else\n    # ensure ext is .rb\n    one_test = File.join(File.dirname(one_test),\n                         \"#{File.basename(one_test, '.*')}.rb\")\n    one_test = File.join(dir, \"#{test_dir}specs/#{one_test}\")\n  end\n\n  raise \"\\nTest #{one_test} does not exist.\\n\" unless File.exist?(one_test)\n\n  start_driver(caps)\n\n  # Ruby 3.0 sorts the Dir.glob order\n  # require support (common.rb)\n  file_name = File.join dir, \"#{test_dir}/*.rb\"\n  Dir.glob(file_name) do |test|\n    require test\n    trace_files << test\n  end\n  puts \"Loading one test: #{one_test}\"\n  require one_test\n  trace_files << one_test\nelse\n  # require all\n  file_names = File.join(dir, \"#{test_dir}**/*.rb\")\n  Dir.glob(file_names) do |test|\n    # load all tests\n    trace_files << test\n    puts \"  #{File.basename(test, '.*')}\"\n    require test\n  end\n\n  start_driver(caps)\nend\n\ntrace_files.map! do |f|\n  f = File.expand_path f\n  # ensure all traced files end in .rb\n  f = File.join(File.dirname(f), \"#{File.basename(f, '.*')}.rb\")\n  f\nend\n\n# Exit after tests.\nMinitest.after_run { $driver&.x }\n"
  },
  {
    "path": "android_tests/readme.md",
    "content": "ruby_lib_android\n=====================\n\nruby_lib's Android tests. Requires `Ruby 2.2+` or better.\n\n- `rake install` Install gems required to run the tests.\n- `rake android` Run all tests.\n- `rake android['android/element/generic']` Run a single test.\n- `arc` Opens the Appium Ruby Console (arc). Enables interactive testing.\n  - `gem install appium_console` if it's not installed already.\n\napi.apk is from [appium/android-apidemos](https://github.com/appium/android-apidemos)\nThe way to generate api.apk is described in the repository.\n\n---\n\n```ruby\nFinished in 2 mins 57 secs\n\n106 runs, 144 assertions, 0 failures, 0 errors, 0 skips\n```\n\n#### Coverage\n\n- apk\n    - [emma-build](https://github.com/appium/android-apidemos/blob/a20597cb97238bf43c073500444b9428fab53f50/README.md#emma-build-for-testing-code-coverage)\n- `appium.txt`\n    ```\n    [caps]\n    platformName = \"android\"\n    deviceName = \"Nexus 7\"\n    app = \"../test_apps/api.apk\"\n    appPackage = \"io.appium.android.apis\"\n    appActivity = \"io.appium.android.apis.ApiDemos\"\n    some_capability = \"some_capability\"\n    androidCoverage = 'io.appium.android.apis/io.appium.android.apis.app.LocalSampleInstrumentation'\n    \n    [appium_lib]\n    sauce_username = \"\"\n    sauce_access_key = \"\"\n    ```\n"
  },
  {
    "path": "appium_lib.gemspec",
    "content": "require_relative 'lib/appium_lib/version'\n\nGem::Specification.new do |s|\n  s.required_ruby_version = '>= 3.1'\n\n  s.name          = 'appium_lib'\n  s.version       = Appium::VERSION\n  s.license       = 'Apache-2.0'\n  s.description   = 'Ruby library for Appium.'\n  s.summary       = 'Ruby library for Appium'\n  s.authors       = ['code@bootstraponline.com', 'Kazuaki Matsuo']\n  s.email         = %w(code@bootstraponline.com fly.49.89.over@gmail.com)\n  s.homepage      = 'https://github.com/appium/ruby_lib' # published as appium_lib\n  s.require_paths = ['lib']\n\n  s.add_dependency 'appium_lib_core', '>= 9.2.1', '< 13.0'\n  s.add_dependency 'nokogiri', '~> 1.8', '>= 1.8.1'\n  s.add_dependency 'tomlrb', '>= 1.1', '< 3.0'\n\n  s.files = `git ls-files`.split(\"\\n\").reject { |v| v.match(/\\A^(ios_tests|android_tests|grid|test_apps)\\/.+/) }\n  s.metadata['rubygems_mfa_required'] = 'true'\nend\n"
  },
  {
    "path": "contributing.md",
    "content": "# Contributing\n\nFor 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.\n\nIf you'd like to adding new driver commands, please refer to https://github.com/appium/ruby_lib_core\n\n## Tests\n\n- Tests are run against [appium's master branch](https://github.com/appium/appium/blob/master/docs/en/contributing-to-appium/appium-from-source.md)\n- The tests are run using the [flaky gem](https://github.com/appium/flaky) on OS X\n- The `arc` command can be run from within the `ios_tests` or `android_tests` folder to open an interactive console\n\n### Run iOS tests\n\niOS tests are run on the iPhone 6 / iOS 9.3 simulator.\n\n- `cd ios_tests`\n- `flake 3 ios` - Run all the iOS tests up to 3 times\n\n### Run Android tests\n\nAndroid tests require running on physical hardware with Android 5.0 (API 21). The emulator is unreliable.\n\n- `cd android_tests`\n- `flake 3 android` - Run all the Android tests up to 3 times\n\n## Publishing\n\n0. 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)\n> $ curl -u username https://rubygems.org/api/v1/api_key.yaml >\n~/.gem/credentials; chmod 0600 ~/.gem/credentials\n\n1. Bump the version number: `thor bump` (`bumpy`, `bumpz`)\n2. Update `CHANGELOG.md`\n3. Generate release note, publish release gem and push the tag to this repository: `thor release`\n"
  },
  {
    "path": "docs/android_uiautomator.md",
    "content": "# Help debugging\n\n- `adb shell uiautomator events` \n    - Prints out accessibility events to the console until the connection to the device is terminated\n    - [URL](https://stuff.mit.edu/afs/sipb/project/android/docs/tools/help/uiautomator/index.html)\n    - **notice**\n        - If Appium is started then it terminates the other `uiautomator` processes\n\n# uiautomator2\n## difference between uiautomator1 and uiautomator2\n- `find_element/s :id, \"ids\"`\n    - uiautomator1\n        - Find elements with `resource_id`\n        - Find elements with string id resource(string.xml based)\n    - uiautomator2\n        - Find elements with `resource_id`\n    - from: Does not appium-uiautomator2-server support finding string ids with \"id\" strategy? [issue](https://github.com/appium/appium/issues/8349)\n"
  },
  {
    "path": "docs/docs.md",
    "content": "# Documentation\n## API Doc of Ruby Client\n- This library: http://www.rubydoc.info/github/appium/ruby_lib\n- Core: http://www.rubydoc.info/github/appium/ruby_lib_core\n- [Ruby selenium-webdriver](https://github.com/SeleniumHQ/selenium/wiki/Ruby-Bindings)\n\n### General\n- [Appium](https://github.com/appium/appium/blob/master/README.md)\n- [Supported platforms](https://github.com/appium/appium/blob/master/docs/en/about-appium/platform-support.md)\n- [All methods supported by Appium](https://github.com/appium/appium-base-driver/blob/master/docs/mjsonwp/protocol-methods.md)\n    - Fundamental Commands: http://appium.io/docs/en/commands/status/ etc\n- [MiniTest Expectations](http://docs.seattlerb.org/minitest/Minitest/Expectations.html)\n\n### Driver types in Ruby Client\n\n```ruby\n# Appium specific driver with helpers available extending Standard Appium Driver.\n@appium_driver = Appium::Driver.new @options, false\n\n# Standard Appium Driver extends Selenium WebDriver.\n@selenium_driver = @appium_driver.start_driver\n```\n\n### Example\n\nExample of automating the built in Android settings.\n\n```ruby\n# run Pry, and paste the following\napk = { \n        platformName: 'android',\n        deviceName: :nexus,\n        appPackage: 'com.android.settings',\n        appActivity: '.Settings',\n        appWaitActivity: '.Settings'\n      }\nAppium::Driver.new({caps: apk}, false).start_driver\n```\n\nExample use of Appium's mobile gesture.\n\n\nLong click on an ImageView in Android.\n\n```\nlast_image = find_elements(:class, 'ImageView').last\nlong_press(element: last_image)\n```\n\nRotate examples. The behaviour is depends on devices.\n\n```ruby\ndriver.rotate :landscape\ndriver.rotate :portrait\n```\n\n- `appium_server_version` Discover the Appium rev running on the server.\n- `element.send_keys \"msg\"` Sends keys to currently active element\n\n\n### APIs\n\n```ruby\ne.name # button, text\ne.value # secure, textfield\ne.type 'some text' # type text into textfield\ne.clear # clear textfield\ne.tag_name # calls .type (patch.rb)\ne.text\ne.size\ne.location\ne.location_rel\ne.click\ne.send_keys 'keys to send'\ne.displayed? # true or false depending if the element is visible\ne.selected? # is the tab selected?\ne.attribute('checked') # is the checkbox checked?\n\n\n# alert example without helper methods\nalert = @driver.switch_to.alert\nalert.text\nalert.accept\nalert.dismiss\n\n# Secure textfield example.\n#\n# Find using default value\ns = textfield 'Password'\n# Enter password\ns.send_keys 'hello'\n# Check value\ns.value == ios_password('hello'.length)\n```\n\n--\n\n#### Driver\n- `start_driver` will restart the driver.\n- `x` will quit the driver and exit Pry.\n- `execute_script` calls `@driver.execute_script`\n- `find_element` calls `@driver.find_element`\n- `find_elements` calls `@driver.find_elements`\n- `no_wait` will set implicit wait to 0. `@driver.manage.timeouts.implicit_wait = 0`\n- `set_wait` will set implicit wait to default seconds. `@driver.manage.timeouts.implicit_wait = default`\n- `set_wait(timeout_seconds)` will set implicit wait to desired timeout. `@driver.manage.timeouts.implicit_wait = timeout`\n- `.click` to tap an element.\n- `.send_keys` or `.type` to type on an element.\n\n#### Cucumber Sauce Integration\n\nReset after each test and when done report the result to Sauce after quiting the driver.\n\n```ruby\nrequire 'rest_client' # https://github.com/archiloque/rest-client\nrequire 'json' # for .to_json\nrequire 'sauce_whisk'\n\nAfter do |scenario|\n  # end the test session, ignoring any exceptions.\n  ignore { $driver.driver_quit }\n  \n  user   = ENV['SAUCE_USERNAME']\n  key    = ENV['SAUCE_ACCESS_KEY']\n  if user && !user.empty? && key && !key.empty?\n    passed = ! scenario.failed?\n    SauceWhisk::Jobs.change_status $driver.driver.session_id, passed\n  end\nend\n```\n"
  },
  {
    "path": "docs/ios_xcuitest.md",
    "content": "## XCUITest\n- Over Appium1.6.0 provides `XCUITest` automation name based on WebDriverAgent.\n    - [appium-xcuitest-driver](https://github.com/appium/appium-xcuitest-driver)\n    - [WebDriverAgent](https://github.com/facebook/WebDriverAgent)\n- How to migrate XCUITest from UIAutomation\n    - [Migrating your iOS tests from UIAutomation](https://github.com/appium/appium/blob/v1.6.2/docs/en/advanced-concepts/migrating-to-xcuitest.md)\n- Mobile gestures for XCUITest\n    - [ios-xctest-mobile-gestures](https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/ios/ios-xctest-mobile-gestures.md)\n    - Required Appium1.6.4+\n\n## find elements\n- supported elements by find_element are:\n    - [appium-xcuitest-driver](https://github.com/appium/appium-xcuitest-driver/blob/master/lib/commands/find.js#L17)\n        - [locatorStrategies](https://github.com/appium/appium-xcuitest-driver/blob/95886f1118d71fe950768f8262179d3608b40fc7/lib/driver.js#L81)\n    - [WebDriverAgent](https://github.com/facebook/WebDriverAgent/blob/8346199212bffceab24192e81bc0118d65132466/WebDriverAgentLib/Commands/FBFindElementCommands.m#L111)\n- Mapping\n    - https://github.com/facebook/WebDriverAgent/blob/master/WebDriverAgentLib/Utilities/FBElementTypeTransformer.m#L19\n\n### with except for XPath and Predicate\n#### examples\n- [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.\n    - If `automationName` is `Appium` or `nil`, then they provide `UIAxxxx`\n    - If `automationName` is `XCUITest`, then they provide `XCUIElementTypexxx`\n\n```ruby\nfind_element(:class, button_class) # Return a element of XCUIElementTypeButton for XCUITest\n```\n\n- [tag/s](https://github.com/appium/ruby_lib/blob/ac03116756a72fbd624fa32ea886123b955d7089/lib/appium_lib/android/helper.rb#L238) is alias of `find_element :class, element`\n\n- `accessibility_id`\n\n```ruby\nfind_element(:accessibility_id, element) # Return a element which has accessibilityIdentifier, `element`.\n```\n\n- `button/s(value)`, `button_exact/buttons_exact`, `text/s(value)`, `text_exact/texts_exact` \n```ruby\nbuttons(value) # Return button elements include `value` as its name attributes.\n```\n\n### with Predicate\n- We recommend to use predicate strategy instead of XPath strategy.\n    - e.g. `find_ele_by_predicate/find_eles_by_predicate`,  `find_ele_by_predicate_include/find_eles_by_predicate_include`\n- A helpful cheatsheet for predicate\n    - https://realm.io/news/nspredicate-cheatsheet/\n- For XCUITest(WebDriverAgent), without 'wd' prefixes are supported.\n    - https://github.com/facebook/WebDriverAgent/wiki/Queries\n    - 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.\n\n#### examples\n- `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.\n\n```ruby\ntextfield(value) # Return a XCUIElementTypeSecureTextField or XCUIElementTypeTextField element which has `value` text.\nfinds_exact(value) # Return any elements include `value` as its name attributes.\n```\n\n### with Class Chain\n- require Appium 1.6.4+\n    - https://github.com/appium/appium-xcuitest-driver/pull/391\n    - https://github.com/appium/java-client/pull/599/files\n- WebDriverAgent\n    - https://github.com/facebook/WebDriverAgent/wiki/Queries\n\n### with XPath\n- It is better to avoid XPath strategy.\n    - https://github.com/appium/appium/blob/v1.6.2/docs/en/advanced-concepts/migrating-to-xcuitest.md#xpath-locator-strategy\n        - > 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.\n    - Improved performance a bit\n        - https://github.com/appium/appium/issues/6842\n        - https://github.com/facebook/WebDriverAgent/issues/306\n- XPath in WebDriverAgent\n    - https://github.com/facebook/WebDriverAgent/blob/2158a8d0f305549532f1338fe1e4628cfbd53cd9/WebDriverAgentLib/Categories/XCElementSnapshot%2BFBHelpers.m#L57\n\n#### examples\n\n```ruby\nxpaths(\"//some xpaths\")\n```\n\n## Gesture\n- `mobile:` commands are provided by WDA.\n- Documentations\n    - https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/ios/ios-xctest-mobile-gestures.md\n- Specs by test code\n    - https://github.com/appium/appium-xcuitest-driver/blob/master/test/functional/basic/gesture-e2e-specs.js\n\n### Workaround\n- `mobile:` commands depends on WDA and Apple's framework and the behaviour depends on them.\n- Sometimes issues occur such as \"doubleTap isn't tapping #548\"\n    - workaround for it:\n        - with `selenium-webdriver >= 3.4.0`\n            ```ruby\n            def double_tap(element)\n              rect = element.rect\n              execute_script 'mobile: doubleTap', x: rect.x + rect.width / 2, y: rect.y + rect.height / 2\n            end\n            ```        \n        - with `selenium-webdriver < 3.4.0`\n            ```ruby\n              def double_tap(element)\n                size = element.size\n                location = element.location\n                execute_script 'mobile: doubleTap', x: location.x + size.width / 2, y: location.y + size.height / 2\n              end\n            ```\n\n## Other actions\nBasically, other actions such as `type` are compatible with `automationName = Appium`.\n\n## Pasteboard\n- Simulator only\n    - https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/ios-xctest-pasteboard.md\n"
  },
  {
    "path": "docs/parallel.md",
    "content": "Appium 1.7.0+ supports single server and multiple sessions, and it requires Xcode 9 for iOS.\n\n# Example\n## Run tests on Multiple Simulators with Xcode 9\n- https://github.com/appium/appium-xcuitest-driver/tree/master/test/functional/parallel\n- https://github.com/appium/ruby_lib/tree/master/ios_tests/parallel\n    - Thread programming: TestParallelRunThread\n    - Process programming: TestParallelRunProcess\n"
  },
  {
    "path": "docs/w3c.md",
    "content": "Perform touch actions for W3C module. Generate `touch` pointer action here and users can use this via `driver.action`\n\n[Documentation](http://www.rubydoc.info/github/appium/ruby_lib_core/Appium%2FCore%2FBase%2FCoreBridgeW3C:action)\n\n# Example\n\n```ruby\ndialect #=> :w3c\n\n# then\nel = find_element(:name, 'Pickers')\ndriver.action.click(el).perform #=> work\n\n\n# Scroll/Swipe\ndriver.action\n      .move_to_location(500, 500).pointer_down(:left)\n      .move_to_location(0, 700)\n      .release.perform\n\n\n# Zoom in\n# multiple action chains\nf1 = driver.action.add_pointer_input(:touch, 'finger1')\nf1.create_pointer_move(duration: 1, x: 200, y: 500,\n                   origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)\nf1.create_pointer_down(:left)\nf1.create_pause(0.5)\nf1.create_pointer_move(duration: 1, x: 200, y: 200,\n                   origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)\nf1.create_pointer_up(:left)\n\nf2 = driver.action.add_pointer_input(:touch, 'finger2')\nf2.create_pointer_move(duration: 1, x: 200, y: 500,\n                   origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)\nf2.create_pointer_down(:left)\nf2.create_pause(0.5)\nf2.create_pointer_move(duration: 1, x: 200, y: 800,\n                   origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)\nf2.create_pointer_up(:left)\n\ndriver.perform_actions [f1, f2]\n```\n\n# Note\n## Coordinate points\n- jsonwp\n    - Relative action coordinates are counted relatively to the **top left point** of element's rectangle\n- W3C\n    - Relative action coordinates are counted relatively to the **center** of element's rectangle\n\n## Limitations\n- WebDriverAgent support only `touch` as a `pointer type`.\n    - 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.\n    - 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)\n"
  },
  {
    "path": "grid/README.md",
    "content": "# 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**\nSelenium Grid 3.4.0 is failed to establish sessions: \n\n# Run Appium\n\n```bash\n$ node . --nodeconfig ~/GitHub/ruby_lib/grid/config.json\n\n# or\n\n$ appium --nodeconfig ~/GitHub/ruby_lib/grid/config.json\n```\n\n# Run Ruby Script\n\n```bash\n$ rake ios # for example\n```\n"
  },
  {
    "path": "grid/appium.txt.ios.example",
    "content": "[caps]\nplatformName = \"ios\"\nplatformVersion = \"11.4\"\ndeviceName =\"iPhone 11\"\nautomationName = 'XCUITest'\napp = \"/absolute/path/to/UICatalog.app.zip\"\nsome_capability = \"some_capability\"\n\n[appium_lib]\nserver_url = \"http://localhost:4444/wd/hub\"\nsauce_username = \"\"\nsauce_access_key = \"\"\nsauce_endpoint = \"\"\nwait = 30\nwait_timeout = 20\nwait_interval = 1\n"
  },
  {
    "path": "grid/config.json",
    "content": "{\n  \"capabilities\":\n  [\n    {\n      \"browserName\": \"iPhone 11\",\n      \"version\":\"11.4\",\n      \"platform\":\"ios\",\n      \"maxInstances\": 1\n    }\n  ],\n  \"configuration\":\n  {\n    \"cleanUpCycle\": 2000,\n    \"timeout\": 60000,\n    \"proxy\": \"org.openqa.grid.selenium.proxy.DefaultRemoteProxy\",\n    \"url\": \"http://localhost:4723\",\n    \"host\": \"localhost\",\n    \"port\": 4723,\n    \"maxSession\": 1,\n    \"register\": true,\n    \"registerCycle\": 5000,\n    \"hubPort\": 4444,\n    \"hubHost\": \"localhost\"\n  }\n}\n"
  },
  {
    "path": "grid/hub_config.json",
    "content": "{\n  \"port\": 4444,\n  \"newSessionWaitTimeout\": -1,\n  \"servlets\" : [],\n  \"withoutServlets\": [],\n  \"custom\": {},\n  \"capabilityMatcher\": \"org.openqa.grid.internal.utils.DefaultCapabilityMatcher\",\n  \"throwOnCapabilityNotPresent\": true,\n  \"cleanUpCycle\": 5000,\n  \"role\": \"hub\",\n  \"debug\": false,\n  \"browserTimeout\": 0,\n  \"timeout\": 1800\n}\n"
  },
  {
    "path": "grid/hub_config_3.json",
    "content": "{\n  \"capabilities\":\n  [\n    {\n      \"browserName\": \"iPhone 11\",\n      \"version\":\"11.4\",\n      \"maxInstances\": 1,\n      \"seleniumProtocol\": \"WebDriver\"\n    }\n  ],\n  \"proxy\": \"org.openqa.grid.selenium.proxy.DefaultRemoteProxy\",\n  \"maxSession\": 5,\n  \"port\": 4444,\n  \"register\": true,\n  \"registerCycle\": 5000,\n  \"hub\": \"http://localhost:4444\",\n  \"nodeStatusCheckTimeout\": 5000,\n  \"nodePolling\": 5000,\n  \"role\": \"hub\",\n  \"unregisterIfStillDownAfter\": 60000,\n  \"downPollingLimit\": 2,\n  \"debug\": true,\n  \"servlets\" : [],\n  \"withoutServlets\": [],\n  \"custom\": {}\n}\n"
  },
  {
    "path": "ios_tests/Gemfile",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nsource 'https://rubygems.org'\neval_gemfile File.join(File.expand_path('..', __dir__), 'Gemfile')\n\ngem 'parallel_tests'\n"
  },
  {
    "path": "ios_tests/LICENSE-2.0.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "ios_tests/Rakefile",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nrequire 'rubygems'\nrequire 'rake'\nrequire 'rubocop/rake_task'\n\ntask default: :ios\n\n# Run sh and ignore exception\ndef run_sh(cmd)\n  sh cmd\nrescue StandardError\n  # Ignored\nend\n\n# Run cmd. On failure run install and try again.\ndef bash(cmd)\n  sh cmd do |successful, result|\n    # exitstatus 7 means bundle install failed\n    # non-zero (except 7 retry path) means the test failed\n    if !successful && result.exitstatus == 7\n      Rake::Task['install'].execute\n      sh cmd\n    elsif !successful\n      raise \"Command failed with status #{result.exitstatus}: #{cmd}\"\n    end\n  end\nend\n\n# Run a single test with:\n# rake ios['ios/element/generic']\n#\n# rake ios['driver']\n#\n# Run all tests with:\n# rake ios\ndesc 'Run the iOS tests'\ntask :ios, :args, :test_file do |_args, test_file|\n  # rake android['ok']\n  # args = android\n  # test_file = {:args=>\"ok\"}\n  test_file = test_file[:args]\n  cmd = 'bundle exec ruby ./lib/run.rb ios'\n  cmd = %(#{cmd} \"#{test_file}\") if test_file\n  bash cmd\nend\n\ndesc 'Run bundle install'\ntask :install do\n  sh 'bundle install'\nend\n\ndesc 'Execute RuboCop static code analysis'\nRuboCop::RakeTask.new(:rubocop) do |t|\n  t.patterns = %w(**/*.rb)\n  t.options = %w(-D)\n  t.fail_on_error = false\nend\n\nclass Device\n  def self.one\n    {\n      automationName: 'xcuitest',\n      platformName: 'ios',\n      platformVersion: '11.0',\n      deviceName: 'iPhone 6',\n      app: \"#{Dir.pwd}/../test_apps/UICatalog.app.zip\",\n      wdaLocalPort: 8100,\n      isCommandsQueueEnabled: false\n    }\n  end\n\n  def self.two\n    {\n      automationName: 'xcuitest',\n      platformName: 'ios',\n      platformVersion: '11.0',\n      deviceName: 'iPhone 6s',\n      app: \"#{Dir.pwd}/../test_apps/UICatalog.app.zip\",\n      wdaLocalPort: 8200,\n      isCommandsQueueEnabled: false\n    }\n  end\nend\n\ndesc 'Run tests with parallel thread'\ntask :run_parallel_t do\n  require_relative 'parallel/test'\n\n  threads = []\n  [Device.one, Device.two].map do |capability|\n    threads << Thread.new do\n      TestParallelRunThread.new(capability).test_run\n    end\n  end\n\n  threads.each(&:join)\nend\n\ndesc 'Run tests with parallel processes'\ntask :run_parallel_p do\n  require_relative 'parallel/test'\n\n  [Device.one, Device.two].each do |capability|\n    fork do\n      TestParallelRunProcess.new(capability).test_run\n    end\n  end\n\n  Process.waitall\nend\n"
  },
  {
    "path": "ios_tests/appium.txt",
    "content": "[caps]\nplatformName = \"ios\"\nplatformVersion = \"18.5\"\ndeviceName =\"iPhone 16 Plus\"\nautomationName = 'XCUITest'\napp = \"../test_apps/UICatalog.app.zip\"\nsomeCapability = \"some_capability\"\nsimulatorStartupTimeout = 600000\nwdaLaunchTimeout = 600000\n\n[appium_lib]\nwait = 30\nwait_timeout = 20\nwait_interval = 1\n"
  },
  {
    "path": "ios_tests/data/unicode.txt",
    "content": "®"
  },
  {
    "path": "ios_tests/flaky.txt",
    "content": "ios = \"lib/ios/specs/\""
  },
  {
    "path": "ios_tests/lib/common.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# common methods\ndef back_click\n  back\nend\n\ndef leave_textfields\n  back_click\n  assert screen == catalog\nend\n\ndef go_to_textfields\n  assert screen == catalog\n  wait_true do\n    find_element(:name, 'Text Fields').click\n    screen == 'Text Fields' # wait for screen transition\n  end\nend\n\ndef screen\n  $driver.find_element(:class, ui_ios.navbar).name\nend\n\ndef catalog\n  'UICatalog'\nend\n\ndef target_bundle_id\n  'com.example.apple-samplecode.UICatalog'\nend\n\ndef ui_ios\n  UI.new($driver)\nend\n\nclass UI\n  def initialize(driver)\n    @driver = driver\n  end\n\n  def navbar\n    'XCUIElementTypeNavigationBar'\n  end\n\n  def button\n    'XCUIElementTypeButton'\n  end\n\n  def static_text\n    'XCUIElementTypeStaticText'\n  end\n\n  def text_field\n    'XCUIElementTypeTextField'\n  end\n\n  def secure_text_field\n    'XCUIElementTypeSecureTextField'\n  end\n\n  def picker\n    'XCUIElementTypePicker'\n  end\n\n  def picker_wheel\n    'XCUIElementTypePickerWheel'\n  end\n\n  def action_sheet\n    'XCUIElementTypeActionSheet'\n  end\n\n  def table\n    'XCUIElementTypeTable'\n  end\n\n  def table_cell\n    'XCUIElementTypeCell'\n  end\n\n  def other\n    'XCUIElementTypeOther'\n  end\n\n  def status_bar\n    'XCUIElementTypeStatusBar'\n  end\nend\n"
  },
  {
    "path": "ios_tests/lib/format.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# helper code useful for writing and verifying tests using Pry\nlist = <<TXT\nalert_click\nalert_text\nalert_accept\nalert_accept_text\nalert_dismiss\nalert_dismiss_text\nTXT\n\nlist.split(\"\\n\").each do |method|\n  puts \"t '#{method}' do\"\n  puts\n  puts 'end'\n  puts\nend\n\n# for Pry\n# class Object\n#   def must_equal b\n#     raise 'not equal' unless self == b\n#   end\n# end\n"
  },
  {
    "path": "ios_tests/lib/ios/specs/common/element/window.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"ios[common/element/window]\"\n\nclass IosTest\n  class Common\n    class Element\n      class Window < Minitest::Test\n        def before_first\n          driver.terminate_app target_bundle_id\n          driver.activate_app target_bundle_id\n          assert_equal screen, catalog\n        end\n\n        def test_01_before_first\n          before_first\n        end\n\n        def test_02_window_size\n          size = window_size\n          assert_equal  size.width.class, Integer\n          assert_equal  size.height.class, Integer\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "ios_tests/lib/ios/specs/common/helper.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"ios[common/helper]\"\nclass IosTest\n  class Common\n    class Helper < Minitest::Test\n      def setup\n        @wait_opts = { timeout: 0.2, interval: 0.2 } # max_wait, interval\n      end\n\n      def test_01_before_first\n        driver.terminate_app target_bundle_id\n        driver.activate_app target_bundle_id\n        assert_equal screen, catalog\n      end\n\n      # There's no `must_not_raise` as the opposite of must_raise\n      #\n      # By default code is expected to not raise exceptions.\n      # must_not_raise is a no-op.\n\n      # wait is a success unless an error is raised\n      # max_wait=0 is infinity to use 0.1\n      def test_02_wait\n        # successful wait should not raise error\n        wait(@wait_opts) { true }\n        wait(@wait_opts) { false }\n        wait(@wait_opts) { nil }\n\n        # failed wait should error\n        assert_raises ::Appium::Core::Wait::TimeoutError do\n          wait(@wait_opts) { raise }\n        end\n\n        # regular rescue will not handle exceptions outside of StandardError hierarchy\n        # must rescue Exception explicitly to rescue everything\n        assert_raises ::Appium::Core::Wait::TimeoutError do\n          wait(@wait_opts) { raise NoMemoryError }\n        end\n\n        assert_raises ::Appium::Core::Wait::TimeoutError do\n          wait(timeout: 0.2, interval: 0.0) { raise NoMemoryError }\n        end\n        e = assert_raises ArgumentError do\n          wait(invalidkey: 2) { true }\n        end\n        assert_equal 'unknown keyword: :invalidkey', e.message\n      end\n\n      def test_03_ignore\n        # ignore should rescue all exceptions\n        ignore { true }\n        ignore { false }\n        ignore { nil }\n        ignore { raise }\n        ignore { raise NoMemoryError }\n      end\n\n      # wait_true is a success unless the value is not true\n      def test_04_wait_true\n        # successful wait should not error\n        wait_true(@wait_opts) { true }\n\n        # failed wait should error\n        assert_raises ::Appium::Core::Wait::TimeoutError do\n          wait_true(@wait_opts) { false }\n        end\n        assert_raises ::Appium::Core::Wait::TimeoutError do\n          wait_true(@wait_opts) { nil }\n        end\n\n        # raise should error\n        assert_raises ::Appium::Core::Wait::TimeoutError do\n          wait_true(@wait_opts) { raise }\n        end\n\n        # regular rescue will not handle exceptions outside of StandardError hierarchy\n        # must rescue Exception explicitly to rescue everything\n        assert_raises ::Appium::Core::Wait::TimeoutError do\n          wait_true(@wait_opts) { raise NoMemoryError }\n        end\n        assert_raises ::Appium::Core::Wait::TimeoutError do\n          wait_true(timeout: 0.2, interval: 0.0) { raise NoMemoryError }\n        end\n\n        e = assert_raises ArgumentError do\n          wait_true(invalidkey: 2) { true }\n        end\n        assert_equal 'unknown keyword: :invalidkey', e.message\n      end\n\n      def test_06_back\n        # start page\n        assert_equal tag(ui_ios.navbar).name, 'UICatalog'\n        # nav to new page.\n        wait_true do\n          text('buttons').click\n          tag(ui_ios.navbar).name == 'Buttons'\n        end\n\n        assert_equal tag(ui_ios.navbar).name, 'Buttons'\n        # go back\n        back_click\n        # start page\n        assert_equal tag(ui_ios.navbar).name, 'UICatalog'\n      end\n\n      def test_07_session_id\n        # Sauce doesn't return '-' so make them optional.\n        assert_match(/\\h{8}-?\\h{4}-?\\h{4}-?\\h{4}-?\\h{12}/, session_id)\n      end\n\n      def test_08_xpath\n        assert_equal xpath(\"//#{ui_ios.static_text}\").name, 'UICatalog'\n      end\n\n      def test_09_xpaths\n        assert_equal xpaths(\"//#{ui_ios.static_text}\").length, 35\n      end\n\n      def uibutton_text\n        'Buttons'\n      end\n\n      def action_sheets\n        'Action Sheets'\n      end\n\n      def test_10_ele_index\n        assert_equal ele_index(ui_ios.static_text, 2).name, action_sheets\n      end\n\n      # TODO: 'string_attr_exact'\n\n      def test_11_find_ele_by_attr\n        el_id = find_ele_by_attr(ui_ios.static_text, 'name', uibutton_text).instance_variable_get :@id\n        assert_match(/\\d+/, el_id)\n      end\n\n      def test_12_find_eles_by_attr\n        # '!' clears the input buffer in Pry so make sure there's\n        # no space after the !\n        set_wait 1\n        # empty array returned when no match\n        found = !find_eles_by_attr(ui_ios.static_text, 'name', uibutton_text).empty?\n        assert_equal found, true\n\n        found = !find_eles_by_attr(ui_ios.static_text, 'name', 'zz').empty?\n        assert_equal found, false\n        set_wait\n      end\n\n      def test_13_find_ele_by_predicate\n        el_text = find_ele_by_predicate(value: uibutton_text).text\n        assert_equal el_text, uibutton_text\n\n        el_name = find_ele_by_predicate(value: uibutton_text).name\n        assert_equal el_name, uibutton_text\n      end\n\n      def test_14_find_eles_by_predicate\n        ele_count = find_eles_by_predicate(value: uibutton_text).length\n        assert_equal ele_count, 1\n\n        ele_count = find_eles_by_predicate(value: 'zz').length\n        assert_equal ele_count, 0\n      end\n\n      # TODO: 'string_attr_include'\n\n      def test_15_find_ele_by_attr_include\n        el_text = find_ele_by_attr_include(ui_ios.static_text, :name, 'button').text\n        assert_equal el_text, uibutton_text\n\n        el_name = find_ele_by_attr_include(ui_ios.static_text, :name, 'button').name\n        assert_equal el_name, uibutton_text\n      end\n\n      def test_16_find_eles_by_attr_include\n        ele_count = find_eles_by_attr_include(ui_ios.static_text, :name, 'e').length\n        assert_equal ele_count, 31\n      end\n\n      def test_17_find_ele_by_predicate_include\n        el_text = find_ele_by_predicate_include(value: 'button').text\n        assert_equal el_text, uibutton_text\n\n        el_name = find_ele_by_predicate_include(value: 'button').name\n        assert_equal el_name, uibutton_text\n      end\n\n      def test_18_find_eles_by_predicate_include\n        assert_equal find_eles_by_predicate_include(value: 'e').length, 51\n      end\n\n      def test_19_first_ele\n        assert_equal first_ele(ui_ios.static_text).name, 'UICatalog'\n      end\n\n      def test_20_last_ele\n        expected = 'Steppers'\n\n        el = last_ele(ui_ios.static_text)\n        assert_equal el.text, expected\n        assert_equal el.name, expected\n      end\n\n      # t 'source' do # tested by get_source\n\n      def test_21_get_source\n        assert_equal get_source.class, String\n      end\n\n      def test_22_invalid_id_should_error\n        assert_raises Selenium::WebDriver::Error::NoSuchElementError do\n          id 'does not exist'\n        end\n\n        assert_raises Selenium::WebDriver::Error::NoSuchElementError do\n          id 'android:id/text1'\n        end\n      end\n\n      def test_23_tag\n        assert_equal tag(ui_ios.navbar).name, 'UICatalog'\n      end\n\n      def test_24_tags\n        assert_equal tags(ui_ios.table_cell).length, 12\n      end\n\n      def test_25_find_eles_by_attr_include_length\n        assert_equal find_eles_by_attr_include(ui_ios.static_text, 'name', 'AAPL').length, 16\n      end\n\n      def test_26_get_page_class\n        act = get_page_class\n\n        assert(act.split(\"\\n\").length >= 7)\n        assert_includes act, '25x XCUIElementTypeOther'\n        assert_includes act, '24x XCUIElementTypeStaticText'\n        assert_includes act, '12x XCUIElementTypeCell'\n        assert_includes act, '1x XCUIElementTypeTable'\n        assert_includes act, '1x XCUIElementTypeNavigationBar'\n        assert_includes act, '1x XCUIElementTypeWindow'\n        assert_includes act, '1x XCUIElementTypeApplication'\n      end\n\n      # TODO: write tests\n      # page_class\n      # px_to_window_rel\n      # lazy_load_strings\n      # xml_keys\n      # xml_values\n      # resolve_id\n      # string_visible_contains\n      # xpath_visible_contains\n      # xpaths_visible_contains\n      # string_visible_exact\n      # xpath_visible_exact\n      # xpaths_visible_exact\n      # raise_no_element_error\n    end\n  end\nend\n"
  },
  {
    "path": "ios_tests/lib/ios/specs/common/patch.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n#  Skip:\n#    status # status patches are already tested in driver.rb\n#    execute # debug output for Pry\n#\n\n# bundle exec rake \"ios[common/patch]\"\nclass IosTest\n  class Common\n    class Patch < Minitest::Test\n      def test_01_before_first\n        driver.terminate_app target_bundle_id\n        driver.activate_app target_bundle_id\n        assert_equal screen, catalog\n      end\n\n      def test_02_appium_core_element_method_name\n        assert_equal first_text.name, 'UICatalog'\n      end\n\n      def test_03_appium_core_element_method_location_rel\n        loc = first_text.location_rel($driver)\n        assert_equal loc.x.class, String\n        assert_equal loc.y.class, String\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "ios_tests/lib/ios/specs/common/version.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nclass IosTest\n  class Common\n    class Version < Minitest::Test\n      def test_01_before_first\n        assert_equal screen, catalog\n      end\n\n      def test_02_appium_version\n        assert_match(/(\\d+)\\.(\\d+).(\\d+)/, ::Appium::VERSION)\n      end\n\n      def test_03_appium_date\n        assert_match(/(\\d+)-(\\d+)-(\\d+)/, ::Appium::DATE)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "ios_tests/lib/ios/specs/common/web_context.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# Tests specifically for areas where the web_context differs in behaviour\n# rake \"ios[common/web_context]\"\n\nclass IosTest\n  class Common\n    class WebContext < Minitest::Test\n      def test_01_before_first\n        driver.terminate_app target_bundle_id\n        driver.activate_app target_bundle_id\n        assert_equal screen, catalog\n      end\n\n      def test_02_get_ios_inspect\n        find_eles_by_predicate_include(value: 'Web').first.click\n\n        wait_true { available_contexts.size >= 2 }\n        web_view_context = available_contexts.find { |c| c.start_with? 'WEBVIEW' } # Get WEBVIEW_59153.1 for example.\n\n        set_context web_view_context\n        assert_equal current_context, web_view_context\n        sleep 1 # Give a chance to load\n        assert_equal page.start_with?(\"\\nhtml\\n\"), true\n      end\n\n      def test_03_xcuitest_get_contexts\n        context = xcuitest_get_contexts\n        assert_equal({ 'id' => 'NATIVE_APP' }, context.first)\n        assert context[1]['id'].include?('WEBVIEW_')\n      end\n\n      def test_04_after_last\n        set_context 'NATIVE_APP'\n        back_click\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "ios_tests/lib/ios/specs/device/device.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# $ rake \"ios[device/device]\"\n\nclass IosTest\n  class Device\n    class Device < Minitest::Test\n      # go back to the main page\n      def go_back\n        back\n        wait { find_ele_by_predicate_include(class_name: ui_ios.navbar, value: 'UICatalog') }\n      end\n\n      def test_01_before_first\n        driver.terminate_app target_bundle_id\n        driver.activate_app target_bundle_id\n        assert_equal screen, catalog\n      end\n\n      def test_02_app_installed\n        installed = app_installed? 'Derrp'\n        assert_equal installed, false\n      end\n\n      def test_03_background_app_homescreen\n        bundle_id = 'com.example.apple-samplecode.UICatalog'\n\n        background_app(-1) # background_app(nil) should work as same.\n\n        # The app goes to background and never come back\n        wait do\n          assert_equal driver.app_state(bundle_id), :running_in_background_suspended\n        end\n\n        driver.activate_app bundle_id\n      end\n\n      def test_04_app_strings\n        assert_includes app_strings, 'A Short Title Is Best'\n        assert_includes app_strings('en'), 'A Short Title Is Best'\n      end\n\n      def test_05_action_chain\n        element = text('Buttons')\n        one_finger_tap x: 0, y: 0, element: element\n\n        wait { button 'UICatalog' } # successfully transitioned to buttons page\n        go_back\n      end\n\n      def test_06_swipe\n        action.move_to_location(75, 500).pointer_down(:left)\n              .move_to_location(75, 20).release.perform\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "ios_tests/lib/ios/specs/device/image_comparison.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# $ rake ios[device/image_comparison]\n\nclass IosTest\n  class Device\n    class ImageComparison < Minitest::Test\n      def test_image_comparison\n        image1 = File.read './data/test_normal.png'\n        image2 = File.read './data/test_has_blue.png'\n\n        # Equal to `$driver.driver.find_image_occurrence`\n        # Equal to `driver.find_image_occurrence`\n        find_result = find_image_occurrence full_image: image1, partial_image: image2\n        rect = find_result['rect']\n        assert_equal({ 'x' => 0, 'y' => 0, 'width' => 750, 'height' => 1334 }, rect)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "ios_tests/lib/ios/specs/driver.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# bundle exec rake \"ios[driver]\"\nclass IosTest\n  class Driver < Minitest::Test\n    def test_01_before_first\n      driver.terminate_app target_bundle_id\n      driver.activate_app target_bundle_id\n      assert_equal screen, catalog\n    end\n\n    def test_02_unicode_defaults\n      data = File.read File.expand_path('../../../data/unicode.txt', __dir__)\n      assert_equal data.strip, 174.chr('UTF-8')\n    end\n\n    def test_03_load_settings\n      appium_txt = File.join(Dir.pwd, 'appium.txt')\n      opts       = Appium.load_settings file: appium_txt, verbose: true\n\n      actual   = ''\n      actual   = File.basename opts[:caps][:app] if opts && opts[:caps]\n      expected = 'UICatalog.app.zip'\n      assert_equal expected, actual\n    end\n\n    def test_04_verify_all_attributes\n      actual                = driver_attributes\n      caps_app_for_teardown = actual[:caps][:app]\n      expected_app = File.absolute_path('../test_apps/UICatalog.app.zip')\n\n      # actual[:caps].to_json send to Appium server\n      caps_with_json = JSON.parse(actual[:caps].to_json)\n      assert_equal caps_with_json['platformName'], 'ios'\n      assert !caps_with_json['platformVersion'].nil?\n      assert_equal caps_with_json['app'], expected_app\n      assert_equal caps_with_json['automationName'], 'XCUITest'\n      assert !caps_with_json['deviceName'].nil?\n      assert_equal caps_with_json['someCapability'], 'some_capability'\n\n      assert_equal actual[:caps][:platformName], 'ios'\n      assert !actual[:caps][:platformVersion].nil?\n      assert_equal actual[:caps][:app], expected_app\n      assert_equal actual[:caps][:automationName], 'XCUITest'\n      assert !actual[:caps][:deviceName].nil?\n      assert_equal actual[:caps][:someCapability], 'some_capability'\n\n      actual_selenium_caps = actual[:caps][:automationName]\n      assert_equal actual_selenium_caps, 'XCUITest'\n      actual[:caps][:app] = caps_app_for_teardown\n    end\n\n    def test_05_verify_attributes_are_immutable\n      assert_equal driver_attributes[:custom_url], 'http://127.0.0.1:4723'\n      driver_attributes[:custom_url] = true\n      assert_equal driver_attributes[:custom_url], 'http://127.0.0.1:4723'\n    end\n\n    def test_06_verify_attribute_of_caps_are_not_immutable_because_it_depends_on_selenium\n      # immutability depends on Selenium\n      for_clean_up                   = driver_attributes[:caps][:app].dup\n      driver_attributes[:caps][:app] = 'fake'\n      expected                       = 'fake'\n      assert_equal driver_attributes[:caps][:app], expected\n\n      # clean up\n      driver_attributes[:caps][:app] = for_clean_up\n    end\n\n    def test_07_no_wait\n      no_wait\n      assert_raises Selenium::WebDriver::Error::NoSuchElementError do\n        find_element(:accessibility_id, 'zz')\n      end\n      set_wait\n    end\n\n    def test_08_app_path_attr\n      apk_name = File.basename driver_attributes[:caps][:app]\n      assert_equal apk_name, 'UICatalog.app.zip'\n    end\n\n    def test_09_driver_class\n      assert_equal $driver.class, Appium::Driver\n    end\n\n    def test_10_status\n      assert appium_server_version['build'].keys.member?('version')\n    end\n\n    def test_11_server_version\n      server_version = appium_server_version['build']['version']\n      assert_match(/(\\d+)\\.(\\d+).(\\d+)/, server_version)\n    end\n\n    def test_12_client_version\n      client_version = appium_client_version\n      expected = { version: ::Appium::VERSION }\n      assert_equal client_version, expected\n    end\n\n    def test_13_restart\n      restart\n      text 'buttons'\n    end\n\n    def test_14_driver\n      assert driver.browser.empty?\n    end\n\n    def test_15_automation_name_is_xcuitest?\n      assert_equal automation_name_is_xcuitest?, true\n    end\n\n    #\n    # Skip:\n    #    screenshot   # this is slow and already tested by Appium\n    #    driver_quit  # tested by restart\n    #    start_driver # tested by restart\n    #\n\n    def test_16_set_wait\n      # fill the @last_waits array with: [30, 30]\n      assert_equal set_wait(30), 30\n      assert_equal set_wait(30), 30\n\n      # verify set_wait with no args works correctly\n      assert_equal set_wait, 30\n      assert_equal set_wait(30), 30\n      assert_equal set_wait, 30\n\n      assert_equal set_wait(2), 2\n      assert_equal set_wait, 30\n      assert_equal set_wait(3), 3\n      assert_equal set_wait, 30\n\n      assert_equal set_wait(2), 2\n      assert_equal set_wait(3), 3\n      assert_equal set_wait, 30\n    end\n\n    def test_17_default_wait\n      set_wait 30\n      assert_equal default_wait, 30 # set in run.rb\n    end\n\n    # returns true unless an error is raised\n    def test_18_exists\n      assert_equal exists(0, 0) { true }, true\n      assert_equal exists(0, 0) { raise 'error' }, false\n    end\n\n    # simple integration sanity test to check for unexpected exceptions\n    def test_19_set_location\n      set_location latitude: 55, longitude: -72, altitude: 33\n    end\n\n    # any elements\n    def test_20_find_elements\n      assert_equal find_elements(:class, ui_ios.table_cell).length, 18\n    end\n\n    # any element\n    def test_21_find_element\n      assert_equal find_element(:class, ui_ios.static_text).class, ::Appium::Core::Element\n    end\n\n    # settings\n    def test_22_get_settings\n      assert !get_settings.nil?\n    end\n\n    def test_23_update_settings\n      update_settings allowInvisibleElements: true\n      assert_equal get_settings['allowInvisibleElements'], true\n    end\n\n    def test_24_events\n      log_event vendor: 'appium', event: 'funEvent'\n      log_events\n    end\n\n    def test_25_device_is_ios\n      assert_equal device_is_ios?, true\n    end\n  end\nend\n"
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/command/multi_app_handler.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"ios[ios/command/multi_app_handler]\"\nclass IosTest\n  class Ios\n    class Command\n      class MultiAppHandler < Minitest::Test\n        # Only for Xcode 9+\n        def test_multip_app_handler\n          driver.terminate_app target_bundle_id\n          driver.activate_app target_bundle_id\n\n          test_app_bundle = target_bundle_id\n\n          assert_equal xcuitest_query_app_status(bundle_id: test_app_bundle), :running_in_foreground\n\n          assert_equal xcuitest_terminate_app(bundle_id: test_app_bundle), true\n          assert_equal xcuitest_query_app_status(bundle_id: test_app_bundle), :not_running\n\n          assert xcuitest_activate_app(bundle_id: test_app_bundle).nil?\n          assert_equal xcuitest_query_app_status(bundle_id: test_app_bundle), :running_in_foreground\n\n          assert xcuitest_activate_app(bundle_id: 'com.apple.Preferences').nil?\n          wait(timeout: 5) do\n            assert_equal xcuitest_query_app_status(bundle_id: test_app_bundle), :running_in_background_suspended\n          end\n\n          assert xcuitest_activate_app(bundle_id: test_app_bundle).nil?\n          wait(timeout: 5) do\n            assert_equal xcuitest_query_app_status(bundle_id: test_app_bundle), :running_in_foreground\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/command/pasteboard.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"ios[ios/command/pasteboard]\"\nclass IosTest\n  class Ios\n    class Command\n      class Pasteboard < Minitest::Test\n        def test_pasteboard\n          driver.terminate_app target_bundle_id\n          driver.activate_app target_bundle_id\n\n          # set blank before testing because pasteboard is remaining during launching simulators\n          set_pasteboard content: 'before'\n          assert_equal get_pasteboard, 'before'\n\n          set_pasteboard content: 'sample content'\n\n          assert_equal get_pasteboard, 'sample content'\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/command/source.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake ios[ios/command/source]\nclass IosTest\n  class Ios\n    class Command\n      class Source < Minitest::Test\n        def test_source\n          assert_equal xcuitest_source(format: :json).is_a?(Hash), true\n          assert_equal xcuitest_source(format: :xml).is_a?(String), true\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/element/alert.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"ios[ios/element/alert]\"\nclass IosTest\n  class Ios\n    class Element\n      class Alert < Minitest::Test\n        def open_alert\n          wait_true do\n            find_element(:name, 'Okay / Cancel').click\n            find_element(:name, 'A Short Title Is Best').displayed?\n          end\n        end\n\n        def test_01_before\n          driver.terminate_app target_bundle_id\n          driver.activate_app target_bundle_id\n\n          assert_equal screen, catalog\n          wait_true do\n            find_element(:name, 'Alert Views').click\n            tag(ui_ios.navbar).name == 'Alert Views' # wait for true\n          end\n        end\n\n        def test_02_alert_accept\n          open_alert\n          alert_accept\n        end\n\n        def test_03_alert_dismiss\n          open_alert\n          alert_dismiss\n        end\n\n        def test_04_after_last\n          back_click\n          assert screen == catalog\n          sleep 1\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/element/button.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# FIXME: The order is broken in Ruby 3.\n# rake \"ios[ios/element/button]\"\n\nclass IosTest\n  class Ios\n    class Element\n      class Button < Minitest::Test\n        def before_first\n          assert_equal screen, catalog\n          # nav to buttons activity\n          wait { find_element(:name, 'Buttons').click }\n        end\n\n        def after_last\n          # nav back to start\n          back_click\n        end\n\n        def test_01_before_first\n          driver.terminate_app target_bundle_id\n          driver.activate_app target_bundle_id\n\n          before_first\n        end\n\n        def test_02_button\n          # by index\n          assert_equal button(3).name, 'UIAccessoryButtonPlus'\n\n          # by name contains\n          assert_equal button('Plus').name, 'UIAccessoryButtonPlus'\n        end\n\n        def test_03_buttons\n          exp = %w(UICatalog UIAccessoryButtonPlus)\n\n          target_buttons = buttons('a')\n          assert_equal target_buttons.map(&:name), exp\n          assert_equal target_buttons.length, exp.length\n        end\n\n        def test_04_first_button\n          assert_equal first_button.name, 'UICatalog'\n        end\n\n        def test_05_last_button\n          expected = 'Button'\n          assert_equal last_button.name, expected\n        end\n\n        def test_06_button_exact\n          assert_equal button_exact('UIAccessoryButtonPlus').name, 'UIAccessoryButtonPlus'\n        end\n\n        def test_07_buttons_exact\n          assert_equal buttons_exact('UIAccessoryButtonPlus').first.name, 'UIAccessoryButtonPlus'\n        end\n\n        def test_08_after_last\n          after_last\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/element/generic.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"ios[ios/element/generic]\"\nclass IosTest\n  class Ios\n    class Element\n      class Generic < Minitest::Test\n        def uibutton_text\n          'Buttons'\n        end\n\n        def verify(element)\n          element = element.first if element.is_a? Array\n          assert_equal element.name, uibutton_text\n        end\n\n        def test_01_before_first\n          driver.terminate_app target_bundle_id\n          driver.activate_app target_bundle_id\n\n          assert_equal screen, catalog\n        end\n\n        def test_02_find\n          verify find 'tons'\n        end\n\n        def test_03_finds\n          verify finds 'tons'\n        end\n\n        def test_04_find_exact\n          verify find_exact uibutton_text\n        end\n\n        def test_05_finds_exact\n          elements = finds_exact uibutton_text\n          assert_equal elements.is_a?(Array), true\n          verify elements\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/element/text.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"ios[ios/element/text]\"\nclass IosTest\n  class Ios\n    class Element\n      class Text < Minitest::Test\n        def ui_catalog\n          'UICatalog'\n        end\n\n        def uiview_steppers\n          'Steppers'\n        end\n\n        def test_01_before_first\n          driver.terminate_app target_bundle_id\n          driver.activate_app target_bundle_id\n\n          assert_equal screen, catalog\n        end\n\n        def test_02_first_text\n          assert_equal first_text.text, ui_catalog\n        end\n\n        def test_03_last_text\n          expected = 'Steppers'\n\n          assert_equal last_text.text, expected\n          assert_equal last_text.name, expected\n        end\n\n        def test_04_text\n          assert_equal text('epp').text, uiview_steppers\n          assert_equal text(1).text, ui_catalog\n          assert_equal text('epp').name, uiview_steppers\n        end\n\n        def test_05_texts\n          exp = ['Date Picker', 'AAPLDatePickerController', 'Picker View', 'AAPLPickerViewController']\n          assert_equal texts.length, 24\n          assert_equal texts('icker').map(&:name), exp\n          assert_equal texts('AAPL').length, 11\n        end\n\n        def test_06_text_exact\n          # should fail\n          set_wait 0\n          act = begin\n            text_exact 'mos'\n          rescue StandardError\n            # nop\n          end\n          assert act.nil?\n          set_wait\n\n          # should pass\n          assert_equal text_exact(ui_catalog).text, ui_catalog\n        end\n\n        def test_07_texts_exact\n          assert_equal texts_exact('UICatalog').length, 1\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/element/textfield.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"ios[ios/element/textfield]\"\nclass IosTest\n  class Element\n    class Textfield < Minitest::Test\n      def enter_text\n        'Placeholder text'\n      end\n\n      def enter_password\n        'Placeholder text'\n      end\n\n      def test_01_before_first\n        driver.terminate_app target_bundle_id\n        driver.activate_app target_bundle_id\n        assert_equal screen, catalog\n        go_to_textfields\n      end\n\n      def test_02_textfield\n        assert_equal textfield(1).text, enter_text\n        assert_equal textfield(enter_text).text, enter_text\n        assert_equal textfield('holder').value, enter_password\n      end\n\n      def test_03_textfields\n        values = textfields('text').map(&:value)\n        assert_equal values.include?(enter_text), true\n        assert_equal values.include?(enter_password), true # secure as well\n        assert_equal textfields.length, 5\n      end\n\n      def test_04_predicate_textfields\n        textfields = find_elements(:predicate, \"type contains[c] 'textfield'\")\n        assert_equal textfields.length, 5\n      end\n\n      def test_05_first_textfield\n        assert_equal first_textfield.text, enter_text\n      end\n\n      def test_06_last_textfield\n        assert_equal last_textfield.text, enter_text\n      end\n\n      def test_07_textfield_exact\n        assert_equal textfield_exact(enter_password).value, enter_password\n      end\n\n      def test_08_textfields_exact\n        assert_equal textfields_exact(enter_password).first.value, enter_password\n      end\n\n      def test_09_textfield_type\n        textfield(1).send_keys \"o'k\"\n\n        assert_equal find_exact(\"o'k\").text, \"o'k\"\n      end\n\n      def test_10_hide_keyboard\n        first_textfield.click\n        hide_keyboard\n      end\n\n      # test textfield methods with no textfields\n\n      def test_11_leave_textfields\n        set_wait 1\n        leave_textfields\n      end\n\n      def test_12_no_textfield\n        assert_raises(Selenium::WebDriver::Error::NoSuchElementError) { textfield(1) }\n        assert_raises(Selenium::WebDriver::Error::NoSuchElementError) { textfield('does not exist') }\n      end\n\n      def test_13_no_textfields\n        assert_equal textfields('does not exist').length, 0\n      end\n\n      def test_14_no_first_textfield\n        assert_raises(Selenium::WebDriver::Error::NoSuchElementError) { first_textfield }\n      end\n\n      def test_15_no_last_textfield\n        assert_raises(Selenium::WebDriver::Error::NoSuchElementError) { last_textfield }\n      end\n\n      def test_16_no_textfield_exact\n        assert_raises(Selenium::WebDriver::Error::NoSuchElementError) { textfield_exact('does not exist') }\n      end\n\n      def test_17_no_textfields_exact\n        assert_equal textfields_exact('does not exist').length, 0\n      end\n\n      def test_18_after_last\n        set_wait 30\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/helper.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"ios[ios/helper]\"\nclass IosTest\n  class Ios\n    class Helper < Minitest::Test\n      def test_01_before_first\n        driver.terminate_app target_bundle_id\n        driver.activate_app target_bundle_id\n\n        assert_equal screen, catalog\n      end\n\n      def test_02_ios_password\n        assert_equal ios_password, 8226.chr('UTF-8')\n        assert_equal ios_password(2), 8226.chr('UTF-8') * 2\n      end\n\n      def test_03_page\n        page # writes to std out\n      end\n\n      def test_04_id\n        id 'Buttons' # 'Various uses of UIButton'\n      end\n\n      def test_05_platform_version\n        assert !platform_version.empty?\n      end\n\n      def test_06_tags_include\n        elements = tags_include class_names: %w(XCUIElementTypeTextView)\n        assert_equal elements.length, 0\n\n        elements = tags_include class_names: %w(XCUIElementTypeTextView XCUIElementTypeStaticText)\n        assert_equal elements.length, 24\n\n        elements = tags_include class_names: %w(XCUIElementTypeTextView XCUIElementTypeStaticText), value: 'u'\n        assert_equal elements.length, 3\n      end\n\n      def test_07_tags_exact\n        elements = tags_exact class_names: %w()\n        assert_equal elements.length, 0\n\n        elements = tags_exact class_names: %w(XCUIElementTypeStaticText)\n        assert_equal elements.length, 24\n\n        elements = tags_exact class_names: %w(XCUIElementTypeTextView XCUIElementTypeStaticText)\n        assert_equal elements.length, 24\n\n        elements = tags_exact class_names: %w(XCUIElementTypeTextView XCUIElementTypeStaticText), value: 'Buttons'\n        assert_equal elements.length, 1\n        assert_equal elements.first.value, 'Buttons'\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/mobile_methods.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake ios[ios/mobile_methods]\nclass IosTest\n  class Ios\n    class MobileMethods < Minitest::Test\n      def test_01_before_first\n        driver.terminate_app target_bundle_id\n        driver.activate_app target_bundle_id\n        assert_equal screen, catalog\n      end\n\n      def test_02_an_element_with_class_chain\n        element = find_element :class_chain, '**/XCUIElementTypeStaticText'\n\n        assert_equal element.name, catalog\n      end\n\n      def test_03_elements_with_class_chain\n        elements = find_elements :class_chain, 'XCUIElementTypeWindow/*/*'\n\n        assert_equal elements.size, 2\n        assert_equal elements[0].name, catalog\n        assert elements[1].name.nil?\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/patch.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"ios[ios/patch]\"\nclass IosTest\n  class Ios\n    class Patch < Minitest::Test\n      def test_01_before_first\n        driver.terminate_app target_bundle_id\n        driver.activate_app target_bundle_id\n        assert_equal screen, catalog\n        go_to_textfields\n      end\n\n      def test_02_label\n        assert_equal textfields[0].label, ''\n      end\n\n      def test_03_type\n        text('text fields').click\n\n        ele = first_textfield\n\n        ele.clear\n        ele.type 'ok'\n        assert_equal ele.text, 'ok'\n      end\n\n      def test_04_after_last\n        leave_textfields\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "ios_tests/lib/ios/specs/ios/xcuitest_gestures.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# rake \"ios[ios/xcuitest_gestures]\"\nclass IosTest\n  class Ios\n    class XcuitestGestures < Minitest::Test\n      def open_alert_ok_cancel\n        wait_true do\n          find_element(:name, 'Okay / Cancel').click\n          find_element(:name, 'A Short Title Is Best').displayed?\n        end\n      end\n\n      def open_alert_custom\n        wait_true do\n          find_element(:name, 'Other').click\n          find_element(:name, 'A Short Title Is Best').displayed?\n        end\n      end\n\n      def test_01_before_first\n        driver.terminate_app target_bundle_id\n        driver.activate_app target_bundle_id\n        assert_equal screen, catalog\n      end\n\n      def test_02_tap\n        element = text('controls')\n        one_finger_tap x: 0, y: 0, element: element\n\n        back_click\n\n        element = text('controls')\n        rect = element.rect\n        one_finger_tap x: rect.x + rect.width / 2, y: rect.y + rect.height / 2\n      end\n\n      def test_03_double_tap\n        element = button('Search')\n        double_tap(element: element)\n      end\n\n      def test_04_touch_and_hold\n        element = button('Tools')\n        touch_and_hold(element: element, duration: 4.0)\n        touch_and_hold(x: 100, y: 100)\n      end\n\n      def test_05_swipe\n        swipe direction: 'down'\n        swipe direction: 'down'\n\n        assert_raises Selenium::WebDriver::Error::NoSuchElementError do\n          text('Toolbars')\n        end\n      end\n\n      def test_06_drag_from_to_for_duration\n        drag_from_to_for_duration from_x: 100, from_y: 100, to_x: 100, to_y: 400\n      end\n\n      def test_07_pinch\n        pinch(scale: 0.5, velocity: -1)\n      end\n\n      def test_08_back_to_top\n        back_click\n      end\n\n      def test_09_select_picker_wheel\n        element = text('Picker View')\n        one_finger_tap x: 0, y: 0, element: element\n\n        e = find_element :class, ui_ios.picker_wheel\n        previous_value = e.text\n        select_picker_wheel(element: e, order: 'next')\n\n        current_element = find_element(:class, ui_ios.picker_wheel)\n        assert_equal current_element.displayed?, true\n        assert current_element.text != previous_value\n      end\n\n      def test_10_back_to_top\n        back_click\n      end\n\n      def test_11_alert\n        wait_true do\n          find_element(:name, 'Alert Views').click\n          tag(ui_ios.navbar).name == 'Alert Views'\n        end\n\n        open_alert_ok_cancel\n        alert action: 'accept'\n\n        open_alert_ok_cancel\n        alert action: 'dismiss'\n\n        open_alert_custom\n        list = alert action: 'getButtons'\n        assert_equal list, ['Choice One', 'Choice Two', 'Cancel']\n        alert action: 'accept', button_label: 'Choice Two'\n      end\n\n      def test_12_back_to_top\n        back_click\n      end\n\n      def test_13_after_last\n        assert_equal screen, catalog\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "ios_tests/lib/run.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# ios tests have a set of core helper methods\nrequire_relative 'common'\n# run file is identical to android\nrequire_relative '../../android_tests/lib/run'\n"
  },
  {
    "path": "ios_tests/parallel/test.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nrequire_relative '../../lib/appium_lib'\n\ndef des_server_caps\n  {\n    debug: true,\n    server_url: ENV['appium_server'] ||= 'http://127.0.0.1:4723',\n    wait: 25,\n    wait_timeout: 20,\n    wait_interval: 0.3\n  }\nend\n\nclass TestParallelRunThread\n  def initialize(capability)\n    @capability = capability\n  end\n\n  def setup\n    @appium = Appium::Driver.new({ caps: @capability, appium_lib: des_server_caps }, false)\n    @appium.start_driver\n  end\n\n  def teardown\n    @appium.quit_driver\n    puts \"finish: #{@capability}\"\n  end\n\n  def test_run\n    setup\n\n    # tap alert\n    @appium.find_element(:name, 'Alerts').click\n    @appium.wait_true do\n      @appium.find_element(:name, 'Show OK-Cancel').click\n      @appium.find_element(:name, 'UIActionSheet <title>').displayed?\n    end\n    @appium.alert action: 'accept'\n    @appium.back\n\n    sleep 5\n\n    # TODO: fixme\n    text_elem = @appium.text(@appium.app_strings['ButtonsExplain'])\n    @appium.driver.action.click(text_elem).perform\n    @appium.back\n\n    teardown\n  end\nend\n\nclass TestParallelRunProcess\n  def initialize(capability)\n    @capability = capability\n  end\n\n  def setup\n    @appium = Appium::Driver.new({ caps: @capability, appium_lib: des_server_caps }, false)\n    Appium.promote_appium_methods TestParallelRunProcess, @appium\n    start_driver\n  end\n\n  def teardown\n    quit_driver\n    puts \"finish: #{@capability}\"\n  end\n\n  def test_run\n    setup\n\n    # tap alert\n    find_element(:name, 'Alerts').click\n    wait_true do\n      find_element(:name, 'Show OK-Cancel').click\n      find_element(:name, 'UIActionSheet <title>').displayed?\n    end\n    alert action: 'accept'\n    back\n\n    sleep 5\n\n    # TODO: fixme\n    # TouchAction\n    text_elem = text(app_strings['ButtonsExplain'])\n    driver.action.click(text_elem).perform\n    back\n\n    teardown\n  end\nend\n"
  },
  {
    "path": "ios_tests/readme.md",
    "content": "ruby_lib_ios\n=====================\n\nruby_lib's iOS tests. Requires `Ruby 2.2+` or better.\n\n- `rake install` Install gems required to run the tests.\n- `rake ios` Run all tests.\n- `rake` Run all the test. Same as `rake ios`\n- `rake ios['ios/element/generic']` Run a single test.\n- `rake run_parallel_t` Run a test in parallel with thread model.\n- `rake run_parallel_p` Run a test in parallel with process model.\n- `arc` Opens the Appium Ruby Console (arc). Enables interactive testing.\n  - `gem install appium_console` if it's not installed already.\n\n`UICatalog6.1` is from [appium/appium](https://github.com/appium/appium/blob/master/assets/UICatalog6.1.app.zip)\n\nThere are two backend drivers available for iOS (automationName). UIAutomation which is supported up-to iOS 9.3 and XCUITest which is supported from 10.0 on. UIAutomation is deprecated but will continue to be supported for the time being.\n\nBy default, the tests are now run against `iPhone 6 Simulator 10.1 (14A345)`\n\n--\n\n```ruby\nFinished in 1 min 57 secs\n\n123 runs, 164 assertions, 0 failures, 0 errors, 0 skips\n```\n\n### Tips for parallel \n\n- https://github.com/grosser/parallel_tests\n   - Usage: https://github.com/appium/ruby_lib_core#run-parallel-tests-with-parallel_tests-gem"
  },
  {
    "path": "lib/appium_lib/android/android.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nrequire_relative 'common/helper'\nrequire_relative 'common/command/command'\n\nrequire_relative 'element/alert'\nrequire_relative 'element/button'\nrequire_relative 'element/generic'\nrequire_relative 'element/textfield'\nrequire_relative 'element/text'\n\n# android - uiautomator2\nrequire_relative 'uiautomator2'\n\n# android - espresso\nrequire_relative 'espresso'\n\nmodule Appium\n  module Android\n    class Bridge\n      def self.for(target)\n        target.extend Appium::Android\n        target.extend Appium::Android::Command\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/appium_lib/android/common/command/command.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Android\n    module Command\n      # Conduct an adb shell script on Appium server.\n      # Require `--relaxed-security` arguments when run Appium server as server side arguments.\n      #\n      # @param [String] command Command for \"adb shell\"\n      # @param [Array] arguments Arguments for the adb command\n      #\n      # @example\n      #\n      #   shell \"echo\", \"list\" #=> \"list\"\n      #\n      def shell(command, arguments)\n        args = { command: command, args: arguments }\n        # --relaxed-security\n        @driver.execute_script 'mobile: shell', args\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/appium_lib/android/common/helper.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Android\n    # @private\n    # http://nokogiri.org/Nokogiri/XML/SAX.html\n    class AndroidElements < Nokogiri::XML::SAX::Document\n      attr_reader :result, :keys, :filter\n\n      # convert to string to support symbols\n      def filter=(value)\n        # nil and false disable the filter\n        return @filter = false unless value # rubocop:disable Lint/ReturnInVoidContext\n\n        @filter = value.to_s.downcase\n      end\n\n      def initialize # rubocop:disable Lint/MissingSuper\n        reset\n        @filter   = false\n      end\n\n      def reset\n        @result   = ''\n        @keys     = %w(text resource-id content-desc)\n      end\n\n      # http://nokogiri.org/Nokogiri/XML/SAX/Document.html\n      def start_element(name, attrs = [], driver = $driver)\n        return if filter && !name.downcase.include?(filter)\n\n        attributes = {}\n\n        attrs.each do |key, value|\n          attributes[key] = value if keys.include?(key) && !value.empty?\n        end\n\n        # scoped to: text resource-id content-desc\n        attributes_values = attributes.values\n        strings           = driver.lazy_load_strings\n        id_matches = strings.empty? ? [] : strings.select { |_key, value| attributes_values.include? value }\n\n        string_ids = nil\n\n        if id_matches && !id_matches.empty?\n          space_suffix = ' ' * 15 # 15 is '  strings.xml: '.length\n          string_ids   = ''\n\n          # add first\n          string_ids += \"#{id_matches.shift[0]}\\n\"\n\n          # use padding for remaining values\n          # [0] = key, [1] = value\n          id_matches.each do |match|\n            string_ids += \"#{space_suffix}#{match[0]}\\n\"\n          end\n        end\n\n        string = ''\n        text   = attributes['text']\n        desc   = attributes['content-desc']\n        id     = attributes['resource-id']\n\n        if !text.nil? && text == desc\n          string += \"  text, desc: #{text}\\n\"\n        else\n          string += \"  text: #{text}\\n\" unless text.nil?\n          string += \"  desc: #{desc}\\n\" unless desc.nil?\n        end\n        string += \"  id: #{id}\\n\" unless id.nil?\n        string += \"  strings.xml: #{string_ids}\" unless string_ids.nil?\n\n        @result += \"\\n#{name}\\n#{string}\" unless attributes.empty?\n      end\n    end # class AndroidElements\n\n    # Android only.\n    # Returns a string containing interesting elements.\n    # The text, content description, and id are returned.\n    # @param class_name [String] the class name to filter on.\n    # if false (default) then all classes will be inspected\n    # @return [String]\n    def get_android_inspect(class_name = false)\n      source = get_source\n\n      doctype_string = '<!doctyp'\n      source_header  = source[0..doctype_string.length].downcase\n      source_is_html = source_header.start_with?(doctype_string, '<html')\n\n      parser = if source_is_html # parse html from webview\n                 @android_html_parser ||= Nokogiri::HTML::SAX::Parser.new(Appium::Common::HTMLElements.new)\n               else\n                 @android_native_parser ||= Nokogiri::XML::SAX::Parser.new(AndroidElements.new)\n               end\n      parser.document.reset # ensure document is reset before parsing\n      parser.document.filter = class_name\n      parser.parse source\n      result = parser.document.result\n      parser.document.reset # clean up any created objects after parsing\n      result\n    end\n\n    # Intended for use with console.\n    # Inspects and prints the current page.\n    # Will return XHTML for Web contexts because of a quirk with Nokogiri.\n    # @option class [Symbol] the class name to filter on. case insensitive include match.\n    # if nil (default) then all classes will be inspected\n    # @return [void]\n    def page(opts = {})\n      class_name = opts.is_a?(Hash) ? opts.fetch(:class, nil) : opts\n      puts get_android_inspect class_name\n      nil\n    end\n\n    # Find the first matching element by id\n    # @param id [String] the id to search for\n    # @return [Element]\n    def id(id)\n      # Android auto resolves strings.xml ids\n      find_element :id, id\n    end\n\n    # Find all matching elements by id\n    # @param id [String] the id to search for\n    # @return [Element]\n    def ids(id)\n      # Android auto resolves strings.xml ids\n      find_elements :id, id\n    end\n\n    # Find the element of type class_name at matching index.\n    # @param class_name [String] the class name to find\n    # @param index [Integer] the index\n    # @return [Element] the found element of type class_name\n    def ele_index(class_name, index)\n      results = tags(class_name)\n      if index == 'last()'\n        index = results.length\n        index -= 1 if index >= 0\n      else\n        raise ArgumentError, 'Index must be >= 1' unless index >= 1\n\n        index -= 1 if index >= 1\n      end\n\n      # uiautomator has issues with index/instance so calculate the index\n      # client side.\n      results[index]\n    end\n\n    # Find the first element that matches class_name\n    # @param class_name [String] the tag to match\n    # @return [Element]\n    def first_ele(class_name)\n      tag(class_name)\n    end\n\n    # Find the last element that matches class_name\n    # @param class_name [String] the tag to match\n    # @return [Element]\n    def last_ele(class_name)\n      ele_index class_name, 'last()'\n    end\n\n    # Find the first element of type class_name\n    #\n    # @param class_name [String] the class_name to search for\n    # @return [Element]\n    def tag(class_name)\n      find_element :class, class_name\n    end\n\n    # Find all elements of type class_name\n    #\n    # @param class_name [String] the class_name to search for\n    # @return [Element]\n    def tags(class_name)\n      find_elements :class, class_name\n    end\n\n    # @private\n    # Detects if the string represents a resourceId\n    # resourceId is only supported on API >= 18 devices\n    #\n    # @param string [String] the string check for a resourceId\n    #                        value will be auto unquoted\n    # @param on_match [String] the string to return on resourceId match\n    #\n    # @return [String] empty string on failure, on_match on successful match\n    def resource_id(string, on_match)\n      return '' unless string\n\n      # unquote the string\n      # \"com.example.Test:id/enter\" -> com.example.Test:id/enter\n      unquote = string.match(/\"(.+)\"/)\n      string = unquote[1] if unquote\n\n      # java_package : type / name\n      #\n      # com.example.Test:id/enter\n      #\n      # ^[a-zA-Z_]      - Java package must start with letter or underscore\n      # [a-zA-Z0-9\\._]* - Java package may contain letters, numbers, periods and underscores\n      # :               - : ends the package and starts the type\n      # [^\\/]+          - type is made up of at least one non-/ characters\n      # \\\\/             - / ends the type and starts the name\n      # [\\S]+$          - the name contains at least one non-space character and then the line is ended\n      resource_id = /^[a-zA-Z_][a-zA-Z0-9._]*:[^\\/]+\\/\\S+$/\n      string.match(resource_id) ? on_match : ''\n    end\n\n    # Returns a string that matches the first element that contains value\n    # For automationName is uiautomator2\n    # example: string_visible_contains_xpath 'UIATextField', 'sign in'\n    # note for XPath: https://github.com/appium/ruby_lib/pull/561\n    #\n    # @param class_name [String] the class name for the element\n    # @param value [String] the value to search for\n    # @return [String]\n    def string_visible_contains_xpath(class_name, value)\n      r_id = resource_id(value, \" or @resource-id='#{value}'\")\n\n      if class_name == '*'\n        return \"//*[contains(translate(@text,'#{value.upcase}', '#{value}'), '#{value}') \" \\\n               \"or contains(translate(@content-desc,'#{value.upcase}', '#{value}'), '#{value}')\" + r_id + ']'\n      end\n\n      \"//#{class_name}[contains(translate(@text,'#{value.upcase}', '#{value}'), '#{value}') \" \\\n      \"or contains(translate(@content-desc,'#{value.upcase}', '#{value}'), '#{value}')\" + r_id + ']'\n    end\n\n    # Returns a string that matches the first element that contains value\n    # For automationName is Appium\n    # example: string_visible_contains 'UIATextField', 'sign in'\n    # note for XPath: https://github.com/appium/ruby_lib/pull/561\n    #\n    # @param class_name [String] the class name for the element\n    # @param value [String] the value to search for\n    # @return [String]\n    def string_visible_contains(class_name, value)\n      value = %(\"#{value}\")\n      if class_name == '*'\n        return (resource_id(value, \"new UiSelector().resourceId(#{value});\") +\n          \"new UiSelector().descriptionContains(#{value});\" \\\n          \"new UiSelector().textContains(#{value});\")\n      end\n\n      class_name = %(\"#{class_name}\")\n      resource_id(value, \"new UiSelector().className(#{class_name}).resourceId(#{value});\") +\n        \"new UiSelector().className(#{class_name}).descriptionContains(#{value});\" \\\n        \"new UiSelector().className(#{class_name}).textContains(#{value});\"\n    end\n\n    # Find the first element that contains value\n    # @param class_name [String] the class name for the element\n    # @param value [String] the value to search for\n    # @return [Element]\n    def complex_find_contains(class_name, value)\n      find_element :uiautomator, string_visible_contains(class_name, value)\n    end\n\n    # Find all elements containing value\n    # @param class_name [String] the class name for the element\n    # @param value [String] the value to search for\n    # @return [Array<Element>]\n    def complex_finds_contains(class_name, value)\n      find_elements :uiautomator, string_visible_contains(class_name, value)\n    end\n\n    # @private\n    # Create an string to exactly match the first element with target value\n    # For automationName is uiautomator2\n    # @param class_name [String] the class name for the element\n    # @param value [String] the value to search for\n    # @return [String]\n    def string_visible_exact_xpath(class_name, value)\n      r_id = resource_id(value, \" or @resource-id='#{value}'\")\n\n      return \"//*[@text='#{value}' or @content-desc='#{value}'\" + r_id + ']' if class_name == '*'\n\n      \"//#{class_name}[@text='#{value}' or @content-desc='#{value}'\" + r_id + ']'\n    end\n\n    # @private\n    # Create an string to exactly match the first element with target value\n    # @param class_name [String] the class name for the element\n    # @param value [String] the value to search for\n    # @return [String]\n    def string_visible_exact(class_name, value)\n      value = %(\"#{value}\")\n\n      if class_name == '*'\n        return (resource_id(value, \"new UiSelector().resourceId(#{value});\") +\n          \"new UiSelector().description(#{value});\" \\\n          \"new UiSelector().text(#{value});\")\n      end\n\n      class_name = %(\"#{class_name}\")\n      resource_id(value, \"new UiSelector().className(#{class_name}).resourceId(#{value});\") +\n        \"new UiSelector().className(#{class_name}).description(#{value});\" \\\n        \"new UiSelector().className(#{class_name}).text(#{value});\"\n    end\n\n    # Find the first element exactly matching value\n    # @param class_name [String] the class name for the element\n    # @param value [String] the value to search for\n    # @return [Element]\n    def complex_find_exact(class_name, value)\n      find_element :uiautomator, string_visible_exact(class_name, value)\n    end\n\n    # Find all elements exactly matching value\n    # @param class_name [String] the class name for the element\n    # @param value [String] the value to search for\n    # @return [Element]\n    def complex_finds_exact(class_name, value)\n      find_elements :uiautomator, string_visible_exact(class_name, value)\n    end\n  end # module Android\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/android/element/alert.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Android\n    # Click the first alert button that contains value or by index.\n    # @param value [Integer, String] either an integer index of the button or the button's name\n    # @return [void]\n    def alert_click(value)\n      button(value).click\n    end\n\n    # Accept the alert.\n    # The last button is considered \"accept.\"\n    # @return [void]\n    def alert_accept\n      last_button.click\n    end\n\n    # Get the text of the alert's accept button.\n    # The last button is considered \"accept.\"\n    # @return [String]\n    def alert_accept_text\n      last_button.text\n    end\n\n    # Dismiss the alert.\n    # The first button is considered \"dismiss.\"\n    # @return [void]\n    def alert_dismiss\n      first_button.click\n    end\n\n    # Get the text of the alert's dismiss button.\n    # The first button is considered \"dismiss.\"\n    # @return [String]\n    def alert_dismiss_text\n      first_button.text\n    end\n  end # module Android\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/android/element/button.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Android\n    BUTTON = 'android.widget.Button'\n    Button = BUTTON # backward compatibility\n\n    IMAGE_BUTTON = 'android.widget.ImageButton'\n    ImageButton = IMAGE_BUTTON # backward compatibility\n\n    # Find the first button that contains value or by index.\n    # @param value [String, Integer] the value to exactly match.\n    # If int then the button at that index is returned.\n    # @return [BUTTON]\n    def button(value)\n      # Don't use ele_index because that only works on one element type.\n      # Android needs to combine button and image button to match iOS.\n      if value.is_a? Numeric\n        index = value\n        raise ArgumentError, \"#{index} is not a valid index. Must be >= 1\" if index <= 0\n\n        # 1 indexed\n        return find_element :uiautomator, _button_visible_selectors(index: index)\n      end\n\n      find_element :uiautomator, _button_contains_string(value)\n    end\n\n    # Find all buttons containing value.\n    # If value is omitted, all buttons are returned.\n    # @param value [String] the value to search for\n    # @return [Array<BUTTON>]\n    def buttons(value = false)\n      return find_elements :uiautomator, _button_visible_selectors unless value\n\n      find_elements :uiautomator, _button_contains_string(value)\n    end\n\n    # Find the first button.\n    # @return [BUTTON]\n    def first_button\n      find_element :uiautomator, _button_visible_selectors(button_index: 0, image_button_index: 0)\n    end\n\n    # Find the last button.\n    # @return [BUTTON]\n    def last_button\n      # uiautomator index doesn't support last\n      # and it's 0 indexed\n      button_index = tags(BUTTON).length\n      button_index -= 1 if button_index.positive?\n      image_button_index = tags(IMAGE_BUTTON).length\n      image_button_index -= 1 if image_button_index.positive?\n\n      find_element :uiautomator,\n                   _button_visible_selectors(button_index: button_index,\n                                             image_button_index: image_button_index)\n    end\n\n    # Find the first button that exactly matches value.\n    # @param value [String] the value to match exactly\n    # @return [BUTTON]\n    def button_exact(value)\n      find_element :uiautomator, _button_exact_string(value)\n    end\n\n    # Find all buttons that exactly match value.\n    # @param value [String] the value to match exactly\n    # @return [Array<BUTTON>]\n    def buttons_exact(value)\n      find_elements :uiautomator, _button_exact_string(value)\n    end\n\n    private\n\n    # @private\n    def raise_no_such_element_if_empty(elements)\n      raise _no_such_element if elements.empty?\n\n      elements.first\n    end\n\n    def _button_visible_selectors(opts = {})\n      button_index       = opts.fetch :button_index, false\n      image_button_index = opts.fetch :image_button_index, false\n\n      if button_index && image_button_index\n        \"new UiSelector().className(#{BUTTON}).instance(#{button_index});\" \\\n          \"new UiSelector().className(#{IMAGE_BUTTON}).instance(#{image_button_index});\"\n      else\n        \"new UiSelector().className(#{BUTTON});\" \\\n          \"new UiSelector().className(#{IMAGE_BUTTON});\"\n      end\n    end\n\n    def _button_exact_string(value)\n      button       = string_visible_exact BUTTON, value\n      image_button = string_visible_exact IMAGE_BUTTON, value\n      button + image_button\n    end\n\n    def _button_contains_string(value)\n      button       = string_visible_contains BUTTON, value\n      image_button = string_visible_contains IMAGE_BUTTON, value\n      button + image_button\n    end\n  end # module Android\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/android/element/generic.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Android\n    # Find the first element containing value\n    # @param value [String] the value to search for\n    # @return [Element]\n    def find(value)\n      complex_find_contains '*', value\n    end\n\n    # Find all elements containing value\n    # @param value [String] the value to search for\n    # @return [Array<Element>]\n    def finds(value)\n      complex_finds_contains '*', value\n    end\n\n    # Find the first element exactly matching value\n    # @param value [String] the value to search for\n    # @return [Element]\n    def find_exact(value)\n      complex_find_exact '*', value\n    end\n\n    # Find all elements exactly matching value\n    # @param value [String] the value to search for\n    # @return [Array<Element>]\n    def finds_exact(value)\n      complex_finds_exact '*', value\n    end\n\n    # @private\n    def scroll_uiselector(content, index = 0)\n      \"new UiScrollable(new UiSelector().scrollable(true).instance(#{index})).scrollIntoView(#{content}.instance(0));\"\n    end\n\n    # Scroll to the first element containing target text or description.\n    # @param text [String] the text or resourceId to search for in the text value and content description\n    # @param scrollable_index [Integer] the index for scrollable views.\n    # @return [Element] the element scrolled to\n    def scroll_to(text, scrollable_index = 0)\n      text = %(\"#{text}\")\n      rid  = resource_id(text, \"new UiSelector().resourceId(#{text})\")\n      args = rid.empty? ? [\"new UiSelector().textContains(#{text})\", \"new UiSelector().descriptionContains(#{text})\"] : [rid]\n      args.each_with_index do |arg, index|\n        elem = find_element :uiautomator, scroll_uiselector(arg, scrollable_index)\n        return elem\n      rescue StandardError => e\n        raise e if index == args.size - 1\n      end\n    end\n\n    # Scroll to the first element with the exact target text or description.\n    # @param text [String] the text or resourceId to search for in the text value and content description\n    # @param scrollable_index [Integer] the index for scrollable views.\n    # @return [Element] the element scrolled to\n    def scroll_to_exact(text, scrollable_index = 0)\n      text = %(\"#{text}\")\n      rid  = resource_id(text, \"new UiSelector().resourceId(#{text})\")\n      args = rid.empty? ? [\"new UiSelector().text(#{text})\", \"new UiSelector().description(#{text})\"] : [rid]\n      args.each_with_index do |arg, index|\n        elem = find_element :uiautomator, scroll_uiselector(arg, scrollable_index)\n        return elem\n      rescue StandardError => e\n        raise e if index == args.size - 1\n      end\n    end\n  end # module Android\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/android/element/text.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# TextView methods\nmodule Appium\n  module Android\n    TEXT_VIEW = 'android.widget.TextView'\n    TextView = TEXT_VIEW\n\n    # Find the first TextView that contains value or by index.\n    # @param value [String, Integer] the value to find.\n    # If int then the TextView at that index is returned.\n    # @return [TextView]\n    def text(value)\n      return ele_index TEXT_VIEW, value if value.is_a? Numeric\n\n      complex_find_contains TEXT_VIEW, value\n    end\n\n    # Find all TextViews containing value.\n    # If value is omitted, all texts are returned.\n    # @param value [String] the value to search for\n    # @return [Array<TEXT_VIEW>]\n    def texts(value = false)\n      return tags TEXT_VIEW unless value\n\n      complex_finds_contains TEXT_VIEW, value\n    end\n\n    # Find the first TextView.\n    # @return [TEXT_VIEW]\n    def first_text\n      first_ele TEXT_VIEW\n    end\n\n    # Find the last TextView.\n    # @return [TEXT_VIEW]\n    def last_text\n      last_ele TEXT_VIEW\n    end\n\n    # Find the first TextView that exactly matches value.\n    # @param value [String] the value to match exactly\n    # @return [TEXT_VIEW]\n    def text_exact(value)\n      complex_find_exact TEXT_VIEW, value\n    end\n\n    # Find all TextViews that exactly match value.\n    # @param value [String] the value to match exactly\n    # @return [Array<TEXT_VIEW>]\n    def texts_exact(value)\n      complex_finds_exact TEXT_VIEW, value\n    end\n  end # module Android\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/android/element/textfield.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Android\n    EDIT_TEXT = 'android.widget.EditText'\n    EditText = EDIT_TEXT\n\n    # Find the first EditText that contains value or by index.\n    # @param value [String, Integer] the text to match exactly.\n    # If int then the EditText at that index is returned.\n    # @return [EDIT_TEXT]\n    def textfield(value)\n      return ele_index EDIT_TEXT, value if value.is_a? Numeric\n\n      complex_find_contains EDIT_TEXT, value\n    end\n\n    # Find all EditTexts containing value.\n    # If value is omitted, all EditTexts are returned.\n    # @param value [String] the value to search for\n    # @return [Array<EDIT_TEXT>]\n    def textfields(value = false)\n      return tags EDIT_TEXT unless value\n\n      complex_finds_contains EDIT_TEXT, value\n    end\n\n    # Find the first EditText.\n    # @return [EDIT_TEXT]\n    def first_textfield\n      first_ele EDIT_TEXT\n    end\n\n    # Find the last EditText.\n    # @return [EDIT_TEXT]\n    def last_textfield\n      last_ele EDIT_TEXT\n    end\n\n    # Find the first EditText that exactly matches value.\n    # @param value [String] the value to match exactly\n    # @return [EDIT_TEXT]\n    def textfield_exact(value)\n      complex_find_exact EDIT_TEXT, value\n    end\n\n    # Find all EditTexts that exactly match value.\n    # @param value [String] the value to match exactly\n    # @return [Array<EDIT_TEXT>]\n    def textfields_exact(value)\n      complex_finds_exact EDIT_TEXT, value\n    end\n  end # module Android\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/android/espresso/bridge.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nrequire_relative '../android'\n\nmodule Appium\n  module Android\n    module Espresso\n      class Bridge\n        def self.for(target)\n          target.extend Appium::Android\n          target.extend Appium::Android::Command\n          target.extend Appium::Android::Espresso\n          target.extend Appium::Android::Espresso::Helper\n          target.extend Appium::Android::Espresso::Element\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/appium_lib/android/espresso/element/button.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Android\n    module Espresso\n      module Element\n        # Find the first button that contains value or by index.\n        # @param value [String, Integer] the value to exactly match.\n        # If int then the button at that index is returned.\n        # @return [Button]\n        def button(value)\n          # Don't use ele_index because that only works on one element type.\n          # Android needs to combine button and image button to match iOS.\n          if value.is_a? Numeric\n            index = value\n            raise ArgumentError, \"#{index} is not a valid index. Must be >= 1\" if index <= 0\n\n            # zero index\n            _button_visible_selectors_xpath(index: index - 1)\n          end\n\n          i = find_elements :xpath, _button_contains_string_xpath(BUTTON, value)\n          e = find_elements :xpath, _button_contains_string_xpath(IMAGE_BUTTON, value)\n\n          raise_no_such_element_if_empty(i + e)\n\n          (i + e)[0]\n        end\n\n        # Find all buttons containing value.\n        # If value is omitted, all buttons are returned.\n        # @param value [String] the value to search for\n        # @return [Array<Button>]\n        def buttons(value = false)\n          return _button_visible_selectors_xpath unless value\n\n          i = find_elements :xpath, _button_contains_string_xpath(BUTTON, value)\n          e = find_elements :xpath, _button_contains_string_xpath(IMAGE_BUTTON, value)\n          i + e\n        end\n\n        # Find the first button.\n        # @return [Button]\n        def first_button\n          _button_visible_selectors_xpath(button_index: 0, image_button_index: 0)\n        end\n\n        # Find the last button.\n        # @return [Button]\n        def last_button\n          # uiautomator index doesn't support last\n          # and it's 0 indexed\n          button_index = tags(::Appium::Android::BUTTON).length\n          button_index -= 1 if button_index.positive?\n          image_button_index = tags(::Appium::Android::IMAGE_BUTTON).length\n          image_button_index -= 1 if image_button_index.positive?\n\n          _button_visible_selectors_xpath(button_index: button_index,\n                                          image_button_index: image_button_index)\n        end\n\n        # Find the first button that exactly matches value.\n        # @param value [String] the value to match exactly\n        # @return [Button]\n        def button_exact(value)\n          i = find_elements :xpath, _button_exact_string_xpath(BUTTON, value)\n          e = find_elements :xpath, _button_exact_string_xpath(IMAGE_BUTTON, value)\n\n          raise_no_such_element_if_empty(i + e)\n\n          (i + e)[0]\n        end\n\n        # Find all buttons that exactly match value.\n        # @param value [String] the value to match exactly\n        # @return [Array<Button>]\n        def buttons_exact(value)\n          i = find_elements :xpath, _button_exact_string_xpath(BUTTON, value)\n          e = find_elements :xpath, _button_exact_string_xpath(IMAGE_BUTTON, value)\n          i + e\n        end\n\n        private\n\n        # @private\n        def raise_no_such_element_if_empty(elements)\n          raise _no_such_element if elements.empty?\n\n          elements.first\n        end\n\n        def _button_visible_selectors_xpath(opts = {})\n          button_index       = opts.fetch :button_index, false\n          image_button_index = opts.fetch :image_button_index, false\n\n          index = opts.fetch :index, false\n\n          b = find_elements :xpath, \"//#{BUTTON}\"\n          i = find_elements :xpath, \"//#{IMAGE_BUTTON}\"\n\n          if index\n            raise_no_such_element_if_empty(b + i)\n            (b + i)[index]\n          elsif button_index && image_button_index\n            raise_no_such_element_if_empty(b + i)\n            b_index = button_index + image_button_index\n            (b + i)[b_index]\n          else\n            b + i\n          end\n        end\n\n        def _button_exact_string_xpath(class_name, value)\n          r_id = resource_id(value, \" or @resource-id='#{value}'\")\n          \"//#{class_name}[@text='#{value}' or @content-desc='#{value}'#{r_id}]\"\n        end\n\n        def _button_contains_string_xpath(class_name, value)\n          r_id = resource_id(value, \" or @resource-id='#{value}'\")\n          \"//#{class_name}[contains(translate(@text,'#{value.upcase}', '#{value}'), '#{value}') \" \\\n            \"or contains(translate(@content-desc,'#{value.upcase}', '#{value}'), '#{value}')#{r_id}]\"\n        end\n      end # module Element\n    end # module Espresso\n  end # module Android\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/android/espresso/element/generic.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Android\n    module Espresso\n      module Element\n        # Scroll to the first element containing target text or description.\n        # Scroll happens upto 30 times in centre of device width.\n        # @param text [String] the text or resourceId to search for in the text value and content description\n        # @return [Element] the element scrolled to\n        def scroll_to(text)\n          err = nil\n          w_s = window_rect\n\n          (1..30).each do |_count|\n            action\n              .move_to_location(w_s.width / 2, (w_s.height * 2) / 5) # pointer based magic number\n              .pointer_down(:left)\n              .move_to_location(0, w_s.height / 5)\n              .release\n              .perform\n            sleep 1 # we must wait finish scrolling\n\n            return text(text)\n          rescue StandardError => e\n            err = e\n          end\n\n          raise err\n        end\n\n        # Scroll to the first element with the exact target text or description.\n        # Scroll happens upto 30 times in centre of device width.\n        # @param text [String] the text or resourceId to search for in the text value and content description\n        # @return [Element] the element scrolled to\n        def scroll_to_exact(text)\n          err = nil\n          w_s = window_rect\n\n          (1..30).each do |_count|\n            action\n              .move_to_location(w_s.width / 2, (w_s.height * 2) / 5) # pointer based magic number\n              .pointer_down(:left)\n              .move_to_location(0, w_s.height / 5)\n              .release\n              .perform\n            sleep 1 # we must wait finish scrolling\n\n            return text_exact(text)\n          rescue StandardError => e\n            err = e\n          end\n\n          raise err\n        end\n      end # module Element\n    end # module Espresso\n  end # module Android\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/android/espresso/element.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nrequire_relative 'element/generic'\nrequire_relative 'element/button'\n\nmodule Appium\n  module Android\n    module Espresso\n      module Element\n      end # module Element\n    end # module Espresso\n  end # module Android\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/android/espresso/helper.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Android\n    module Espresso\n      module Helper\n        # Find the first element that contains value\n        # @param class_name [String] the class name for the element\n        # @param value [String] the value to search for\n        # @return [Element]\n        def complex_find_contains(class_name, value)\n          find_element :xpath, string_visible_contains_xpath(class_name, value)\n        end\n\n        # Find all elements containing value\n        # @param class_name [String] the class name for the element\n        # @param value [String] the value to search for\n        # @return [Array<Element>]\n        def complex_finds_contains(class_name, value)\n          find_elements :xpath, string_visible_contains_xpath(class_name, value)\n        end\n\n        # Find the first element exactly matching value\n        # @param class_name [String] the class name for the element\n        # @param value [String] the value to search for\n        # @return [Element]\n        def complex_find_exact(class_name, value)\n          find_element :xpath, string_visible_exact_xpath(class_name, value)\n        end\n\n        # Find all elements exactly matching value\n        # @param class_name [String] the class name for the element\n        # @param value [String] the value to search for\n        # @return [Element]\n        def complex_finds_exact(class_name, value)\n          find_elements :xpath, string_visible_exact_xpath(class_name, value)\n        end\n      end # module Helper\n    end # module Espresso\n  end # module Android\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/android/espresso.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nrequire_relative 'espresso/helper'\nrequire_relative 'espresso/element'\nrequire_relative 'espresso/bridge'\n\nmodule Appium\n  module Android\n    module Espresso\n      # parent\n    end # module Espresso\n  end # module Android\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/android/uiautomator2/bridge.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nrequire_relative '../android'\n\nmodule Appium\n  module Android\n    module Uiautomator2\n      class Bridge\n        def self.for(target)\n          target.extend Appium::Android\n          target.extend Appium::Android::Command\n          target.extend Appium::Android::Uiautomator2\n          target.extend Appium::Android::Uiautomator2::Helper\n          target.extend Appium::Android::Uiautomator2::Element\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/appium_lib/android/uiautomator2/element/button.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Android\n    module Uiautomator2\n      module Element\n        # Find the first button that contains value or by index.\n        # @param value [String, Integer] the value to exactly match.\n        # If int then the button at that index is returned.\n        # @return [Button]\n        def button(value)\n          # Don't use ele_index because that only works on one element type.\n          # Android needs to combine button and image button to match iOS.\n          if value.is_a? Numeric\n            index = value\n            raise ArgumentError, \"#{index} is not a valid index. Must be >= 1\" if index <= 0\n\n            result = find_elements :uiautomator, _button_visible_selectors(index: index)\n            raise _no_such_element if result.empty?\n\n            return result[value - 1]\n          end\n\n          elements = find_elements :uiautomator, _button_contains_string(value)\n          raise_no_such_element_if_empty(elements)\n        end\n\n        # Find all buttons containing value.\n        # If value is omitted, all buttons are returned.\n        # @param value [String] the value to search for\n        # @return [Array<Button>]\n        def buttons(value = false)\n          return find_elements :uiautomator, _button_visible_selectors unless value\n\n          find_elements :uiautomator, _button_contains_string(value)\n        end\n\n        # Find the first button.\n        # @return [Button]\n        def first_button\n          elements = find_elements :uiautomator, _button_visible_selectors(button_index: 0, image_button_index: 0)\n          raise_no_such_element_if_empty(elements)\n        end\n\n        # Find the last button.\n        # @return [Button]\n        def last_button\n          # uiautomator index doesn't support last\n          # and it's 0 indexed\n          button_index = tags(::Appium::Android::Button).length\n          button_index -= 1 if button_index.positive?\n          image_button_index = tags(::Appium::Android::ImageButton).length\n          image_button_index -= 1 if image_button_index.positive?\n\n          elements = find_elements :uiautomator,\n                                   _button_visible_selectors(button_index: button_index,\n                                                             image_button_index: image_button_index)\n          raise_no_such_element_if_empty(elements)\n        end\n\n        # Find the first button that exactly matches value.\n        # @param value [String] the value to match exactly\n        # @return [Button]\n        def button_exact(value)\n          elements = find_elements :uiautomator, _button_exact_string(value)\n          raise_no_such_element_if_empty(elements)\n        end\n\n        # Find all buttons that exactly match value.\n        # @param value [String] the value to match exactly\n        # @return [Array<Button>]\n        def buttons_exact(value)\n          find_elements :uiautomator, _button_exact_string(value)\n        end\n\n        private\n\n        # @private\n        def raise_no_such_element_if_empty(elements)\n          raise _no_such_element if elements.empty?\n\n          elements.first\n        end\n\n        # @private\n        def _button_visible_selectors(opts = {})\n          button_index       = opts.fetch :button_index, false\n          image_button_index = opts.fetch :image_button_index, false\n\n          if button_index && image_button_index\n            \"new UiSelector().className(#{::Appium::Android::Button}).instance(#{button_index});\" \\\n              \"new UiSelector().className(#{::Appium::Android::ImageButton}).instance(#{image_button_index});\"\n          else\n            \"new UiSelector().className(#{::Appium::Android::Button});\" \\\n              \"new UiSelector().className(#{::Appium::Android::ImageButton});\"\n          end\n        end\n\n        # @private\n        def _button_exact_string(value)\n          button       = string_visible_exact ::Appium::Android::Button, value\n          image_button = string_visible_exact ::Appium::Android::ImageButton, value\n          button + image_button\n        end\n\n        # @private\n        def _button_contains_string(value)\n          button       = string_visible_contains ::Appium::Android::Button, value\n          image_button = string_visible_contains ::Appium::Android::ImageButton, value\n          button + image_button\n        end\n      end # module Element\n    end # module Uiautomator2\n  end # module Android\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/android/uiautomator2/element.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nrequire_relative 'element/button'\n\nmodule Appium\n  module Android\n    module Uiautomator2\n      module Element\n      end # module Element\n    end # module Uiautomator2\n  end # module Android\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/android/uiautomator2/helper.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Android\n    module Uiautomator2\n      module Helper\n        # Returns a string that matches the first element that contains value\n        # For automationName is Appium\n        # example: string_visible_contains 'UIATextField', 'sign in'\n        # note for XPath: https://github.com/appium/ruby_lib/pull/561\n        #\n        # @param class_name [String] the class name for the element\n        # @param value [String] the value to search for\n        # @return [String]\n        def string_visible_contains(class_name, value)\n          value = %(\"#{value}\")\n          if class_name == '*'\n            return (resource_id(value, \"new UiSelector().resourceId(#{value});\") +\n              \"new UiSelector().descriptionContains(#{value});\" \\\n              \"new UiSelector().textContains(#{value});\")\n          end\n\n          class_name = %(\"#{class_name}\")\n          resource_id(value, \"new UiSelector().className(#{class_name}).resourceId(#{value});\") +\n            \"new UiSelector().className(#{class_name}).descriptionContains(#{value});\" \\\n            \"new UiSelector().className(#{class_name}).textContains(#{value});\"\n        end\n\n        # Find the first element that contains value\n        # @param class_name [String] the class name for the element\n        # @param value [String] the value to search for\n        # @return [Element]\n        def complex_find_contains(class_name, value)\n          elements = find_elements :uiautomator, string_visible_contains(class_name, value)\n          raise _no_such_element if elements.empty?\n\n          elements.first\n        end\n\n        # Find all elements containing value\n        # @param class_name [String] the class name for the element\n        # @param value [String] the value to search for\n        # @return [Array<Element>]\n        def complex_finds_contains(class_name, value)\n          find_elements :uiautomator, string_visible_contains(class_name, value)\n        end\n\n        # @private\n        # Create an string to exactly match the first element with target value\n        # @param class_name [String] the class name for the element\n        # @param value [String] the value to search for\n        # @return [String]\n        def string_visible_exact(class_name, value)\n          value = %(\"#{value}\")\n\n          if class_name == '*'\n            return (resource_id(value, \"new UiSelector().resourceId(#{value});\") +\n              \"new UiSelector().description(#{value});\" \\\n              \"new UiSelector().text(#{value});\")\n          end\n\n          class_name = %(\"#{class_name}\")\n          resource_id(value, \"new UiSelector().className(#{class_name}).resourceId(#{value});\") +\n            \"new UiSelector().className(#{class_name}).description(#{value});\" \\\n            \"new UiSelector().className(#{class_name}).text(#{value});\"\n        end\n\n        # Find the first element exactly matching value\n        # @param class_name [String] the class name for the element\n        # @param value [String] the value to search for\n        # @return [Element]\n        def complex_find_exact(class_name, value)\n          elements = find_elements :uiautomator, string_visible_exact(class_name, value)\n          raise _no_such_element if elements.empty?\n\n          elements.first\n        end\n\n        # Find all elements exactly matching value\n        # @param class_name [String] the class name for the element\n        # @param value [String] the value to search for\n        # @return [Element]\n        def complex_finds_exact(class_name, value)\n          find_elements :uiautomator, string_visible_exact(class_name, value)\n        end\n      end # module Helper\n    end # module Uiautomator2\n  end # module Android\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/android/uiautomator2.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nrequire_relative 'uiautomator2/helper'\nrequire_relative 'uiautomator2/element'\nrequire_relative 'uiautomator2/bridge'\n\nmodule Appium\n  module Android\n    module Uiautomator2\n      # parent\n    end # module Uiautomator2\n  end # module Android\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/appium.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nrequire 'rubygems'\nrequire 'selenium-webdriver'\nrequire 'nokogiri'\n\nrequire 'appium_lib_core'\n\n# base\nrequire_relative 'driver'\nrequire_relative 'sauce_labs'\n\n# common\nrequire_relative 'common/wait'\nrequire_relative 'common/log'\nrequire_relative 'common/helper'\nrequire_relative 'common/http_client'\nrequire_relative 'common/device'\nrequire_relative 'common/command'\n\n# ios\nrequire_relative 'ios/ios'\n\n# android\nrequire_relative 'android/android'\n\nmodule Appium\n  class << self\n    # Load arbitrary text ([toml format](https://github.com/toml-lang/toml))\n    # The toml is parsed by https://github.com/fbernier/tomlrb .\n    #\n    # ```\n    # [caps]\n    # app = \"path/to/app\"\n    #\n    # [appium_lib]\n    # port = 8080\n    # ```\n    #\n    # :app is expanded\n    # :require is expanded\n    # all keys are converted to symbols\n    #\n    # @param opts [Hash] file: '/path/to/appium.txt', verbose: true\n    # @return [hash] the symbolized hash with updated :app and :require keys\n    def load_settings(opts = {})\n      raise ArgumentError, 'opts must be a hash' unless opts.is_a? Hash\n      raise ArgumentError, 'opts must not be empty' if opts.empty?\n\n      toml = opts[:file]\n      raise ArgumentError, 'Must pass a capability file which has [caps] and [appium_lib]' unless toml\n\n      verbose = opts.fetch :verbose, false\n\n      Appium::Logger.info \"appium settings path: #{toml}\" if verbose\n\n      toml_exists = File.exist? toml\n      Appium::Logger.info \"Exists? #{toml_exists}\" if verbose\n\n      raise ArgumentError, \"toml doesn't exist #{toml}\" unless toml_exists\n\n      require 'tomlrb'\n      Appium::Logger.info \"Loading #{toml}\" if verbose\n\n      data = Tomlrb.load_file(toml, symbolize_keys: true)\n\n      Appium::Logger.info data if verbose && !data.empty?\n\n      # FIXME: Deprecated. Will remove when we remove 'Appium::Driver.absolute_app_path'\n      if data\n        if data['caps']\n          if data['caps'][:app] && !data['caps'][:app].empty?\n            data['caps'][:app] = Appium::Driver.absolute_app_path data\n          elsif data['caps']['app'] && !data['caps']['app'].empty?\n            data['caps']['app'] = Appium::Driver.absolute_app_path data\n          end\n        elsif data[:caps]\n          if data[:caps][:app] && !data[:caps][:app].empty?\n            data[:caps][:app] = Appium::Driver.absolute_app_path data\n          elsif data[:caps]['app'] && !data[:caps]['app'].empty?\n            data[:caps]['app'] = Appium::Driver.absolute_app_path data\n          end\n        end\n      end\n\n      if data && data[:appium_lib] && data[:appium_lib][:require]\n        parent_dir = File.dirname toml\n        data[:appium_lib][:require] = expand_required_files(parent_dir, data[:appium_lib][:require])\n      end\n\n      data\n    end\n    # @see load_settings\n    alias load_appium_txt load_settings\n\n    # @param [String] base_dir parent directory of loaded appium.txt (toml)\n    # @param [String] file_paths\n    # @return [Array] list of require files as an array, nil if require doesn't exist\n    def expand_required_files(base_dir, file_paths)\n      # ensure files are absolute\n      Array(file_paths).map! do |f|\n        file = File.exist?(f) ? f : File.join(base_dir, f)\n        file = File.expand_path file\n\n        File.exist?(file) ? file : nil\n      end\n      file_paths.compact! # remove nils\n\n      files = []\n\n      # now expand dirs\n      file_paths.each do |item|\n        unless File.directory? item\n          # save file\n          files << item\n          next # only look inside folders\n        end\n        Dir.glob(File.expand_path(File.join(item, '**', '*.rb'))) do |f|\n          # do not add folders to the file list\n          files << File.expand_path(f) unless File.directory? f\n        end\n      end\n\n      files\n    end\n\n    # This method is intended to work with page objects that share\n    # a common module. For example, Page::HomePage, Page::SignIn\n    # those could be promoted on with Appium.promote_singleton_appium_methods Page\n    #\n    # If you are promoting on an individual class then you should use\n    # Appium.promote_appium_methods instead. The singleton method is intended\n    # only for the shared module use case.\n    #\n    # if modules is a module instead of an array, then the constants of\n    # that module are promoted on.\n    # otherwise, the array of modules will be used as the promotion target.\n    #\n    # @param [Array<Module>] modules An array of modules\n    # @param [Driver] driver A driver to extend for\n    def promote_singleton_appium_methods(modules, driver = $driver)\n      raise ArgumentError, 'Global $driver is nil' if driver.nil?\n\n      target_modules = []\n\n      if modules.is_a? Module\n        modules.constants.each do |sub_module|\n          target_modules << modules.const_get(sub_module)\n        end\n      else\n        raise ArgumentError, 'modules must be a module or an array' unless modules.is_a? Array\n\n        target_modules = modules\n      end\n\n      target_modules.each do |const|\n        # noinspection RubyResolve\n        driver.public_methods(false).each do |m|\n          # override unless there's an existing method with matching arity\n          next if const.respond_to?(m) && const.method(m).arity == driver.method(m).arity\n\n          const.send(:define_singleton_method, m) do |*args, &block|\n            super(*args, &block) # promote.rb\n          rescue NoMethodError, ArgumentError\n            driver.send m, *args, &block if driver.respond_to?(m)\n          end\n        end\n      end\n    end\n\n    ##\n    # Promote appium methods to class instance methods\n    #\n    # @param [Array<Class>] class_array An array of classes\n    # @param [Driver] driver A driver to extend for\n    #\n    # To promote methods to all classes:\n    #\n    # @example\n    #\n    #   Appium.promote_appium_methods Object\n    #\n    # It's better to promote on specific classes instead of Object\n    #\n    # @example\n    #\n    #   # promote on rspec\n    #   Appium.promote_appium_methods RSpec::Core::ExampleGroup\n    #\n    # @example\n    #\n    #   # promote on minispec\n    #   Appium.promote_appium_methods Minitest::Spec\n    #\n    def promote_appium_methods(class_array, driver = $driver)\n      raise ArgumentError, 'Driver is nil' if driver.nil?\n\n      # Wrap single class into an array\n      class_array = [class_array] unless class_array.instance_of? Array\n      # Promote Appium driver methods to class instance methods.\n      class_array.each do |klass|\n        driver.public_methods(false).each do |method|\n          klass.class_eval do\n            # NOTE: Do not skip re-definding methods to not keep old instance information.\n            # Probably the global driver ($driver) stuff needs to override (re-defined)\n            # every time to not keep unexpected state.\n            # https://github.com/appium/ruby_lib/issues/917\n\n            # Remove the method before adding it.\n            remove_method method if method_defined? method\n\n            define_method method do |*args, &block|\n              # Prefer existing method.\n              # super will invoke method missing on driver\n              super(*args, &block)\n\n              # minitest also defines a name method,\n              # so rescue argument error\n              # and call the name method on $driver\n            rescue NoMethodError, ArgumentError\n              if args.size == 1 && args.first.is_a?(Hash)\n                # To prevent warnings by keyword arguments (for Ruby 2.7 and 3)\n                driver.send method, **args.first, &block if driver.respond_to?(method)\n              else\n                ::Appium::Logger.warn \"Should fix this '#{args}' for Ruby 2.7 (and 3)\" if args.first.is_a?(Hash)\n\n                driver.send method, *args, &block if driver.respond_to?(method)\n              end\n            end\n          end\n        end\n      end\n      nil # return nil\n    end\n  end # class << self\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/common/command.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Common\n    module Command\n      # parent\n    end\n  end\nend\n"
  },
  {
    "path": "lib/appium_lib/common/device.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Device\n    extend Forwardable\n  end # module Device\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/common/helper.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# Generic helper methods not specific to a particular tag name\nmodule Appium\n  module Common\n    # iOS .name returns the accessibility attribute if it's set. if not set, the string value is used.\n    # Android .name returns the accessibility attribute and nothing if it's not set.\n    #\n    # .text should be cross platform so prefer that over name, unless both\n    # Android and iOS have proper accessibility attributes.\n    # .text and .value should be the same so use .text over .value.\n    #\n    # secure class_name is iOS only because it can't be implemented using uiautomator for Android.\n    #\n    # find_element :text doesn't work so use XPath to find by text.\n\n    # Return yield and ignore any exceptions.\n    def ignore\n      yield\n    rescue Exception # rubocop:disable Lint/RescueException\n      # Ignored\n    end\n\n    # Navigate back.\n    # @return [void]\n    def back\n      @driver.navigate.back\n    end\n\n    # For Sauce Labs reporting. Returns the current session id.\n    # @return [String]\n    #\n    # @example\n    #\n    #   @driver.session_id #=> \"some-session-ids\"\n    #\n    def session_id\n      @driver.session_id\n    end\n\n    # Returns the first element that matches the provided xpath.\n    #\n    # @param xpath_str [String] the XPath string\n    # @return [Element]\n    def xpath(xpath_str)\n      @driver.find_element :xpath, xpath_str\n    end\n\n    # Returns all elements that match the provided xpath.\n    #\n    # @param xpath_str [String] the XPath string\n    # @return [Array<Element>]\n    def xpaths(xpath_str)\n      @driver.find_elements :xpath, xpath_str\n    end\n\n    # json and ap are required for the source method.\n    require 'json'\n\n    # @private\n    # http://nokogiri.org/Nokogiri/XML/SAX.html\n    class CountElements < Nokogiri::XML::SAX::Document\n      attr_reader :result\n\n      def initialize(platform) # rubocop:disable Lint/MissingSuper\n        reset\n        @platform = platform\n      end\n\n      def reset\n        @result = Hash.new 0\n      end\n\n      # http://nokogiri.org/Nokogiri/XML/SAX/Document.html\n      def start_element(name, attrs = [])\n        element_visible = case @platform.to_sym\n                          when :android\n                            true\n                          else # :ios, :windows\n                            Hash[attrs]['visible'] == 'true'\n                          end\n\n        @result[name] += 1 if element_visible\n      end\n\n      def formatted_result\n        @result\n          .sort_by { |_element, count| count }\n          .reverse\n          .reduce('') { |acc, element| \"#{acc}#{element[1]}x #{element[0]}\\n\" }\n          .strip\n      end\n    end # class CountElements\n\n    # Returns a string of class counts of visible elements.\n    # @return [String]\n    #\n    # @example\n    #\n    #   get_page_class #=> \"24x XCUIElementTypeStaticText\\n12x XCUIElementTypeCell\\n8x XCUIElementTypeOther\\n\n    #                  #    2x XCUIElementTypeWindow\\n1x XCUIElementTypeStatusBar\\n1x XCUIElementTypeTable\\n1\n    #                  #    x XCUIElementTypeNavigationBar\\n1x XCUIElementTypeApplication\"\n    #\n    def get_page_class\n      parser = @count_elements_parser ||= Nokogiri::XML::SAX::Parser.new(CountElements.new(@core.device))\n\n      parser.document.reset\n      parser.parse get_source\n\n      parser.document.formatted_result\n    end\n\n    # Count all classes on screen and print to stdout.\n    # Useful for appium_console.\n    # @return [nil]\n    #\n    # @example\n    #\n    #   page_class\n    #     # 24x XCUIElementTypeStaticText\n    #     # 12x XCUIElementTypeCell\n    #     # 8x XCUIElementTypeOther\n    #     # 2x XCUIElementTypeWindow\n    #     # 1x XCUIElementTypeStatusBar\n    #     # 1x XCUIElementTypeTable\n    #     # 1x XCUIElementTypeNavigationBar\n    #     # 1x XCUIElementTypeApplication\n    #\n    def page_class\n      puts get_page_class\n      nil\n    end\n\n    # Prints xml of the current page\n    # @return [void]\n    def source\n      _print_source get_source\n    end\n\n    # Returns XML string for the current page\n    # Same as driver.page_source\n    # @return [String]\n    def get_source\n      @driver.page_source\n    end\n\n    # Converts pixel values to window relative values\n    #\n    # @example\n    #\n    #   px_to_window_rel x: 50, y: 150 #=> #<OpenStruct x=\"50.0 / 375.0\", y=\"150.0 / 667.0\">\n    #\n    def px_to_window_rel(opts = {}, driver = $driver)\n      w = driver.window_size\n      x = opts.fetch :x, 0\n      y = opts.fetch :y, 0\n\n      OpenStruct.new(x: \"#{x.to_f} / #{w.width.to_f}\",\n                     y: \"#{y.to_f} / #{w.height.to_f}\")\n    end\n\n    # @private\n    def lazy_load_strings\n      # app strings only works on local apps.\n      # on disk apps (ex: com.android.settings) will error\n      @lazy_load_strings ||= ignore { app_strings } || {}\n    end\n\n    # Search strings.xml's values for target.\n    # @param target [String] the target to search for in strings.xml values\n    # @return [Array]\n    def xml_keys(target)\n      lazy_load_strings\n      @lazy_load_strings.select { |key, _value| key.downcase.include? target.downcase }\n    end\n\n    # Search strings.xml's keys for target.\n    # @param target [String] the target to search for in strings.xml keys\n    # @return [Array]\n    def xml_values(target)\n      lazy_load_strings\n      @lazy_load_strings.select { |_key, value| value.downcase.include? target.downcase }\n    end\n\n    # Resolve id in strings.xml and return the value.\n    # @param id [String] the id to resolve\n    # @return [String]\n    def resolve_id(id)\n      lazy_load_strings\n      @lazy_load_strings[id]\n    end\n\n    # @private\n    class HTMLElements < Nokogiri::XML::SAX::Document\n      attr_reader :filter\n\n      # convert to string to support symbols\n      def filter=(value)\n        # nil and false disable the filter\n        return @filter = false unless value # rubocop:disable Lint/ReturnInVoidContext\n\n        @filter = value.to_s.downcase\n      end\n\n      def initialize # rubocop:disable Lint/MissingSuper\n        reset\n        @filter = false\n      end\n\n      def reset\n        @element_stack     = []\n        @elements_in_order = []\n        @skip_element      = false\n      end\n\n      def result\n        @elements_in_order.reduce('') do |r, e|\n          name = e.delete :name\n          attr_string = e.reduce('') do |string, attr|\n            attr1 = attr[1] ? attr[1].strip : attr[1]\n            \"#{string}  #{attr[0]}: #{attr1}\\n\"\n          end\n\n          return r if attr_string.nil? || attr_string.empty?\n\n          \"#{r}\\n#{name}\\n#{attr_string}\"\n        end\n      end\n\n      def start_element(name, attrs = [])\n        @skip_element = filter && !filter.include?(name.downcase)\n        return if @skip_element\n\n        element = { name: name }\n        attrs.each { |a| element[a[0]] = a[1] }\n        @element_stack.push element\n        @elements_in_order.push element\n      end\n\n      def end_element(name)\n        return if filter && !filter.include?(name.downcase)\n\n        element_index = @element_stack.rindex { |e| e[:name] == name }\n        @element_stack.delete_at element_index\n      end\n\n      def characters(chars)\n        return if @skip_element\n\n        element        = @element_stack.last\n        element[:text] = chars\n      end\n    end\n\n    # @private\n    def _no_such_element\n      error_message = 'An element could not be located on the page using the given search parameters.'\n      raise Selenium::WebDriver::Error::NoSuchElementError, error_message\n    end\n\n    # @private\n    def _print_source(source)\n      opts = Nokogiri::XML::ParseOptions::NOBLANKS | Nokogiri::XML::ParseOptions::NONET\n      doc = if source.start_with? '<html'\n              Nokogiri::HTML(source) { |cfg| cfg.options = opts }\n            else\n              Nokogiri::XML(source)  { |cfg| cfg.options = opts }\n            end\n      puts doc.to_xml indent: 2\n    end\n  end\nend\n"
  },
  {
    "path": "lib/appium_lib/common/http_client.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nrequire 'appium_lib_core'\nrequire_relative '../version'\n\nmodule Appium\n  module Http\n    class Default < ::Appium::Core::Base::Http::Default\n      # Default HTTP client inherit Appium::Core::Base::Http::Default, but has different DEFAULT_HEADERS\n      DEFAULT_HEADERS = { 'Accept' => CONTENT_TYPE, 'User-Agent' => \"appium/ruby_lib/#{::Appium::VERSION}\" }.freeze\n    end\n  end\nend\n"
  },
  {
    "path": "lib/appium_lib/common/log.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Common\n    # @param [String|Hash] type You can get particular type's logs.\n    # @return [[Selenium::WebDriver::LogEntry]] A list of logs data.\n    #\n    # @example\n    #\n    #   @driver.get_log(\"syslog\") #=> [[Selenium::WebDriver::LogEntry]]\n    #   @driver.get_log(:syslog)  #=> [[Selenium::WebDriver::LogEntry]]\n    #\n    def get_log(type)\n      @driver.logs.get type\n    end\n\n    # Get a list of available log types\n    #\n    # @return [[String]] A list of available log types.\n    #\n    # @example\n    #\n    #   @driver.get_available_log_types #=> [:syslog, :crashlog, :performance]\n    #\n    def get_available_log_types\n      @driver.logs.available_types\n    end\n  end # module Common\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/common/wait.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nrequire 'appium_lib_core'\n\nmodule Appium\n  module Common\n    class Wait\n      include ::Appium::Core::Waitable\n    end\n\n    # Check every interval seconds to see if yield returns a truthy value.\n    # Note this isn't a strict boolean true, any truthy value is accepted.\n    # false and nil are considered failures.\n    # Give up after timeout seconds.\n    #\n    # Wait code from the selenium Ruby gem\n    # https://github.com/SeleniumHQ/selenium/blob/cf501dda3f0ed12233de51ce8170c0e8090f0c20/rb/lib/selenium/webdriver/common/wait.rb\n    #\n    # If only a number is provided then it's treated as the timeout value.\n    #\n    # @param [Hash|Numeric] opts Options. If the value is _Numeric_, the value is set as `{ timeout: value }`\n    # @option opts [Numeric] :timeout Seconds to wait before timing out. Set default by `appium_wait_timeout` (30).\n    # @option opts [Numeric] :interval Seconds to sleep between polls. Set default by `appium_wait_interval` (0.5).\n    # @option opts [String] :message Exception message if timed out.\n    # @option opts [Array, Exception] :ignore Exceptions to ignore while polling (default: Exception)\n    #\n    # @example\n    #\n    #     wait_true(timeout: 20, interval: 0.2, message: 'custom message') { button_exact('Back') }.click\n    #     wait_true(20) { button_exact('Back') }.click\n    #\n    def wait_true(opts = {})\n      opts = { timeout: opts } if opts.is_a? Numeric\n\n      if opts.is_a? Hash\n        opts.empty? ? @core.wait_true { yield } : @core.wait_true(**opts) { yield }\n      else\n        ::Appium::Logger.warn('Arguments should be Hash like {timeout: 100}')\n      end\n    end\n\n    # Check every interval seconds to see if yield doesn't raise an exception.\n    # Give up after timeout seconds.\n    #\n    # Wait code from the selenium Ruby gem\n    # https://github.com/SeleniumHQ/selenium/blob/cf501dda3f0ed12233de51ce8170c0e8090f0c20/rb/lib/selenium/webdriver/common/wait.rb\n    #\n    # If only a number is provided then it's treated as the timeout value.\n    #\n    # @param [Hash|Numeric] opts Options. If the value is _Numeric_, the value is set as `{ timeout: value }`\n    # @option opts [Numeric] :timeout Seconds to wait before timing out. Set default by `appium_wait_timeout` (30).\n    # @option opts [Numeric] :interval Seconds to sleep between polls. Set default by `appium_wait_interval` (0.5).\n    # @option opts [String] :message Exception message if timed out.\n    # @option opts [Array, Exception] :ignore Exceptions to ignore while polling (default: Exception)\n    #\n    # @example\n    #\n    #     wait(timeout: 20, interval: 0.2, message: 'custom message') { button_exact('Back') }.click\n    #     wait(20) { button_exact('Back') }.click\n    #\n    def wait(opts = {})\n      opts = { timeout: opts } if opts.is_a? Numeric\n      if opts.is_a? Hash\n        opts.empty? ? @core.wait { yield } : @core.wait(**opts) { yield }\n      else\n        ::Appium::Logger.warn('Arguments should be Hash like {timeout: 100}')\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/appium_lib/driver.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# Load only Minitest is loaded\nif defined?(Minitest::VERSION)\n  # Fix uninitialized constant Minitest (NameError)\n  module Minitest\n    # Fix superclass mismatch for class Spec\n    class Runnable\n    end\n\n    begin\n      class Test < Runnable\n      end\n    rescue TypeError => te\n      # http://docs.seattlerb.org/minitest/History_rdoc.html#label-5.11.0+-2F+2018-01-01\n      # for 5.11.0/5.11.1\n      # `Minitest::Test` became a subclass of `Minitest::Result`\n      raise TypeError, te.message unless te.message == 'superclass mismatch for class Test'\n\n      class Test < Result\n      end\n    end\n  end\nend\n\nrequire 'appium_lib_core'\nrequire 'uri'\n\nmodule Appium\n  class Driver\n    extend Forwardable\n\n    # Methods forwarded to the underlying Appium::Core::Base::Driver instance\n    # (exposed via `#driver`). Previously these were wired up implicitly by\n    # `extend ::Appium::Core::Device` through a static compatibility list in\n    # `ruby_lib_core` (see appium/ruby_lib_core#97). Defining them here lets\n    # `ruby_lib_core` eventually drop that list.\n    CORE_BRIDGE_METHODS = %i[\n      take_element_screenshot save_viewport_screenshot\n      lock device_locked? unlock\n      hide_keyboard is_keyboard_shown\n      ime_activate ime_available_engines ime_active_engine ime_activated ime_deactivate\n      get_settings update_settings\n      within_context current_context available_contexts set_context\n      push_file pull_file pull_folder\n      keyevent press_keycode long_press_keycode\n      match_images_features find_image_occurrence get_images_similarity compare_images\n      app_strings background_app\n      install_app remove_app app_installed? activate_app terminate_app\n      app_state\n      stop_recording_screen stop_and_save_recording_screen\n      shake device_time\n      execute_cdp\n    ].freeze\n\n    def_delegators :driver, *CORE_BRIDGE_METHODS\n\n    # @private\n    class << self\n      def convert_to_symbol(value)\n        if value.nil?\n          value\n        else\n          value.to_sym\n        end\n      end\n\n      # @private\n      def get_cap(caps, name)\n        name_with_prefix = \"#{::Appium::Core::Base::Bridge::APPIUM_PREFIX}#{name}\"\n        caps[convert_to_symbol name] ||\n          caps[name] ||\n          caps[convert_to_symbol name_with_prefix] ||\n          caps[name_with_prefix]\n      end\n    end\n\n    # attr readers are promoted to global scope. To avoid clobbering, they're\n    # made available via the driver_attributes method\n    #\n    # attr_accessor is repeated for each one so YARD documents them properly.\n\n    # The amount to sleep in seconds before every webdriver http call.\n    attr_accessor :global_webdriver_http_sleep\n\n    # SauceLab's settings\n    attr_reader :sauce\n    # Username for use on Sauce Labs. Set `false` to disable Sauce, even when SAUCE_USERNAME is in ENV.\n    # same as @sauce.username\n    attr_reader :sauce_username\n    # Access Key for use on Sauce Labs. Set `false` to disable Sauce, even when SAUCE_ACCESS_KEY is in ENV.\n    # same as @sauce.access_key\n    attr_reader :sauce_access_key\n    # Override the Sauce Appium endpoint to allow e.g. TestObject tests\n    # same as @sauce.endpoint\n    attr_reader :sauce_endpoint\n\n    # from Core\n    # read http://www.rubydoc.info/github/appium/ruby_lib_core/Appium/Core/Driver\n    attr_reader :caps\n    attr_reader :custom_url\n    attr_reader :default_wait\n    attr_reader :appium_port\n    attr_reader :appium_device\n    attr_reader :automation_name\n    attr_reader :listener\n    attr_reader :http_client\n    attr_reader :appium_wait_timeout\n    attr_reader :appium_wait_interval\n\n    # Appium's server version\n    attr_reader :appium_server_status\n    # Boolean debug mode for the Appium Ruby bindings\n    attr_reader :appium_debug\n    # Returns the driver\n    # @return [Driver] the driver\n    attr_reader :driver\n    # Instance of Appium::Core::Driver\n    attr_reader :core\n\n    # Creates a new driver. The driver is defined as global scope by default.\n    # We can avoid defining global driver.\n    #\n    # @example\n    #\n    #   require 'rubygems'\n    #   require 'appium_lib'\n    #\n    #   # platformName takes a string or a symbol.\n    #   # Start iOS driver with global scope\n    #   opts = {\n    #            caps: {\n    #              platformName: :ios,\n    #              app: '/path/to/MyiOS.app'\n    #            },\n    #            appium_lib: {\n    #              server_url: 'http://127.0.0.1:4723'\n    #              wait_timeout: 30\n    #            }\n    #          }\n    #   appium_driver = Appium::Driver.new(opts, true)\n    #   appium_driver.start_driver\n    #\n    #   # Start Android driver with global scope\n    #   opts = {\n    #            caps: {\n    #              platformName: :android,\n    #              app: '/path/to/my.apk'\n    #            },\n    #            appium_lib: {\n    #              wait_timeout: 30,\n    #              wait_interval: 1\n    #            }\n    #          }\n    #   appium_driver = Appium::Driver.new(opts, true)\n    #   appium_driver.start_driver\n    #\n    #   # Start iOS driver without global scope\n    #   opts = {\n    #            caps: {\n    #              platformName: :ios,\n    #              app: '/path/to/MyiOS.app'\n    #            },\n    #            appium_lib: {\n    #              wait_timeout: 30\n    #            }\n    #          }\n    #   appium_driver = Appium::Driver.new(opts, false)\n    #   appium_driver.start_driver\n    #\n    #   # Start iOS driver without global scope\n    #   opts = {\n    #            caps: {\n    #              platformName: :ios,\n    #              app: '/path/to/MyiOS.app'\n    #            },\n    #            appium_lib: {\n    #              wait_timeout: 30\n    #            },\n    #            global_driver: false\n    #          }\n    #   appium_driver = Appium::Driver.new(opts)\n    #   appium_driver.start_driver\n    #\n    # @param opts [Object] A hash containing various options.\n    # @param global_driver [Bool] A bool require global driver before initialize.\n    # @return [Driver]\n    def initialize(opts = {}, global_driver = false)\n      # Capybara can't put `global_driver` as the 2nd argument.\n      global_driver = opts.delete :global_driver if global_driver.nil?\n\n      $driver&.driver_quit if global_driver\n\n      raise ArgumentError, 'opts must be a hash' unless opts.is_a? Hash\n\n      @core = ::Appium::Core.for(opts)\n      extend ::Appium::Core::Device\n\n      opts = Appium.symbolize_keys opts\n      appium_lib_opts = opts[:appium_lib] || {}\n\n      @caps = @core.caps\n      @custom_url = @core.custom_url\n      @default_wait = @core.default_wait || 0\n      @appium_port = @core.port\n      @appium_wait_timeout = @core.wait_timeout\n      @appium_wait_interval = @core.wait_interval\n      @listener = @core.listener\n      @appium_device = @core.device\n      @automation_name = @core.automation_name\n\n      # Arrange the app capability. This must be after @core = ::Appium::Core.for(opts)\n      set_app_path(opts)\n\n      # enable debug patch\n      @appium_debug = appium_lib_opts.fetch :debug, !!defined?(Pry) # rubocop:disable Style/DoubleNegation\n      set_sauce_related_values(appium_lib_opts)\n\n      # Extend Common methods\n      extend Appium::Common\n      extend Appium::Device\n\n      # Extend each driver's methods\n      extend_for(device: @core.device, automation_name: @core.automation_name)\n\n      # for command\n\n      if @appium_debug\n        Appium::Logger.debug opts unless opts.empty?\n        Appium::Logger.debug \"Debug is: #{@appium_debug}\"\n        Appium::Logger.debug \"Device is: #{@core.device}\"\n      end\n\n      # Save global reference to last created Appium driver for top level methods.\n      $driver = self if global_driver\n\n      self # rubocop:disable Lint/Void # return newly created driver\n    end\n\n    private\n\n    # @private\n    def extend_for(device:, automation_name:)\n      case device\n      when :android\n        case automation_name\n        when :uiautomator2\n          ::Appium::Android::Uiautomator2::Bridge.for(self)\n        when :espresso\n          ::Appium::Android::Espresso::Bridge.for(self)\n        else # default and UiAutomator\n          ::Appium::Android::Bridge.for(self)\n        end\n      when :ios, :tvos\n        # default and XCUITest\n        ::Appium::Ios::Xcuitest::Bridge.for(self)\n      when :mac\n        # no Mac specific extentions\n        Appium::Logger.debug('mac')\n      when :windows\n        # no windows specific extentions\n        Appium::Logger.debug('windows')\n      when :tizen\n        # https://github.com/Samsung/appium-tizen-driver\n        Appium::Logger.debug('tizen')\n      when :youiengine\n        # https://github.com/YOU-i-Labs/appium-youiengine-driver\n        Appium::Logger.debug('YouiEngine')\n      else\n        case automation_name\n        when :youiengine\n          # https://github.com/YOU-i-Labs/appium-youiengine-driver\n          Appium::Logger.debug('YouiEngine')\n        else\n          Appium::Logger.debug('no device matched') # core also shows warning message\n        end\n      end\n    end\n\n    # @private\n    # Deprecated. TODO: remove\n    def set_app_path(opts)\n      return unless @core.caps\n\n      # return the path exists on the local\n      app_path = Driver.get_cap(@core.caps, 'app')\n      return if app_path.nil?\n      return if File.exist?(app_path)\n\n      @core.caps['app'] = self.class.absolute_app_path opts\n    end\n\n    # @private\n    def set_sauce_related_values(appium_lib_opts)\n      @sauce = Appium::SauceLabs.new(appium_lib_opts)\n      @sauce_username   = @sauce.username\n      @sauce_access_key = @sauce.access_key\n      @sauce_endpoint   = @sauce.endpoint\n    end\n\n    public\n\n    # Returns a hash of the driver attributes\n    def driver_attributes\n      {\n        caps:                @core.caps,\n        automation_name:     @core.automation_name,\n        custom_url:          @core.custom_url,\n        default_wait:        @default_wait,\n        sauce_username:      @sauce.username,\n        sauce_access_key:    @sauce.access_key,\n        sauce_endpoint:      @sauce.endpoint,\n        port:                @core.port,\n        device:              @core.device,\n        debug:               @appium_debug,\n        listener:            @listener,\n        wait_timeout:        @core.wait_timeout,\n        wait_interval:       @core.wait_interval\n      }\n    end\n\n    def device_is_android?\n      @core.device == :android\n    end\n\n    def device_is_ios?\n      @core.device == :ios\n    end\n\n    def device_is_windows?\n      @core.device == :windows\n    end\n\n    # Return true if automationName is 'uiautomator2'\n    # @return [Boolean]\n    def automation_name_is_uiautomator2?\n      !@core.automation_name.nil? && @core.automation_name == :uiautomator2\n    end\n\n    # Return true if automationName is 'Espresso'\n    # @return [Boolean]\n    def automation_name_is_espresso?\n      !@core.automation_name.nil? && @core.automation_name == :espresso\n    end\n\n    # Return true if automationName is 'XCUITest'\n    # @return [Boolean]\n    def automation_name_is_xcuitest?\n      !@core.automation_name.nil? && @core.automation_name == :xcuitest\n    end\n\n    # An entry point to chain W3C actions\n    # Read https://www.rubydoc.info/github/appium/ruby_lib_core/Appium/Core/Base/Bridge/W3C#action-instance_method\n    #\n    # @return [Selenium::WebDriver::PointerActions]\n    #\n    # @example\n    #\n    #     element = find_element(:id, \"some id\")\n    #     action.click(element).perform # The `click` is a part of `PointerActions`\n    #\n    def action\n      @driver&.action\n    end\n\n    # Returns the server's version info\n    #\n    # @example\n    #   {\n    #     \"build\" => {\n    #         \"version\" => \"0.18.1\",\n    #         \"revision\" => \"d242ebcfd92046a974347ccc3a28f0e898595198\"\n    #     }\n    #   }\n    #\n    # @return [Hash]\n    def appium_server_version\n      @core.appium_server_version\n    rescue Selenium::WebDriver::Error::WebDriverError => ex\n      raise ::Appium::Core::Error::ServerError unless ex.message.include?('content-type=\"\"')\n\n      # server (TestObject for instance) does not respond to status call\n      {}\n    end\n    alias remote_status appium_server_version\n\n    # Return the platform version as an array of integers\n    # @return [Array<Integer>]\n    def platform_version\n      return [] if @driver.nil?\n\n      p_version = @driver.capabilities['platformVersion']\n      p_version.split('.').map(&:to_i)\n    end\n\n    # Returns the client's version info\n    #\n    # @example\n    #\n    #   {\n    #       \"version\" => \"9.1.1\"\n    #   }\n    #\n    # @return [Hash]\n    def appium_client_version\n      { version: ::Appium::VERSION }\n    end\n\n    # [Deprecated] Converts app_path to an absolute path.\n    #\n    # opts is the full options hash (caps and appium_lib). If server_url is set\n    # then the app path is used as is.\n    #\n    # if app isn't set then an error is raised.\n    #\n    # @return [String] APP_PATH as an absolute path\n    def self.absolute_app_path(opts)\n      raise ArgumentError, 'opts must be a hash' unless opts.is_a? Hash\n\n      caps = opts[:caps] || opts['caps'] || {}\n      app_path = get_cap(caps, 'app')\n      raise ArgumentError, 'absolute_app_path invoked and app is not set!' if app_path.nil? || app_path.empty?\n      # Sauce storage API. http://saucelabs.com/docs/rest#storage\n      return app_path if app_path.start_with? 'sauce-storage:'\n      return app_path if app_path =~ URI::DEFAULT_PARSER.make_regexp # public URL for Sauce\n\n      ::Appium::Logger.warn('[Deprecation] Converting the path to absolute path will be removed. ' \\\n                            'Please specify the full path which can be accessible from the appium server')\n\n      absolute_app_path = File.expand_path app_path\n      if File.exist? absolute_app_path\n        absolute_app_path\n      else\n        ::Appium::Logger.info(\"Use #{app_path}\")\n        app_path\n      end\n    end\n\n    # Get the server url\n    # @return [String] the server url\n    def server_url\n      return @core.custom_url if @core.custom_url\n      return @sauce.server_url if @sauce.sauce_server_url?\n\n      \"http://127.0.0.1:#{@core.port}\"\n    end\n\n    # Restarts the driver\n    # @return [Driver] the driver\n    def restart\n      driver_quit\n      start_driver\n    end\n\n    # Takes a png screenshot and saves to the target path.\n    #\n    # @example\n    #\n    #   screenshot '/tmp/hi.png'\n    #\n    # @param png_save_path [String] the full path to save the png\n    # @return [File]\n    def screenshot(png_save_path)\n      @driver&.save_screenshot png_save_path\n    end\n\n    # Takes a png screenshot of particular element's area\n    #\n    # @example\n    #\n    #   el = find_element :accessibility_id, zzz\n    #   element_screenshot el, '/tmp/hi.png'\n    #\n    # @param [String] element Element take a screenshot\n    # @param [String] png_save_path the full path to save the png\n    # @return [File]\n    def element_screenshot(element, png_save_path)\n      @driver&.take_element_screenshot element, png_save_path\n      nil\n    end\n\n    # Quits the driver\n    # @return [void]\n    def driver_quit\n      @driver&.quit\n      @driver = nil\n    rescue Selenium::WebDriver::Error::WebDriverError\n      nil\n    end\n    alias quit_driver driver_quit\n\n    # Get the device window's size.\n    # @return [Selenium::WebDriver::Dimension]\n    #\n    # @example\n    #\n    #   size = @driver.window_size\n    #   size.width #=> Integer\n    #   size.height #=> Integer\n    #\n    def window_size\n      # maybe exception is expected as no driver created\n      raise NoDriverInstanceError if @driver.nil?\n\n      @driver.window_size\n    end\n\n    # Get the device window's rect.\n    # @return [Selenium::WebDriver::Rectangle]\n    #\n    # @example\n    #\n    #   size = @driver.window_size\n    #   size.width #=> Integer\n    #   size.height #=> Integer\n    #   size.x #=> Integer\n    #   size.y #=> Integer\n    #\n    def window_rect\n      raise NoDriverInstanceError if @driver.nil?\n\n      @driver.window_rect\n    end\n\n    # Creates a new global driver and quits the old one if it exists.\n    # You can customise http_client as the following\n    #\n    # Read http://www.rubydoc.info/github/appium/ruby_lib_core/Appium/Core/Device to understand more what the driver\n    # can call instance methods.\n    #\n    # @example\n    #\n    #   require 'rubygems'\n    #   require 'appium_lib'\n    #\n    #   # platformName takes a string or a symbol.\n    #   # Start iOS driver\n    #   opts = {\n    #            caps: {\n    #              platformName: :ios,\n    #              app: '/path/to/MyiOS.app'\n    #            },\n    #            appium_lib: {\n    #              wait_timeout: 30\n    #            }\n    #          }\n    #   appium_driver = Appium::Driver.new(opts) #=> return an Appium::Driver instance\n    #   appium_driver.start_driver #=> return an Appium::Core::Base::Driver\n    #\n    # @option http_client_ops [Hash] :http_client Custom HTTP Client\n    # @option http_client_ops [Hash] :open_timeout Custom open timeout for http client.\n    # @option http_client_ops [Hash] :read_timeout Custom read timeout for http client.\n    # @return [Selenium::WebDriver] the new global driver\n    def start_driver(http_client_ops = { http_client: nil, open_timeout: 999_999, read_timeout: 999_999 })\n      if http_client_ops[:http_client].nil?\n        http_client = ::Appium::Http::Default.new(open_timeout: http_client_ops[:open_timeout],\n                                                  read_timeout: http_client_ops[:read_timeout])\n      end\n\n      # TODO: do not kill the previous session in the future version.\n      if $driver.nil?\n        driver_quit\n      else\n        $driver.driver_quit\n      end\n\n      # If automationName is set only in server side, then the following automation_name should be nil before\n      # starting driver.\n      automation_name = @core.automation_name\n\n      @driver = @core.start_driver(server_url: server_url,\n                                   http_client_ops: {\n                                     http_client: http_client,\n                                     open_timeout: 999_999,\n                                     read_timeout: 999_999\n                                   })\n      @http_client = @core.http_client\n\n      # if automation_name was nil before start_driver, then re-extend driver specific methods\n      # to be able to extend correctly.\n      extend_for(device: @core.device, automation_name: @core.automation_name) if automation_name.nil?\n\n      @appium_server_status = appium_server_version\n\n      @driver\n    end\n\n    # To ignore error for Espresso Driver\n    def set_implicit_wait(wait)\n      @driver.manage.timeouts.implicit_wait = wait\n    rescue Selenium::WebDriver::Error::UnknownError => e\n      unless e.message.include?('The operation requested is not yet implemented by Espresso driver')\n        raise ::Appium::Core::Error::ServerError\n      end\n\n      {}\n    end\n\n    # Set implicit wait to zero.\n    def no_wait\n      @driver&.manage&.timeouts&.implicit_wait = 0\n    end\n\n    # Set implicit wait. Default to @default_wait.\n    #\n    # @example\n    #\n    #   set_wait 2\n    #   set_wait # @default_wait\n    #\n    #\n    # @param timeout [Integer] the timeout in seconds\n    # @return [void]\n    def set_wait(timeout = nil)\n      timeout = @default_wait if timeout.nil?\n      @driver&.manage&.timeouts&.implicit_wait = timeout\n    end\n\n    # Returns existence of element.\n    #\n    # Example:\n    #\n    # exists { button('sign in') } ? puts('true') : puts('false')\n    #\n    # @param [Integer] pre_check The amount in seconds to set the\n    #                             wait to before checking existence\n    # @param [Integer] post_check The amount in seconds to set the\n    #                             wait to after checking existence\n    # @yield The block to call\n    # @return [Boolean]\n    def exists(pre_check = 0, post_check = @default_wait)\n      # do not uset set_wait here.\n      # it will cause problems with other methods reading the default_wait of 0\n      # which then gets converted to a 1 second wait.\n      @driver&.manage&.timeouts&.implicit_wait = pre_check\n      # the element exists unless an error is raised.\n      exists = true\n\n      begin\n        yield # search for element\n      rescue StandardError\n        exists = false # error means it's not there\n      end\n\n      # restore wait\n      @driver&.manage&.timeouts&.implicit_wait = post_check if post_check != pre_check\n\n      exists\n    end\n\n    # The same as @driver.execute_script\n    # @param [String] script The script to execute\n    # @param [*args] args The args to pass to the script\n    # @return [Object]\n    def execute_script(script, *args)\n      raise NoDriverInstanceError if @driver.nil?\n\n      @driver.execute_script script, *args\n    end\n\n    ###\n    # Wrap calling selenium webdrier APIs via ruby_core\n    ###\n    # Get the window handles of open browser windows\n    def execute_async_script(script, *args)\n      raise NoDriverInstanceError if @driver.nil?\n\n      @driver.execute_async_script script, *args\n    end\n\n    # Run a set of script against the current session, allowing execution of many commands in one Appium request.\n    # Supports {https://webdriver.io/docs/api.html WebdriverIO} API so far.\n    # Please read {http://appium.io/docs/en/commands/session/execute-driver command API} for more details\n    # about acceptable scripts and the output.\n    #\n    # @param [String] script The string consisting of the script itself\n    # @param [String] type The name of the script type.\n    #                      Defaults to 'webdriverio'. Depends on server implementation which type is supported.\n    # @param [Integer] timeout_ms The number of `ms` Appium should wait for the script to finish\n    #                          before killing it due to timeout.\n    #\n    # @return [Appium::Core::Base::Device::ExecuteDriver::Result] The script result parsed by\n    #                          Appium::Core::Base::Device::ExecuteDriver::Result.\n    #\n    # @raise [::Selenium::WebDriver::Error::UnknownError] If something error happens in the script.\n    #                                                     It has the original message.\n    #\n    # @example\n    #      script = <<~SCRIPT\n    #        const status = await driver.status();\n    #        console.warn('warning message');\n    #        return [status];\n    #      SCRIPT\n    #      r = @@driver.execute_driver(script: script, type: 'webdriverio', timeout: 10_000)\n    #      r        #=> An instance of Appium::Core::Base::Device::ExecuteDriver::Result\n    #      r.result #=> The `result` key part as the result of the script\n    #      r.logs   #=> The `logs` key part as `{'log' => [], 'warn' => [], 'error' => []}`\n    #\n    def execute_driver(script: '', type: 'webdriverio', timeout_ms: nil)\n      raise NoDriverInstanceError if @driver.nil?\n\n      @driver.execute_driver(script: script, type: type, timeout_ms: timeout_ms)\n    end\n\n    def window_handles\n      raise NoDriverInstanceError if @driver.nil?\n\n      @driver.window_handles\n    end\n\n    # Get the current window handle\n    def window_handle\n      raise NoDriverInstanceError if @driver.nil?\n\n      @driver.window_handle\n    end\n\n    def navigate\n      raise NoDriverInstanceError if @driver.nil?\n\n      @driver.navigate\n    end\n\n    def manage\n      raise NoDriverInstanceError if @driver.nil?\n\n      @driver.manage\n    end\n\n    def get(url)\n      raise NoDriverInstanceError if @driver.nil?\n\n      @driver.get(url)\n    end\n\n    def current_url\n      raise NoDriverInstanceError if @driver.nil?\n\n      @driver.current_url\n    end\n\n    def title\n      raise NoDriverInstanceError if @driver.nil?\n\n      @driver.title\n    end\n\n    # @return [TargetLocator]\n    # @see TargetLocator\n    def switch_to\n      raise NoDriverInstanceError if @driver.nil?\n\n      @driver.switch_to\n    end\n    ###\n    # End core\n    ###\n\n    # Calls @driver.find_elements_with_appium\n    #\n    # @example\n    #\n    #   @driver = Appium::Driver.new(opts, false)\n    #   @driver.start_driver\n    #   @driver.find_elements :predicate, yyy\n    #\n    # If you call `Appium.promote_appium_methods`, you can call `find_elements` directly.\n    #\n    # @example\n    #\n    #   @driver = Appium::Driver.new(opts, false)\n    #   @driver.start_driver\n    #   @driver.find_elements :predicate, yyy\n    #\n    # If you call `Appium.promote_appium_methods`, you can call `find_elements` directly.\n    #\n    # @param [*args] args The args to use\n    # @return [Array<Element>] Array is empty when no elements are found.\n    def find_elements(*args)\n      raise NoDriverInstanceError if @driver.nil?\n\n      @driver.find_elements(*args)\n    end\n\n    # Calls @driver.find_element\n    #\n    # @example\n    #\n    #   @driver = Appium::Driver.new(opts, false)\n    #   @driver.start_driver\n    #   @driver.find_element :accessibility_id, zzz\n    #\n    # If you call `Appium.promote_appium_methods`, you can call `find_element` directly.\n    #\n    # @param [*args] args The args to use\n    # @return [Element]\n    def find_element(*args)\n      raise NoDriverInstanceError if @driver.nil?\n\n      @driver.find_element(*args)\n    end\n\n    # Return ImageElement if current view has a partial image\n    #\n    # @param [String] png_img_path A path to a partial image you'd like to find\n    #\n    # @return [::Appium::Core::ImageElement]\n    # @raise [::Appium::Core::Error::NoSuchElementError|::Appium::Core::Error::CoreError] No such element\n    #\n    # @example\n    #\n    #     @driver.find_element_by_image './test/functional/data/test_element_image.png'\n    #\n    def find_element_by_image(png_img_path)\n      raise NoDriverInstanceError if @driver.nil?\n\n      @driver.find_element_by_image(png_img_path)\n    end\n\n    # Return ImageElement if current view has partial images\n    #\n    # @param [[String]] png_img_paths Paths to a partial image you'd like to find\n    #\n    # @return [[::Appium::Core::ImageElement]]\n    # @return [::Appium::Core::Error::CoreError]\n    #\n    # @example\n    #\n    #     @driver.find_elements_by_image ['./test/functional/data/test_element_image.png']\n    #\n    def find_elements_by_image(png_img_paths)\n      raise NoDriverInstanceError if @driver.nil?\n\n      @driver.find_elements_by_image(png_img_paths)\n    end\n\n    # Calls @driver.set_location\n    #\n    # @note This method does not work on real devices.\n    #\n    # @param  [Hash] opts consisting of:\n    # @option opts [Float] :latitude the latitude in degrees (required)\n    # @option opts [Float] :longitude the longitude in degees (required)\n    # @option opts [Float] :altitude the altitude, defaulting to 75\n    # @return [Selenium::WebDriver::Location] the location constructed by the selenium webdriver\n    def set_location(opts = {})\n      raise NoDriverInstanceError if @driver.nil?\n\n      latitude = opts.fetch(:latitude)\n      longitude = opts.fetch(:longitude)\n      altitude = opts.fetch(:altitude, 75)\n      @driver.set_location(latitude, longitude, altitude)\n    end\n\n    # @since Appium 1.16.0\n    #\n    # Logs a custom event. The event is available via {::Appium::Core::Events#get}.\n    #\n    # @param [String] vendor The vendor prefix for the event\n    # @param [String] event The name of event\n    # @return [nil]\n    #\n    # @example\n    #\n    #   log_event vendor: 'appium', event: 'funEvent'\n    #\n    #   log_event = { vendor: 'appium', event: 'anotherEvent' }\n    #   log_events #=> {...., 'appium:funEvent' => [1572957315, 1572960305],\n    #              #          'appium:anotherEvent' => 1572959315}\n    #\n    def log_event(vendor:, event:)\n      raise NoDriverInstanceError if @driver.nil?\n\n      @driver.logs.event vendor: vendor, event: event\n    end\n\n    def log_event=(log_event)\n      raise if @driver.nil?\n      unless log_event.is_a?(Hash)\n        raise ::Appium::Core::Error::ArgumentError('log_event should be Hash like { vendor: \"appium\", event: \"funEvent\"}')\n      end\n\n      @driver.logs.event vendor: log_event[:vendor], event: log_event[:event]\n    end\n\n    # @since Appium 1.16.0\n    # Returns events with filtering with 'type'. Defaults to all available events.\n    #\n    # @param [String] type The type of events to get\n    # @return [Hash]\n    #\n    # @example\n    #\n    #   log_events #=> {}\n    #   log_events #=> {'commands' => [{'cmd' => 123455, ....}], 'startTime' => 1572954894127, }\n    #\n    def log_events(type = nil)\n      raise NoDriverInstanceError if @driver.nil?\n\n      @driver.logs.events(type)\n    end\n\n    # Quit the driver and Pry.\n    # quit and exit are reserved by Pry.\n    # @return [void]\n    def x\n      driver_quit\n      exit # exit pry\n    end\n  end # class Driver\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/error.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  class Error < StandardError; end\n\n  # Driver instance hasn't been created yet.\n  class NoDriverInstanceError < Appium::Error; end\n\n  class ArgumentError < ArgumentError; end\nend\n"
  },
  {
    "path": "lib/appium_lib/ios/common/errors.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Ios\n    class CommandError < RuntimeError\n    end\n  end\nend\n"
  },
  {
    "path": "lib/appium_lib/ios/common/helper.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Ios\n    # @private\n    class UITestElementsPrinter < Nokogiri::XML::SAX::Document\n      attr_accessor :filter\n\n      def start_element(type, attrs = [])\n        return if filter && !filter.eql?(type)\n\n        page = attrs.each_with_object({}) do |attr, hash|\n          hash[attr[0]] = attr[1] if %w(name label value hint visible).include?(attr[0])\n          hash\n        end\n        _print_attr(type, page['name'], page['label'], page['value'], page['hint'], page['visible'])\n      end\n\n      # @private\n      def _print_attr(type, name, label, value, hint, visible) # rubocop:disable Metrics/ParameterLists\n        puts type.to_s if name || label || value || hint || visible\n\n        if name == label && name == value\n          puts \"   name, label, value: #{name}\" if name\n        elsif name == label\n          puts \"   name, label: #{name}\" if name\n          puts \"   value: #{value}\" if value\n        elsif name == value\n          puts \"   name, value: #{name}\" if name\n          puts \"  label: #{label}\" if label\n        else\n          puts \"   name: #{name}\" if name\n          puts \"  label: #{label}\" if label\n          puts \"  value: #{value}\" if value\n        end\n        puts \"   hint: #{hint}\" if hint\n        puts \"   visible: #{visible}\" if visible\n      end\n    end\n\n    # iOS only. On Android uiautomator always returns an empty string for EditText password.\n    #\n    # Password character returned from value of UIASecureTextField\n    # @param length [Integer] the length of the password to generate\n    # @return [String] the returned string is of size length\n    def ios_password(length = 1)\n      8226.chr('UTF-8') * length\n    end\n\n    # Prints a string of interesting elements to the console.\n    #\n    # @example\n    #     ```ruby\n    #     page class: :UIAButton # filter on buttons\n    #     page class: :UIAButton, window: 1\n    #     ```\n    #\n    # @option visible [Symbol] visible value to filter on\n    # @option class [Symbol] class name to filter on\n    #\n    # @return [void]\n    def page(opts = {})\n      class_name = opts.is_a?(Hash) ? opts.fetch(:class, nil) : opts\n\n      source = get_source\n\n      # current_context may be nil which breaks start_with\n      if current_context&.start_with?('WEBVIEW')\n        parser = @android_html_parser ||= Nokogiri::HTML::SAX::Parser.new(Appium::Common::HTMLElements.new)\n        parser.document.reset\n        parser.document.filter = class_name\n        parser.parse source\n        result = parser.document.result\n        puts result\n        result\n      else\n        parser = Nokogiri::XML::SAX::Parser.new(UITestElementsPrinter.new)\n        if class_name\n          parser.document.filter = class_name.is_a?(Symbol) ? class_name.to_s : class_name\n        end\n        parser.parse source\n        nil\n      end\n    end\n\n    # Find by id\n    # @param id [String] the id to search for\n    # @return [Element]\n    def id(id)\n      find_element(:id, id)\n    end\n\n    # Get the element of type class_name at matching index.\n    # @param class_name [String] the class name to find\n    # @param index [Integer] the index\n    # @return [Element]\n    def ele_index(class_name, index)\n      raise ArgumentError, 'Index must be >= 1' unless index == 'last()' || (index.is_a?(Integer) && index >= 1)\n\n      elements = tags(class_name)\n\n      if index == 'last()'\n        result = elements.last\n      else\n        # elements array is 0 indexed\n        index -= 1\n        result = elements[index]\n      end\n\n      raise _no_such_element if result.nil?\n\n      result\n    end\n\n    # @private\n    def string_attr_exact(class_name, attr, value)\n      %(//#{class_name}[@visible=\"true\" and @#{attr}=\"#{value}\"])\n    end\n\n    # Find the first element exactly matching class and attribute value.\n    # Note: Uses XPath\n    # Note: For XCUITest, this method return ALL elements include displayed or not displayed elements.\n    # @param class_name [String] the class name to search for\n    # @param attr [String] the attribute to inspect\n    # @param value [String] the expected value of the attribute\n    # @return [Element]\n    def find_ele_by_attr(class_name, attr, value)\n      @driver.find_element :xpath, string_attr_exact(class_name, attr, value)\n    end\n\n    # Find all elements exactly matching class and attribute value.\n    # Note: Uses XPath\n    # Note: For XCUITest, this method return ALL elements include displayed or not displayed elements.\n    # @param class_name [String] the class name to match\n    # @param attr [String] the attribute to compare\n    # @param value [String] the value of the attribute that the element must have\n    # @return [Array<Element>]\n    def find_eles_by_attr(class_name, attr, value)\n      @driver.find_elements :xpath, string_attr_exact(class_name, attr, value)\n    end\n\n    # @private\n    def string_attr_include(class_name, attr, value)\n      %(//#{class_name}[@visible=\"true\" and contains(translate(@#{attr},\"#{value.upcase}\", \"#{value}\"), \"#{value}\")])\n    end\n\n    # Find the first element exactly matching attribute case insensitive value.\n    # Note: Uses Predicate\n    # @param value [String] the expected value of the attribute\n    # @return [Element]\n    def find_ele_by_predicate(class_name: '*', value:)\n      elements = find_eles_by_predicate(class_name: class_name, value: value)\n      raise _no_such_element if elements.empty?\n\n      elements.first\n    end\n\n    # Find all elements exactly matching attribute case insensitive value.\n    # Note: Uses Predicate\n    # @param value [String] the value of the attribute that the element must have\n    # @param class_name [String] the tag name to match\n    # @return [Array<Element>]\n    def find_eles_by_predicate(class_name: '*', value:)\n      predicate = if class_name == '*'\n                    %(name == \"#{value}\" || label == \"#{value}\" || value == \"#{value}\")\n                  else\n                    %(type == \"#{class_name}\" && ) +\n                      %((name == \"#{value}\" || label == \"#{value}\" || value == \"#{value}\"))\n                  end\n      @driver.find_elements :predicate, predicate\n    end\n\n    # Get the first tag by attribute that exactly matches value.\n    # Note: Uses XPath\n    # @param class_name [String] the tag name to match\n    # @param attr [String] the attribute to compare\n    # @param value [String] the value of the attribute that the element must include\n    # @return [Element] the element of type tag who's attribute includes value\n    def find_ele_by_attr_include(class_name, attr, value)\n      @driver.find_element :xpath, string_attr_include(class_name, attr, value)\n    end\n\n    # Get tags by attribute that include value.\n    # Note: Uses XPath\n    # @param class_name [String] the tag name to match\n    # @param attr [String] the attribute to compare\n    # @param value [String] the value of the attribute that the element must include\n    # @return [Array<Element>] the elements of type tag who's attribute includes value\n    def find_eles_by_attr_include(class_name, attr, value)\n      @driver.find_elements :xpath, string_attr_include(class_name, attr, value)\n    end\n\n    # Get the first elements that include insensitive value.\n    # Note: Uses Predicate\n    # @param value [String] the value of the attribute that the element must include\n    # @return [Element] the element of type tag who's attribute includes value\n    def find_ele_by_predicate_include(class_name: '*', value:)\n      elements = find_eles_by_predicate_include(class_name: class_name, value: value)\n      raise _no_such_element if elements.empty?\n\n      elements.first\n    end\n\n    # Get elements that include case insensitive value.\n    # Note: Uses Predicate\n    # @param value [String] the value of the attribute that the element must include\n    # @param class_name [String] the tag name to match\n    # @return [Array<Element>] the elements of type tag who's attribute includes value\n    def find_eles_by_predicate_include(class_name: '*', value:)\n      predicate = if class_name == '*'\n                    %(name contains[c] \"#{value}\" || label contains[c] \"#{value}\" || value contains[c] \"#{value}\")\n                  else\n                    %(type == \"#{class_name}\" && ) +\n                      %((name contains[c] \"#{value}\" || label contains[c] \"#{value}\" || value contains[c] \"#{value}\"))\n                  end\n      @driver.find_elements :predicate, predicate\n    end\n\n    # Get the first tag that matches class_name\n    # @param class_name [String] the tag to match\n    # @return [Element]\n    def first_ele(class_name)\n      ele_index class_name, 1\n    end\n\n    # Get the last tag that matches class_name\n    # @param class_name [String] the tag to match\n    # @return [Element]\n    def last_ele(class_name)\n      ele_index class_name, 'last()'\n    end\n\n    # Returns the first **visible** element matching class_name\n    #\n    # @param class_name [String] the class_name to search for\n    # @return [Element]\n    def tag(class_name)\n      ele_by_json(typeArray: [class_name], onlyVisible: true)\n    end\n\n    # Returns all visible elements matching class_name\n    #\n    # @param class_name [String] the class_name to search for\n    # @return [Element]\n    def tags(class_name)\n      eles_by_json(typeArray: [class_name], onlyVisible: true)\n    end\n\n    # Returns all visible elements matching class_names and value\n    # This method calls find_element/s and element.value/text many times.\n    # So, if you set many class_names, this method's performance become worse.\n    #\n    # @param class_names [Array[String]] the class_names to search for\n    # @param value [String] the value to search for\n    # @return [Array[Element]]\n    def tags_include(class_names:, value: nil)\n      return unless class_names.is_a? Array\n\n      class_names.flat_map do |class_name|\n        value ? eles_by_json_visible_contains(class_name, value) : tags(class_name)\n      end\n    end\n\n    # Returns all visible elements matching class_names and value.\n    # This method calls find_element/s and element.value/text many times.\n    # So, if you set many class_names, this method's performance become worse.\n    #\n    # @param class_names [Array[String]] the class_names to search for\n    # @param value [String] the value to search for\n    # @return [Array[Element]]\n    def tags_exact(class_names:, value: nil)\n      return unless class_names.is_a? Array\n\n      class_names.flat_map do |class_name|\n        value ? eles_by_json_visible_exact(class_name, value) : tags(class_name)\n      end\n    end\n\n    # @private\n    # Returns an object that matches the first element that contains value\n    #\n    # example: ele_by_json_visible_contains 'UIATextField', 'sign in'\n    #\n    # @param element [String] the class name for the element\n    # @param value [String] the value to search for\n    # @return [String]\n    def string_visible_contains(element, value)\n      contains = {\n        target: value,\n        substring: true,\n        insensitive: true\n      }\n\n      {\n        typeArray: [element],\n        onlyVisible: true,\n        name: contains,\n        label: contains,\n        value: contains\n      }\n    end\n\n    # Find the first element that contains value.\n    # For Appium(automation name), not XCUITest\n    # @param element [String] the class name for the element\n    # @param value [String] the value to search for\n    # @return [Element]\n    def ele_by_json_visible_contains(element, value)\n      ele_by_json string_visible_contains element, value\n    end\n\n    # Find all elements containing value\n    # For Appium(automation name), not XCUITest\n    # @param element [String] the class name for the element\n    # @param value [String] the value to search for\n    # @return [Array<Element>]\n    def eles_by_json_visible_contains(element, value)\n      eles_by_json string_visible_contains element, value\n    end\n\n    # @private\n    # Create an object to exactly match the first element with target value\n    # @param element [String] the class name for the element\n    # @param value [String] the value to search for\n    # @return [String]\n    def string_visible_exact(element, value)\n      exact = {\n        target: value,\n        substring: false,\n        insensitive: false\n      }\n\n      {\n        typeArray: [element],\n        onlyVisible: true,\n        name: exact,\n        label: exact,\n        value: exact\n      }\n    end\n\n    # Find the first element exactly matching value\n    # For Appium(automation name), not XCUITest\n    # @param element [String] the class name for the element\n    # @param value [String] the value to search for\n    # @return [Element]\n    def ele_by_json_visible_exact(element, value)\n      ele_by_json string_visible_exact element, value\n    end\n\n    # Find all elements exactly matching value\n    # For Appium(automation name), not XCUITest\n    # @param element [String] the class name for the element\n    # @param value [String] the value to search for\n    # @return [Element]\n    def eles_by_json_visible_exact(element, value)\n      eles_by_json string_visible_exact element, value\n    end\n\n    #\n    # predicate - the predicate to evaluate on the main app\n    #\n    # visible - if true, only visible elements are returned. default true\n    #\n    def _all_pred(opts)\n      predicate = opts[:predicate]\n      raise ArgumentError, 'predicate must be provided' unless predicate\n\n      visible = opts.fetch :visible, true\n      %($.mainApp().getAllWithPredicate(\"#{predicate}\", #{visible});)\n    end\n\n    # returns element matching predicate contained in the main app\n    #\n    # predicate - the predicate to evaluate on the main app\n    #\n    # visible - if true, only visible elements are returned. default true\n    # @return [Element]\n    def ele_with_pred(opts)\n      # true = return only visible\n      find_element(:uiautomation, _all_pred(opts))\n    end\n\n    # returns elements matching predicate contained in the main app\n    #\n    # predicate - the predicate to evaluate on the main app\n    #\n    # visible - if true, only visible elements are returned. default true\n    # @return [Array<Element>]\n    def eles_with_pred(opts)\n      find_elements(:uiautomation, _all_pred(opts))\n    end\n\n    def _validate_object(*objects)\n      raise ArgumentError, 'objects must be an array' unless objects.is_a? Array\n\n      objects.each do |obj|\n        next unless obj # obj may be nil. if so, ignore.\n\n        valid_keys   = %i[target substring insensitive]\n        unknown_keys = obj.keys - valid_keys\n        raise ArgumentError, \"Unknown keys: #{unknown_keys}\" unless unknown_keys.empty?\n\n        target = obj[:target]\n        raise ArgumentError, 'target must be a string' unless target.is_a? String\n\n        substring = obj[:substring]\n        raise ArgumentError, 'substring must be a boolean' unless [true, false].include? substring\n\n        insensitive = obj[:insensitive]\n        raise ArgumentError, 'insensitive must be a boolean' unless [true, false].include? insensitive\n      end\n    end\n\n    # For Appium(automation name), not XCUITest\n    # typeArray - array of string types to search for. Example: [\"UIAStaticText\"]\n    # onlyFirst - boolean. returns only the first result if true. Example: true\n    # onlyVisible - boolean. returns only visible elements if true. Example: true\n    # target - string. the target value to search for. Example: \"Buttons, Various uses of UIButton\"\n    # substring - boolean. matches on substrings if true otherwise an exact mathc is required. Example: true\n    # insensitive - boolean. ignores case sensitivity if true otherwise it's case sensitive. Example: true\n    #\n    # opts = {\n    #   typeArray: [\"UIAStaticText\"],\n    #   onlyFirst: true,\n    #   onlyVisible: true,\n    #   name: {\n    #     target: \"Buttons, Various uses of UIButton\",\n    #     substring: false,\n    #     insensitive: false,\n    #   },\n    #   label: {\n    #     target: \"Buttons, Various uses of UIButton\",\n    #     substring: false,\n    #     insensitive: false,\n    #   },\n    #   value: {\n    #     target: \"Buttons, Various uses of UIButton\",\n    #     substring: false,\n    #     insensitive: false,\n    #   }\n    # }\n    #\n    def _by_json(opts)\n      valid_keys = %i(typeArray onlyFirst onlyVisible name label value)\n      unknown_keys = opts.keys - valid_keys\n      raise ArgumentError, \"Unknown keys: #{unknown_keys}\" unless unknown_keys.empty?\n\n      type_array = opts[:typeArray]\n      raise ArgumentError, 'typeArray must be an array' unless type_array.is_a? Array\n\n      only_first = opts[:onlyFirst]\n      raise ArgumentError, 'onlyFirst must be a boolean' unless [true, false].include? only_first\n\n      only_visible = opts[:onlyVisible]\n      raise ArgumentError, 'onlyVisible must be a boolean' unless [true, false].include? only_visible\n\n      # name/label/value are optional. when searching for class only, then none\n      # will be present.\n      _validate_object opts[:name], opts[:label], opts[:value]\n\n      # NOTE: that mainWindow is sometimes nil so it's passed as a param\n      # $._elementOrElementsByType will validate that the window isn't nil\n      element_or_elements_by_type = <<-JS\n        (function() {\n          var opts = #{opts.to_json};\n          var result = false;\n\n          try {\n            result = $._elementOrElementsByType($.mainWindow(), opts);\n          } catch (e) {\n          }\n\n          return result;\n        })();\n      JS\n\n      res = execute_script element_or_elements_by_type\n      res || raise(Appium::Ios::CommandError, 'mainWindow is nil')\n    end\n\n    # For Appium(automation name), not XCUITest\n    # example usage:\n    #\n    # eles_by_json({\n    #   typeArray: [\"UIAStaticText\"],\n    #   onlyVisible: true,\n    #   name: {\n    #     target: \"Buttons, Various uses of UIButton\",\n    #     substring: false,\n    #     insensitive: false,\n    #   },\n    # })\n    def eles_by_json(opts)\n      opts[:onlyFirst] = false\n      _by_json opts\n    end\n\n    # see eles_by_json\n    def ele_by_json(opts)\n      opts[:onlyFirst] = true\n      result = _by_json(opts).first\n      raise _no_such_element if result.nil?\n\n      result\n    end\n  end # module Ios\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/ios/element/alert.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Ios\n    # Accept the alert.\n    # @return [void]\n    def alert_accept\n      # @driver.switch_to.alert.accept\n      # \".switch_to.alert\" calls alert_text so use bridge directly\n      driver.send(:bridge).accept_alert\n    end\n\n    # Dismiss the alert.\n    # @return [void]\n    def alert_dismiss\n      # @driver.switch_to.alert.dismiss\n      # \".switch_to.alert\" calls alert_text so use bridge directly\n      driver.send(:bridge).dismiss_alert\n    end\n  end # module Ios\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/ios/element/button.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# XCUIElementTypeButton methods\nmodule Appium\n  module Ios\n    UIA_BUTTON = 'UIAButton'\n    UIAButton = UIA_BUTTON\n\n    XCUIELEMENT_TYPE_BUTTON = 'XCUIElementTypeButton'\n    XCUIElementTypeButton = XCUIELEMENT_TYPE_BUTTON\n\n    # @return [String] Class name for button\n    def button_class\n      UIA_BUTTON\n    end\n\n    # Find the first UIAButton|XCUIElementTypeButton that contains value or by index.\n    # @param value [String, Integer] the value to exactly match.\n    # If int then the UIAButton|XCUIElementTypeButton at that index is returned.\n    # @return [UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON]\n    def button(value)\n      # return button at index.\n      return ele_index button_class, value if value.is_a? Numeric\n\n      ele_by_json_visible_contains button_class, value\n    end\n\n    # Find all UIAButtons|XCUIElementTypeButtons containing value.\n    # If value is omitted, all UIAButtons|XCUIElementTypeButtons are returned.\n    # @param value [String] the value to search for\n    # @return [Array<UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON>]\n    def buttons(value = false)\n      return tags button_class unless value\n\n      eles_by_json_visible_contains button_class, value\n    end\n\n    # Find the first UIAButton|XCUIElementTypeButton.\n    # @return [UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON]\n    def first_button\n      first_ele button_class\n    end\n\n    # TODO: add documentation regarding previous element.\n    #       Previous UIAElement is differ from UIAButton|XCUIElementTypeButton. So, the results are different.\n    # Find the last UIAButton|XCUIElementTypeButton.\n    # @return [UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON]\n    def last_button\n      last_ele button_class\n    end\n\n    # Find the first UIAButton|XCUIElementTypeButton that exactly matches value.\n    # @param value [String] the value to match exactly\n    # @return [UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON]\n    def button_exact(value)\n      ele_by_json_visible_exact button_class, value\n    end\n\n    # Find all UIAButtons|XCUIElementTypeButtons that exactly match value.\n    # @param value [String] the value to match exactly\n    # @return [Array<UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON>]\n    def buttons_exact(value)\n      eles_by_json_visible_exact button_class, value\n    end\n  end # module Ios\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/ios/element/generic.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Ios\n    # Find the first element containing value\n    # @param value [String] the value to search for\n    # @return [Element]\n    def find(value)\n      ele_by_json_visible_contains '*', value\n    end\n\n    # Find all elements containing value\n    # @param value [String] the value to search for\n    # @return [Array<Element>]\n    def finds(value)\n      eles_by_json_visible_contains '*', value\n    end\n\n    # Find the first element exactly matching value\n    # @param value [String] the value to search for\n    # @return [Element]\n    def find_exact(value)\n      ele_by_json_visible_exact '*', value\n    end\n\n    # Find all elements exactly matching value\n    # @param value [String] the value to search for\n    # @return [Array<Element>]\n    def finds_exact(value)\n      eles_by_json_visible_exact '*', value\n    end\n\n    private\n\n    def raise_error_if_no_element(element)\n      error_message = 'An element could not be located on the page using the given search parameters.'\n      raise(::Selenium::WebDriver::Error::NoSuchElementError, error_message) if element.nil?\n\n      element\n    end\n\n    # Return visible elements.\n    def select_visible_elements(elements)\n      elements.select(&:displayed?)\n    end\n  end # module Ios\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/ios/element/text.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# UIAStaticText|XCUIElementTypeStaticText methods\nmodule Appium\n  module Ios\n    UIA_STATIC_TEXT = 'UIAStaticText'\n    UIAStaticText = UIA_STATIC_TEXT\n\n    XCUIELEMENT_TYPE_STATIC_TEXT = 'XCUIElementTypeStaticText'\n    XCUIElementTypeStaticText = XCUIELEMENT_TYPE_STATIC_TEXT\n\n    # @return [String] Class name for text\n    def static_text_class\n      UIA_STATIC_TEXT\n    end\n\n    # Find the first UIAStaticText|XCUIElementTypeStaticText that contains value or by index.\n    # @param value [String, Integer] the value to find.\n    # If int then the UIAStaticText|XCUIElementTypeStaticText at that index is returned.\n    # @return [UIA_STATIC_TEXT|XCUIELEMENT_TYPE_STATIC_TEXT]\n    def text(value)\n      return ele_index static_text_class, value if value.is_a? Numeric\n\n      ele_by_json_visible_contains static_text_class, value\n    end\n\n    # Find all UIAStaticTexts|XCUIElementTypeStaticTexts containing value.\n    # If value is omitted, all UIAStaticTexts|XCUIElementTypeStaticTexts are returned\n    # @param value [String] the value to search for\n    # @return [Array<UIA_STATIC_TEXT|XCUIELEMENT_TYPE_STATIC_TEXT>]\n    def texts(value = false)\n      return tags static_text_class unless value\n\n      eles_by_json_visible_contains static_text_class, value\n    end\n\n    # Find the first UIAStaticText|XCUIElementTypeStaticText.\n    # @return [UIA_STATIC_TEXT|XCUIELEMENT_TYPE_STATIC_TEXT]\n    def first_text\n      first_ele static_text_class\n    end\n\n    # Find the last UIAStaticText|XCUIElementTypeStaticText.\n    # @return [UIA_STATIC_TEXT|XCUIELEMENT_TYPE_STATIC_TEXT]\n    def last_text\n      last_ele static_text_class\n    end\n\n    # Find the first UIAStaticText|XCUIElementTypeStaticText that exactly matches value.\n    # @param value [String] the value to match exactly\n    # @return [UIA_STATIC_TEXT|XCUIElementTypeStaticText]\n    def text_exact(value)\n      ele_by_json_visible_exact static_text_class, value\n    end\n\n    # Find all UIAStaticTexts|XCUIElementTypeStaticTexts that exactly match value.\n    # @param value [String] the value to match exactly\n    # @return [Array<UIA_STATIC_TEXT|XCUIElementTypeStaticText>]\n    def texts_exact(value)\n      eles_by_json_visible_exact static_text_class, value\n    end\n  end # module Ios\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/ios/element/textfield.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Ios\n    UIA_TEXT_FIELD = 'UIATextField'\n    UIATextField = UIA_TEXT_FIELD\n    UIA_SECURE_TEXT_FIELD = 'UIASecureTextField'\n    UIASecureTextField = UIA_SECURE_TEXT_FIELD\n\n    XCUIELEMENT_TYPE_TEXT_FIELD = 'XCUIElementTypeTextField'\n    XCUIElementTypeTextField = XCUIELEMENT_TYPE_TEXT_FIELD\n    XCUIELEMENT_TYPE_SECURE_TEXT_FIELD = 'XCUIElementTypeSecureTextField'\n    XCUIElementTypeSecureTextField = XCUIELEMENT_TYPE_SECURE_TEXT_FIELD\n\n    # @return [String] Class name for text field\n    def text_field_class\n      UIA_TEXT_FIELD\n    end\n\n    # @return [String] Class name for secure text field\n    def secure_text_field_class\n      UIA_SECURE_TEXT_FIELD\n    end\n\n    # Find the first TextField that contains value or by index.\n    # Note: Uses XPath\n    # @param value [String, Integer] the text to match exactly.\n    # If int then the TextField at that index is returned.\n    # @return [TextField]\n    def textfield(value)\n      if value.is_a? Numeric\n        index = value\n        raise ArgumentError, \"#{index} is not a valid index. Must be >= 1\" if index <= 0\n\n        index -= 1 # eles_by_json and _textfields_with_predicate is 0 indexed.\n        result = eles_by_json(_textfield_visible)[index]\n        raise _no_such_element if result.nil?\n\n        return result\n      end\n\n      ele_by_json _textfield_contains_string value\n    end\n\n    # Find all TextFields containing value.\n    # If value is omitted, all TextFields are returned.\n    # @param value [String] the value to search for\n    # @return [Array<TextField>]\n    def textfields(value = false)\n      return eles_by_json _textfield_visible unless value\n\n      eles_by_json _textfield_contains_string value\n    end\n\n    # Find the first TextField.\n    # @return [TextField]\n    def first_textfield\n      ele_by_json _textfield_visible\n    end\n\n    # Find the last TextField.\n    # @return [TextField]\n    def last_textfield\n      result = eles_by_json(_textfield_visible).last\n      raise _no_such_element if result.nil?\n\n      result\n    end\n\n    # Find the first TextField that exactly matches value.\n    # @param value [String] the value to match exactly\n    # @return [TextField]\n    def textfield_exact(value)\n      ele_by_json _textfield_exact_string value\n    end\n\n    # Find all TextFields that exactly match value.\n    # @param value [String] the value to match exactly\n    # @return [Array<TextField>]\n    def textfields_exact(value)\n      eles_by_json _textfield_exact_string value\n    end\n\n    private\n\n    # Appium\n    def _textfield_visible\n      { typeArray: [UIA_TEXT_FIELD, UIA_SECURE_TEXT_FIELD], onlyVisible: true }\n    end\n\n    # Appium\n    def _textfield_exact_string(value)\n      exact = { target: value, substring: false, insensitive: false }\n      exact_obj = { name: exact, label: exact, value: exact }\n      _textfield_visible.merge(exact_obj)\n    end\n\n    # Appium\n    def _textfield_contains_string(value)\n      contains = { target: value, substring: true, insensitive: true }\n      contains_obj = { name: contains, label: contains, value: contains }\n      _textfield_visible.merge(contains_obj)\n    end\n  end # module Ios\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/ios/ios.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nrequire_relative 'common/helper'\nrequire_relative 'common/errors'\n\nrequire_relative 'element/alert'\nrequire_relative 'element/button'\nrequire_relative 'element/generic'\nrequire_relative 'element/textfield'\nrequire_relative 'element/text'\n\nrequire_relative 'xcuitest'\n\nmodule Appium\n  module Ios\n    class Bridge\n      def self.for(target)\n        target.extend Appium::Ios\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/bridge.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nrequire_relative '../ios'\n\nmodule Appium\n  module Ios\n    module Xcuitest\n      class Bridge\n        def self.for(target)\n          target.extend Appium::Ios\n          target.extend Appium::Ios::Xcuitest\n          target.extend Appium::Ios::Xcuitest::PasteBoard\n          target.extend Appium::Ios::Xcuitest::Source\n          target.extend Appium::Ios::Xcuitest::Helper\n          target.extend Appium::Ios::Xcuitest::Gesture\n          target.extend Appium::Ios::Xcuitest::MultiAppHandler\n          target.extend Appium::Ios::Xcuitest::Element\n          target.extend Appium::Ios::Xcuitest::GetContext\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/command/certificate.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nrequire 'base64'\n\nmodule Appium\n  module Ios\n    module Xcuitest\n      module Certificate\n        # Generates Apple's over-the-air configuration profile for certificate deployment\n        # based on the given PEM certificate content.\n        # https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/iPhoneOTAConfiguration/Introduction/Introduction.html\n        # https://github.com/appium/appium-xcuitest-driver/pull/652\n        #\n        # @param [string] cer_file The content of the certificate file.\n        #\n        # @example\n        #\n        #     install_certificate cer_file: \"path/to/cert.cer\"\n        #\n        def install_certificate(cer_file:)\n          args = { content: Base64.encode64(cer_file) }\n\n          @driver.execute_script 'mobile: installCertificate', args\n        end\n      end\n    end # module Xcuitest\n  end # module Ios\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/command/gestures.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Ios\n    module Xcuitest\n      module Gesture\n        # @param [string] direction Either 'up', 'down', 'left' or 'right'.\n        # @option opts [Element] :element Element to swipe on\n        #\n        #   ```ruby\n        #   swipe direction: \"down\"\n        #   ```\n        def swipe(direction:, element: nil)\n          args = { direction: direction }\n          args[:element] = element.id if element\n\n          @driver.execute_script 'mobile: swipe', args\n        end\n\n        # @param [string] direction Either 'up', 'down', 'left' or 'right'.\n        # @option opts [Double] :distance scroll distance, proportional to scroll view height.\n        #   the value is supposed to be in between 0.0 and 1.0.\n        # @option opts [String] :name the accessibility id of the child element, to which scrolling is performed.\n        # @option opts [Element] :element Element id to long tap on.\n        # @option opts [bool] :to_visible Boolean parameter. If set to true then asks to scroll to the first visible\n        #   element in the parent container. Has no effect if element is not set\n        # @option opts [String] :predicate_string the NSPredicate locator of the child element,\n        #   to which the scrolling should be performed. Has no effect if element is not a container\n        #\n        #   ```ruby\n        #   scroll direction: \"down\"\n        #   ```\n        # rubocop:disable Metrics/ParameterLists\n        def scroll(direction:, distance: nil, name: nil, element: nil, to_visible: nil, predicate_string: nil)\n          return 'Set \"up\", \"down\", \"left\" or \"right\" for :direction' unless %w(up down left right).include?(direction)\n\n          args = { direction: direction }\n          args[:element] = element.id if element\n          args[:distance] = distance if distance\n          args[:name] = name if name\n          args[:toVisible] = to_visible if to_visible\n          args[:predicateString] = predicate_string if predicate_string\n\n          @driver.execute_script 'mobile: scroll', args\n        end\n        # rubocop:enable Metrics/ParameterLists\n\n        # @param scale [scale] X tap coordinate of type float. Mandatory parameter\n        # @param velocity [float] Y tap coordinate of type float. Mandatory parameter\n        # @option opts [Element] :element Element id to long tap on.\n        #\n        #   ```ruby\n        #   pinch scale: 0.5, velocity: -1\n        #   ```\n        def pinch(scale:, velocity: 1.0, element: nil)\n          args = { scale: scale, velocity: velocity }\n          args[:element] = element.id if element\n\n          @driver.execute_script 'mobile: pinch', args\n        end\n\n        # @param x [float] X Screen x tap coordinate of type float. Mandatory parameter only if element is not set\n        # @param y [float] Y Screen y tap coordinate of type float. Mandatory parameter only if element is not set\n        # @option opts [Element] :element Element to long tap on.\n        #\n        #   ```ruby\n        #   double_tap x: 100, y: 100\n        #   double_tap element: find_element(:accessibility_id, \"some item\")\n        #   ```\n        def double_tap(x: nil, y: nil, element: nil)\n          return 'Set x, y or element' if (x.nil? || y.nil?) && element.nil?\n\n          args = element.nil? ? { x: x, y: y } : { element: element.id }\n          @driver.execute_script 'mobile: doubleTap', args\n        end\n\n        # @param x [float] Screen x long tap coordinate of type float. Mandatory parameter only if element is not set\n        # @param y [float] Screen y long tap coordinate of type float. Mandatory parameter only if element is not set\n        # @param duration [Float] The float duration of press action in seconds. Mandatory parameter\n        # @option opts [Element] :element The internal element identifier (as hexadecimal hash string) to long tap on\n        #\n        #   ```ruby\n        #   touch_and_hold x: 100, y: 100\n        #   touch_and_hold x: 100, y: 100, duration: 2.0\n        #   touch_and_hold element: find_element(:accessibility_id, \"some item\")\n        #   ```\n        def touch_and_hold(x: nil, y: nil, element: nil, duration: 1.0)\n          return 'Set x, y or element' if (x.nil? || y.nil?) && element.nil?\n\n          args = element.nil? ? { x: x, y: y } : { element: element.id }\n          args[:duration] = duration\n          @driver.execute_script 'mobile: touchAndHold', args\n        end\n\n        # @param [Element] element Element to long tap on.\n        #\n        #   ```ruby\n        #   two_finger_tap element: find_element(:accessibility_id, \"some item\")\n        #   ```\n        def two_finger_tap(element:)\n          args = { element: element.id }\n          @driver.execute_script 'mobile: twoFingerTap', args\n        end\n\n        # @param x [float] X tap coordinate of type float. Mandatory parameter\n        # @param y [float] Y tap coordinate of type float. Mandatory parameter\n        # @option opts [Element] :element Element id to long tap on. x and y tap coordinates will be calculated\n        #   relatively to the current element position on the screen if this argument is provided.\n        #   Otherwise they should be calculated relatively to screen borders.\n        #\n        #   ```ruby\n        #   one_finger_tap x: 100, y: 100\n        #   one_finger_tap x: 100, y: 100, element: find_element(:accessibility_id, \"some item\")\n        #   ```\n        def one_finger_tap(x:, y:, element: nil)\n          args = { x: x, y: y }\n          args[:element] = element.id if element\n          @driver.execute_script 'mobile: tap', args\n        end\n\n        # rubocop:disable Metrics/ParameterLists\n        # @param duration [float] Float number of seconds in range [0.5, 60]. How long the tap gesture at starting\n        #   drag point should be before to start dragging. Mandatory parameter\n        # @param from_x [float] The x coordinate of starting drag point (type float). Mandatory parameter\n        # @param from_y [float] The y coordinate of starting drag point (type float). Mandatory parameter\n        # @param to_x [float] The x coordinate of ending drag point (type float). Mandatory parameter\n        # @param to_y [float] The y coordinate of ending drag point (type float). Mandatory parameter\n        # @option opts [Element] :element  Element id to perform drag on. All the coordinates will be calculated\n        #   relatively this this element position on the screen. Absolute screen coordinates are expected\n        #   if this argument is not set\n        #\n        #   ```ruby\n        #   drag_from_to_for_duration from_x: 100, from_y: 100, to_x: 150, to_y: 150\n        #   ```\n        def drag_from_to_for_duration(from_x:, from_y:, to_x:, to_y:, duration: 1.0, element: nil)\n          args = { fromX: from_x, fromY: from_y, toX: to_x, toY: to_y, duration: duration }\n          args[:element] = element.id if element\n          @driver.execute_script 'mobile: dragFromToForDuration', args\n        end\n        # rubocop:enable Metrics/ParameterLists\n\n        # https://github.com/facebook/WebDriverAgent/pull/523\n        # https://github.com/appium/appium-xcuitest-driver/pull/420\n        # @param order [String] The order to move picker to. \"next\" or \"previous\".\n        # @param element [Element]  Element id to perform select picker wheel on.\n        # @option opts [Integer] :offset The value in range [0.01, 0.5]. Default is 0.2 in server side.\n        #   https://github.com/facebook/WebDriverAgent/pull/549/files\n        #\n        #   ```ruby\n        #   select_picker_wheel order: \"next\", element: find_element(:accessibility_id, \"some picker\")\n        #   ```\n        def select_picker_wheel(element:, order:, offset: nil)\n          return 'Set \"next\" or \"previous\" for :order' unless %w(next previous).include?(order)\n\n          args = { element: element.id, order: order }\n          args[:offset] = offset if offset\n          @driver.execute_script 'mobile: selectPickerWheelValue', args\n        end\n\n        # @param action [String] The following actions are supported: accept, dismiss and getButtons. Mandatory parameter\n        # @param button_label [String] The label text of an existing alert button to click on.\n        #   This is an optional parameter and is only valid in combination with accept and dismiss actions.\n        # @return {} or Selenium::WebDriver::Error::NoSuchAlertError if no action sheet or alert\n        #   or button labels if action is equal to getButtons.\n        #\n        #   ```ruby\n        #   alert action: \"accept\"\n        #   alert action: \"dismiss\"\n        #   ```\n        def alert(action:, button_label: nil)\n          return 'Set \"accept\", \"dismiss\" or \"getButtons\" for :action' unless %w(accept dismiss getButtons).include?(action)\n\n          args = { action: action }\n          args[:button_label] if button_label\n          @driver.execute_script 'mobile: alert', args\n        end\n      end # module Gesture\n    end # module Xcuitest\n  end # module Ios\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/command/get_context.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Ios\n    module Xcuitest\n      # Get the contexts available, with information about the url and title of each webview\n      module GetContext\n        #\n        # Get contexts\n        #\n        # @example\n        #\n        #     xcuitest_get_contexts #=> [{ 'id' => 'NATIVE_APP' },\n        #                       # { 'id' => 'WEBVIEW_41467.1', 'title' => 'Apple', 'url' => 'https://www.apple.com/' }]\n        #\n        def xcuitest_get_contexts\n          @driver.execute_script 'mobile: getContexts', {}\n        end\n      end # module GetContext\n    end # module Xcuitest\n  end # module Ios\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/command/multi_app_handler.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Ios\n    module Xcuitest\n      # **Note** Works only for Xcode 9+.\n      # Instance methods have `xcuitest_` prefix to prevent conflicts for core commands.\n      # see: https://github.com/appium/ruby_lib_core/blob/82e2526de95b05e8a49872e0b69835e99acc66e5/lib/appium_lib_core/common/command.rb#L39\n      module MultiAppHandler\n        # Installs given application to the device under test. If the same application is already installed\n        # then it's going to be installed over it, which allows to test upgrades.\n        # Be careful while reinstalling the main application under test - make sure you called terminateApp\n        # for it first, otherwise WebDriverAgent will detect it as a potential application crash.\n        #\n        # @param [String] app The path to an existing .ipa/.app file on the server file system, zipped .app file\n        #                     or an URL pointing to a remote .ipa/.zip file. Mandatory argument.\n        # @return {}\n        #\n        # @example\n        #\n        #     xcuitest_install_app(app: \"path/to/app.app\")\n        #\n        def xcuitest_install_app(app:)\n          @driver.install_app app\n        end\n\n        # Verifies whether the application with given bundle identifier is installed on the device.\n        #\n        # @param [String] bundle_id The bundle identifier of the application, which is going to be verified.\n        # @return [boolean]\n        #\n        # @example\n        #\n        #     xcuitest_app_installed?(bundle_id: \"io.appium.bundle\") #=> true or false\n        #\n        def xcuitest_app_installed?(bundle_id:)\n          @driver.app_installed? bundle_id\n        end\n\n        # Uninstalls an existing application from the device under test. This endpoint does not verify\n        # whether the application is already installed or not before uninstalling it.\n        #\n        # @param [String] bundle_id The bundle identifier of the application, which is going to be uninstalled.\n        # @return {}\n        #\n        # @example\n        #\n        #     xcuitest_remove_app(bundle_id: \"io.appium.bundle\") #=> 1\n        #\n        def xcuitest_remove_app(bundle_id:)\n          @driver.remove_app bundle_id\n        end\n\n        # Executes an existing application on the device. If the application is already running then\n        # it will be brought to the foreground.\n        #\n        # @param [String] bundle_id The bundle identifier of the application, which is going to be executed.\n        # @return {}\n        #\n        # @example\n        #\n        #     xcuitest_launch_app(bundle_id: \"io.appium.bundle\") #=> 1\n        #\n        def xcuitest_launch_app(bundle_id:)\n          args = { bundleId: bundle_id }\n          @driver.execute_script 'mobile: launchApp', args\n        end\n\n        # Terminates an existing application on the device. If the application is not running then\n        # the returned result will be false, otherwise true.\n        #\n        # @param [String] bundle_id The bundle identifier of the application, which is going to be terminated.\n        # @return {}\n        #\n        # @example\n        #\n        #     xcuitest_terminate_app(bundle_id: \"io.appium.bundle\") #=> 1\n        #\n        def xcuitest_terminate_app(bundle_id:)\n          @driver.terminate_app bundle_id\n        end\n\n        # Get the status of an existing application on the device.\n        # State:\n        #   0: The current application state cannot be determined/is unknown\n        #   1: The application is not running\n        #   2: The application is running in the background and is suspended\n        #   3: The application is running in the background and is not suspended\n        #   4: The application is running in the foreground\n        #\n        # For more details: https://developer.apple.com/documentation/xctest/xcuiapplicationstate\n        #\n        # @param [String] bundle_id A target app's bundle id\n        # @return [0|1|2|3|4] A number of the state\n        #\n        # @example\n        #\n        #     xcuitest_query_app_status(bundle_id: \"io.appium.bundle\") #=> 1\n        #\n        def xcuitest_query_app_status(bundle_id:)\n          @driver.app_state bundle_id\n        end\n\n        # Activates an existing application on the device under test and moves it to the foreground.\n        # The application should be already running in order to activate it.\n        # The call is ignored if the application is already in foreground.\n        #\n        # @param [String] bundle_id The bundle identifier of the application, which is going to be brought to the foreground.\n        # @return {}\n        #\n        # @example\n        #\n        #     xcuitest_activate_app(bundle_id: \"io.appium.bundle\") #=> 1\n        #\n        def xcuitest_activate_app(bundle_id:)\n          @driver.activate_app bundle_id\n        end\n      end\n    end # module Xcuitest\n  end # module Ios\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/command/pasteboard.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Ios\n    module Xcuitest\n      module PasteBoard\n        # @param [string] content The content of the pasteboard. The previous content is going to be overridden.\n        #                         The parameter is mandatory\n        # @option opts [string] :encoding Encoding of the given content. UTF-8 by default.\n        #\n        #   ```ruby\n        #   set_pasteboard content: \"sample content\"\n        #   ```\n        def set_pasteboard(content:, encoding: nil)\n          args = { content: content }\n          args[:encoding] = encoding if encoding\n\n          @driver.execute_script 'mobile: setPasteboard', args\n        end\n\n        # @option opts [string] :encoding Encoding of the received pasteboard content. UTF-8 by default.\n        #\n        #   ```ruby\n        #   get_pasteboard encoding: \"shift-jis\"\n        #   ```\n        def get_pasteboard(encoding: nil)\n          args = {}\n          args[:encoding] = encoding if encoding\n\n          @driver.execute_script 'mobile: getPasteboard', args\n        end\n      end\n    end # module Xcuitest\n  end # module Ios\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/command/source.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Ios\n    module Xcuitest\n      # Instance method have `xcuitest_` prefix to prevent conflicts for core commands.\n      module Source\n        # @param [String|Symbol] format :xml or :json. :xml is by default.\n        #\n        #   ```ruby\n        #   xcuitest_source format: :json\n        #   ```\n        def xcuitest_source(format: :xml)\n          format = format.to_s if format.is_a? Symbol\n          args = { format: format }\n\n          @driver.execute_script 'mobile: source', args\n        end\n      end # module Gesture\n    end # module Xcuitest\n  end # module Ios\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/command.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nrequire_relative 'command/pasteboard'\nrequire_relative 'command/gestures'\nrequire_relative 'command/source'\nrequire_relative 'command/multi_app_handler'\nrequire_relative 'command/get_context'\n"
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/element/button.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# XCUIElementTypeButton methods\nmodule Appium\n  module Ios\n    module Xcuitest\n      module Element\n        # XCUIElementTypeButton = 'XCUIElementTypeButton'\n\n        # @return [String] Class name for button\n        def button_class\n          ::Appium::Ios::XCUIELEMENT_TYPE_BUTTON\n        end\n\n        # Find the first UIAButton|XCUIElementTypeButton that contains value or by index.\n        # @param value [String, Integer] the value to exactly match.\n        # If int then the UIAButton|XCUIElementTypeButton at that index is returned.\n        # @return [UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON]\n        def button(value)\n          # return button at index.\n          return ele_index button_class, value if value.is_a? Numeric\n\n          raise_error_if_no_element buttons(value).first\n        end\n\n        # Find all UIAButtons|XCUIElementTypeButtons containing value.\n        # If value is omitted, all UIAButtons|XCUIElementTypeButtons are returned.\n        # @param value [String] the value to search for\n        # @return [Array<UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON>]\n        def buttons(value = false)\n          return tags button_class unless value\n\n          elements = find_eles_by_predicate_include(class_name: button_class, value: value)\n          select_visible_elements elements\n        end\n\n        # Find the first UIAButton|XCUIElementTypeButton.\n        # @return [UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON]\n        def first_button\n          first_ele button_class\n        end\n\n        # TODO: add documentation regarding previous element.\n        #       Previous UIAElement is differ from UIAButton|XCUIElementTypeButton. So, the results are different.\n        # Find the last UIAButton|XCUIElementTypeButton.\n        # @return [UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON]\n        def last_button\n          last_ele button_class\n        end\n\n        # Find the first UIAButton|XCUIElementTypeButton that exactly matches value.\n        # @param value [String] the value to match exactly\n        # @return [UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON]\n        def button_exact(value)\n          raise_error_if_no_element buttons_exact(value).first\n        end\n\n        # Find all UIAButtons|XCUIElementTypeButtons that exactly match value.\n        # @param value [String] the value to match exactly\n        # @return [Array<UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON>]\n        def buttons_exact(value)\n          elements = find_eles_by_predicate(class_name: button_class, value: value)\n          select_visible_elements elements\n        end\n      end # moudule button\n    end # module Xcuitest\n  end # module Ios\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/element/generic.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Ios\n    module Xcuitest\n      module Element\n        # Find the first element containing value\n        # @param value [String] the value to search for\n        # @return [Element]\n        def find(value)\n          raise_error_if_no_element finds(value).first\n        end\n\n        # Find all elements containing value\n        # @param value [String] the value to search for\n        # @return [Array<Element>]\n        def finds(value)\n          elements = find_eles_by_predicate_include value: value\n          select_visible_elements elements\n        end\n\n        # Find the first element exactly matching value\n        # @param value [String] the value to search for\n        # @return [Element]\n        def find_exact(value)\n          raise_error_if_no_element finds_exact(value).first\n        end\n\n        # Find all elements exactly matching value\n        # @param value [String] the value to search for\n        # @return [Array<Element>]\n        def finds_exact(value)\n          elements = find_eles_by_predicate value: value\n          select_visible_elements elements\n        end\n\n        private\n\n        def raise_error_if_no_element(element)\n          error_message = 'An element could not be located on the page using the given search parameters.'\n          raise(::Selenium::WebDriver::Error::NoSuchElementError, error_message) if element.nil?\n\n          element\n        end\n\n        # Return visible elements.\n        def select_visible_elements(elements)\n          elements.select(&:displayed?)\n        end\n      end # module Element\n    end # module Xcuitest\n  end # module Ios\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/element/text.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# UIAStaticText|XCUIElementTypeStaticText methods\nmodule Appium\n  module Ios\n    module Xcuitest\n      module Element\n        # XCUIELEMENT_TYPE_STATIC_TEXT = 'XCUIElementTypeStaticText'\n\n        # @return [String] Class name for text\n        def static_text_class\n          ::Appium::Ios::XCUIELEMENT_TYPE_STATIC_TEXT\n        end\n\n        # Find the first UIAStaticText|XCUIElementTypeStaticText that contains value or by index.\n        # @param value [String, Integer] the value to find.\n        # If int then the UIAStaticText|XCUIElementTypeStaticText at that index is returned.\n        # @return [UIA_STATIC_TEXT|XCUIELEMENT_TYPE_STATIC_TEXT]\n        def text(value)\n          return ele_index static_text_class, value if value.is_a? Numeric\n\n          raise_error_if_no_element texts(value).first\n        end\n\n        # Find all UIAStaticTexts|XCUIElementTypeStaticTexts containing value.\n        # If value is omitted, all UIAStaticTexts|XCUIElementTypeStaticTexts are returned\n        # @param value [String] the value to search for\n        # @return [Array<UIA_STATIC_TEXT|XCUIELEMENT_TYPE_STATIC_TEXT>]\n        def texts(value = false)\n          return tags static_text_class unless value\n\n          elements = find_eles_by_predicate_include(class_name: static_text_class, value: value)\n          select_visible_elements elements\n        end\n\n        # Find the first UIAStaticText|XCUIElementTypeStaticText.\n        # @return [UIA_STATIC_TEXT|XCUIELEMENT_TYPE_STATIC_TEXT]\n        def first_text\n          first_ele static_text_class\n        end\n\n        # Find the last UIAStaticText|XCUIElementTypeStaticText.\n        # @return [UIA_STATIC_TEXT|XCUIELEMENT_TYPE_STATIC_TEXT]\n        def last_text\n          last_ele static_text_class\n        end\n\n        # Find the first UIAStaticText|XCUIElementTypeStaticText that exactly matches value.\n        # @param value [String] the value to match exactly\n        # @return [UIA_STATIC_TEXT|XCUIELEMENT_TYPE_STATIC_TEXT]\n        def text_exact(value)\n          raise_error_if_no_element texts_exact(value).first\n        end\n\n        # Find all UIAStaticTexts|XCUIElementTypeStaticTexts that exactly match value.\n        # @param value [String] the value to match exactly\n        # @return [Array<UIA_STATIC_TEXT|XCUIELEMENT_TYPE_STATIC_TEXT>]\n        def texts_exact(value)\n          elements = find_eles_by_predicate(class_name: static_text_class, value: value)\n          select_visible_elements elements\n        end\n      end # module Text\n    end # module XCUITest\n  end # module Ios\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/element/textfield.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Ios\n    module Xcuitest\n      module Element\n        # XCUIElementTypeTextField = 'XCUIElementTypeTextField'\n        # XCUIElementTypeSecureTextField = 'XCUIElementTypeSecureTextField'\n\n        # @return [String] Class name for text field\n        def text_field_class\n          ::Appium::Ios::XCUIELEMENT_TYPE_TEXT_FIELD\n        end\n\n        # @return [String] Class name for secure text field\n        def secure_text_field_class\n          ::Appium::Ios::XCUIELEMENT_TYPE_SECURE_TEXT_FIELD\n        end\n\n        # Find the first TextField that contains value or by index.\n        # Note: Uses XPath\n        # @param value [String, Integer] the text to match exactly.\n        # If int then the TextField at that index is returned.\n        # @return [TextField]\n        def textfield(value)\n          if value.is_a? Numeric\n            index = value\n            raise ArgumentError, \"#{index} is not a valid index. Must be >= 1\" if index <= 0\n\n            index -= 1 # eles_by_json and _textfields_with_predicate is 0 indexed.\n            result = _textfields_with_predicate[index]\n            raise _no_such_element if result.nil?\n\n            return result\n\n          end\n\n          raise_error_if_no_element textfields(value).first\n        end\n\n        # Find all TextFields containing value.\n        # If value is omitted, all TextFields are returned.\n        # @param value [String] the value to search for\n        # @return [Array<TextField>]\n        def textfields(value = false)\n          return tags_include(class_names: [text_field_class, secure_text_field_class]) unless value\n\n          elements = tags_include class_names: [text_field_class, secure_text_field_class], value: value\n          select_visible_elements elements\n        end\n\n        # Find the first TextField.\n        # @return [TextField]\n        def first_textfield\n          _textfield_with_predicate\n        end\n\n        # Find the last TextField.\n        # @return [TextField]\n        def last_textfield\n          result = _textfields_with_predicate.last\n          raise _no_such_element if result.nil?\n\n          result\n        end\n\n        # Find the first TextField that exactly matches value.\n        # @param value [String] the value to match exactly\n        # @return [TextField]\n        def textfield_exact(value)\n          raise_error_if_no_element textfields_exact(value).first\n        end\n\n        # Find all TextFields that exactly match value.\n        # @param value [String] the value to match exactly\n        # @return [Array<TextField>]\n        def textfields_exact(value)\n          elements = tags_exact class_names: [text_field_class, secure_text_field_class], value: value\n          select_visible_elements elements\n        end\n\n        private\n\n        # @private\n        # for XCUITest\n        def _textfield_with_predicate\n          raise_error_if_no_element _textfields_with_predicate.first\n        end\n\n        # @private\n        # for XCUITest\n        def _textfields_with_predicate\n          elements = tags_include(class_names: [text_field_class, secure_text_field_class])\n          select_visible_elements elements\n        end\n      end # module TextField\n    end # module XCUITest\n  end # module Ios\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/element.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nrequire_relative 'element/text'\nrequire_relative 'element/textfield'\nrequire_relative 'element/generic'\nrequire_relative 'element/button'\n\nmodule Appium\n  module Ios\n    module Xcuitest\n      module Element\n        # no\n      end # module Element\n    end # module Xcuitest\n  end # module Ios\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/ios/xcuitest/helper.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  module Ios\n    module Xcuitest\n      module Helper\n        # @private\n        def string_attr_exact(class_name, attr, value)\n          if attr == '*'\n            %((//#{class_name})[@*[.=\"#{value}\"]])\n          else\n            %((//#{class_name})[@#{attr}=\"#{value}\"])\n          end\n        end\n\n        # @private\n        def string_attr_include(class_name, attr, value)\n          if attr == '*'\n            %((//#{class_name})[@*[contains(translate(., \"#{value.upcase}\", \"#{value}\"), \"#{value}\")]])\n          else\n            %((//#{class_name})[contains(translate(@#{attr}, \"#{value.upcase}\", \"#{value}\"), \"#{value}\")])\n          end\n        end\n\n        # Get the last tag that matches class_name\n        # @param class_name [String] the tag to match\n        # @return [Element]\n        def last_ele(class_name)\n          visible_elements = tags class_name\n          raise _no_such_element if visible_elements.empty?\n\n          visible_elements.last\n        end\n\n        # Returns the first **visible** element matching class_name\n        #\n        # @param class_name [String] the class_name to search for\n        # @return [Element]\n        def tag(class_name)\n          raise_error_if_no_element tags(class_name).first\n        end\n\n        # Returns all visible elements matching class_name\n        #\n        # @param class_name [String] the class_name to search for\n        # @return [Element]\n        def tags(class_name)\n          elements = @driver.find_elements :class, class_name\n          select_visible_elements elements\n        end\n\n        # Returns all visible elements matching class_names and value\n        # This method calls find_element/s and element.value/text many times.\n        # So, if you set many class_names, this method's performance become worse.\n        #\n        # @param class_names [Array[String]] the class_names to search for\n        # @param value [String] the value to search for\n        # @return [Array[Element]]\n        def tags_include(class_names:, value: nil)\n          return unless class_names.is_a? Array\n\n          c_names = class_names.map { |class_name| %(type == \"#{class_name}\") }.join(' || ')\n\n          predicate = if value\n                        %((#{c_names}) && (name contains[c] \"#{value}\" || label contains[c] \"#{value}\" || value contains[c] \"#{value}\")) # rubocop:disable Layout/LineLength\n                      else\n                        c_names\n                      end\n\n          elements = @driver.find_elements :predicate, predicate\n          select_visible_elements elements\n        end\n\n        # Returns all visible elements matching class_names and value.\n        # This method calls find_element/s and element.value/text many times.\n        # So, if you set many class_names, this method's performance become worse.\n        #\n        # @param class_names [Array[String]] the class_names to search for\n        # @param value [String] the value to search for\n        # @return [Array[Element]]\n        def tags_exact(class_names:, value: nil)\n          return unless class_names.is_a? Array\n\n          c_names = class_names.map { |class_name| %(type == \"#{class_name}\") }.join(' || ')\n\n          predicate = if value\n                        %((#{c_names}) && (name ==[c] \"#{value}\" || label ==[c] \"#{value}\" || value ==[c] \"#{value}\"))\n                      else\n                        c_names\n                      end\n\n          elements = @driver.find_elements :predicate, predicate\n          select_visible_elements elements\n        end\n      end # module Helper\n    end # module Xcuitest\n  end # module Ios\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/ios/xcuitest.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nrequire_relative 'xcuitest/element'\nrequire_relative 'xcuitest/command'\nrequire_relative 'xcuitest/helper'\nrequire_relative 'xcuitest/bridge'\n\nmodule Appium\n  module Ios\n    module Xcuitest\n      # parent\n    end # module Xcuitest\n  end # module Ios\nend # module Appium\n"
  },
  {
    "path": "lib/appium_lib/sauce_labs.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  class SauceLabs\n    # Username for use on Sauce Labs. Set `false` to disable Sauce, even when SAUCE_USERNAME is in ENV.\n    attr_reader :username\n    # Access Key for use on Sauce Labs. Set `false` to disable Sauce, even when SAUCE_ACCESS_KEY is in ENV.\n    attr_reader :access_key\n    # Override the Sauce Appium endpoint to allow e.g. TestObject tests. Default is 'ondemand.saucelabs.com:443/wd/hub'.\n    attr_reader :endpoint\n\n    #\n    # Create a SauceLabs instance to manage sauce labs related attributes.\n    #\n    # @param [Hash] appium_lib_opts Appium library parameter\n    # @return [Appium::SauceLabs]\n    #\n    # @example\n    #\n    #   opts_blank = {}\n    #   sauce_labs_blank = Appium::SauceLabs.new(opts_blank)\n    #   sauce_labs_blank.username   #=> nil\n    #   sauce_labs_blank.access_key #=> nil\n    #   sauce_labs_blank.endpoint   #=> \"ondemand.saucelabs.com:443/wd/hub\"\n    #\n    #   opts = { sauce_username: \"user-name\",\n    #            sauce_access_key: \"access-key-to-sauce-labs\",\n    #            sauce_endpoint: \"ondemand.other_saucelabs.com:443/wd/hub\",\n    #          }\n    #   sauce_labs = Appium::SauceLabs.new(opts)\n    #   sauce_labs.username   #=> \"user-name\"\n    #   sauce_labs.access_key #=> \"access-key-to-sauce-labs\"\n    #   sauce_labs.endpoint   #=> \"ondemand.other-saucelabs.com:443/wd/hub\"\n    #\n    def initialize(appium_lib_opts)\n      @username   = appium_lib_opts.fetch :sauce_username, ENV.fetch('SAUCE_USERNAME', nil)\n      @username   = nil if !@username || (@username.is_a?(String) && @username.empty?)\n\n      @access_key = appium_lib_opts.fetch :sauce_access_key, ENV.fetch('SAUCE_ACCESS_KEY', nil)\n      @access_key = nil if !@access_key || (@access_key.is_a?(String) && @access_key.empty?)\n\n      @endpoint   = appium_lib_opts.fetch :sauce_endpoint, ENV.fetch('SAUCE_ENDPOINT', nil)\n      @endpoint   = 'ondemand.saucelabs.com:443/wd/hub' if !@endpoint || (@endpoint.is_a?(String) && @endpoint.empty?)\n    end\n\n    #\n    # Return true if an instance of Appium::SauceLabs has sauce_username and sauce_access_key.\n    # @return [Boolean]\n    #\n    # @example\n    #\n    #   sauce_labs_blank.sauce_server_url? #=> false\n    #   sauce_labs.sauce_server_url?       #=> true\n    #\n    def sauce_server_url?\n      !username.nil? && !access_key.nil?\n    end\n\n    #\n    # Return a particular server url to access to. Default is the local address.\n    # @return [String]\n    #\n    # @example\n    #\n    #   sauce_labs_blank.server_url #=> \"http://127.0.0.1:4723/wd/hub\"\n    #   sauce_labs.server_url #=> \"https://user-name:access-key-to-sauce-labs@ondemand.other-saucelabs.com:443/wd/hub\"\n    #\n    def server_url\n      sauce_server_url? ? \"https://#{username}:#{access_key}@#{endpoint}\" : 'http://127.0.0.1:4723/wd/hub'\n    end\n  end\nend\n"
  },
  {
    "path": "lib/appium_lib/version.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule Appium\n  # Version and Date are defined on the 'Appium' module, not 'Appium::Common'\n  VERSION = '16.2.0' unless defined? ::Appium::VERSION\n  DATE    = '2026-04-19' unless defined? ::Appium::DATE\nend\n"
  },
  {
    "path": "lib/appium_lib.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# Enforce UTF-8 Encoding\nEncoding.default_external = Encoding::UTF_8\nEncoding.default_internal = Encoding::UTF_8\n\nrequire 'forwardable' unless defined? Forwardable\n\n# Init global driver\n$driver = nil\n\nrequire_relative 'appium_lib/appium'\n"
  },
  {
    "path": "readme.md",
    "content": "# appium_lib\n\n[![Gem Version](https://badge.fury.io/rb/appium_lib.svg)](http://badge.fury.io/rb/appium_lib)\n\n[![Downloads](https://img.shields.io/gem/dt/appium_lib.svg)](https://rubygems.org/gems/appium_lib)\n\n- [appium_lib on RubyGems](https://rubygems.org/gems/appium_lib)\n- [Documentation for appium_lib](https://www.rubydoc.info/github/appium/ruby_lib)\n    - [Documentation for core lib](http://www.rubydoc.info/github/appium/ruby_lib_core)\n        - Especially [driver method for Appium](http://www.rubydoc.info/github/appium/ruby_lib_core/Appium/Core/Device)\n\nHelper methods for writing cross platform (iOS, Android) tests in Ruby using Appium. Note that user waits should not exceed 120 seconds if they're going to run on Sauce Labs.\n\n**Recommend** to use [ruby_lib_core](https://github.com/appium/ruby_lib_core), which works as a Ruby client for Appium. `ruby_lib` wraps the core library with some additional helpful methods, but some of wrapped methods may have unexpected complexity.\nOrdinary, `ruby_lib` worked with class driver, `$driver`, mainly.\nWe can avoid the class driver with current `ruby_lib`, but if you'd like to implement your test cases based on instance driver, `@driver`, you can consider using `ruby_lib_core` first.\n\n# Setup\n## Requirement\n- [Appium](https://github.com/appium/appium#requirements)\n- Ruby: 3.0+\n\n### Ruby Lib and Appium\n\n- Ruby library version over `12.0.0` is based on Selenium v4\n    - Please read [changelog of 12.0.0](CHANGELOG.md#1200---2021-11-06) for more details to migrate from v11 to v12\n- Ruby library version over `9.8.0` requires Appium over `1.8`\n- Ruby library version under `9.7.5` can work with Appium under `1.7`\n\n## Start appium server\n\n### Appium 2\n\n```bash\n$ npm install --location=global appium\n$ appium driver install xcuitest  # proper driver name to install\n$ appium server\n```\n\n> **Note** Please set `server_url` properly like the below for Appium v1.\n> ```\n>  opts = {\n>    caps: {\n>      automationName: 'xcuitest'\n>      platformName: 'ios',\n>      app: '/path/to/MyiOS.app'\n>    },\n>    appium_lib: {\n>      server_url: 'http://127.0.0.1:4723/wd/hub'\n>    }\n>  }\n>  appium_driver = Appium::Driver.new(opts)\n>  appium_driver.start_driver\n> ```\n\n### Appium 1\n```bash\n$ npm install -g appium\n$ appium\n```\n\n## Install / Upgrade\n\n```bash\ngem install appium_lib\n```\n\n## [Sauce Labs env vars](https://github.com/appium/ruby_lib/blob/master/lib/appium_lib/sauce_labs.rb)\n\n- `SAUCE_USERNAME` Sauce username\n- `SAUCE_ACCESS_KEY` Sauce API key\n- `SAUCE_ENDPOINT` Alternative Sauce Appium Server endpoint (only use if directed)\n\n(Note: If these variables are set, all tests will use Sauce Labs unless over-ridden in configuration.)\n\n# Documentation\n\n- [Getting started](https://github.com/appium/appium)\n- [Overview](https://github.com/appium/ruby_lib/blob/master/docs/docs.md)\n- [Ruby Android methods](https://github.com/appium/ruby_lib/blob/master/docs/android_docs.md)\n- [Ruby iOS methods](https://github.com/appium/ruby_lib/blob/master/docs/ios_docs.md)\n    - [Tips for XCUITest for iOS](https://github.com/appium/ruby_lib/blob/master/docs/ios_xcuitest.md)\n\n# Related libraries\n- [ruby_lib_core](https://github.com/appium/ruby_lib_core): Bridged commands, WebDriver dependencies\n    - We add new endpoints for Appium in the core library, and `ruby_lib` call the methods.\n- [ruby_console](https://github.com/appium/ruby_console): Appium Ruby Console\n- [appium_capybara](https://github.com/appium/appium_capybara): Gem enabling appium support in capybara\n\n# Load Pry\n`Pry.config.pager = false` is set if you have no `.pryrc` files and `Pry` is defined.\n\n# Run tests in parallel\nThis repository has examples for running tests in parallel. Read [ios_tests](https://github.com/appium/ruby_lib/tree/master/ios_tests) to see them.\n\n# Contribute\n## How to add new commands for `driver`\n- Add the new commands in [ruby_lib_core](https://github.com/appium/ruby_lib_core). [An example](https://github.com/appium/ruby_lib_core/commit/cdb02c29c8663d22d643b52fd65c8b2d1373bebb)\n\n## How to add new helpful methods\n- Add the new methods in this library\n"
  },
  {
    "path": "release_notes.md",
    "content": "#### v16.2.0 2026-04-19\n\n- [939a204](https://github.com/appium/ruby_lib/commit/939a20461738c80f9a19bb9ee8fe41030ab6c91e) Release 16.2.0\n- [324b646](https://github.com/appium/ruby_lib/commit/324b646adcf182b92cad66bd53ec8f7b1892b34f) feat: define device methods natively on Appium::Driver (#1109)\n- [5e60d97](https://github.com/appium/ruby_lib/commit/5e60d973ca74fe25af3b58ad7dcf9ce46d209b08) chore: Update rubocop requirement from 1.86.0 to 1.86.1 (#1108)\n- [76a85fd](https://github.com/appium/ruby_lib/commit/76a85fde1c05b5a479179d07e062a2ca9b18d48d) chore: Bump actions/cache from 4 to 5 (#1107)\n- [555767c](https://github.com/appium/ruby_lib/commit/555767cf885f49705cfeea8be4688f7bddb08cd7) ci: add android (#1106)\n- [59a27af](https://github.com/appium/ruby_lib/commit/59a27af6c3c2bbfd37664e59d2a9e3322250199c) feat: drop deprecated start_logs_broadcast/stop_logs_broadcast methods (#1105)\n- [4bd31dc](https://github.com/appium/ruby_lib/commit/4bd31dc1b15de6dccb80a5eb2f70e5c592af7293) chore: Update rubocop requirement from 1.85.1 to 1.86.0 (#1104)\n- [070e4e3](https://github.com/appium/ruby_lib/commit/070e4e34294e1d2a6bf57519493e4f47d96a7fae) chore: Update rubocop requirement from 1.85.0 to 1.85.1 (#1103)\n- [e624cea](https://github.com/appium/ruby_lib/commit/e624cea7ab88fd543f77d63517eb0fc4b3d138fe) chore: Bump futureware-tech/simulator-action from 4 to 5 (#1102)\n- [6192589](https://github.com/appium/ruby_lib/commit/6192589e4379e4405d6dbf0c99fb583544be996c) chore: Update rubocop requirement from 1.84.2 to 1.85.0 (#1101)\n- [211cb0b](https://github.com/appium/ruby_lib/commit/211cb0bfb746b51db6f24d27a7d1ae8153fc6937) chore: Update rubocop requirement from 1.84.1 to 1.84.2 (#1100)\n- [56e092d](https://github.com/appium/ruby_lib/commit/56e092de3ff7c4c29a2cf9f63672563f60f5457f) chore: Update rubocop requirement from 1.84.0 to 1.84.1 (#1099)\n- [858cacb](https://github.com/appium/ruby_lib/commit/858cacb2675dcfd7935bee7c8fc9dbfd6eae60c1) chore: Update rubocop requirement from 1.82.1 to 1.84.0 (#1098)\n- [0451b50](https://github.com/appium/ruby_lib/commit/0451b50e15723b649d92f4f1476d5b575ed92482) ci: add pr title check\n- [d5a27a8](https://github.com/appium/ruby_lib/commit/d5a27a8de9fcca37accd851686c6a8a90a40b374) chore: Update rubocop requirement from 1.82.0 to 1.82.1 (#1097)\n\n\n#### v16.1.1 2025-12-28\n\n- [2efaf09](https://github.com/appium/ruby_lib/commit/2efaf0937dfaf3759d370607fdea05c890df634a) Release 16.1.1\n- [121316f](https://github.com/appium/ruby_lib/commit/121316f8c74cbcdab6073c7b7cb8ef5b46f28bb6) chore: add deprecated in docstrings for start_logs_broadcast/stop_logs_broadcast (#1095)\n- [2736ab2](https://github.com/appium/ruby_lib/commit/2736ab2cb77cf7a149bd2e933f1c5af5e5e6c8cc) ci: use ruby v4 (#1094)\n- [0fe4fbc](https://github.com/appium/ruby_lib/commit/0fe4fbce26f71211e15eea11ff624b1fbeb23767) chore: Update rubocop requirement from 1.81.7 to 1.82.0 (#1093)\n- [5676f33](https://github.com/appium/ruby_lib/commit/5676f338c399cddc41f3b830d82eccd7a955466c) chore: Bump futureware-tech/simulator-action from 3 to 4 (#1092)\n- [9b7b69b](https://github.com/appium/ruby_lib/commit/9b7b69b26c20b0dd23a218d4994cac634504fb08) chore: Bump actions/setup-node from 3 to 6 (#1091)\n- [00d640d](https://github.com/appium/ruby_lib/commit/00d640dd460a013a924b27a2865d605563f44e2d) chore: Bump actions/checkout from 3 to 6 (#1090)\n- [2272004](https://github.com/appium/ruby_lib/commit/2272004b6127b49bc555bdf13a61fd8370f0adec) ci: add github actions dependabot config\n- [0ffe7d4](https://github.com/appium/ruby_lib/commit/0ffe7d48eddf59817686cf72b2811af11d7b34c3) chore: Update rubocop requirement from 1.81.6 to 1.81.7 (#1089)\n- [1b9628c](https://github.com/appium/ruby_lib/commit/1b9628c0098499e5c0c763f2f1e63578ce1a3dae) chore: Update rubocop requirement from 1.81.1 to 1.81.6 (#1088)\n- [99d15ca](https://github.com/appium/ruby_lib/commit/99d15ca8e0339da425f2cc93c360fbd1e4231453) chore: Update rubocop requirement from 1.81.0 to 1.81.1 (#1087)\n- [94f8d72](https://github.com/appium/ruby_lib/commit/94f8d72e251b3513db7c1ddd6009cef76c6b620f) chore: Update rubocop requirement from 1.80.2 to 1.81.0 (#1086)\n- [31a7747](https://github.com/appium/ruby_lib/commit/31a77475ce32fe1cfb61e8a9e5b8c9c4671603fb) chore: Update rubocop requirement from 1.80.1 to 1.80.2 (#1084)\n- [38c0dcb](https://github.com/appium/ruby_lib/commit/38c0dcb248a5cd8e458027304c6a3fb11f97cf95) ci: use newer dependencies (#1085)\n- [e925497](https://github.com/appium/ruby_lib/commit/e925497539a5cfa374a1855642bcf524f3cbdb0d) chore: Update rubocop requirement from 1.80.0 to 1.80.1 (#1083)\n- [a3b6a09](https://github.com/appium/ruby_lib/commit/a3b6a09bf6faf9ac870704b6430412113d2d9262) chore: Update rubocop requirement from 1.79.2 to 1.80.0 (#1082)\n- [dfa1010](https://github.com/appium/ruby_lib/commit/dfa10104bcd8f1e477f8aa8da5437ae89df2a330) chore: Update rubocop requirement from 1.79.1 to 1.79.2 (#1081)\n- [454dcfb](https://github.com/appium/ruby_lib/commit/454dcfb4cea592a7e295b787f2c6f9c8d78a53b1) chore: Update rubocop requirement from 1.79.0 to 1.79.1 (#1080)\n- [facc0db](https://github.com/appium/ruby_lib/commit/facc0db652c1f5d4c82d7b5be7dfdf80fba4d509) chore: Update rubocop requirement from 1.78.0 to 1.79.0 (#1079)\n- [d9df353](https://github.com/appium/ruby_lib/commit/d9df35303244433576026b17db1388a1b1135b05) chore: Update rubocop requirement from 1.77.0 to 1.78.0 (#1078)\n- [8d3b64c](https://github.com/appium/ruby_lib/commit/8d3b64c09ff623791255f93910f16f2d4c26d132) chore: Update rubocop requirement from 1.76.2 to 1.77.0 (#1077)\n- [83283a9](https://github.com/appium/ruby_lib/commit/83283a98f0e396d25d4c9b6d9eb65a14a1b043e1) chore: Update rubocop requirement from 1.76.1 to 1.76.2 (#1076)\n- [f92405a](https://github.com/appium/ruby_lib/commit/f92405a943139284ab189a50f189714e56244e9b) chore: Update rubocop requirement from 1.76.0 to 1.76.1 (#1075)\n- [a8cf9da](https://github.com/appium/ruby_lib/commit/a8cf9daa6e1703a9adef7c62e3f061ecdf345101) chore: Update rubocop requirement from 1.75.8 to 1.76.0 (#1074)\n- [1e3c2f6](https://github.com/appium/ruby_lib/commit/1e3c2f6bec7e84be3f05095ac09421be25c5f940) chore: Update rubocop requirement from 1.75.7 to 1.75.8 (#1073)\n- [48c869e](https://github.com/appium/ruby_lib/commit/48c869e660c0701cf659ca2965286070629b2cf7) chore: Update rubocop requirement from 1.75.6 to 1.75.7 (#1072)\n- [a7dbd63](https://github.com/appium/ruby_lib/commit/a7dbd63df5c19f8d0a03d8f35a22d64ac95550bf) chore: Update hashdiff requirement from ~> 1.1.0 to ~> 1.2.0 (#1071)\n- [710884d](https://github.com/appium/ruby_lib/commit/710884d4eaffa7a2d62615907934ab35e19e3639) chore: Update rubocop requirement from 1.75.5 to 1.75.6 (#1070)\n- [6e58d17](https://github.com/appium/ruby_lib/commit/6e58d17499371b8e4bfed9a57922ba9f94ca0c9f) chore: Update rubocop requirement from 1.75.4 to 1.75.5 (#1069)\n- [0398421](https://github.com/appium/ruby_lib/commit/039842150019d0e844542551ada80256ebaf18ab) chore: Update rubocop requirement from 1.75.3 to 1.75.4 (#1068)\n- [2f73e58](https://github.com/appium/ruby_lib/commit/2f73e5810cb9f4430a8baa39bfd2d959a333819a) chore: Update rubocop requirement from 1.75.2 to 1.75.3 (#1067)\n- [17b591b](https://github.com/appium/ruby_lib/commit/17b591b1e78a092431b597ba43bb7085616391ed) chore: Update rubocop requirement from 1.75.1 to 1.75.2 (#1066)\n- [b49421a](https://github.com/appium/ruby_lib/commit/b49421a28dfaa40f22e6dc45a59b85de2b27cad0) chore: Update rubocop requirement from 1.74.0 to 1.75.1 (#1065)\n\n\n#### v16.1.0 2025-03-27\n\n- [caca559](https://github.com/appium/ruby_lib/commit/caca559c1fb70d0376860a5b8590c71e33eb453f) Release 16.1.0\n- [1673d38](https://github.com/appium/ruby_lib/commit/1673d38e38fab8f510f494564810723508ff8ff7) feat: allow including ruby lib core 11 (#1064)\n\n\n#### v16.0.1 2025-03-16\n\n- [97de309](https://github.com/appium/ruby_lib/commit/97de309bd6a60b22e2937b51086f7e7491e035cc) Release 16.0.1\n- [8a0bc17](https://github.com/appium/ruby_lib/commit/8a0bc17f0352f158cbb80c44676f90ec1b57e287) chore: allow appium lib core to use 10\n- [ea9f6ab](https://github.com/appium/ruby_lib/commit/ea9f6ab852896a43e01c57ea608334806cc8834f) chore: Update rubocop requirement from 1.73.2 to 1.74.0 (#1062)\n- [7ed65df](https://github.com/appium/ruby_lib/commit/7ed65dfbbacba5093476139629bd828e1b9f67a9) chore: Update rubocop requirement from 1.73.0 to 1.73.2 (#1061)\n- [7c1f16c](https://github.com/appium/ruby_lib/commit/7c1f16c7f3441879c7c1836c4a63336e276da066) chore: Update rubocop requirement from 1.72.2 to 1.73.0 (#1059)\n- [2524c42](https://github.com/appium/ruby_lib/commit/2524c42c626473bdfac846905e42eabf889570bd) chore: Update rubocop requirement from 1.72.1 to 1.72.2 (#1058)\n- [7294b88](https://github.com/appium/ruby_lib/commit/7294b887dd744e107217840144ead4e4a137f9bc) chore: Update rubocop requirement from 1.71.2 to 1.72.1 (#1056)\n\n\n#### v16.0.0 2025-02-16\n\n- [f260936](https://github.com/appium/ruby_lib/commit/f26093663056bee2c170d74283928b517d5071dc) Release 16.0.0\n- [134af92](https://github.com/appium/ruby_lib/commit/134af92efc674377940c82d7f819b4eb98816653) feat: drop `/wd/hub` from the default url config (#1055)\n- [1f7f8cb](https://github.com/appium/ruby_lib/commit/1f7f8cb82ad6499421125d1ca1aabb601af5a869) chore: Update rubocop requirement from 1.71.1 to 1.71.2 (#1054)\n- [fcfc777](https://github.com/appium/ruby_lib/commit/fcfc777eef0b4909896506b83ceeef02702e9811) chore: Update rubocop requirement from 1.71.0 to 1.71.1 (#1053)\n- [34f0695](https://github.com/appium/ruby_lib/commit/34f069526befbd9d449bea27aae0bd2172557abe) chore: Update rubocop requirement from 1.70.0 to 1.71.0 (#1052)\n- [c48681c](https://github.com/appium/ruby_lib/commit/c48681cdc6ccceda612b735457b4496946eab8c6) chore: Update fakefs requirement from ~> 2.8.0 to ~> 3.0.0 (#1050)\n\n\n#### v15.3.0 2025-01-22\n\n- [030f83b](https://github.com/appium/ruby_lib/commit/030f83ba4d48480f3ac664d0029dc1aae7b90d7d) Release 15.3.0\n- [8befdbe](https://github.com/appium/ruby_lib/commit/8befdbe07d9d415ee04a09096326e670e901be20) feat: bump mini Ruby version to 3.1 by following core (#1051)\n- [35edaf4](https://github.com/appium/ruby_lib/commit/35edaf4b9cfdda5b0f18b91189cf04d6c714356c) chore: Update rubocop requirement from = 1.69.2 to = 1.70.0 (#1049)\n- [c45abdf](https://github.com/appium/ruby_lib/commit/c45abdfc2423e3fc0fb9d7b347751cc61dc65295) chore: Update rubocop requirement from = 1.69.1 to = 1.69.2 (#1048)\n- [9776747](https://github.com/appium/ruby_lib/commit/97767471108d7270e74255fcc1ffc1bd04c1a895) chore: Update fakefs requirement from ~> 2.7.1 to ~> 2.8.0 (#1047)\n- [961bc02](https://github.com/appium/ruby_lib/commit/961bc02c359ff05c75802e6d313e08cb4d24e09e) chore: Update fakefs requirement from ~> 2.5.0 to ~> 2.7.1 (#1046)\n- [93cffb5](https://github.com/appium/ruby_lib/commit/93cffb5547756dc76ba6897350877446410464ec) chore: Update rubocop requirement from = 1.69.0 to = 1.69.1 (#1045)\n- [304f953](https://github.com/appium/ruby_lib/commit/304f953f8eb0514a145360ea885722860791ac36) chore: Update rubocop requirement from = 1.68.0 to = 1.69.0 (#1044)\n- [e47c764](https://github.com/appium/ruby_lib/commit/e47c764fe6d581006731549dce49f5e0cd2312c1) chore: Update rubocop requirement from = 1.67.0 to = 1.68.0 (#1043)\n- [40db502](https://github.com/appium/ruby_lib/commit/40db502c68586af5c9acac988fdbbb04e9a5899b) chore: Update rubocop requirement from = 1.66.1 to = 1.67.0 (#1042)\n- [87da90b](https://github.com/appium/ruby_lib/commit/87da90b00bb98e5a76b4a7fb3312965fe7abb644) chore: Update rubocop requirement from = 1.66.0 to = 1.66.1 (#1041)\n- [57a1e79](https://github.com/appium/ruby_lib/commit/57a1e7903ca31ee5a7ff3d37f98d51f9abf591d1) chore: Update rubocop requirement from = 1.65.1 to = 1.66.0 (#1040)\n\n\n#### v15.2.2 2024-08-06\n\n- [08ac85a](https://github.com/appium/ruby_lib/commit/08ac85ace5a451886431f10367f544708a792954) Release 15.2.2\n- [b741383](https://github.com/appium/ruby_lib/commit/b74138352b7f274d89e0af36efe3d65a574ed502) fix: non-app capability handling (#1039)\n\n\n#### v15.2.1 2024-08-03\n\n- [693dc16](https://github.com/appium/ruby_lib/commit/693dc167cbbcbe1ab08d1142958207d635c480a3) Release 15.2.1\n- [d98126c](https://github.com/appium/ruby_lib/commit/d98126c47e04d7d152f85a2a75c3fdcb3011ae96) ci: add ci (#1037)\n- [fd2e639](https://github.com/appium/ruby_lib/commit/fd2e639b62e9b5c533915e7e860621391479c4aa) chore: modify rubocop.yml a bit\n- [0d1c2b8](https://github.com/appium/ruby_lib/commit/0d1c2b87b8f2ac456372bf4cbb2441fffae5cf27) chore: Update rubocop requirement from = 1.65.0 to = 1.65.1 (#1036)\n\n\n#### v15.2.0 2024-07-20\n\n- [d73525e](https://github.com/appium/ruby_lib/commit/d73525eec584c3c31690dcd55a6c52d641d43f9f) Release 15.2.0\n- [6b5d969](https://github.com/appium/ruby_lib/commit/6b5d9693f10e64a521f6ac5d31c78d71e5f0f6be) feat: raise its own defined errors (#1035)\n- [4a74c60](https://github.com/appium/ruby_lib/commit/4a74c60937e66bf028a66e4f05a324ce8b2077ce) chore: Update rubocop requirement from = 1.64.1 to = 1.65.0 (#1034)\n- [fa4cea4](https://github.com/appium/ruby_lib/commit/fa4cea4e5bea0aa4e3ed7052ba77812c82684fe0) chore: Update rubocop requirement from = 1.64.0 to = 1.64.1 (#1033)\n- [96ce262](https://github.com/appium/ruby_lib/commit/96ce26264d985b5260e99573486e8f712bfb12e3) chore: Update rubocop requirement from = 1.63.5 to = 1.64.0 (#1032)\n- [14590cc](https://github.com/appium/ruby_lib/commit/14590cce6f6cbef8c20e12ae10b00bf3f7b5ab3a) chore: tweak changelog format\n\n\n#### v15.1.0 2024-05-19\n\n- [b1534cc](https://github.com/appium/ruby_lib/commit/b1534cc8e781e37f9632fa1cbaa6e2422b6a768d) Release 15.1.0\n- [f6cc482](https://github.com/appium/ruby_lib/commit/f6cc482e6bcf75cd4388911355700e31da74b578) chore: tweak deps\n- [c034ec5](https://github.com/appium/ruby_lib/commit/c034ec5cb74e442db6db4cfc8365a43c903cbbfc) feat: update ruby lib core to v9 (#1030)\n- [50bca8f](https://github.com/appium/ruby_lib/commit/50bca8f8acd2c4c144684cd33dd0ea9787a40bf5) chore: Update rubocop requirement from = 1.63.4 to = 1.63.5 (#1028)\n- [415b3c6](https://github.com/appium/ruby_lib/commit/415b3c6b52e28f3b43cdd95a0684b1e9aadc0ae8) chore: Update rubocop requirement from = 1.63.3 to = 1.63.4 (#1027)\n- [7461e6a](https://github.com/appium/ruby_lib/commit/7461e6a44569245b6dbd1b352f3ff76503bb1bbb) docs: remove no longer used docs\n- [66e323c](https://github.com/appium/ruby_lib/commit/66e323c08dbc9616366e55ebf3835530549edf37) chore: remove unused docs_block\n\n\n#### v15.0.1 2024-04-26\n\n- [3ab38a7](https://github.com/appium/ruby_lib/commit/3ab38a7339bf077dd85d9b700f08ddfe2ca608e5) Release 15.0.1\n- [720dfdd](https://github.com/appium/ruby_lib/commit/720dfdd31f0feacf5926f668ff15e521920e360c) chore: bump thor and remove unused posix\n- [c869327](https://github.com/appium/ruby_lib/commit/c869327d50d2046a2c45e3a360b8667e006f9f56) chore: Update rubocop requirement from = 1.63.2 to = 1.63.3 (#1026)\n- [6543765](https://github.com/appium/ruby_lib/commit/65437658a89b234fbc431246266a383a0988009a) chore: Update rubocop requirement from = 1.63.1 to = 1.63.2 (#1025)\n- [2b428b5](https://github.com/appium/ruby_lib/commit/2b428b5e714e83ee283bce993fd3eba61827a287) chore: Update rubocop requirement from = 1.63.0 to = 1.63.1 (#1024)\n\n\n#### v15.0.0 2024-04-11\n\n- [203a605](https://github.com/appium/ruby_lib/commit/203a6052db42039c89cd000f245f1534379bc86b) Release 15.0.0\n- [7ab9f44](https://github.com/appium/ruby_lib/commit/7ab9f442ee9a9d22ad021316171e6824628eeb99) chore: Update rubocop requirement from = 1.62.1 to = 1.63.0 (#1023)\n- [ad20d82](https://github.com/appium/ruby_lib/commit/ad20d828e8124f37c3ab3055c744c2c76c74f563) ci: add 3.3\n- [df9752c](https://github.com/appium/ruby_lib/commit/df9752c5176db395e7a427a77c4755293ff75cee) feat: remove \"spec\" deps (#1022)\n- [c5a7216](https://github.com/appium/ruby_lib/commit/c5a7216c005bb819ff7bc3fe313e7400777b9587) test: add empty test code (#1021)\n- [c450c20](https://github.com/appium/ruby_lib/commit/c450c20bae801e2f9f9ce66a9df2e352a614f73f) feat: bump ruby lib core v8 (#1018)\n- [9d40e0e](https://github.com/appium/ruby_lib/commit/9d40e0e2c2cbe571fd788c12565b3cb3d92f16a4) chore: Update rubocop requirement from = 1.62.0 to = 1.62.1 (#1020)\n- [98861af](https://github.com/appium/ruby_lib/commit/98861af3d779ce288937344a63aec7cbefed9db1) chore: Update rubocop requirement from = 1.61.0 to = 1.62.0 (#1017)\n- [1b385bc](https://github.com/appium/ruby_lib/commit/1b385bc2bab3f45d38a4f58e8c79ddbbe58d5596) chore: Update rubocop requirement from = 1.60.2 to = 1.61.0 (#1016)\n- [612d944](https://github.com/appium/ruby_lib/commit/612d944fc60b202d3e24c7e052004cef1b69c8d0) chore: Update rubocop requirement from = 1.60.1 to = 1.60.2 (#1013)\n\n\n#### v14.0.0 2024-01-25\n\n- [50cf980](https://github.com/appium/ruby_lib/commit/50cf980b570acd7d2d95ea64d1d1b0225f96c73b) Release 14.0.0\n- [978ed76](https://github.com/appium/ruby_lib/commit/978ed769120338d817fd69dadeb3894549021245) bump the major version as deprecation code removal\n- [ea3cc5d](https://github.com/appium/ruby_lib/commit/ea3cc5d41653f1df4b8bdad1ec36f142c1430e47) feat: remove deprecated export_session (#1015)\n\n\n#### v13.0.2 2024-01-25\n\n- [9c52fd3](https://github.com/appium/ruby_lib/commit/9c52fd3a8f0ef88d7c4e83f210ab22f817a30632) Release 13.0.2\n- [d14669e](https://github.com/appium/ruby_lib/commit/d14669ebfe091f06e5c248787c753419cee9ed6f) chore: restrict the ruby core version (#1014)\n- [202718c](https://github.com/appium/ruby_lib/commit/202718ca86a99a3443510c9992f21752c090136c) chore: Update rubocop requirement from = 1.60.0 to = 1.60.1 (#1011)\n- [4e93dce](https://github.com/appium/ruby_lib/commit/4e93dce9d7c4d86fb568ca60cfb8d9918f3b20f6) chore: Update rubocop requirement from = 1.59.0 to = 1.60.0 (#1010)\n- [cb2f421](https://github.com/appium/ruby_lib/commit/cb2f42108c600752b120e06917eea3b0a15f2b6f) chore: Update hashdiff requirement from ~> 1.0.0 to ~> 1.1.0 (#1009)\n- [7342c05](https://github.com/appium/ruby_lib/commit/7342c055090e49f03a8c5d5229c1d795d0c60fd5) chore: Update rubocop requirement from = 1.58.0 to = 1.59.0 (#1008)\n- [033eb4f](https://github.com/appium/ruby_lib/commit/033eb4f70cf5a6a5ba015bb86c1f61f2c4ca341e) chore: Update rubocop requirement from = 1.57.2 to = 1.58.0 (#1007)\n- [d3b9c56](https://github.com/appium/ruby_lib/commit/d3b9c56bfa5dbf9939499bd9d1b10639914a4a46) chore: Update rubocop requirement from = 1.57.1 to = 1.57.2 (#1006)\n- [fd8e103](https://github.com/appium/ruby_lib/commit/fd8e103a507e7c6a1815cfb0b590c84cedb8caca) chore: Update rubocop requirement from = 1.57.0 to = 1.57.1 (#1005)\n- [5d3e809](https://github.com/appium/ruby_lib/commit/5d3e809d1e7c05b276b5e19a05822204d4d852fb) chore: Update rubocop requirement from = 1.56.4 to = 1.57.0 (#1004)\n- [e6383f8](https://github.com/appium/ruby_lib/commit/e6383f84c723e08db670bd2b59f88d07da210eb5) chore: Update rubocop requirement from = 1.56.2 to = 1.56.4 (#1003)\n- [c37e87f](https://github.com/appium/ruby_lib/commit/c37e87f6b50e71e99bccf2c3601def497412482c) chore: Update rubocop requirement from = 1.56.1 to = 1.56.2 (#1001)\n- [ee96909](https://github.com/appium/ruby_lib/commit/ee969091251d3fb5ace65ef2d0f0d543880bb4dd) chore: Update rubocop requirement from = 1.56.0 to = 1.56.1 (#1000)\n- [4282704](https://github.com/appium/ruby_lib/commit/42827044578a215ac8cd024f15e56ccfb075a760) chore: Update rubocop requirement from = 1.55.1 to = 1.56.0 (#999)\n- [2083158](https://github.com/appium/ruby_lib/commit/20831586a664e39b51e953fc755860b5d1255a9a) chore: Update rubocop requirement from = 1.55.0 to = 1.55.1 (#998)\n- [7807e5d](https://github.com/appium/ruby_lib/commit/7807e5d2de3803c08a480d2e760b0d7d8957b06d) chore: Update rubocop requirement from = 1.54.2 to = 1.55.0 (#997)\n- [093449f](https://github.com/appium/ruby_lib/commit/093449fbf31eb8751b9c07affa2d4204312bd887) docs: readme.md\n- [e156bbd](https://github.com/appium/ruby_lib/commit/e156bbd5ef012db7a2c0472a7a51764a592b25a6) chore: add CODEOWNERS\n- [00a5b5d](https://github.com/appium/ruby_lib/commit/00a5b5dcef0a3bf53ed52f19ce765ffc9d22990e) chore: Update rubocop requirement from = 1.53.1 to = 1.54.2 (#996)\n- [d5c1caa](https://github.com/appium/ruby_lib/commit/d5c1caad5f2f91f6ecf66dfe137a54ee6693fb22) chore: Update rubocop requirement from = 1.53.0 to = 1.53.1 (#993)\n- [6aa7001](https://github.com/appium/ruby_lib/commit/6aa70019fd7d33fdbc35b292a640708f3a98a6e1) chore: Update rubocop requirement from = 1.52.1 to = 1.53.0 (#992)\n\n\n#### v13.0.1 2023-06-19\n\n- [777e15d](https://github.com/appium/ruby_lib/commit/777e15d7c0a727cbe25b1e51a3ba7a68759a12db) Release 13.0.1\n- [d6a2afe](https://github.com/appium/ruby_lib/commit/d6a2afede2c39f242a47e995efe2ff047afe35cd) chore: Update appium_lib_core requirement from ~> 6.0 to >= 6, < 8 (#991)\n\n\n#### v13.0.0 2023-06-18\n\n- [a5add59](https://github.com/appium/ruby_lib/commit/a5add59a76fd88883c323566387c03b95a6db265) Release 13.0.0\n- [7af0cde](https://github.com/appium/ruby_lib/commit/7af0cdeab1afa8832cf7725fb14705f49b1fa1dd) feat: drop Ruby 2.7 (#990)\n- [2a3bee4](https://github.com/appium/ruby_lib/commit/2a3bee4ce4ebd82a6e8e27923332ec50c8252de5) chore: Update rubocop requirement from = 1.52.0 to = 1.52.1 (#989)\n- [669beaa](https://github.com/appium/ruby_lib/commit/669beaa5734d34ea5f6af4ccf345d594ba52225f) chore: Update rubocop requirement from = 1.51.0 to = 1.52.0 (#988)\n- [b96709e](https://github.com/appium/ruby_lib/commit/b96709e9b0833bfe898b35326564bfa8a819ac2a) chore: Update fakefs requirement from ~> 2.4.0 to ~> 2.5.0 (#987)\n- [d075903](https://github.com/appium/ruby_lib/commit/d075903ff5586a996a6775a3fbe938765c66c50c) chore: Update rubocop requirement from = 1.50.2 to = 1.51.0 (#986)\n\n\n#### v12.2.2 2023-04-27\n\n- [2f3ac2d](https://github.com/appium/ruby_lib/commit/2f3ac2df0e770e033076429059f5b96dde0565b5) Release 12.2.2\n- [aba17f0](https://github.com/appium/ruby_lib/commit/aba17f0ba8d91e070ad37ad6e1cf2dde60da3ef9) fix: tune quit in start_driver to not raise an exception there (#985)\n\n\n#### v12.2.1 2023-04-24\n\n- [8e93297](https://github.com/appium/ruby_lib/commit/8e932971b216be735290757d1885498e8d57347f) Release 12.2.1\n- [a47a7ad](https://github.com/appium/ruby_lib/commit/a47a7ad905ce36b94568cdf54b45eeeffd3eaad5) docs: remove travis badge\n- [a93d286](https://github.com/appium/ruby_lib/commit/a93d286106d706ef5bb6d97680542b2f79483d4f) fix default_wait value (#983)\n- [712ab14](https://github.com/appium/ruby_lib/commit/712ab14dd6d798962b228da831bebd20f2c73403) chore: Update rubocop requirement from = 1.49.0 to = 1.50.2 (#982)\n- [363067e](https://github.com/appium/ruby_lib/commit/363067edd60ba9d557c37d4153398000f5447067) chore: Update rubocop requirement from = 1.48.1 to = 1.49.0 (#979)\n- [779cbc0](https://github.com/appium/ruby_lib/commit/779cbc020f10fb405c3b02a96a1215864a571028) chore: Update rubocop requirement from = 1.47.0 to = 1.48.1 (#978)\n- [225c510](https://github.com/appium/ruby_lib/commit/225c510042ccc1e32ed716b8fa4f6b617ebd409f) chore: Update rubocop requirement from = 1.46.0 to = 1.47.0 (#976)\n- [9715260](https://github.com/appium/ruby_lib/commit/9715260e2d752b3967cbfb2f052c4693d883f634) chore: Update rubocop requirement from = 1.45.1 to = 1.46.0 (#975)\n- [1fd3bf7](https://github.com/appium/ruby_lib/commit/1fd3bf7988d54e3cbf9be4cdd8a2ffef0ffffb6a) core#quit_driver is deprecated use core.driver.quit (#973)\n- [3850ae2](https://github.com/appium/ruby_lib/commit/3850ae2b3fc2e09389ba04cbf741369aab37f7c1) chore: Update fakefs requirement from ~> 2.3.0 to ~> 2.4.0 (#972)\n- [a4d1808](https://github.com/appium/ruby_lib/commit/a4d1808c381165559d8efd453337cfe2a0f5262d) chore: Update fakefs requirement from ~> 2.2.0 to ~> 2.3.0 (#971)\n- [a913380](https://github.com/appium/ruby_lib/commit/a9133804acc497ac72a48644bba3b77afb7a71b7) chore: Update fakefs requirement from ~> 2.0.0 to ~> 2.2.0 (#970)\n- [129bebb](https://github.com/appium/ruby_lib/commit/129bebb79c9eab5933bf10f76a56540a6995fffc) chore: Update rubocop requirement from = 1.44.1 to = 1.45.1 (#969)\n- [1781671](https://github.com/appium/ruby_lib/commit/17816716ee3f7bdcae8eeb24a4dc279735929524) chore: Update rubocop requirement from = 1.44.0 to = 1.44.1 (#968)\n- [852af7d](https://github.com/appium/ruby_lib/commit/852af7d2cbf08408f541bb7850a6bfef7b6270b6) chore: Update rubocop requirement from = 1.43.0 to = 1.44.0 (#967)\n- [06a3194](https://github.com/appium/ruby_lib/commit/06a3194c3e57006f8ac957b3aca2eeb2bf640d9f) chore: Update rubocop requirement from = 1.42.0 to = 1.43.0 (#966)\n- [a19f211](https://github.com/appium/ruby_lib/commit/a19f211a7ed0030de0b243db62c4be297cb584cb) chore: Update fakefs requirement from ~> 1.9.0 to ~> 2.0.0 (#965)\n- [9ea6c91](https://github.com/appium/ruby_lib/commit/9ea6c9126a90a405beb4d1bd86eebc4652db5698) chore: Update rubocop requirement from = 1.41.1 to = 1.42.0 (#964)\n\n\n#### v12.2.0 2022-12-25\n\n- [83c756d](https://github.com/appium/ruby_lib/commit/83c756d67c3f19deff6e9270856e0889f3de8b9b) Release 12.2.0\n- [e963c02](https://github.com/appium/ruby_lib/commit/e963c025630cb8eaab6dcdf47b1a9b402db98541) chore: bump the ruby core ver (#963)\n- [ce80e17](https://github.com/appium/ruby_lib/commit/ce80e17369268be2c8da2a7007a8f5173c144404) chore: remove  non-xuitest stuff (#960)\n- [7011c05](https://github.com/appium/ruby_lib/commit/7011c05ccd14bbdb92652be8ec811d5c04c9dcc7) chore: Update rubocop requirement from = 1.41.0 to = 1.41.1 (#962)\n- [18dc444](https://github.com/appium/ruby_lib/commit/18dc44429aba30dc675e0be020699790aa0f41ec) chore: Update rubocop requirement from = 1.40.0 to = 1.41.0 (#961)\n\n\n#### v12.1.3 2022-12-13\n\n- [65f8b1c](https://github.com/appium/ruby_lib/commit/65f8b1c4406f358bf4a44ef0d4d7ae429ddc23c4) Release 12.1.3\n- [4b95151](https://github.com/appium/ruby_lib/commit/4b95151ade73494304fa9c07aca465d54e779a24) feat: do not use deprecated methods (#959)\n- [56b9d06](https://github.com/appium/ruby_lib/commit/56b9d06bb3ee94919b48d7b3c216ffe244ba6730) chore: Update rubocop requirement from = 1.39.0 to = 1.40.0 (#958)\n- [19e0b0c](https://github.com/appium/ruby_lib/commit/19e0b0c51bde24cf1522ed27f74cfad913b46a67) chore: Update fakefs requirement from ~> 1.8.0 to ~> 1.9.0 (#957)\n- [40786c1](https://github.com/appium/ruby_lib/commit/40786c1aabbe464003a393abf22e7e8dd105816c) chore: Update rubocop requirement from = 1.38.0 to = 1.39.0 (#956)\n\n\n#### v12.1.2 2022-11-13\n\n- [c3330bd](https://github.com/appium/ruby_lib/commit/c3330bd208d4aba2cdc616f5ca4ac23a3ec4790a) Release 12.1.2\n- [40ca5c8](https://github.com/appium/ruby_lib/commit/40ca5c8a200638e145f71c27b320d19d1f3f63db) fix: non app in the caps by toml (#955)\n- [b953b30](https://github.com/appium/ruby_lib/commit/b953b30c854232d11628ef894a8d6d43f8b59883) chore: Update rubocop requirement from = 1.37.1 to = 1.38.0 (#954)\n- [a62597a](https://github.com/appium/ruby_lib/commit/a62597a5b0c7ff0a593e7fecaec66729b44ef78e) chore: Update rubocop requirement from = 1.37.0 to = 1.37.1 (#953)\n- [049ac4e](https://github.com/appium/ruby_lib/commit/049ac4ec86399fe5406b6b0ca336ac0e2a8c2735) chore: Update rubocop requirement from = 1.36.0 to = 1.37.0 (#952)\n\n\n#### v12.1.1 2022-10-19\n\n- [83c89c1](https://github.com/appium/ruby_lib/commit/83c89c107ea0e030b7eae2d8ab664c38766df6ed) Release 12.1.1\n- [e40222d](https://github.com/appium/ruby_lib/commit/e40222d66f497fe295aea982ef0c042b901f6e3f) fix: use warn (#951)\n- [a9b7558](https://github.com/appium/ruby_lib/commit/a9b75583e9923ade4f4fd16cb7fad03cc0f7c1be) docs: tweak\n- [600f867](https://github.com/appium/ruby_lib/commit/600f8670f97d91babfd84e1c6c1ef34d2682b883) docs: updating (#950)\n- [a81ea4b](https://github.com/appium/ruby_lib/commit/a81ea4b2a74ea71fa62c1756ffea2f85da57d49b) docd: udpate readme\n- [8f20fe1](https://github.com/appium/ruby_lib/commit/8f20fe12b728195a8d2eb7d39004de4075caeff8) Release 12.1.0\n- [b00662a](https://github.com/appium/ruby_lib/commit/b00662a3976aeadc8d5385fd00129fb9dafa967c) chore: specify latest core\n- [98a3c6b](https://github.com/appium/ruby_lib/commit/98a3c6b9720eeff74f6eefda6e54196477854ed3) feat: update the minimal ruby lib core version (#946)\n- [45a2194](https://github.com/appium/ruby_lib/commit/45a21942311ed4e5b88df3ad9ddb540693422b5e) docs: update the readme\n- [c29cf02](https://github.com/appium/ruby_lib/commit/c29cf0284041f449dc594248cadf47bf7ca074ae) chore: Update rubocop requirement from = 1.35.1 to = 1.36.0 (#944)\n- [26ff210](https://github.com/appium/ruby_lib/commit/26ff21044030eb833c5c167026834f8a522c1a7c) chore: Update rubocop requirement from = 1.35.0 to = 1.35.1 (#941)\n- [1984bd0](https://github.com/appium/ruby_lib/commit/1984bd09e4fa55a41b9c1cf22ae9c4fffa51b149) chore: Update rubocop requirement from = 1.34.1 to = 1.35.0 (#940)\n- [71f889b](https://github.com/appium/ruby_lib/commit/71f889b2671696244609d2ce970dc602be28644a) chore: Update rubocop requirement from = 1.34.0 to = 1.34.1 (#939)\n- [6d4c02d](https://github.com/appium/ruby_lib/commit/6d4c02d0f8d59d5debe60d782260bf1b2e4b80ad) chore: Update rubocop requirement from = 1.33.0 to = 1.34.0 (#938)\n- [6d10490](https://github.com/appium/ruby_lib/commit/6d104904974798e187fc07ad6f98875c09368ca7) chore: Update rubocop requirement from = 1.32.0 to = 1.33.0 (#937)\n- [0144c9c](https://github.com/appium/ruby_lib/commit/0144c9c9d7331e5384de0a528eedf82be98affbd) chore: Update rubocop requirement from = 1.31.2 to = 1.32.0 (#936)\n- [6d08328](https://github.com/appium/ruby_lib/commit/6d083282eb0f04dc70453d5290af2eb6f3d5da90) chore: Update rubocop requirement from = 1.31.1 to = 1.31.2 (#934)\n- [8554315](https://github.com/appium/ruby_lib/commit/8554315055cb5742cb8251e087a7e6d0cc3b7504) chore: Update rubocop requirement from = 1.31.0 to = 1.31.1 (#933)\n- [50b76c6](https://github.com/appium/ruby_lib/commit/50b76c6713d5ae1134dbe7f2d5cfae95df9dede6) chore: Update rubocop requirement from = 1.30.1 to = 1.31.0 (#932)\n- [b55c2a5](https://github.com/appium/ruby_lib/commit/b55c2a58e5ea0ffc215e43dc8e1b28a99c7be372) chore: Update fakefs requirement from ~> 1.7.0 to ~> 1.8.0 (#931)\n- [7c501bc](https://github.com/appium/ruby_lib/commit/7c501bc47f8a40bf83088a43af2892d46cef561c) chore: Update fakefs requirement from ~> 1.5.0 to ~> 1.7.0 (#930)\n- [574e3c4](https://github.com/appium/ruby_lib/commit/574e3c4acc9f38419250aa3a046143acc8d55a75) chore: Update rubocop requirement from = 1.30.0 to = 1.30.1 (#929)\n- [0dacfea](https://github.com/appium/ruby_lib/commit/0dacfea1924f953ae8c6328c97065dcdb6b372d7) chore: Update rubocop requirement from = 1.29.1 to = 1.30.0 (#928)\n- [cf368c8](https://github.com/appium/ruby_lib/commit/cf368c848a76cf5a86c26f006cd4ff412f1f8a86) chore: Update fakefs requirement from ~> 1.4.0 to ~> 1.5.0 (#927)\n- [2e9190a](https://github.com/appium/ruby_lib/commit/2e9190aa8905c3d06adcc16a87209f3841e4cdc4) chore: Update rubocop requirement from = 1.29.0 to = 1.29.1 (#926)\n- [99360fb](https://github.com/appium/ruby_lib/commit/99360fb8b0aab56fc3eb6e903cf89e10bbd8b78b) chore: Update rubocop requirement from = 1.28.2 to = 1.29.0 (#925)\n- [9bf18ce](https://github.com/appium/ruby_lib/commit/9bf18ce0365f4c677d81d83b3a33ef7125a8e1dd) chore: Update rubocop requirement from = 1.28.1 to = 1.28.2 (#924)\n- [d7a5983](https://github.com/appium/ruby_lib/commit/d7a598369c0e28f8924e04aaa6d2159662fa710f) chore: Update rubocop requirement from = 1.28.0 to = 1.28.1 (#923)\n- [e33f440](https://github.com/appium/ruby_lib/commit/e33f4408ccf28564316196b9555b23aaa83d9b5e) chore: Update rubocop requirement from = 1.27.0 to = 1.28.0 (#922)\n- [e598c26](https://github.com/appium/ruby_lib/commit/e598c2681c565c8d52338c6bb544374df5c3729b) chore: Update rubocop requirement from = 1.26.1 to = 1.27.0 (#921)\n\n\n#### v12.0.1 2022-04-02\n\n- [ae4bddd](https://github.com/appium/ruby_lib/commit/ae4bddd7ba5bf3aafe8fedc44919bb02b4f260be) Release 12.0.1\n- [a5d4c4f](https://github.com/appium/ruby_lib/commit/a5d4c4f08cd3fc5d2ca575595f0741b4d22bf7b9) fix: remove the method and define again instead (#920)\n- [484006b](https://github.com/appium/ruby_lib/commit/484006b903c6bc15b5ce1767cf9c407c978afab9) docs: tweak\n- [e22140e](https://github.com/appium/ruby_lib/commit/e22140e970ddb5975e16a5d4f46b1d9a29da2c31) chore: Update rubocop requirement from = 1.26.0 to = 1.26.1 (#919)\n- [a900972](https://github.com/appium/ruby_lib/commit/a9009728f9cee8a432fe6d1b0cd7caf1e77b0106) chore: Update rubocop requirement from = 1.25.1 to = 1.26.0 (#918)\n- [923ba1c](https://github.com/appium/ruby_lib/commit/923ba1ca8602fd404090efef09174166794ce074) chore: Update rubocop requirement from = 1.25.0 to = 1.25.1 (#916)\n- [0dc8e19](https://github.com/appium/ruby_lib/commit/0dc8e19a2c481c3d6dea3be4e309f0aafd256656) chore: Update rubocop requirement from = 1.24.1 to = 1.25.0 (#915)\n- [b02bb65](https://github.com/appium/ruby_lib/commit/b02bb653dfc8ff7c770155b7c4c8d6afaecd8a5c) chore: Update rubocop requirement from = 1.24.0 to = 1.24.1 (#914)\n- [b6ade8d](https://github.com/appium/ruby_lib/commit/b6ade8d5cca1260071c236566e660e41b65aa118) chore: Update appium_lib_core requirement from ~> 5.0.0 to >= 5.0, < 5.2 (#913)\n- [eac87a4](https://github.com/appium/ruby_lib/commit/eac87a4cc8bf55bfe6fc8820ff947713042c79a4) chore: Update rubocop requirement from = 1.23.0 to = 1.24.0 (#912)\n- [ac25f13](https://github.com/appium/ruby_lib/commit/ac25f13f7c36017c13449b5038b2f698806ee1eb) chore: Update rubocop requirement from = 1.22.3 to = 1.23.0 (#911)\n\n\n#### v12.0.0 2021-11-06\n\n- [3060ef3](https://github.com/appium/ruby_lib/commit/3060ef3bf06c19a79731a49985efa75c3337dd27) Release 12.0.0\n- [2c76d15](https://github.com/appium/ruby_lib/commit/2c76d15edafb43e8c0124bfd4c1c9e95f61fb725) chore: bump version to 12.0.0\n- [19bc90f](https://github.com/appium/ruby_lib/commit/19bc90fef5646f3cde201654ae4fd92da2124b1c) docs: update readme\n- [3239d7f](https://github.com/appium/ruby_lib/commit/3239d7f9a64529c8afc87c2f99a7984eb3057fd5) docs: update changelog\n- [bbf56a5](https://github.com/appium/ruby_lib/commit/bbf56a5e502bdb1e2b38245c879eafbc7d9c0ea9) chore: bump core to 5.0.0, bump version to rc5\n- [b785de1](https://github.com/appium/ruby_lib/commit/b785de188f15da76e91c2a10cccd95c13de3c331) chore: bump the version\n- [d14d151](https://github.com/appium/ruby_lib/commit/d14d15167cc462d75acbef8d7d82b0fb728ec3a5) Merge branch 'master' of github.com:appium/ruby_lib\n- [35bf3ed](https://github.com/appium/ruby_lib/commit/35bf3edcf6dcbfd0b2122aa32bfb85d7209bc52f) chore: bump core version\n- [e990681](https://github.com/appium/ruby_lib/commit/e990681bad2932e895d3e706e5db2593d727b2b7) chore: Update rubocop requirement from = 1.22.2 to = 1.22.3 (#910)\n- [9d3f1b6](https://github.com/appium/ruby_lib/commit/9d3f1b62bc32ef1ea210a92a69d444bc830680f8) docs: remove outdated docs\n- [1049a68](https://github.com/appium/ruby_lib/commit/1049a688cbd11b468002e0fb1c1d1a960a6350c7) chore: bump version to 12.0.0.rc3\n- [8448f29](https://github.com/appium/ruby_lib/commit/8448f299ad91cf47f69c961da811310cd13d906b) chore: remove selendroid stuff\n- [171f3bd](https://github.com/appium/ruby_lib/commit/171f3bd0a9443a7c0c386c8a2c1340f6117c4aa9) chore: update tests with W3C spec for interactions (#909)\n- [01505ed](https://github.com/appium/ruby_lib/commit/01505ed5bf51ce386f285ae1790b91f48bc38487) chore: bump version\n- [8a873f2](https://github.com/appium/ruby_lib/commit/8a873f2c0606488b640d0c4c21237ddb5db97516) chore: bump core version to rc6\n- [2bf24f2](https://github.com/appium/ruby_lib/commit/2bf24f2fc93141415fee1f43a5434a722c64e576) chore: Update fakefs requirement from ~> 1.3.0 to ~> 1.4.0 (#906)\n- [7e9f58c](https://github.com/appium/ruby_lib/commit/7e9f58c483f1c600525d9dc1584b7a4712a33b6a) chore: Update rubocop requirement from = 1.22.1 to = 1.22.2 (#907)\n- [5683456](https://github.com/appium/ruby_lib/commit/5683456f6c6f434d3fa1490a250d23acc3033729) feat: apply core 5.x for selenium v4 (#905)\n- [c0098b4](https://github.com/appium/ruby_lib/commit/c0098b480786ce0442d3d06bf4d3d161375c760d) chore: Update rubocop requirement from = 1.12.0 to = 1.12.1 (#904)\n- [2adbb0e](https://github.com/appium/ruby_lib/commit/2adbb0e03e55f57f0c4001d1577d1577dfd63ae2) chore: Update rubocop requirement from = 1.11.0 to = 1.12.0 (#903)\n- [83769cc](https://github.com/appium/ruby_lib/commit/83769cc9bc8a96cb0526e950a9b7e8d656e84390) chore: Update rubocop requirement from = 1.8.1 to = 1.11.0 (#902)\n- [6e6b61d](https://github.com/appium/ruby_lib/commit/6e6b61d455773147c76f41df65503fb6d61d6019) chore: Update tomlrb requirement from ~> 1.1 to >= 1.1, < 3.0 (#886)\n- [0e34f82](https://github.com/appium/ruby_lib/commit/0e34f82310b9906af858ccf5230a7b0f23fd12f9) chore: Create Dependabot config file (#900)\n- [4783382](https://github.com/appium/ruby_lib/commit/47833829bed009416949ed8ecd60e1a8356e28ce) chore: address 11.2\n\n\n#### v11.2.0 2021-01-25\n\n- [06f2e54](https://github.com/appium/ruby_lib/commit/06f2e54b4b55df25e624272b5a2cd7b23a000298) Release 11.2.0\n- [8489c32](https://github.com/appium/ruby_lib/commit/8489c32dbb9c2b499af82e874aa532f2c9f63d8d) chore: Update rubocop requirement from = 1.8.0 to = 1.8.1 (#897)\n- [eba6a68](https://github.com/appium/ruby_lib/commit/eba6a68b93f010101b3713fef162c23e6c75b330) chore: Update rubocop requirement from = 1.7.0 to = 1.8.0 (#896)\n\n\n#### v11.1.0 2020-12-29\n\n- [bc3da9b](https://github.com/appium/ruby_lib/commit/bc3da9bc1ee58d5e96811b72f3ed737ed0e9c401) Release 11.1.0\n- [3c33cd6](https://github.com/appium/ruby_lib/commit/3c33cd639f8ce55fb81c5ae2116a863407529599) ci: Set up CI with Azure Pipelines (#895)\n- [ecee089](https://github.com/appium/ruby_lib/commit/ecee08981f935295e6413cd98dea4366cbc7bc69) feat: work with Ruby 3 (#893)\n- [bb3d715](https://github.com/appium/ruby_lib/commit/bb3d715e39509ac091b8f493cca42eb4fe8fd5bf) feat: work with Ruby 3 (#892)\n- [eb5cee7](https://github.com/appium/ruby_lib/commit/eb5cee7a926b90bbedd6aa28f013a0b3c5f38510) chore: Update rubocop requirement from = 1.6.1 to = 1.7.0 (#891)\n- [219181d](https://github.com/appium/ruby_lib/commit/219181d80f3b86999706f90a68996945fdc7b1d0) fix: rubocop (#890)\n- [334b791](https://github.com/appium/ruby_lib/commit/334b791a3c4420598e3e832023aa1a16af92492f) chore: Update fakefs requirement from ~> 0.13.0 to ~> 1.3.0 (#888)\n\n\n#### v11.0.0 2020-12-19\n\n- [b4313b0](https://github.com/appium/ruby_lib/commit/b4313b09e62dd22bb95c2e0bc6edd296c7ece7b4) Release 11.0.0\n- [42f01dd](https://github.com/appium/ruby_lib/commit/42f01dd3513e82f9a7ed25ac9055a65dfaa7d81f) feat: bump ruby version (#887)\n- [dc228b3](https://github.com/appium/ruby_lib/commit/dc228b33487281d0428dcd20e92263d7132dd53e) ci: move to GitHub Actions (#882)\n\n\n#### v10.6.0 2020-04-03\n\n- [65f690f](https://github.com/appium/ruby_lib/commit/65f690f1fec62a5f8868270287b0099d8b22a2ac) Release 10.6.0\n- [f792db3](https://github.com/appium/ruby_lib/commit/f792db3afbfe3f6056e0af60ce9f6be3e2cecadc) feat: remove pager off (#879)\n- [7ad3189](https://github.com/appium/ruby_lib/commit/7ad318925c0cd2c3e73cc015a1ec929485b8af85) Update hashdiff requirement from ~> 0.3.7 to ~> 1.0.0 (#874)\n- [457e765](https://github.com/appium/ruby_lib/commit/457e7657175e6c9ba981ca476098469e91e522e1) Update rubocop requirement from ~> 0.61.0 to ~> 0.68.1 (#875)\n- [9a2b9fa](https://github.com/appium/ruby_lib/commit/9a2b9fa736877141f92d35b9e2ae97657d9955d7) Update rake requirement from ~> 12.0 to ~> 13.0 (#876)\n- [8748244](https://github.com/appium/ruby_lib/commit/8748244f75ae9344e8b22dd20b2d42fb0bd84d75) fix ruby27 warning (#872)\n- [f1734ab](https://github.com/appium/ruby_lib/commit/f1734ab0ff2a210463ab6a83120a673e1b6efd4a) ci: add 2.7 (#871)\n- [b26a8f7](https://github.com/appium/ruby_lib/commit/b26a8f7c00c966ee3f193b4c97255a4751f0041e) fix a yardoc syntax\n\n\n#### v10.5.0 2019-11-09\n\n- [722c3a9](https://github.com/appium/ruby_lib/commit/722c3a9aa387d3537b648a50dc24070e62fcc57a) Release 10.5.0\n- [7a2197b](https://github.com/appium/ruby_lib/commit/7a2197b46f6ec15f1adc8626bbff1be74640e98e) feat: Add log event/s (#868)\n\n\n#### v10.4.1 2019-09-11\n\n- [12317e4](https://github.com/appium/ruby_lib/commit/12317e4d74b20d01813526b28e642e3522193fa3) Release 10.4.1\n- [58218e1](https://github.com/appium/ruby_lib/commit/58218e18f74df362e874b2a39d9e922b27b6bd5e) fix ios page (#866)\n- [7f010e7](https://github.com/appium/ruby_lib/commit/7f010e70149847ae5af8dcf08eae889311f78e6d) fix typo in a comment\n\n\n#### v10.4.0 2019-07-19\n\n- [954a3a8](https://github.com/appium/ruby_lib/commit/954a3a8d4d5cd56fa5a4e80d021805759dbf5e10) Release 10.4.0\n- [8289c9f](https://github.com/appium/ruby_lib/commit/8289c9f8e19fab754538f229e1a5513e2994dba3) fix warning message in driver detection (#864)\n- [5e61241](https://github.com/appium/ruby_lib/commit/5e612419ccd4dc5f5bd8b657a972cce4113bf9e7) update core 3.2 (#863)\n- [1f58984](https://github.com/appium/ruby_lib/commit/1f5898400dd1928bfe42ddd5f842d1f8738f2f76) Update readme.md (#861)\n\n\n#### v10.3.1 2019-04-11\n\n- [ef89749](https://github.com/appium/ruby_lib/commit/ef89749d25c7044fe27fa4b7c1adfd011b60bba1) Release 10.3.1\n- [d90f149](https://github.com/appium/ruby_lib/commit/d90f1499f6c7f5c8222f7915d60c7a7218d43949) remove ';' to avoid 'Unclosed paren in expression' (#859)\n\n\n#### v10.3.0 2019-03-31\n\n- [499e824](https://github.com/appium/ruby_lib/commit/499e824668f63958c2fe047b76841612f74d2c1c) Release 10.3.0\n- [fa90527](https://github.com/appium/ruby_lib/commit/fa90527b709cbb2e9ea1e86276a2a884d2a9d4c3) bump core to 3.1.x (#857)\n- [8e7abee](https://github.com/appium/ruby_lib/commit/8e7abeee3b0bc46b8d28b4352bed39819d68cbaf) Bump rubocop 23 (#855)\n\n\n#### v10.2.0 2019-03-01\n\n- [f1b8a2e](https://github.com/appium/ruby_lib/commit/f1b8a2e32fc935508e13431570fd7de4a90b6bd7) Release 10.2.0\n- [dbac05e](https://github.com/appium/ruby_lib/commit/dbac05e58dc25c1e682a4183dff4ead7202a857c) Fix find element by image (#854)\n\n\n#### v10.1.0 2019-02-21\n\n- [4b43cf7](https://github.com/appium/ruby_lib/commit/4b43cf7b240a7b4cab7b22198ed4dd1307611545) Release 10.1.0\n- [588f83f](https://github.com/appium/ruby_lib/commit/588f83f07360d581a317709a539aea8ecb175617) Case sensitive exact (#853)\n\n\n#### v10.0.0 2019-02-08\n\n- [4e4ec29](https://github.com/appium/ruby_lib/commit/4e4ec298096f13f60db51bda2019c8e12a0d0c25) Release 10.0.0\n- [f64e2e4](https://github.com/appium/ruby_lib/commit/f64e2e406e41b596a6e38de9227cc594938f8a06) Fix newline in doc (#850)\n- [a3b3073](https://github.com/appium/ruby_lib/commit/a3b3073d041270d6bbcb21bf8c795c172a90a59a) bump core (#848)\n- [41c940c](https://github.com/appium/ruby_lib/commit/41c940c73fd4ec12ac5bd8119a0a22422dc26819) remove wrong comment\n\n\n#### v9.18.0 2019-01-13\n\n- [32f3272](https://github.com/appium/ruby_lib/commit/32f327239055362ef630979d5975d0fac64d94c6) Release 9.18.0\n- [e0f3683](https://github.com/appium/ruby_lib/commit/e0f36830edf0c33617efa50907c44b4ddc58702d) Enhance espresso adaptation for text, button, finds wrappers (#844)\n- [fb49333](https://github.com/appium/ruby_lib/commit/fb49333c46a7b612920d05d2f9ebc51fd7bfdb20) Add ruby 260 (#843)\n\n\n#### v9.17.0 2018-12-15\n\n- [84f71e4](https://github.com/appium/ruby_lib/commit/84f71e47b86a2f7a1de71c13888adce68622a35b) Release 9.17.0\n- [13f9551](https://github.com/appium/ruby_lib/commit/13f9551f8273cbf1ef959dfd79dc0c53a2c2e0d0) Can call w3c action (#842)\n- [908c3f0](https://github.com/appium/ruby_lib/commit/908c3f08cfea7895a2128b606f6b258c60b894dd) tweak android test code (#841)\n- [af27d01](https://github.com/appium/ruby_lib/commit/af27d011862163653c73aab037d16bcfb3abd28a) remove deprecation or unnecessary code (#839)\n\n\n#### v9.16.1 2018-11-28\n\n- [fa8d4ed](https://github.com/appium/ruby_lib/commit/fa8d4ed2aaa5259a1fa744be955555cf775ead3e) Release 9.16.1\n- [5172e19](https://github.com/appium/ruby_lib/commit/5172e19fc55d4649f679b50d0560d146b9e9ac71) fix version comparision, show warning if the appium version is under 1.6.0 (#837)\n- [152d04a](https://github.com/appium/ruby_lib/commit/152d04aa3c428e610c7e511a05a3563195e7cc81) remove a wrong comment\n- [65efdfd](https://github.com/appium/ruby_lib/commit/65efdfd121a5a01e2c8c0a7ca26df9c66ab446f0) fix generated docs (#835)\n- [81f369b](https://github.com/appium/ruby_lib/commit/81f369bca6d393eb273375035602e39bc89f13a6) update a description of ruby_lib_core\n\n\n#### v9.16.0 2018-11-14\n\n- [621a9eb](https://github.com/appium/ruby_lib/commit/621a9ebaf18bcd80eb0e1f5fc17fbb4dddf5293a) Release 9.16.0\n- [b634a7d](https://github.com/appium/ruby_lib/commit/b634a7d32123c6ad0ebea59798fe5c99721782bd) Use thor (#832)\n- [58f10f0](https://github.com/appium/ruby_lib/commit/58f10f01d1b02bc0619b189c7f7920e7b14332ca) add a line for ruby_lib_core\n- [3bb224c](https://github.com/appium/ruby_lib/commit/3bb224cc7a23f868fdd570ed6113019d6f349984) Do not take care of path of :app for windows (#831)\n\n\n#### v9.15.2 2018-11-07\n\n- [12eb2f3](https://github.com/appium/ruby_lib/commit/12eb2f39fe8d022efe0fb4a666c8661f9270cc7d) Release 9 15 2 (#829)\n- [bb005f7](https://github.com/appium/ruby_lib/commit/bb005f7c594101a460460a8c771610eabc51da73) add execute_async_script (#828)\n- [00dcf13](https://github.com/appium/ruby_lib/commit/00dcf13c7757d248a0aa94ccdada3183951d2f54) wrap some of selenium webdriver apis in bridge for Appium::Driver (#827)\n- [8b42a97](https://github.com/appium/ruby_lib/commit/8b42a9726eae67f52d79820e27ff3a0169d7a0f5) Bump rubocop (#826)\n- [4f25e39](https://github.com/appium/ruby_lib/commit/4f25e3996f444be8c3031117df15b5da8c373d62) Update ios_xcuitest.md (#825)\n- [2a66e84](https://github.com/appium/ruby_lib/commit/2a66e843a5bca7442c5f48d2c514a18169b923c3) Bump ios version for test target (#822)\n- [5fea863](https://github.com/appium/ruby_lib/commit/5fea863f7b2b48522f556d9eecff0fbb3a59e330) add an example of multiple action chains (#819)\n- [ca1b070](https://github.com/appium/ruby_lib/commit/ca1b070ac05fbcf9bfa9eb17479780ae021fcbd4) update grid environments (#818)\n\n\n#### v9.15.1 2018-08-27\n\n- [14d1835](https://github.com/appium/ruby_lib/commit/14d1835fc2d8385af5b8b4489d6b6bb077e510e4) Release 9 15 1 (#817)\n- [5f6c18e](https://github.com/appium/ruby_lib/commit/5f6c18ed9774fe027ee748e812ff91ee6d15a130) Add extend core (#816)\n- [c6e5321](https://github.com/appium/ruby_lib/commit/c6e532186b7552212ba61ab2e351dba247a35312) Tweak gemspec (#814)\n- [2864eec](https://github.com/appium/ruby_lib/commit/2864eec1d05fb69a461c37e4295f159aebe406ca) add tests and tweak helpers which handle xml (#813)\n- [e04afe9](https://github.com/appium/ruby_lib/commit/e04afe92dbe6ea38773c234deb97cb4a7f8ffdd2) Revert \"Use ::REXML::Document by default in CountElements (#811)\" (#812)\n- [1dcc665](https://github.com/appium/ruby_lib/commit/1dcc6650974a57369cc6b087b577cc1146bdaa1f) Use ::REXML::Document by default in CountElements (#811)\n\n\n#### v9.15.0 2018-08-10\n\n- [b09ea84](https://github.com/appium/ruby_lib/commit/b09ea848cc595d8d3ef6494e0a26770521b9432c) Release 9 15 0 (#810)\n- [2e05c62](https://github.com/appium/ruby_lib/commit/2e05c62b07d7c8e395e429fe8b5add58cd41d2d2) Fix rubocop for mighty (#809)\n- [b4da941](https://github.com/appium/ruby_lib/commit/b4da94126b8f7791c510e81d7f080b248bbcdb72) add a pull reqeust template (#808)\n- [e553b3f](https://github.com/appium/ruby_lib/commit/e553b3fab6e733cb91a42dab93ea5331af79fa76) add a section about parallel tests (#807)\n- [6c6b73f](https://github.com/appium/ruby_lib/commit/6c6b73f18e76c73e71fde1ddf265913472423bce) update core version (#806)\n- [a1b2182](https://github.com/appium/ruby_lib/commit/a1b2182ac1f85b0f48ff934221876e9fd3292189) Relax absolute app path (#804)\n- [30ca236](https://github.com/appium/ruby_lib/commit/30ca236d871e06efc069ff59c5f13753dc109971) add a limitation in readme (#803)\n\n\n#### v9.14.3 2018-07-07\n\n- [355ce1a](https://github.com/appium/ruby_lib/commit/355ce1a1618a06353da5dbc02eeb339031e9ded1) Release 9 14 3 (#799)\n- [cc35f60](https://github.com/appium/ruby_lib/commit/cc35f60ee1b42204a9a368e1e7679354e4f05ee7) update (#798)\n- [08edb8c](https://github.com/appium/ruby_lib/commit/08edb8c92aa62d7227a9a49c9d33bcbb82de7841) add tizen (#797)\n\n\n#### v9.14.2 2018-06-25\n\n- [15d656c](https://github.com/appium/ruby_lib/commit/15d656c7de10a52f3da233a78e939733d9ca4f2a) Release 9 14 2 (#796)\n- [4a8261f](https://github.com/appium/ruby_lib/commit/4a8261fc24274a876d03aa61ea81028d070c3a46) add find element/s by image (#795)\n- [23bf449](https://github.com/appium/ruby_lib/commit/23bf44916c9e97af4e6cd0b9b64f87078aae05d2) add install certificate (#789)\n- [3791c86](https://github.com/appium/ruby_lib/commit/3791c86940d52d6eba5aeb29afd4d26698ec9777) Update readme.md (#791)\n- [b9679e1](https://github.com/appium/ruby_lib/commit/b9679e1295a031933b124530b85b30f9f086d2f3) Add get contexts (#788)\n\n\n#### v9.14.1 2018-05-31\n\n- [cc322d6](https://github.com/appium/ruby_lib/commit/cc322d6a36ad85014b3eed1cdec4481f07b6a95d) Release 9 14 1 (#787)\n- [b2772d9](https://github.com/appium/ruby_lib/commit/b2772d952117a9e5d760904ddbfaf5828e8d44cf) Fix an initialisation error (#786)\n\n\n#### v9.14.0 2018-05-28\n\n- [d60947d](https://github.com/appium/ruby_lib/commit/d60947df856da65dd31fcdbc34d71719a75d9003) Release 9 14 0 (#783)\n\n\n#### v9.13.0 2018-05-08\n\n- [c8b797e](https://github.com/appium/ruby_lib/commit/c8b797ef404c57a24b00e9c355ec36b3335f4a5f) Release 9 13 0 (#781)\n\n\n#### v9.12.1 2018-05-06\n\n- [8ce022f](https://github.com/appium/ruby_lib/commit/8ce022f0f8eabe668230f9aa63a0228d60704c05) Release 9 12 1 (#780)\n- [c9b0470](https://github.com/appium/ruby_lib/commit/c9b0470e866c6e70ba689628d4e0924db39f452c) add no hash but numeric case in wait (#779)\n- [9a8356b](https://github.com/appium/ruby_lib/commit/9a8356b84198c6c9afb4d1dcf9a9c4067424b4c8) Add syslog websocket ios re (#777)\n\n\n#### v9.12.0 2018-04-25\n\n- [7a5a12c](https://github.com/appium/ruby_lib/commit/7a5a12ce78ce0a8154ea55ff7f44ecd10ba5b771) Release 9 12 0 (#775)\n- [7dcb4fa](https://github.com/appium/ruby_lib/commit/7dcb4fa287e61c813ab8f522e5a4d397a95f5039) remove hot fix actions (#773)\n\n\n#### v9.11.1 2018-04-22\n\n- [778aaf4](https://github.com/appium/ruby_lib/commit/778aaf4dfd5879759fd296f770aef59a6eca685e) Release 9 11 1 (#772)\n- [c89f526](https://github.com/appium/ruby_lib/commit/c89f526e97be008b4320c89d7a02267dcb23aa1d) fix some tests and fix compatibility for wait (#771)\n\n\n#### v9.11.0 2018-04-19\n\n- [91f4db4](https://github.com/appium/ruby_lib/commit/91f4db40f0b1e29bc77231f3ce850bee193d4968) Release 9 11 0 (#770)\n- [74437a7](https://github.com/appium/ruby_lib/commit/74437a7d10203ae6125dbcecd11d761b0dad3819) add mobile logs broadcast (#764)\n- [97c6421](https://github.com/appium/ruby_lib/commit/97c6421a557adb40dc134e0a6d65687e918498f3) remove old docs (#768)\n- [f58dace](https://github.com/appium/ruby_lib/commit/f58dacea3a003c8c7f4871fd788e9545185cb958) add some comments in examples for drivers (#767)\n- [0852bc7](https://github.com/appium/ruby_lib/commit/0852bc7c894015312f42ed252d1cfce185c6cf4e) clean docs up (#765)\n\n\n#### v9.10.0 2018-02-14\n\n- [5538a43](https://github.com/appium/ruby_lib/commit/5538a43c96adda5b7400fd50e60f650873fef8b2) Release 9 10 0 (#763)\n\n\n#### v9.9.2 2018-02-12\n\n- [31908a9](https://github.com/appium/ruby_lib/commit/31908a96bf6389f93e6dc3c013bf9d0a9a5b9e12) Release 9 9 2 (#762)\n- [51eb451](https://github.com/appium/ruby_lib/commit/51eb451348005a7f6b8e0677570811690b7208da) Fix Security Vulnerability (#761)\n\n\n#### v9.9.1 2018-02-02\n\n- [591048d](https://github.com/appium/ruby_lib/commit/591048d98b63f1cde559227e166705147880902e) Release 9 9 1 (#759)\n- [03f2850](https://github.com/appium/ruby_lib/commit/03f2850f04e1a4fcb33b6f28f9c14e1efb694eff) Fix minitest revert (#758)\n\n\n#### v9.9.0 2018-01-29\n\n- [913c6b5](https://github.com/appium/ruby_lib/commit/913c6b5098ebdd6659d949121b42f4a38d8c34d4) Release 9 9 0 (#756)\n- [b8d73ca](https://github.com/appium/ruby_lib/commit/b8d73cafcc429e04f06b891d688513a9622c730a) fix test and add the latest grid (#754)\n\n\n#### v9.8.5 2018-01-26\n\n- [228c5dd](https://github.com/appium/ruby_lib/commit/228c5dd39189b61e4b541852d740fb5d67c8dfbd) Release 9 8 5 (#753)\n- [4dc8882](https://github.com/appium/ruby_lib/commit/4dc888211c605ad1d3fc7b38cd8427109698c0cd) Update CHANGELOG.md (#752)\n- [d185307](https://github.com/appium/ruby_lib/commit/d185307774bf2a9bc8a3d4e2ef871b0c00e1d73c) fix Minitest::VERSION error (#751)\n\n\n#### v9.8.4 2018-01-25\n\n- [7b72377](https://github.com/appium/ruby_lib/commit/7b72377d4541c9e7d313631fc543ca93037b892c) Release 9 8 4 (#749)\n- [eeea236](https://github.com/appium/ruby_lib/commit/eeea2362bb4660f53cf274c155c57169de225e6a) fix: add condition flow for minitest (#748)\n\n\n#### v9.8.3 2018-01-14\n\n- [5de0bec](https://github.com/appium/ruby_lib/commit/5de0bec7bed7096a92531e866f75f95ec29941bf) Release 9 8 3 (#746)\n- [d45ab00](https://github.com/appium/ruby_lib/commit/d45ab00320e4ceac60d01e4dadf5a171ecee9c14) Bump core to 124 (#743)\n- [275b0a3](https://github.com/appium/ruby_lib/commit/275b0a3ffe9d189e9876dbfcaa748302d6951755) add ruby 2.5 for travis (#742)\n\n\n#### v9.8.2 2017-12-27\n\n- [500a7a3](https://github.com/appium/ruby_lib/commit/500a7a39e9db4642332ff5e1816d342cf5b4d4d5) Release 9 8 2 (#741)\n- [d465462](https://github.com/appium/ruby_lib/commit/d465462d1ba315a201ab11a01f5272046353fa27) update core (#740)\n- [987c4e3](https://github.com/appium/ruby_lib/commit/987c4e37372ca5c5d42a58ead6423b3e941e5ad7) add handling multiple apps (#738)\n- [1b8f8e3](https://github.com/appium/ruby_lib/commit/1b8f8e362359a1486508f23bc7f6b9cfafa103c5) Update and add description for actions (#737)\n- [c691c36](https://github.com/appium/ruby_lib/commit/c691c360e6052cf6adf369bc4c222478b18ab716) Add run shell sortcut for android (#732)\n\n\n#### v9.8.1 2017-12-17\n\n- [1081ae0](https://github.com/appium/ruby_lib/commit/1081ae01e7cf5c4682cadcf0219b07912cc3734f) Release 9 8 1 (#731)\n- [8212de4](https://github.com/appium/ruby_lib/commit/8212de4037f8c0bcd0c9a5d828dec6db32ace697) update ruby_core to fix creating session for the W3C createSession for Appium (#730)\n- [e89b08f](https://github.com/appium/ruby_lib/commit/e89b08f931b378f5b56a2dbdd1b78e8ed382db9f) docs: fix the xcuitest link (#727)\n- [e12787d](https://github.com/appium/ruby_lib/commit/e12787dc1ebd35a9760e9e59e094bc30b2dfe627) add alias (#725)\n- [047ed32](https://github.com/appium/ruby_lib/commit/047ed3296ce5a33a4ea9814348dc4b8af2fbebcc) Release 9 8 0 (#724)\n- [5bfb413](https://github.com/appium/ruby_lib/commit/5bfb4130869ca7979e5216efac452c206edf3c06) docs: update ruby lib core (#722)\n- [6b5a449](https://github.com/appium/ruby_lib/commit/6b5a4493186083a09348ec060842a7dce15bfc5a) docs: update readme and insert URL to the core library (#721)\n- [3bab5b2](https://github.com/appium/ruby_lib/commit/3bab5b2bf8c82af3c81f32352de99cdba30b3c5a) doc: update comments (#720)\n- [9dfa0b9](https://github.com/appium/ruby_lib/commit/9dfa0b9c0c3df6f7ec88d578e304ad1fd3704742) refactor: replace core directory to core library (#718)\n- [04a6f45](https://github.com/appium/ruby_lib/commit/04a6f45bd6bbbce463919207a37bccdb5a39bdfc) docs: update readme (#719)\n\n\n#### v9.7.5 2017-11-04\n\n- [1e1bb7e](https://github.com/appium/ruby_lib/commit/1e1bb7e3f1f500fa0dffe361b875b6b16941e290) Release 9 7 5 (#717)\n- [6a6d07e](https://github.com/appium/ruby_lib/commit/6a6d07e80686a171f76ea4fa013996e7f81f6fb9) fix: take care capybara case (#716)\n\n\n#### v9.7.4 2017-10-28\n\n- [8522f49](https://github.com/appium/ruby_lib/commit/8522f496eff2a72648a563af8ce06cb8c7270256) Release 9 7 4 (#715)\n- [ad6ca97](https://github.com/appium/ruby_lib/commit/ad6ca9709351b99f547b789846be3faf62f6558f) fix: Define source in common section (#714)\n- [bb80136](https://github.com/appium/ruby_lib/commit/bb80136adf909f49582ff69f2c9276669b4edf78) remove todo (#712)\n- [b7a6e1d](https://github.com/appium/ruby_lib/commit/b7a6e1d3e2ed0a04de571c857f6c469ac6f24153) refactor: Define multi touch base class (#711)\n- [14ff169](https://github.com/appium/ruby_lib/commit/14ff169cf91b36750d1e8cb498723884dcdc66b8) feature: add unlock (#710)\n\n\n#### v9.7.3 2017-10-21\n\n- [e570a64](https://github.com/appium/ruby_lib/commit/e570a640106c57521335f837082cf00abf0d8c10) update changelog (#709)\n- [f598950](https://github.com/appium/ruby_lib/commit/f5989500dabcd21cd6daaacab828942de998497a) Release 9 7 3 (#708)\n- [67385e9](https://github.com/appium/ruby_lib/commit/67385e9c203c4bbd062c7bf3397fca7bbb8d636b) refactor: Separate touch actions (#707)\n- [d1dd4fb](https://github.com/appium/ruby_lib/commit/d1dd4fbea8958e0b317c59fd2a5aaa0d027078e9) refactor: set uiautomator2 by default for android (#706)\n- [8c92ace](https://github.com/appium/ruby_lib/commit/8c92ace7c3c27ee31714c8f3e7d2ebeb48bc07ec) feature: Add espresso bridge (#705)\n- [cc4f9e7](https://github.com/appium/ruby_lib/commit/cc4f9e7f67ab66ca0f20849b3b249b99b0671783) feature: Add espresso (#704)\n- [6088233](https://github.com/appium/ruby_lib/commit/60882332ca2a08cfcd7b6f5e6b37df98a68e396a) docs: clean up (#703)\n- [5cf149c](https://github.com/appium/ruby_lib/commit/5cf149c1304e5abc2fccd5477f22f6fd70f1cb85) docs: add examples and tag_name (#702)\n- [dd4ace1](https://github.com/appium/ruby_lib/commit/dd4ace10ee650e8b1e2c8bb50a4a29288a350949) add an example for the predicate (#701)\n- [3ea887d](https://github.com/appium/ruby_lib/commit/3ea887d17b6c0b7235f21e3424ada65fe662df22) feature: add get source for xcuitest (#699)\n- [9af174f](https://github.com/appium/ruby_lib/commit/9af174fd343481f2b38cd96344a7c24c071e5695) docs: update docs for search context (#700)\n- [798c3aa](https://github.com/appium/ruby_lib/commit/798c3aae8f5ec42f0286b17624e2d667e362b24c) feature: introduce process model (#698)\n- [3c6b146](https://github.com/appium/ruby_lib/commit/3c6b146ef21daefa2b86e24581483ee21a264de8) docs: separate parallel tests (#695)\n- [c73ed12](https://github.com/appium/ruby_lib/commit/c73ed12973efb4c4fea031810e2ca6678f363191) refactor: make export session path manageable (#694)\n\n\n#### v9.7.2 2017-10-07\n\n- [f949287](https://github.com/appium/ruby_lib/commit/f94928755a29917cf6e1a04d702bff5e4823eedc) docs: update changelog (#693)\n- [1f20df4](https://github.com/appium/ruby_lib/commit/1f20df4ea663c881d10d173c2df178169f257c95) Release 9 7 2 (#692)\n- [51cba8e](https://github.com/appium/ruby_lib/commit/51cba8eca4346af945322898a5c61b91f60e4026) doc: add error message (#691)\n- [b9bb275](https://github.com/appium/ruby_lib/commit/b9bb2751313ea478ee775d979543f05dc44f9e21) feature: add flatten_hash_keys (#688)\n- [3bdc1f9](https://github.com/appium/ruby_lib/commit/3bdc1f9cf6ad5eb2279dfd6cb43e35fc469720de) fix: path for uiautomation (#690)\n- [3102784](https://github.com/appium/ruby_lib/commit/31027845774373e22b907242944f391ddf755581) fix: export session (#689)\n- [212f70e](https://github.com/appium/ruby_lib/commit/212f70e4f982d047e9f409b32fc5f4fc779ceb10) docs: Add documentation (#685)\n- [38670ef](https://github.com/appium/ruby_lib/commit/38670efc19b2350191cc440c1fc911fd20007694) docs: Add documentation (#683)\n\n\n#### v9.7.1 2017-10-01\n\n- [ebde85f](https://github.com/appium/ruby_lib/commit/ebde85fac616ac09e19a5f8215195e536d88344d) Release 9 7 1 (#682)\n- [db29b66](https://github.com/appium/ruby_lib/commit/db29b664172935f7814266c7357e099969404fe3) fix: Fix appium version error (#681)\n\n\n#### v9.7.0 2017-10-01\n\n- [bf12459](https://github.com/appium/ruby_lib/commit/bf124597977514e4d338efaaea5a29bdcbef5578) Release 9 7 0 (#679)\n- [a6240cb](https://github.com/appium/ruby_lib/commit/a6240cb3144679865b9ca455a3906586268c20db) refactor: Move window size method and touch related actions (#678)\n- [36ef57b](https://github.com/appium/ruby_lib/commit/36ef57b9b11c8efc0a6b458cf5c1a11c75b7ef0e) docs: update documentation and comments (#677)\n- [e3f5b0d](https://github.com/appium/ruby_lib/commit/e3f5b0d91b35d5b2b3b11e63911e2bf48ca11f08) refactor: define bridge in core (#676)\n- [eb7680f](https://github.com/appium/ruby_lib/commit/eb7680f6db1e821901045beacba0a8b80de722fb) refactor: collect no agrs in core/command (#675)\n- [f174e75](https://github.com/appium/ruby_lib/commit/f174e75e81912ddd5118e066349774caf54b4a74) remove some todos which isn't need more (#673)\n- [8471880](https://github.com/appium/ruby_lib/commit/84718805fb4c6246692564295294073b90ada700) refactor: separate core android ios more (#670)\n- [2e09e83](https://github.com/appium/ruby_lib/commit/2e09e839cce26571fb5857097d3c7f3391bfe3ff) refactor: move some drivers in core (#669)\n- [35b0ded](https://github.com/appium/ruby_lib/commit/35b0dedcfc08e66e6e7a9414db645e129bf5d373) refactor: replace extend for to bridge for in driver (#668)\n- [c1b6923](https://github.com/appium/ruby_lib/commit/c1b69232d556338dbcde1652af78534ce6b750c9) doc: add routes references (#667)\n- [d44f00a](https://github.com/appium/ruby_lib/commit/d44f00a6cb8f52770da4ae7b7d69b8eaf3ae1581) refactor: Reduce patch_webdriver_element and some DEPRECATIONs (#663)\n- [2f24cb2](https://github.com/appium/ruby_lib/commit/2f24cb2ba17becbbe0e5e96bd2e4eb672f026024) feature: update toggle touch id enrollment (#664)\n- [895874d](https://github.com/appium/ruby_lib/commit/895874d51f5491db6a26669ae8e6f78c243c6eb3) refactor: add some comments and remote_status (#662)\n- [e813dfe](https://github.com/appium/ruby_lib/commit/e813dfe5689c450945df41d8c1973d9d58b8b0ff) refactor: put warn if no device matched (#658)\n- [d95b02e](https://github.com/appium/ruby_lib/commit/d95b02e6fa6a78525af120e0096beb3559dc6f72) refactor: re-struct directories (#655)\n- [070be93](https://github.com/appium/ruby_lib/commit/070be935f52184f34462cd5b48ca3bf842c45ea2) docs: update the way to call Appium::Driver.new (#656)\n- [f600fe6](https://github.com/appium/ruby_lib/commit/f600fe6fbc55281c58b2593d0aa55ae93a32a913) refactor: separate some methods and modules (#651)\n\n\n#### v9.6.1 2017-08-27\n\n- [a542287](https://github.com/appium/ruby_lib/commit/a5422874b4ab60430ab9d58289aac001ecd90ecf) Release 9 6 1 (#650)\n- [cb9450d](https://github.com/appium/ruby_lib/commit/cb9450d207fb2e23b4dfef4318f47ea3d04c7689) refactor: divide dependencies (#649)\n- [0673ad7](https://github.com/appium/ruby_lib/commit/0673ad71a0c13e72c96fa7928ce1077c3684d4c2) feature: add commands for get_pasteboard and set_pasteboard (#648)\n- [420c855](https://github.com/appium/ruby_lib/commit/420c855efb27e2dd84fce8b0dbeb0e86d41f72ee) use 1.8.0 to reduce constant ::Fixnum error (#647)\n- [f801cf2](https://github.com/appium/ruby_lib/commit/f801cf20127205c0c6daae91961276e17a402675) test: add a test for tap (#646)\n- [eafaa3d](https://github.com/appium/ruby_lib/commit/eafaa3d73124c46fba372730290dde9e2bac812d) doc: Update CHANGELOG.md (#645)\n\n\n#### v9.6.0 2017-08-20\n\n- [e1a2cd4](https://github.com/appium/ruby_lib/commit/e1a2cd493a370655b390a1d3803a85fbdb5f7f9d) Release 9 6 0 (#643)\n- [6c6e916](https://github.com/appium/ruby_lib/commit/6c6e9165998a457188b1e53476c9bdbb18fa2ef7) refactor: separate uiautomator2 (#642)\n- [2b1a5ee](https://github.com/appium/ruby_lib/commit/2b1a5eef44be48df5e14dc42000b4a776a2bae5b) Append documentations (#640)\n- [6ee404d](https://github.com/appium/ruby_lib/commit/6ee404ddbe932b97d50904a2f273b7404485d79e) refactor: Separate xcuitest more (#639)\n- [8a7c386](https://github.com/appium/ruby_lib/commit/8a7c386a51e9f83826e1d5d799cc509cd0c7e3ae) feature: test code for multiple iOS simulators (#637)\n- [b7daaac](https://github.com/appium/ruby_lib/commit/b7daaac9b2262c80ee679263a809bd98371b312b) fix: Fix Android scroll_to and scroll_to_exact (#638)\n- [65b2c7a](https://github.com/appium/ruby_lib/commit/65b2c7a9edb65e50c61c5e64408e9d7ee36465cf) refactor: remove unused definition and rename arguments for initilizer (#635)\n- [35d3b11](https://github.com/appium/ruby_lib/commit/35d3b11dafac3363902fc0352a62d957fd90a947) Alias `quit_driver` to `driver_quit`. (#634)\n- [214cf72](https://github.com/appium/ruby_lib/commit/214cf72bd8aefffb974d5757d218a668e14a87c7) fix: Fix android tests and add broken ime methods (#633)\n- [aaf307d](https://github.com/appium/ruby_lib/commit/aaf307d9bacc30d5c9edb0507d1541ef626d3308) refactor: loading xcuitest related methods only for XCUITest case (#631)\n- [20bc86a](https://github.com/appium/ruby_lib/commit/20bc86a5195ef0f6d51ccba68019c1228cd2a0f1) add extending bridge commands for W3C (#632)\n- [6288409](https://github.com/appium/ruby_lib/commit/62884095bd59b420c1eb0d9295e9d3f31ca16195) refactor: set global driver as arguments (#629)\n\n\n#### v9.5.0 2017-08-05\n\n- [19177f5](https://github.com/appium/ruby_lib/commit/19177f5348300a0e2e1e0510b99efac2f3067201) Release 9 5 0 (#628)\n- [4219f1d](https://github.com/appium/ruby_lib/commit/4219f1d3f639a421bc4fc6a772c242d782357ae1) feature: support selenium-webdriver3.4.1+ (#627)\n\n\n#### v9.4.10 2017-07-30\n\n- [6eae1b6](https://github.com/appium/ruby_lib/commit/6eae1b6412ba8dc6c967a44dd9a987944c8e6444) Release 9 4 10 (#626)\n- [3df1b2d](https://github.com/appium/ruby_lib/commit/3df1b2d212f1f0ea9975b80009894e4fa138a414) refactor: search contexts and its structure (#625)\n- [673bdef](https://github.com/appium/ruby_lib/commit/673bdeffba6946e932096e0bc44d5e8faaf3ec07) refactor: reduce complexity in android helper (#624)\n- [d5c9118](https://github.com/appium/ruby_lib/commit/d5c9118ca06f2e3daf3ea41ebe9aaf5769e7493e) Create ISSUE_TEMPLATE.md (#623)\n- [355207c](https://github.com/appium/ruby_lib/commit/355207cbb234a1f6fb98da1d5e328f371b35cbd8) doc: append a documentation for android coverage (#622)\n- [47a5ba9](https://github.com/appium/ruby_lib/commit/47a5ba98ed2ce7387382c6fbc38721a72331a8d1) refactor: use element.rect for Selenium Webdriver 3.4.0+ (#621)\n- [7cfa539](https://github.com/appium/ruby_lib/commit/7cfa539fe4359a40151d006c0a301496024a1c3f) chore: ignoring DS Store (#620)\n- [d834c97](https://github.com/appium/ruby_lib/commit/d834c97780e7e95d1488c57a6fae7e751db5fe6f) feature: add react native app (#619)\n- [947106f](https://github.com/appium/ruby_lib/commit/947106fdc5a8d2653b65cfa473a4eb1111835085) feature: add commit message format to handle release note smarter (#616)\n- [d126ba1](https://github.com/appium/ruby_lib/commit/d126ba14ba0533f3a54cb51a849443adbcf84e91) add progname (#615)\n- [9c4d555](https://github.com/appium/ruby_lib/commit/9c4d555c97ad99bbd6f0c8e359713fac959f8717) remove rails/duplicable and related methods (#614)\n\n\n#### v9.4.9 2017-07-01\n\n- [cfe84fc](https://github.com/appium/ruby_lib/commit/cfe84fc009c418eebe95babf8160f36209f9fecf) Release 9 4 9 (#613)\n- [0e88589](https://github.com/appium/ruby_lib/commit/0e885890e3c9d7f5067869a9893009f0a32f7af0) fix handling element for xcuitest guestures (#611)\n\n\n#### v9.4.8 2017-06-24\n\n- [209fb3f](https://github.com/appium/ruby_lib/commit/209fb3fce4f2e567c6d6ba2395eec9b98669d02d) Release 9 4 8 (#610)\n- [40c92eb](https://github.com/appium/ruby_lib/commit/40c92eb1a7e01663d2b9b47314d9e7a9fa0e6586) Add visibility for ios (#609)\n- [20307a0](https://github.com/appium/ruby_lib/commit/20307a06269aef7123c865091062b97cdbbe8430) mark deprecated for client side xpath strategy (#608)\n- [5d40446](https://github.com/appium/ruby_lib/commit/5d40446a913432113931d9430ff36c8179cc6cbb) Return a result of yield (#606)\n- [cc913ed](https://github.com/appium/ruby_lib/commit/cc913edb4bc24c18a58c2c5490dfb7b5a705d303) add getting current package name (#605)\n- [fa33239](https://github.com/appium/ruby_lib/commit/fa332395c2f4fae70bf672fb12f002a3194cdc2c) inherit selenium's wait (#603)\n\n\n#### v9.4.7 2017-06-11\n\n- [ef9efbd](https://github.com/appium/ruby_lib/commit/ef9efbd6d3fadfaebaa4245bed40d28aec33be32) Release 9 4 7 (#601)\n- [29f031a](https://github.com/appium/ruby_lib/commit/29f031a0b8d180289cfd8a9de4216300916cd5cc) Ignore server version check for grid (#600)\n- [1b7a4b4](https://github.com/appium/ruby_lib/commit/1b7a4b45074761141d25b1461d0c23672889905d) Update CHANGELOG.md (#597)\n\n\n#### v9.4.6 2017-05-25\n\n- [a44ea77](https://github.com/appium/ruby_lib/commit/a44ea770287407ba9b488e25e259884676c89709) Release 9 4 6 (#593)\n- [9f9c688](https://github.com/appium/ruby_lib/commit/9f9c688d1a9d0b2213dc41a256a0085a603f128e) exclude test directories and grids (#592)\n\n\n#### v9.4.5 2017-05-25\n\n- [8e7ea79](https://github.com/appium/ruby_lib/commit/8e7ea79ca476bdc172015aea3ed2b4dc3b571d00) Release 9 4 5 (#590)\n- [4001282](https://github.com/appium/ruby_lib/commit/40012821fd3a3b5f7f484de951bec9fbb00f225c) add grid 2.x (#589)\n- [fa00890](https://github.com/appium/ruby_lib/commit/fa008908ce95d1d8cd76bd9bb1ea927b36a64f9a) update some grid parameters (#588)\n- [44e12cb](https://github.com/appium/ruby_lib/commit/44e12cb2f0aec3a9f9954819c68646ed83efb297) add grid settings (#587)\n- [4d98683](https://github.com/appium/ruby_lib/commit/4d986830facd0e4ef1978e247a3c8ffd0a02427b) skip loading Pry.config.pager = false if users have .pryrc (#585)\n- [517f30d](https://github.com/appium/ruby_lib/commit/517f30d6cdbcbf683311612c705ac876b1e3521a) fix some ambiguous gesture (#584)\n- [b69f0e0](https://github.com/appium/ruby_lib/commit/b69f0e0ce061ebeb6462b0118411af85b388addd) replace attr_accessor to attr_reader (#583)\n- [5eff035](https://github.com/appium/ruby_lib/commit/5eff0353ee32a40e56dea8b36a9b3bb86269579e) add touch and hold (#581)\n- [e736359](https://github.com/appium/ruby_lib/commit/e736359bc9b8b3a369dcbcc727cb858d2f98e94f) add alert test case (#579)\n\n\n#### v9.4.4 2017-05-13\n\n- [230bac6](https://github.com/appium/ruby_lib/commit/230bac6fbcf26645111f76caab64dbf46de84897) Release 9 4 4 (#577)\n- [1facf0f](https://github.com/appium/ruby_lib/commit/1facf0f70d9607ba7d7e062d87ee7a900dbcd90a) add mobile alert (#575)\n- [a2b0675](https://github.com/appium/ruby_lib/commit/a2b067520de4237bd2cd71fd2a22f002cc3a8814) add travis example for ios (#573)\n- [2ff78b1](https://github.com/appium/ruby_lib/commit/2ff78b190f53011c9f0b26777cb1caf64410eaf8) clean hide_keybaord for ios (#572)\n- [27e10f8](https://github.com/appium/ruby_lib/commit/27e10f8ba310ce933171b169607172e593344ad7) revert _fix_android_native_source and instance counting (#571)\n- [4a70d78](https://github.com/appium/ruby_lib/commit/4a70d78d1fcf008654d54d47660f341321a3922e) update latest apk for android tests (#570)\n- [bd7d67b](https://github.com/appium/ruby_lib/commit/bd7d67b2dd12590937cf059e198d64bde6f9141d) add special thanks (#567)\n\n\n#### v9.4.3 2017-05-03\n\n- [c413bd7](https://github.com/appium/ruby_lib/commit/c413bd77d0fec58e1c2cce6821694bcf659b9e1b) Release 9 4 3 (#566)\n- [8e600af](https://github.com/appium/ruby_lib/commit/8e600af469f0e00f1fb6cce331c72b13d11598c8) fix tests for uiautomator2 (#565)\n- [ab8ecf8](https://github.com/appium/ruby_lib/commit/ab8ecf860088f690777e7c8086c31753463577c8) Update android_uiautomator.md (#564)\n- [4f035d3](https://github.com/appium/ruby_lib/commit/4f035d39a0b3a3c39a9ef6a5cd0d2cb19d39f7d4) Use uiautomator for uiautomator2 (#561)\n- [71d8eb6](https://github.com/appium/ruby_lib/commit/71d8eb676bf5ac6d83c5da112d068865d76ebab4) Add link to issue in generating release notes (#562)\n- [915e75d](https://github.com/appium/ruby_lib/commit/915e75d08e89b4248ca104124f7430463c13ab22) don't use selenium-webdriver 3.5+ (#559)\n- [7e9c8ef](https://github.com/appium/ruby_lib/commit/7e9c8ef7fbed4e076fa6aec49f20d786fa6cbdf6) update workaround (#557)\n- [801a5a0](https://github.com/appium/ruby_lib/commit/801a5a07e5c1c062f5d108a844721c7a569765a3) add workaround (#556)\n\n\n#### v9.4.2 2017-04-21\n\n- [0cd41ef](https://github.com/appium/ruby_lib/commit/0cd41ef58b6abf8444fcb95db59aebb2c6c2a890) Release 9 4 2 (#554)\n- [d01ebd2](https://github.com/appium/ruby_lib/commit/d01ebd28d350eab752dcc10f6f9675610cbb596c) fix drag_from_to_for_duration (#553)\n- [4f5a474](https://github.com/appium/ruby_lib/commit/4f5a4743b0acebbdefe6091a49cd86e1e3aa7eeb) add offset (#551)\n\n\n#### v9.4.1 2017-04-19\n\n- [491a142](https://github.com/appium/ruby_lib/commit/491a142942cc0eb8addfb15e2bbd805d260cebc0) Release 9 4 1 (#550)\n- [d721297](https://github.com/appium/ruby_lib/commit/d721297a634cebc0d22f26a132345126036c71d6) separate find_element/s for uiautomator and xpath (#547)\n\n\n#### v9.4.0 2017-04-17\n\n- [9492690](https://github.com/appium/ruby_lib/commit/9492690f80efaab79ce165e16dd335fca9717c4a) Release 9 4 0 (#545)\n- [2ea94c3](https://github.com/appium/ruby_lib/commit/2ea94c3933f1ecd1362c33f306348236facefc37) add mobile gesture (#542)\n- [1c7dd0f](https://github.com/appium/ruby_lib/commit/1c7dd0ff844265e76b3f2e15a0e6b3651005518f) use xpath instead of uiselectors (#544)\n- [5841a39](https://github.com/appium/ruby_lib/commit/5841a39d60b0986f1a1dd786b910bfbd6223d124) add mobile gesture for XCUITest (#537)\n\n\n#### v9.3.8 2017-04-13\n\n- [7a7cf44](https://github.com/appium/ruby_lib/commit/7a7cf44c3cb11a90142285b8e8d731dc452b89eb) Release 9 3 8 (#540)\n- [5e67b88](https://github.com/appium/ruby_lib/commit/5e67b8813950148661bc4491811a696edeffc63c) allow using TestObject server (#538)\n- [9fdf89f](https://github.com/appium/ruby_lib/commit/9fdf89f9c3993730aabf1b8e25f03a773e565d98) add link to mobile gesture for XCUITets (#536)\n\n\n#### v9.3.7 2017-04-09\n\n- [8daf6f7](https://github.com/appium/ruby_lib/commit/8daf6f773c9b8acd7a89e2a9225fd834de5b4e2e) Release 9 3 7 (#535)\n- [893c714](https://github.com/appium/ruby_lib/commit/893c714f4b60985753950f74e9e4b3bfb5f066eb) Remove appium suffix from find element (#532)\n- [61ee15c](https://github.com/appium/ruby_lib/commit/61ee15c58ec536db1c32f8e278f8214148c96552) Update docs for find_element/s (#531)\n- [17d17e6](https://github.com/appium/ruby_lib/commit/17d17e65a52cc22d093f913084673cb3a33b450c) fix markup (#526)\n- [9de862c](https://github.com/appium/ruby_lib/commit/9de862ca6440e8a2e864b7b342725ac7699c096b) fix the android doc markup (#525)\n\n\n#### v9.3.6 2017-03-31\n\n- [0f1e3aa](https://github.com/appium/ruby_lib/commit/0f1e3aa48ce2d561af0a5897ab62017306009d8b) Release 9 3 6 (#523)\n- [4ae0815](https://github.com/appium/ruby_lib/commit/4ae081549cf1aad89c6d304fc8a8b9499db96160) Add toggle touch id enrollment (#521)\n\n\n#### v9.3.5 2017-03-26\n\n- [c652bb3](https://github.com/appium/ruby_lib/commit/c652bb3332016a3c8ba7502e31477a330ab1c1ab) Release 9 3 5 (#520)\n- [c8ae26d](https://github.com/appium/ruby_lib/commit/c8ae26d6c9c400c5f40c3d1b620a3a5ba09c5932) Add some android commands (#517)\n- [e0db50e](https://github.com/appium/ruby_lib/commit/e0db50e5635dc359620eec9f79609f55af6ba529) Add class chain (#515)\n- [43ea919](https://github.com/appium/ruby_lib/commit/43ea919e4830477751f98aa6cf2475a54bcecb8e) [WIP]add scrollable index param into scroll_uiselector (#507)\n- [80f8071](https://github.com/appium/ruby_lib/commit/80f80715dcee6de968700ece40894222af41579a) add clearing actions after calling perform (#512)\n\n\n#### v9.3.4 2017-03-16\n\n- [2b01065](https://github.com/appium/ruby_lib/commit/2b01065d0b2c2287ed9568cb23de5e459082ef62) Release 9 3 4 (#509)\n- [0abf62f](https://github.com/appium/ruby_lib/commit/0abf62f0fa99d1ce0841a98e86a6ca334a143f0e) add doc for uiautomator (#508)\n- [0199159](https://github.com/appium/ruby_lib/commit/0199159b6f0193884ebcffbfa460b3403859e537) Search with predicate (#504)\n- [dbd8762](https://github.com/appium/ruby_lib/commit/dbd87620b771e7448e9826181b0ae595701ccaa2) Update deactive app for xcuitest (#502)\n- [e06b25e](https://github.com/appium/ruby_lib/commit/e06b25ed1df5ed1a67fcf1a59767cc42ddcdb0d0) add a test for predicate (#499)\n- [447f13c](https://github.com/appium/ruby_lib/commit/447f13cd799652d203bed4fc557b3c251ef2aa2c) Use awesome print 1.7 (#498)\n- [a68cc5f](https://github.com/appium/ruby_lib/commit/a68cc5fc38b64d1d41945024a808df9af90828d7) remove workaround for rainbow (#497)\n\n\n#### v9.3.3 2017-02-18\n\n- [422a468](https://github.com/appium/ruby_lib/commit/422a4683f10fc99d3731985d532b71e1fe80b4e6) Release 9 3 3 (#494)\n- [c09cf1e](https://github.com/appium/ruby_lib/commit/c09cf1efb33b276d6faf179b1344435df5dc7d16) add tags_include and tags_exact to find value (#490)\n\n\n#### v9.3.2 2017-02-11\n\n- [39fd66f](https://github.com/appium/ruby_lib/commit/39fd66f354b6fdd6bba7ae6f5e28f86dc301cdf9) Release 9 3 2 (#487)\n- [7edcd09](https://github.com/appium/ruby_lib/commit/7edcd098be56c0ea72c4d33f91600009df1c1b88) Update changelog and add tests (#486)\n- [5731059](https://github.com/appium/ruby_lib/commit/5731059766542b5a7615fff20644db42177586e4) allow SAUCE_ENDPOINT env var to override sauce server url/path (#485)\n\n\n#### v9.3.1 2017-02-05\n\n- [fa555d1](https://github.com/appium/ruby_lib/commit/fa555d10e7a5c48e4976fbbf2e9c061a5948d6bd) Release 9 3 1 (#484)\n- [c3bc3be](https://github.com/appium/ruby_lib/commit/c3bc3bed375c76e5a7c5fd76bb1225adad54656c) add changelog (#483)\n- [6849567](https://github.com/appium/ruby_lib/commit/68495675f35856bbf4179176f23a3c05f4cb1592) add getting performance command (#480)\n- [0b52c16](https://github.com/appium/ruby_lib/commit/0b52c16b6bf0591b500b1f6e1ebc04c0a7032cc6) Fix missed var rename (#481)\n- [54a8979](https://github.com/appium/ruby_lib/commit/54a897908c066905fd99b5eee7d539a757e987ac) add android tests for capabilities (#477)\n- [5ba85ec](https://github.com/appium/ruby_lib/commit/5ba85ec455378505dd953002ae5aca8bbd980a1f) add documents for toml (#478)\n- [bab7df7](https://github.com/appium/ruby_lib/commit/bab7df7f097fef9e848f33a60d70d0e7e018c25c) Clarify disabling Sauce Labs. (#471)\n- [cf0bda0](https://github.com/appium/ruby_lib/commit/cf0bda06c392274949843888272a762b9ed01a47) remove outdated methods (#475)\n\n\n#### v9.3.0 2017-01-22\n\n- [a1c2872](https://github.com/appium/ruby_lib/commit/a1c287296c9eace08ef19449998fba7229b65697) Release 9 3 0 (#474)\n- [23d937a](https://github.com/appium/ruby_lib/commit/23d937a60da55c2d95ccbbda07ad23bda1b53a7b) update changelogs for v9.3.0 (#472)\n- [34803ef](https://github.com/appium/ruby_lib/commit/34803ef6b7b94df9ef4e147ba8fec5c1d2cfaada) arrange docs (#470)\n- [c1106aa](https://github.com/appium/ruby_lib/commit/c1106aaa6f48a4ed22dc1a7e55c9c4119cdef15c) fix returning only visible elements (#465)\n- [0104a87](https://github.com/appium/ruby_lib/commit/0104a87fad933598bb2b8ac1174319857494ba21) add capability to be able to set default timeout/interval for wait/wait_true (#468)\n- [1372e64](https://github.com/appium/ruby_lib/commit/1372e6453536eb64829825b5bf405ad0f11a9a46) fix typo (#467)\n- [a5ddd4a](https://github.com/appium/ruby_lib/commit/a5ddd4aa1d5f009b9024ee5aa5434805ba73895c) fix swipe, pinch, zoom (#466)\n- [a1c2e9e](https://github.com/appium/ruby_lib/commit/a1c2e9e815e9f85c929da857e26f419629d760df) fix appium server's version check (#464)\n\n\n#### v9.2.0 2017-01-09\n\n- [958ae3e](https://github.com/appium/ruby_lib/commit/958ae3e2fc84b78191baf22e967c8a2fb7eded22) Release 9 2 0 (#460)\n- [292acdf](https://github.com/appium/ruby_lib/commit/292acdf323e7725ef6cc09f2c56d94a8f54ec801) update changelog for 9.2.0 (#458)\n- [1457728](https://github.com/appium/ruby_lib/commit/1457728872214746d9792d916a262a5f996e78ef) Remove last waits (#456)\n- [b10cf83](https://github.com/appium/ruby_lib/commit/b10cf837edafea96e2b2d13e7adf6a87dd448723) add examples for predicate (#455)\n- [d050100](https://github.com/appium/ruby_lib/commit/d050100c0f461c639c417f64ec12d569c412bfb6) Add some documents (#454)\n- [6ee434f](https://github.com/appium/ruby_lib/commit/6ee434f9dbabb7bdb775692382972731c39a71c9) set auomation name from server if client side is nil (#451)\n- [6abb146](https://github.com/appium/ruby_lib/commit/6abb14627fc454684ad4766d9dd95dfd4b52d564) add link to locatorStrategies (#449)\n- [74dc747](https://github.com/appium/ruby_lib/commit/74dc747f56fe78f2bd883c1070d2ea25af0fa382) add changelog (#448)\n- [4e8a449](https://github.com/appium/ruby_lib/commit/4e8a449bf2ff5a3e6f778389b336ecd1a712c25f) arrange a bit (#446)\n- [4efeefa](https://github.com/appium/ruby_lib/commit/4efeefa7e3cb751dcc11280e26169e4ba57b3065) Release 9 1 3 (#445)\n- [ba2fbdc](https://github.com/appium/ruby_lib/commit/ba2fbdcb206609259134fc09eac7940c21cc2c13) Release 9.1.3\n\n\n#### v9.1.3 2017-01-04\n\n- [ba2fbdc](https://github.com/appium/ruby_lib/commit/ba2fbdcb206609259134fc09eac7940c21cc2c13) Release 9.1.3\n- [f0c15c5](https://github.com/appium/ruby_lib/commit/f0c15c5b0211b40a8412583c5180a19dc4b56047) update documentations in xcuitest (#444)\n- [67114d1](https://github.com/appium/ruby_lib/commit/67114d1c16f4289c9aa4e7bb02fcc05a08cc3575) Improve performance for button/s and text/s (#442)\n- [2d1f30e](https://github.com/appium/ruby_lib/commit/2d1f30e9b4d89dc51bb546d535c0bd3f14687394) simplify a bit and move tests to suitable file (#441)\n- [1efed4c](https://github.com/appium/ruby_lib/commit/1efed4cbf45b889ca9e64f91346e786a89ba3c42) add documentation for alternative long_press method (#440)\n- [71e629f](https://github.com/appium/ruby_lib/commit/71e629f34065b6a6e39e9bc18bcf4eb0576be0cb) update small changes (#439)\n- [cec023c](https://github.com/appium/ruby_lib/commit/cec023cc9388afe5283c7637622f369a9b891b1e) Use open timeout and read timeout and require selenium-webdriver3.0.4+ (#437)\n- [ffa78a6](https://github.com/appium/ruby_lib/commit/ffa78a64b1dd68fa24c80779eff0a9c2ab685c19) Release 9 1 2 (#434)\n- [22401b0](https://github.com/appium/ruby_lib/commit/22401b065f2317e82d37b5188ad9c18c701b0a41) Release 9.1.2\n\n\n#### v9.1.2 2016-12-25\n\n- [22401b0](https://github.com/appium/ruby_lib/commit/22401b065f2317e82d37b5188ad9c18c701b0a41) Release 9.1.2\n- [ab3ba8e](https://github.com/appium/ruby_lib/commit/ab3ba8e0fd9e6867b63c5cd0a3f929aca8fc236b) Fix set immediate value (#432)\n- [75acc43](https://github.com/appium/ruby_lib/commit/75acc4313fffca87c3c9c54214175a9981c0d540) disable lint unified integer (#431)\n- [baf5f3c](https://github.com/appium/ruby_lib/commit/baf5f3c7bc3cf51b5f38878f40d88563546dfc10) update tests for finds_exact (#429)\n- [42df79b](https://github.com/appium/ruby_lib/commit/42df79b4cd0b5a36f52628f0acdeb688c5170c0c) fix identicalConditionalBranches (#428)\n- [2a91a6d](https://github.com/appium/ruby_lib/commit/2a91a6dcd50097101e212b1ed9fc64a470dd95da) add appium_client_version (#421)\n- [7c39087](https://github.com/appium/ruby_lib/commit/7c39087676071a4cf27d97fc309e13e968dfb21c) fix rubocop associated with block call (#422)\n- [1979cd8](https://github.com/appium/ruby_lib/commit/1979cd824947d1182fb99ff0f00dbfff165c0aab) Release 9 1 1 (#427)\n- [c016ba3](https://github.com/appium/ruby_lib/commit/c016ba3f9d265ca8b851ec8ed85670ee50b4215b) Release 9.1.1\n\n\n#### v9.1.1 2016-12-19\n\n- [c016ba3](https://github.com/appium/ruby_lib/commit/c016ba3f9d265ca8b851ec8ed85670ee50b4215b) Release 9.1.1\n- [125f144](https://github.com/appium/ruby_lib/commit/125f144481f0b01ab7014ca83968924e7bf827ba) bugfix for finding an array of exact elements in ios (#424)\n- [586205a](https://github.com/appium/ruby_lib/commit/586205ab9d6ce0c286a6036616a7755b74f6a1ba) Release 9 1 0 (#419)\n- [ba9ec64](https://github.com/appium/ruby_lib/commit/ba9ec64031f242b3065674b1e4f8b236b391f9fa) Release 9.1.0\n\n\n#### v9.1.0 2016-12-18\n\n- [ba9ec64](https://github.com/appium/ruby_lib/commit/ba9ec64031f242b3065674b1e4f8b236b391f9fa) Release 9.1.0\n- [5e2ed6a](https://github.com/appium/ruby_lib/commit/5e2ed6a984837ff30efa39ebd36e2ee5fc607c89) update readme and template (#418)\n- [e4b4426](https://github.com/appium/ruby_lib/commit/e4b4426a1322a3a552bad93c4d8a54c9592bebc6) Fix rubocop (#417)\n- [da4ed34](https://github.com/appium/ruby_lib/commit/da4ed34296ebffff8ed6d6b970ca5ca5a47ca72f) Require ruby 22 (#416)\n- [858863a](https://github.com/appium/ruby_lib/commit/858863ad88e0d4e32acb109c6bd087a040817fd2) Support over selenium-webdriver3.0.2 (#413)\n- [fbcaa62](https://github.com/appium/ruby_lib/commit/fbcaa62219eca64ebe8892f02d91b0103ee53909) update selenium-webdriver 3.0 and add patches to work with Appium (#383)\n- [19fb322](https://github.com/appium/ruby_lib/commit/19fb322fe0d9fc184fc708d111764e8b38c3c188) update some tips for finding elements (#412)\n- [e485121](https://github.com/appium/ruby_lib/commit/e4851210a2d0202bea3a62aea7f7c33798476466) Release 9 0 0 (#411)\n- [54ff9c4](https://github.com/appium/ruby_lib/commit/54ff9c45df80ce901b718347e79e761f93a4316b) Release 9.0.0\n\n\n#### v9.0.0 2016-12-09\n\n- [54ff9c4](https://github.com/appium/ruby_lib/commit/54ff9c45df80ce901b718347e79e761f93a4316b) Release 9.0.0\n- [930d4c7](https://github.com/appium/ruby_lib/commit/930d4c701865cfab603c5030bd92d6049bb8b5ad) add documentations (#410)\n- [e765d1f](https://github.com/appium/ruby_lib/commit/e765d1f437a842c942e3efde0a33e15327571ced) Fix tests for xcuitest strategy (#408)\n- [cfabca1](https://github.com/appium/ruby_lib/commit/cfabca11933247e7fba6946d3128cf58035bd820) Feature/xcuitest (#388)\n- [75dd133](https://github.com/appium/ruby_lib/commit/75dd133d3279233312926aff66ec026a7c2e8766) Release 8 2 1 (#407)\n- [ad91ee4](https://github.com/appium/ruby_lib/commit/ad91ee47a96bf7a19b6f784dc760ac70b8788e5a) Release 8.2.1\n\n\n#### v8.2.1 2016-11-29\n\n- [ad91ee4](https://github.com/appium/ruby_lib/commit/ad91ee47a96bf7a19b6f784dc760ac70b8788e5a) Release 8.2.1\n- [62488a5](https://github.com/appium/ruby_lib/commit/62488a551ee2545096a2f4256a41c39a82d506fc) bugfix_swipe_with_deltas (#405)\n- [fdeec0d](https://github.com/appium/ruby_lib/commit/fdeec0de9ac198d77d361c1fb18fc64679d98ac2) Add docs (#404)\n- [63ce8fa](https://github.com/appium/ruby_lib/commit/63ce8fa4eafffe0607b4fc11d86fbdab01a8f7bb) Release 8.2.0 (#403)\n- [4535ec9](https://github.com/appium/ruby_lib/commit/4535ec91f435255ae31b4c4fea9d96e5405d79f5) Release 8.2.0\n- [afcc91e](https://github.com/appium/ruby_lib/commit/afcc91eabea63ec93f70f22b1095f7ce7022af76) Release 8.1.0\n\n\n#### v8.2.0 2016-11-26\n\n- [4535ec9](https://github.com/appium/ruby_lib/commit/4535ec91f435255ae31b4c4fea9d96e5405d79f5) Release 8.2.0\n- [afcc91e](https://github.com/appium/ruby_lib/commit/afcc91eabea63ec93f70f22b1095f7ce7022af76) Release 8.1.0\n- [8a08021](https://github.com/appium/ruby_lib/commit/8a080213dbe4843f50b6acfbe80628209bfd143d) add endpoint for handling IME in remote bridge (#400)\n- [222cd47](https://github.com/appium/ruby_lib/commit/222cd47f69ba24b82a122734b0a136e5d6aed330) Allow to name toml files differently than appium.txt, fixes #280 (#397)\n- [d3a9235](https://github.com/appium/ruby_lib/commit/d3a9235767d6ba770246afac0e62ac58da0eb4b0) update release note and documentation (#396)\n- [b5ac170](https://github.com/appium/ruby_lib/commit/b5ac170f1269e273a01a51429c5e45d2f3e989b1) Release 810 (#394)\n- [95d3a65](https://github.com/appium/ruby_lib/commit/95d3a6535472559590c4d043e887d15acc445a1a) Release 8.1.0\n- [4b5d817](https://github.com/appium/ruby_lib/commit/4b5d81752565f02645e301555e4be78b0235daf5) Release 8.1.0\n\n\n#### v8.1.0 2016-11-18\n\n- [95d3a65](https://github.com/appium/ruby_lib/commit/95d3a6535472559590c4d043e887d15acc445a1a) Release 8.1.0\n- [4b5d817](https://github.com/appium/ruby_lib/commit/4b5d81752565f02645e301555e4be78b0235daf5) Release 8.1.0\n- [6c38ca5](https://github.com/appium/ruby_lib/commit/6c38ca5276342ade6168eb9080424a03608a1b3e) replace end_ to delta_ because end_ is deprecated in #380 (#392)\n- [09654ab](https://github.com/appium/ruby_lib/commit/09654ab9dbc69a31eff7e7bd426db985da09e3b8) Add EventListener to Driver (#389)\n- [2d8fc5f](https://github.com/appium/ruby_lib/commit/2d8fc5ff7acce9417847e66772b59fc691c1dbaa) Added touch id endpoint (#384)\n- [11b80e3](https://github.com/appium/ruby_lib/commit/11b80e398e98fbc71e580f659764ba54f87da4f3) Added double_tap and two_finger_tap to Appium::TouchAction (#377)\n- [2a9f79c](https://github.com/appium/ruby_lib/commit/2a9f79caae337e8770aa56c47d0bd9c17cf1569f) swipe proffers use of delta_x, delta_y instead of end_x, end_y which … (#380)\n- [6705226](https://github.com/appium/ruby_lib/commit/67052266b601270d2432c18b47739c9681af5563) Use secure sauce endpoint (https://ondemand.saucelabs.com:443) (#378)\n- [acdcff0](https://github.com/appium/ruby_lib/commit/acdcff06ae10f1ff4461ed94486346b4514a6e3a) Merge pull request #376 from sergey-plevako-badoo/add_double_tap_and_two_finger_tap\n- [eea3a6f](https://github.com/appium/ruby_lib/commit/eea3a6feaccd317b8a8ac4e2f83cc867613cdd02) Added double_tap and two_finger_tap to Appium::TouchAction\n- [ac03116](https://github.com/appium/ruby_lib/commit/ac03116756a72fbd624fa32ea886123b955d7089) Include url in raised connection error (#374)\n- [924c28b](https://github.com/appium/ruby_lib/commit/924c28bfa675b23b2519565dbcb0ee3531f05cd9) Fix docs of find elements (#372)\n- [8b71cdc](https://github.com/appium/ruby_lib/commit/8b71cdc81be8f50f5f97f0131aee5f3dc67c3eb7) Add default value for duration in swipe (#368)\n- [f58c8aa](https://github.com/appium/ruby_lib/commit/f58c8aa5a9eb349a7224c5c460c5a866444ff5dd) Merge pull request #363 from SrinivasanTarget/master\n- [f8cff26](https://github.com/appium/ruby_lib/commit/f8cff2659992962b6ab5bf49fa075b02d2d110ef) updated webdriver dependency\n\n\n#### v8.0.2 2016-01-29\n\n- [d67cbba](https://github.com/appium/ruby_lib/commit/d67cbbac43f511515f6e6f53197cfae2bb7671e0) Release 8.0.2\n- [ec6815d](https://github.com/appium/ruby_lib/commit/ec6815dcc56ec0e1b56e2ae9eab5786e93d20eec) Update iOS platform version\n- [92be077](https://github.com/appium/ruby_lib/commit/92be077e9eee04f411ac6d93c66004c51fddcbf1) Merge pull request #361 from SrinivasanTarget/master\n- [02a3f5f](https://github.com/appium/ruby_lib/commit/02a3f5f049059401a594db5c4d01202f7112f258) Add device_time\n- [aeb8f9a](https://github.com/appium/ruby_lib/commit/aeb8f9aff7f7288b9f932182a19f8a99c4ffe2fd) Update selenium-webdriver dependency to 2.49\n\n\n#### v8.0.1 2016-01-10\n\n- [ed91786](https://github.com/appium/ruby_lib/commit/ed917866929f0f7b0ff7ef0aedb5a9b35fdcc95b) Release 8.0.1\n- [373f110](https://github.com/appium/ruby_lib/commit/373f11073ba9e8505be18e1826a02cc7d4b62478) Update contributing.md\n- [be4dca6](https://github.com/appium/ruby_lib/commit/be4dca6e8918e368864c383d34a0974c4a0f2a59) Merge pull request #358 from bayandin/change-toml-parser\n- [9a386c4](https://github.com/appium/ruby_lib/commit/9a386c4cb305a9e7440f8c699317087c36f1db33) Replace toml with tomlrb\n- [2ce8376](https://github.com/appium/ruby_lib/commit/2ce83763f7f81caf972b394fa5da7b8cf3065ca7) Merge pull request #357 from bayandin/selenium-compatibility\n- [28f6efb](https://github.com/appium/ruby_lib/commit/28f6efbacfa4954ab487bafd801cb0a68dee8d5d) Do not check platformName in passed caps\n\n\n#### v8.0.0 2015-10-08\n\n- [e71fd1e](https://github.com/appium/ruby_lib/commit/e71fd1e1a220d9453a954ece00e07875a6b5f7ef) Release 8.0.0\n- [c89464f](https://github.com/appium/ruby_lib/commit/c89464f22314d7521292f2b3e9367e53f1c5f00e) Update selenium-webdriver dependency to 2.48\n- [d9fbf8b](https://github.com/appium/ruby_lib/commit/d9fbf8b71c895328c7c0f5ca1de9d4d76490a235) Merge pull request #354 from titusfortner/command_fix\n- [829c76b](https://github.com/appium/ruby_lib/commit/829c76b8f2e2b535dc230106a5e403663d301145) fix COMMANDS location\n- [ad8bf40](https://github.com/appium/ruby_lib/commit/ad8bf400711005f32440618b370ee2551f172a7d) Update badges\n- [252e838](https://github.com/appium/ruby_lib/commit/252e83806318df7df28e9060d3f8e1e56dc732ba) Disable Travis email spam\n\n\n#### v7.0.0 2015-05-08\n\n- [af83896](https://github.com/appium/ruby_lib/commit/af838966d0724793d3dbfa35798ca6dd9f8a3143) Release 7.0.0\n- [7bb780d](https://github.com/appium/ruby_lib/commit/7bb780d2f3d4bbbc2dcade6cd0aa9fdf5cd7b3d9) Fix make_docs script\n- [b8cc4dd](https://github.com/appium/ruby_lib/commit/b8cc4dd425c6b1605d0a67ded8b51dac0ac0373d) Add note about implicit wait change\n- [2599a46](https://github.com/appium/ruby_lib/commit/2599a465896add2cf11634d26bf81bba4a99f39c) Fix set_location Android test on emulator\n- [8162e27](https://github.com/appium/ruby_lib/commit/8162e274732172229df48834c188fbf7d3819430) Work around empty app strings\n- [1657f8c](https://github.com/appium/ruby_lib/commit/1657f8c58c8c8505c3e7f07657fddc6c0b8f154e) Merge pull request #333 from hipyard/geolocation_pr\n- [dbb32b2](https://github.com/appium/ruby_lib/commit/dbb32b25e11576411ae4f62735b4f38e71e074d4) add set_location method for setting geolocation\n- [e441d6d](https://github.com/appium/ruby_lib/commit/e441d6d7d2219194cda58f194c07553e81c4d4d8) Merge pull request #334 from hipyard/settable_logger\n- [ed56450](https://github.com/appium/ruby_lib/commit/ed56450de85926f9bf991f4c50dca81fadad3376) logger setter method\n- [8634cad](https://github.com/appium/ruby_lib/commit/8634cad862f98fcd74e2262261dc86c21f3b5595) Merge pull request #336 from JaniJegoroff/fix-tests\n- [4afcf6f](https://github.com/appium/ruby_lib/commit/4afcf6fac61a973f41e165cf2bb8e48aab5d9ac4) Fix for \"undefined local variable or method\" errors\n- [9ea0754](https://github.com/appium/ruby_lib/commit/9ea07543fd760b3da09ae2673618caff0a383ae2) Merge pull request #330 from JaniJegoroff/add-locked-method\n- [73a7dc0](https://github.com/appium/ruby_lib/commit/73a7dc0b45098e4b26e5fef62207a87e4d6e61a1) Add device_locked? method\n- [1348a8c](https://github.com/appium/ruby_lib/commit/1348a8c015b36d7346542443229b3dfe338a3e48) Update .rubocop.yml\n- [de37577](https://github.com/appium/ruby_lib/commit/de37577fec4eac123c8b07873acd6d0a81de1cc4) Update dependencies\n- [b19d0e0](https://github.com/appium/ruby_lib/commit/b19d0e03940d80314cb61c3c86f28c6f54e9da57) Improve promote method documentation\n- [1b88060](https://github.com/appium/ruby_lib/commit/1b88060dc0a439e02323f52d6d695b1587aeba17) Merge pull request #329 from appium/rubocop\n- [e9d1986](https://github.com/appium/ruby_lib/commit/e9d1986a1e46319bfb42fa30de8c4778f6dbc3fb) Fix remaining rubocop issues\n- [7feace9](https://github.com/appium/ruby_lib/commit/7feace96c7030455a45c7527d3b5c4f184c3abab) Merge pull request #327 from JaniJegoroff/stable-android-tests\n- [502c9d5](https://github.com/appium/ruby_lib/commit/502c9d56e1f1fcfcce1f6016b1484499ec5f2522) Fix for Android tests\n- [b73c782](https://github.com/appium/ruby_lib/commit/b73c78237c4b331b9e4602bd92da7a2de45afc15) Fix rubocop Rakefile issues\n- [93cb8a5](https://github.com/appium/ruby_lib/commit/93cb8a59aa7f4fb0b398aa67cd5b93b6e34534b2) Run rubocop on more files\n- [cd8638b](https://github.com/appium/ruby_lib/commit/cd8638b8dc5a3a313dbbad4c42ed9291789139a8) Merge pull request #325 from JaniJegoroff/rubocop-android-tests\n- [bd54f96](https://github.com/appium/ruby_lib/commit/bd54f9690e57695f85da8378a1f45fc7a314681b) Rubocop - Style/UnlessElse\n- [3c520a9](https://github.com/appium/ruby_lib/commit/3c520a90e8639bdb265f3849ff5d84ad751f5d78) Rubocop - Metrics/LineLength\n- [e80398f](https://github.com/appium/ruby_lib/commit/e80398f149d8f3767512831b91af598e98ec4d59) Rubocop - Lint/RescueException\n- [b41a3da](https://github.com/appium/ruby_lib/commit/b41a3dabbf662eaa3d6498245d2f305d7e0d96a9) Rubocop - Style/Semicolon\n- [af3ea2e](https://github.com/appium/ruby_lib/commit/af3ea2ee0f8aba75262966025965ef5cc6af0f86) Rubocop - Style/PredicateName\n- [7907af6](https://github.com/appium/ruby_lib/commit/7907af6f67add544ca122eb696ec5647b6a8652b) Rubocop - Style/BlockComments\n- [95d34b7](https://github.com/appium/ruby_lib/commit/95d34b71e268d67c7561e96d8a9206f6d9895b0b) Rubocop - Style/SignalException\n- [cd6728f](https://github.com/appium/ruby_lib/commit/cd6728f4836aea74bed25b1d4571d73319cd280d) Rubocop - Style/SymbolProc\n- [e383ac6](https://github.com/appium/ruby_lib/commit/e383ac618411c5055839bbd3a908e050e4039fdc) Rubocop - Style/PercentLiteralDelimiters\n- [211bd82](https://github.com/appium/ruby_lib/commit/211bd821deb40a20034c1c20bcc1572a8ba47aef) Rubocop - Style/LeadingCommentSpace\n- [d141499](https://github.com/appium/ruby_lib/commit/d14149962c3ec7788beda980fa849dc5ca4683e8) Rubocop - Style/CommentIndentation\n- [45dbc04](https://github.com/appium/ruby_lib/commit/45dbc0414df6c59879760d92b14ac3aa999b3d6f) Rubocop - Style/CommentAnnotation\n- [db0961f](https://github.com/appium/ruby_lib/commit/db0961f03351bb04cdc6f43421bd1099b1e9bbfa) Rubocop - Style/DeprecatedHashMethods\n- [d710d6e](https://github.com/appium/ruby_lib/commit/d710d6e68c19abaf1f30ea7c645f83c3efc80af0) Rubocop - Style/EmptyLinesAroundBlockBody\n- [e8875c1](https://github.com/appium/ruby_lib/commit/e8875c176710d49b1aa65db074cf4cc5f602df09) Rubocop - Style/SpaceInsideParens\n- [b489f48](https://github.com/appium/ruby_lib/commit/b489f48adc96c4241ec53dfe73b94161d1d8dbd1) Rubocop - Lint/AmbiguousRegexpLiteral\n- [807f258](https://github.com/appium/ruby_lib/commit/807f258766be2a892f7e1ddb8fb9eb89dd36c680) Rubocop - Style/TrailingComma\n- [432144f](https://github.com/appium/ruby_lib/commit/432144fbc54ff91985b54c9100b2b45f238a0b90) Rubocop - Style/MethodDefParentheses\n- [510a2a6](https://github.com/appium/ruby_lib/commit/510a2a6ebc8ad3bfd6e8ad3c2720b8ac2ea76885) Rubocop - Lint/DeprecatedClassMethods\n- [47f1790](https://github.com/appium/ruby_lib/commit/47f179040dfaab80e043eaf11e5d2582b91c06c6) Rubocop - Style/BracesAroundHashParameters\n- [1b946fb](https://github.com/appium/ruby_lib/commit/1b946fbc2de48d73623c0f20340d74e2b2ecec9b) Rubocop - Style/HashSyntax\n- [86163f7](https://github.com/appium/ruby_lib/commit/86163f7ec0a247dd73885de14011821b6ebb2100) Rubocop - Style/TrailingBlankLines\n- [a7aef30](https://github.com/appium/ruby_lib/commit/a7aef30492334e57aa9e1e421062840765b852b3) Rubocop rake task\n- [1be017b](https://github.com/appium/ruby_lib/commit/1be017b14e1fedef9511a0341839b45d1d754c36) Merge pull request #324 from appium/rubocop\n- [fb534a0](https://github.com/appium/ruby_lib/commit/fb534a0078a0ce2097990591455f35d3d843da9b) Fix more rubocop issues\n- [893165d](https://github.com/appium/ruby_lib/commit/893165dc1a869a2d240c054e13d26438728efb98) Merge pull request #323 from JaniJegoroff/rubocop-ios-tests\n- [b1d9d5f](https://github.com/appium/ruby_lib/commit/b1d9d5fbdc54cb19a4b334d8820dfa7122118a9d) Rubocop - Metrics/LineLength\n- [39d8b4e](https://github.com/appium/ruby_lib/commit/39d8b4e8354cf8afbd96d8721582cdcab4b49b48) Rubocop - Lint/RescueException\n- [1460120](https://github.com/appium/ruby_lib/commit/1460120819e09c5879882661de49e7042d0892a4) Rubocop - Lint/HandleExceptions\n- [7f04d50](https://github.com/appium/ruby_lib/commit/7f04d50f7bea7a042115653d3f45d84d181b302c) Rubocop - Style/Semicolon\n- [1615e6d](https://github.com/appium/ruby_lib/commit/1615e6df1bd0dd5e721a5226cffb781d5a7c08bf) Rubocop -Lint/ShadowingOuterLocalVariable\n- [15e7c62](https://github.com/appium/ruby_lib/commit/15e7c62e068fdff2b935c53ad731351655027ce0) Rubocop - Style/SignalException\n- [0ecda98](https://github.com/appium/ruby_lib/commit/0ecda987aa73799dd45c423b5a1b7d28f595ca17) Rubocop - Style/BlockComments\n- [6dc9ee1](https://github.com/appium/ruby_lib/commit/6dc9ee16ab4d71f69da30f2e277dec787ebea8fd) Rubocop - Style/BlockComments\n- [a9d9573](https://github.com/appium/ruby_lib/commit/a9d9573a0b79490d357cd44ae8ac51f77bbfb83e) Rubocop - Style/SpaceAroundEqualsInParameterDefault\n- [66f4e14](https://github.com/appium/ruby_lib/commit/66f4e146a945db5a992c14805542ce3a4eb39ba0) Rubocop - Style/LeadingCommentSpace\n- [6c8efda](https://github.com/appium/ruby_lib/commit/6c8efdaca119c2b16728aac34ec97ed5516a689a) Rubocop - Style/PredicateName\n- [aef6dc9](https://github.com/appium/ruby_lib/commit/aef6dc9bfff3a7f17180ef5f3cd71013b8e3b256) Rubocop - Style/EmptyLinesAroundBlockBody\n- [c964236](https://github.com/appium/ruby_lib/commit/c9642368577156ac339755df0677432c8b21e11e) Rubocop - Style/CommentIndentation\n- [d9478af](https://github.com/appium/ruby_lib/commit/d9478afd066cd9add9993306ab6936cd450478b5) Rubocop - Style/SpaceAroundOperators\n- [22a329e](https://github.com/appium/ruby_lib/commit/22a329e4412be870fae9ddfef23974382038f05b) Rubocop - Style/BarePercentLiterals\n- [9b855c9](https://github.com/appium/ruby_lib/commit/9b855c904d578f7dcc317bee3d5db2f0d5108843) Rubocop - Style/SymbolProc\n- [4720e82](https://github.com/appium/ruby_lib/commit/4720e829b878ca048fa363073ba1f1fbe6afe1ec) Rubocop - Lint/AmbiguousRegexpLiteral\n- [7477497](https://github.com/appium/ruby_lib/commit/747749775a814bfc231037c1f41860e0df8a3b52) Rubocop - Style/StringLiterals\n- [40c060b](https://github.com/appium/ruby_lib/commit/40c060b64b64115a6780832955c84781db0381d4) Rubocop - Style/SpaceAfterNot\n- [2793129](https://github.com/appium/ruby_lib/commit/2793129df74057592069593db1eee80a4c5d673d) Rubocop - Style/CommentAnnotation\n- [e7750e9](https://github.com/appium/ruby_lib/commit/e7750e9897febdbd27192548af7b156925b9273d) Rubocop - Style/RedundantSelf\n- [403badd](https://github.com/appium/ruby_lib/commit/403badd2aaba11bd833210083a809fdd46da7e4e) Rubocop - Style/MethodDefParentheses\n- [a62ed2a](https://github.com/appium/ruby_lib/commit/a62ed2abf937da9875f7f16e8ffa0f390a5a33d7) Fix Rubocop rake task pattern\n- [1aaa1db](https://github.com/appium/ruby_lib/commit/1aaa1db2020a9dc37e3caa858c9290a814daf9e4) Rubocop rake task\n- [d2e1857](https://github.com/appium/ruby_lib/commit/d2e185708e41807e11bc1e607b9baada8e711823) Rubocop - Style/TrailingWhitespace\n- [602cb2a](https://github.com/appium/ruby_lib/commit/602cb2a18dfca30f4d0b6aeed84a5786175c1929) Rubocop - Style/TrailingBlankLines\n- [19507f5](https://github.com/appium/ruby_lib/commit/19507f584515484eba7b98acfada55bcf9d81e0e) Merge pull request #322 from JaniJegoroff/fix-ios-tests\n- [f0f4f84](https://github.com/appium/ruby_lib/commit/f0f4f847a244ed06b5bf53b5c9b02a3562b1cce2) Fixed iOS tests and updated documentation\n- [305ce9c](https://github.com/appium/ruby_lib/commit/305ce9c956be4879b3bb70f56a4df71fb4380c62) Add .rubocop.yml\n- [4b0383c](https://github.com/appium/ruby_lib/commit/4b0383c86c0fcfa98ab759b3f9d1b386ac33bb6b) Add travis. Update migration doc\n- [3dc3d0c](https://github.com/appium/ruby_lib/commit/3dc3d0cec10cd256dc4adb89e6c53b85107678ef) Merge pull request #320 from JaniJegoroff/rubocop-warning-fixes\n- [e539d7c](https://github.com/appium/ruby_lib/commit/e539d7c7596af1c56587a5056fef74d936ddc0ce) Renamed method installed? to app_installed?\n- [4ba5ed9](https://github.com/appium/ruby_lib/commit/4ba5ed90f19c5d9cf71b461142bc1a5890d20574) Link to new Ruby docs\n- [47276b5](https://github.com/appium/ruby_lib/commit/47276b5c11f47e0940d4407031f8bd7918c43094) Rubocop - Lint/UselessAssignment\n- [7ec6396](https://github.com/appium/ruby_lib/commit/7ec6396a166793c467fc7b1539d34f7ac6b55105) Rubocop - Style/ClassAndModuleChildren\n- [25cd420](https://github.com/appium/ruby_lib/commit/25cd420a602744ed30ff0fb99aef9c2821d46d8b) Rubocop - Style/PredicateName\n- [52d4910](https://github.com/appium/ruby_lib/commit/52d4910133c828de8d807de30e88104d772ab28c) Rubocop - Style/MethodName\n- [9df1000](https://github.com/appium/ruby_lib/commit/9df1000719f99aff44f1ac9623190531bf76b6c7) Rubocop - Style/CommentAnnotation\n- [156d595](https://github.com/appium/ruby_lib/commit/156d59563c663d937a3405098bb6204854d91592) Rubocop - Style/BlockComments\n- [dbda46d](https://github.com/appium/ruby_lib/commit/dbda46dcf7072fa5e8ad6304920f246245377f13) Rubocop - Style/LineEndConcatenation\n- [8c34235](https://github.com/appium/ruby_lib/commit/8c342350ad939875893e8efda347de7e0b4fd03b) Rubocop - Metrics/BlockNesting\n- [97e54a6](https://github.com/appium/ruby_lib/commit/97e54a6b73669ffe52d23665b8492d49b54e03fa) Rubocop - Style/VariableName\n- [5222346](https://github.com/appium/ruby_lib/commit/52223461b25e61de5fb3f3e73fbf8a3aef356188) Rubocop - Style/AlignParameters\n- [22f849e](https://github.com/appium/ruby_lib/commit/22f849e6318c9843ea9f03c3cb68b9e60b29c323) Rubocop - Metrics/MethodLength (custom method length)\n- [58aae60](https://github.com/appium/ruby_lib/commit/58aae603561270163a792354da9113fb59242f67) Rubocop - Style/ConstantName (cop disabled)\n- [2bc8006](https://github.com/appium/ruby_lib/commit/2bc8006d2e21ba9088f3e6ed14be9c57af905565) Rubocop - Style/IfUnlessModifier\n- [3434ec7](https://github.com/appium/ruby_lib/commit/3434ec76648eb354e6ea77c382f800ea7c64d098) Rubocop - Style/AlignHash\n- [548f632](https://github.com/appium/ruby_lib/commit/548f632ce73b7ded082982301369248004af4a55) Rubocop - Style/MultilineOperationIndentation\n- [610c172](https://github.com/appium/ruby_lib/commit/610c172530d141a98c28880f9cc0973be6123183) Rubocop - Lint/AmbiguousRegexpLiteral\n- [c68702d](https://github.com/appium/ruby_lib/commit/c68702d78459b94a656db7644eb03aae5616d26c) Rubocop - Style/SignalException\n- [318372e](https://github.com/appium/ruby_lib/commit/318372e7a90d34f2ce00816b9f824d41adebb36c) Rubocop - Style/NilComparison\n- [7994d0f](https://github.com/appium/ruby_lib/commit/7994d0fe82d1353d4f91bddea3cbbb583d0ef5d6) Rubocop - Style/PercentLiteralDelimiters\n- [4a6902d](https://github.com/appium/ruby_lib/commit/4a6902dbbfe74eb83d290643138aab803c4abf5f) Rubocop - Style/GuardClause\n- [07ebfbf](https://github.com/appium/ruby_lib/commit/07ebfbfac19aba459b5711ace9fe87cfe877c2db) Rubocop - Style/SingleSpaceBeforeFirstArg\n- [ded2c9a](https://github.com/appium/ruby_lib/commit/ded2c9a400549942178146addcc3eb86251f768b) Rubocop - Style/CaseEquality\n- [cd7c67e](https://github.com/appium/ruby_lib/commit/cd7c67e56293297c49becaff1eb213e782ab5819) Rubocop - Style/MultilineTernaryOperator\n- [afddea3](https://github.com/appium/ruby_lib/commit/afddea3188c4ce877e6babdf32833e0485b5864b) Rubocop - Style/CaseIndentation\n- [a843671](https://github.com/appium/ruby_lib/commit/a8436714e000887cbf2b22a77369686df32e937a) Rubocop - Style/EmptyLinesAroundClassBody\n- [829b17d](https://github.com/appium/ruby_lib/commit/829b17dd7625c3ece5b79ae8c8c053fa6c70d337) Rubocop - Lint/ShadowingOuterLocalVariable\n- [f5fd8cf](https://github.com/appium/ruby_lib/commit/f5fd8cf487194a53c9c72d738c1c69e669b97cfb) Rubocop - Style/RedundantSelf\n- [4444168](https://github.com/appium/ruby_lib/commit/444416801d5bf7176c83e4bddd60969b375a4ec5) Rubocop - Style/LeadingCommentSpace\n- [b18ae54](https://github.com/appium/ruby_lib/commit/b18ae540e02f3de50851fbf5128d53a31328fbb5) Rubocop - Lint/UnusedMethodArgument\n- [4e24752](https://github.com/appium/ruby_lib/commit/4e2475266401ae72f7506ed5e14cf340d19e4898) Rubocop - Style/FirstParameterIndentation\n- [5841e9d](https://github.com/appium/ruby_lib/commit/5841e9d6c6879f2aa3a0b13791e6a93086f8a96f) Rubocop - Style/DeprecatedHashMethods\n- [0264c37](https://github.com/appium/ruby_lib/commit/0264c376d9f81ce1037a106314594e23438ca723) Rubocop - Lint/DeprecatedClassMethods\n- [1923f64](https://github.com/appium/ruby_lib/commit/1923f6484b7920199604647b682ba935213bb813) Rubocop - Metrics/LineLength\n- [0ab729a](https://github.com/appium/ruby_lib/commit/0ab729a16b6678ac993dafd93d05d8cf6ceb0703) Custom config file for Rubocop\n- [6f18e6f](https://github.com/appium/ruby_lib/commit/6f18e6f24519bc77581da2fcd1a9d048b2850e15) Rubocop - Style/ColonMethodCall\n- [7ba83e5](https://github.com/appium/ruby_lib/commit/7ba83e575ae255f561e919a5a850cab96a14b3bc) Rubocop - Style/IndentationWidth\n- [20ebd0b](https://github.com/appium/ruby_lib/commit/20ebd0bc014e7f9e5ee3066b20562d602bf87751) Rubocop - Style/BracesAroundHashParameters\n- [9b08ab7](https://github.com/appium/ruby_lib/commit/9b08ab7f43ca6b0bbfea42afcec61146348bcd19) Rubocop - Style/HashSyntax\n- [7f28fb2](https://github.com/appium/ruby_lib/commit/7f28fb250abf7b6ea0279c9b19432f13ecfee90c) Rubocop - Style/MultilineOperationIndentation\n- [978b648](https://github.com/appium/ruby_lib/commit/978b6485b6b959f0cd2b481d67d2972914e84abf) Rubocop - Style/CommentAnnotation\n- [e939a7c](https://github.com/appium/ruby_lib/commit/e939a7cd8d720aaabc8c5a8f1e9bdfc82db1bdd2) Rubocop - Style/CommentIndentation\n- [40b6e10](https://github.com/appium/ruby_lib/commit/40b6e10b1aacad0747c1ff26795c27064f77538a) Rubocop - Style/EmptyLinesAroundModuleBody\n- [49ba5a9](https://github.com/appium/ruby_lib/commit/49ba5a9c9a7d5178f8f65b10a6f78670c4e9bada) Rubocop - Style/ClassCheck\n- [5b40de9](https://github.com/appium/ruby_lib/commit/5b40de93f3b533304802e1dbf90ea9448a5f5ffa) Rubocop - Style/SelfAssignment\n- [3e20158](https://github.com/appium/ruby_lib/commit/3e20158258d0ca85bb947cba81e4b1c70f6c44b9) Rubocop - Style/EmptyLines\n- [91de46e](https://github.com/appium/ruby_lib/commit/91de46e1fde964a64ff580a629e5d87481603cb7) Revert \"Rubocop - Style/RegexpLiteral\"\n- [d79ad18](https://github.com/appium/ruby_lib/commit/d79ad184c27a88766b38b27f5dd0ad0d361af592) Rubocop - Style/RegexpLiteral\n- [9a38dfb](https://github.com/appium/ruby_lib/commit/9a38dfb2255e47c732cc5ae72a76d366f96be198) Rubocop - Lint/AmbiguousOperator\n- [ab06fa4](https://github.com/appium/ruby_lib/commit/ab06fa4f47c8fde0108cafa3de15fb8eb5176170) Rubocop - Lint/UnusedBlockArgument\n- [4ce71f8](https://github.com/appium/ruby_lib/commit/4ce71f82b554c193bd741c100c9fdd15f193773c) Rubocop - Style/SymbolProc\n- [8389f70](https://github.com/appium/ruby_lib/commit/8389f70a91dc9ae540b94b89ed67f65dce9fefc5) Rubocop - Style/BarePercentLiterals\n- [b818def](https://github.com/appium/ruby_lib/commit/b818defb371a4fe69b30254255556422ecc8e9c0) Rubocop - Style/MethodDefParentheses\n- [f2ed949](https://github.com/appium/ruby_lib/commit/f2ed949ae8fa94ca54241a37856c5805afc8e983) Rubocop - Style/SpaceAroundOperators\n- [4fe1f3c](https://github.com/appium/ruby_lib/commit/4fe1f3c6f852d17c4463bddff87005947cd3e5da) Rubocop - Style/AccessModifierIndentation\n- [76a8888](https://github.com/appium/ruby_lib/commit/76a8888350af9f2e94777d48dd56440fc74ef5d7) Rubocop - Style/RedundantReturn\n- [96c65d7](https://github.com/appium/ruby_lib/commit/96c65d7ecb12d426bb8b004abe27d487cf7144ba) Rubocop - Style/TrailingComma\n- [da9c079](https://github.com/appium/ruby_lib/commit/da9c079b81d9078d6f1d9381231f4b2ca27df4db) Rubocop - Style/SpaceInsideBlockBraces\n- [3fc783e](https://github.com/appium/ruby_lib/commit/3fc783e98800c1bad9bda20ce956e9e1729e6caf) Rubocop - Style/TrailingWhitespace\n- [55b3c90](https://github.com/appium/ruby_lib/commit/55b3c9022dcf21141b6efd4d0f6afc440910c288) Rubocop - Style/SpaceAroundEqualsInParameterDefault\n- [677d7e2](https://github.com/appium/ruby_lib/commit/677d7e21eff15d72c02386c97b4cc454442d0f51) Rubocop - Style/TrailingBlankLines\n- [0084c57](https://github.com/appium/ruby_lib/commit/0084c57cdbde899edd4d79dfbead2a6b107eaf86) Rubocop rake task\n- [0059d23](https://github.com/appium/ruby_lib/commit/0059d2337f8d8f2948028c73ecd8a1c681c6636c) Set default wait to 0\n- [b5bb400](https://github.com/appium/ruby_lib/commit/b5bb4003d78988ec33546cf02d274c86bfa83dbb) Validate resourceId before searching\n- [c41ee41](https://github.com/appium/ruby_lib/commit/c41ee416214571e304465d135ff18be8c5bcf86b) Add issuestats badges\n- [2bb8694](https://github.com/appium/ruby_lib/commit/2bb869486e31145124c64cfd555bac9f57e576b7) Raise command error on nil mainWindow for iOS\n- [f2122de](https://github.com/appium/ruby_lib/commit/f2122de35a9bed7756207d679f9a83c68dcc4642) Don't crash when mainWindow is UIAElementNil\n\n\n#### v6.0.0 2015-01-26\n\n- [ea11190](https://github.com/appium/ruby_lib/commit/ea11190b9ab36e34226d988f85fe612af6f769de) Release 6.0.0\n- [d15371d](https://github.com/appium/ruby_lib/commit/d15371deb2bbb0e6a441c7b38cabdc83b3e36256) Update readme.md\n- [4f99dd3](https://github.com/appium/ruby_lib/commit/4f99dd31ad0a1976214858195b5911e79a42c3a1) Merge pull request #302 from whoward/use-logger\n- [1673a69](https://github.com/appium/ruby_lib/commit/1673a694121d2ae24ffd1530eb71b7015d44dc52) Use the logger object for outputting debug information\n- [4573473](https://github.com/appium/ruby_lib/commit/457347379f26804af143269e896f45869e2860e1) Create index_paths.md\n\n\n#### v5.0.1 2014-12-30\n\n- [9b15701](https://github.com/appium/ruby_lib/commit/9b157011965442e6f021dcfeef588450277f1c6a) Release 5.0.1\n- [d2e12d8](https://github.com/appium/ruby_lib/commit/d2e12d8275f01f1652430d7908dd118bbfeec706) Merge pull request #298 from sbonebrake/upgrade_awesome_print\n- [4478662](https://github.com/appium/ruby_lib/commit/44786624397303e9785ce9322b7c6e625e70694e) Upgrade awesome_print and remove the ostruct patch. This fixes issue #297.\n- [fbf9a6e](https://github.com/appium/ruby_lib/commit/fbf9a6ed170f65d91f53617f0509c5b222bf3859) Update migration.md\n- [d5172bd](https://github.com/appium/ruby_lib/commit/d5172bd773f8d36e66e9b573c74e99d762d1c28d) Update migration.md\n\n\n#### v5.0.0 2014-12-23\n\n- [7c3bc19](https://github.com/appium/ruby_lib/commit/7c3bc19905d0f008192a59dc7f5a938e3701ec8f) Release 5.0.0\n- [0585d78](https://github.com/appium/ruby_lib/commit/0585d78042ec6e32e00dc349c70fb56179db6b1d) Fix page command on Android\n- [1f2d10a](https://github.com/appium/ruby_lib/commit/1f2d10afa37b9ca863f94eac9558467b3c2539f4) Test touchactions in new file\n- [6a638c4](https://github.com/appium/ruby_lib/commit/6a638c4a752f135830cb57f58ec5e373b8461944) Fix webview page inspection\n- [ddd94b4](https://github.com/appium/ruby_lib/commit/ddd94b498601bfd961dc449f00e584ed6bf753d8) Remove method_missing\n- [ad10640](https://github.com/appium/ruby_lib/commit/ad10640c58ba1435b32a4d3a8268f66ae4c4b74e) Fix set_immediate_value & update debugging\n- [7c9e8d0](https://github.com/appium/ruby_lib/commit/7c9e8d0ee33a2d067d4e8c5cb19abf456306851a) Don't try and hide the keyboard after .type\n- [544e34a](https://github.com/appium/ruby_lib/commit/544e34a7cb8c749947e0f1ac4f2cf02a561a32c3) Fix #291 always set implicit wait to default wait\n- [d6dacd0](https://github.com/appium/ruby_lib/commit/d6dacd03624d8fce68cfbe7419bc0046072955b8) Clean up button test on iOS\n- [2967a52](https://github.com/appium/ruby_lib/commit/2967a5212cdabbf972d7000ddc275eab7f0293ef) Update contributing.md\n- [ad35078](https://github.com/appium/ruby_lib/commit/ad35078239f62483345505da2289aa2820a19333) Update contributing.md\n- [3943039](https://github.com/appium/ruby_lib/commit/394303988c41631b1715dd4731eedbc92de2a568) Create contributing.md\n- [20c0c4d](https://github.com/appium/ruby_lib/commit/20c0c4d66ef6f2bab9e7ddaae64e778d510c20bb) Merge pull request #289 from sofaking/master\n- [0e223ac](https://github.com/appium/ruby_lib/commit/0e223ac4097e8e6f43c2a33177355ddf852562c5) iOS text elements tests are green\n- [16b33af](https://github.com/appium/ruby_lib/commit/16b33af71bd9aec70f01635f775b9cc82c52ae4d) iOS button elements tests are green\n- [524d412](https://github.com/appium/ruby_lib/commit/524d412ca2576f2b5d0f284fcb9414960b62b97b) Get back to catalog after web view test\n- [06c3a75](https://github.com/appium/ruby_lib/commit/06c3a75d9350f603b2c06c73341b55020f5217fb) iOS driver tests are green\n- [c2e80f0](https://github.com/appium/ruby_lib/commit/c2e80f0351ffb2f71a7702d1d9e6d75b734f53ef) iOS web context test is green\n- [718e6f5](https://github.com/appium/ruby_lib/commit/718e6f541e594c820ab98b13ecc30ac0ae101774) Generic element tests for iOS are green now\n- [0651054](https://github.com/appium/ruby_lib/commit/065105471867a87ea364064191defb43107f79d3) ios helper tests are green now\n- [1356454](https://github.com/appium/ruby_lib/commit/1356454390a001c85e885ae00510167362ca89db) Compatibility with Rubies older than 2.1.0\n- [99c0b12](https://github.com/appium/ruby_lib/commit/99c0b128da5c6c4e7df2fb1313b7e84f1d6075c9) Add bootcamp guide & example links\n- [8d2daeb](https://github.com/appium/ruby_lib/commit/8d2daeb9544f6743856552c6828e71bbdecf130f) Fix iOS 8.1 driver test\n- [c52b099](https://github.com/appium/ruby_lib/commit/c52b09959ffa60784c1b91bf8d7eb9c1a4456725) Update button test\n- [a069f28](https://github.com/appium/ruby_lib/commit/a069f28854b722e56a34b4796d43c9aed3e833e6) Fix iOS 8.1 test device/device\n- [4643510](https://github.com/appium/ruby_lib/commit/4643510b8f0ac474340f65ab017b318fd06563a3) Update iOS 8.1 test ios/element/button  ✓\n- [44c930a](https://github.com/appium/ruby_lib/commit/44c930acce8ee9ef55f9de418922aefc0de39933) Merge pull request #285 from sbonebrake/touch_action_sauce_fix\n- [bbb4cc2](https://github.com/appium/ruby_lib/commit/bbb4cc2c65174d340a38d08f8e48ef55fef8d2ae) Fix for issue #283 'Ruby bindings TouchAction broken on Sauce Labs'\n- [3cfe864](https://github.com/appium/ruby_lib/commit/3cfe8648827ed6f78fb4d3bb9610f15aebbb38ed) Update tests for new api.apk\n- [f1e353a](https://github.com/appium/ruby_lib/commit/f1e353a5720a8dd202be7edd1f6f11235c8aad4a) Skip launch_app test\n- [8000cfa](https://github.com/appium/ruby_lib/commit/8000cfaa5268d70288d0e3f4ae7e2c8386b5076b) Add _app suffix to install/remove/launch\n- [bc81782](https://github.com/appium/ruby_lib/commit/bc8178235ed2dd97491d1ab528c68c01cd17a0bc) Fix android common/device test\n- [252df47](https://github.com/appium/ruby_lib/commit/252df470e9f6fb13f855f0ff2c7320b71499dbfd) Reimplement ele_index / tag to avoid xpath\n- [c5cf51d](https://github.com/appium/ruby_lib/commit/c5cf51d489e2e1d75e5b649f1c7767ec475d268a) Rewrite iOS helpers\n- [eb22269](https://github.com/appium/ruby_lib/commit/eb22269712354e5ad9e8af1db30954136930c425) Fix iOS textfield tests\n- [cfad029](https://github.com/appium/ruby_lib/commit/cfad029ea595f12e0328e7600c7d8c5e2abcd431) Rewrite iOS textfield helpers\n- [98a561b](https://github.com/appium/ruby_lib/commit/98a561beae09017eaa8be4b1d7cdaf5e3d6e1575) Add _elementOrElementsByType for iOS\n- [0b9aa53](https://github.com/appium/ruby_lib/commit/0b9aa5399ea7e4bd981ec7b65513f15423c07a6a) Regenerate docs\n- [b7def85](https://github.com/appium/ruby_lib/commit/b7def85c2bd734049121f7f3ca184d0b26e477fe) Fix accessor docs\n- [b38c783](https://github.com/appium/ruby_lib/commit/b38c7830250067c25834796e4a513fda7e6f3588) Update predicate methods. Fix version ref\n- [8d3bbc5](https://github.com/appium/ruby_lib/commit/8d3bbc53fb75e7f5fe60ffe7219f8fcb18095262) Restore xpath based textfield helper for iOS\n- [de61d18](https://github.com/appium/ruby_lib/commit/de61d18c1a0952cf72a34143672f5f46f962b3d2) Fix ios/element/text test\n- [d90446d](https://github.com/appium/ruby_lib/commit/d90446db37ffdc8db31bdacecc0a4083d91dd6ae) Fix common/helper iOS test\n- [5042465](https://github.com/appium/ruby_lib/commit/50424651ce90bd9d311cac2c6648dd3908a95a85) Update device attr docs\n- [e1f041f](https://github.com/appium/ruby_lib/commit/e1f041f96bc9acee6b218db646be078d68a21495) Device Modes\n- [dfdacdf](https://github.com/appium/ruby_lib/commit/dfdacdfbd3a1a932dcf98ac46a4f0ff8d38356b3) Update docs.md\n- [a0a74a9](https://github.com/appium/ruby_lib/commit/a0a74a95c2dd842202380946befe496b324a50b8) Add example of automating preinstalled Android app\n- [4569b0e](https://github.com/appium/ruby_lib/commit/4569b0e80ebafac295f39e42d93204d440320eff) Merge pull request #267 from 0x1mason/2969\n- [cfe9f29](https://github.com/appium/ruby_lib/commit/cfe9f2982d1dff85591ff7375dd92bf54bbd1e75) Added start_activity function and tests\n- [af6d44c](https://github.com/appium/ruby_lib/commit/af6d44c6ccd3f32a9553be3c290000421edae92d) Add User-Agent\n- [29dfcbe](https://github.com/appium/ruby_lib/commit/29dfcbe45f9f70602fa29213a032114d3a751150) Merge pull request #266 from Jonahss/master\n- [ca42554](https://github.com/appium/ruby_lib/commit/ca425545770af7530c6820be59f211a0d0f50009) added get_settings and update_settings methods\n- [7cd7431](https://github.com/appium/ruby_lib/commit/7cd74310638df62683f804f6e961cb34832ca728) Merge pull request #252 from jskswamy/master\n- [3ab6f01](https://github.com/appium/ruby_lib/commit/3ab6f01676e03d263be4bdb9193eef125204cc0d) Update nokogiri\n- [afcbd6b](https://github.com/appium/ruby_lib/commit/afcbd6b6ed868c189b383235a5a81762b0258a08) Update gemspec\n- [5f0c1c5](https://github.com/appium/ruby_lib/commit/5f0c1c569b2eb6014982cd9c1c246215dc3375ab) Fix textfield index\n- [d4517b8](https://github.com/appium/ruby_lib/commit/d4517b878763523068f99b89b38a1ea3b0a98c4b) Update comment\n- [b71c9d4](https://github.com/appium/ruby_lib/commit/b71c9d4dfe5d00e368b7fe56a88a6accfeb7485e) Fix get_source\n- [c352e68](https://github.com/appium/ruby_lib/commit/c352e6855e9d503199d86640d232dce7bda1734b) Fix uiautomator's invalid xml #243\n- [c2b5dcb](https://github.com/appium/ruby_lib/commit/c2b5dcbf733575ffa846432b21fa97575415aab3) Use predicates for ios/element/textfield\n\n\n#### v4.1.0 2014-07-21\n\n- [a13158f](https://github.com/appium/ruby_lib/commit/a13158fb926212d84f26120c3bc5355c8cd34baf) Release 4.1.0\n- [be1c710](https://github.com/appium/ruby_lib/commit/be1c710134ee9a001b8e71c0ce5cbb5786bebf1e) Update android specs\n- [4edd949](https://github.com/appium/ruby_lib/commit/4edd94989519ec14acf9c694d9ed3ae6a5939b10) Update self.promote_singleton_appium_methods\n- [82a236a](https://github.com/appium/ruby_lib/commit/82a236a84742f1eb6d55acab00d8f222d721bd9a) Update docs.md\n- [a724d5d](https://github.com/appium/ruby_lib/commit/a724d5d3711cdfa3ea420663949c06017189bf02) Fix #224\n- [d05bfe8](https://github.com/appium/ruby_lib/commit/d05bfe85d6c356a8ea6a0f151aaf21dfef979736) Fix docs\n- [c04d6f0](https://github.com/appium/ruby_lib/commit/c04d6f048ee4e24c66bef662e31a0d957360e7a7) Fix wait / wait_true by using selenium wait method\n- [da19c8c](https://github.com/appium/ruby_lib/commit/da19c8cca5753f06576b82bbbb6e77e7e36bcb9c) Add iOS 7 note to swipe\n- [4f4d800](https://github.com/appium/ruby_lib/commit/4f4d80094eac5a4fbc2c11b8050155b2f767839c) Add client side xpath support\n\n\n#### v4.0.0 2014-07-05\n\n- [8cc004a](https://github.com/appium/ruby_lib/commit/8cc004ad04ec087a8a11c06ca0749a5e2c6586a7) Release 4.0.0\n- [e8c52c6](https://github.com/appium/ruby_lib/commit/e8c52c67226c94689c715a87ec7cee49c20c0821) Add note to android install test\n- [e5b3939](https://github.com/appium/ruby_lib/commit/e5b3939068f3fcd65ecd04f3f6fdd8652a159c43) Update install test on Android\n- [e02498c](https://github.com/appium/ruby_lib/commit/e02498c59272a173aed2eca662ef0c38539b6b24) Fix #152\n- [b9db60f](https://github.com/appium/ruby_lib/commit/b9db60fc686c190561d352689dbdd410f1a42123) Reset parser before/after parsing\n- [9c4672b](https://github.com/appium/ruby_lib/commit/9c4672ba9e5912d7a7aee0b80c78144295c0d5a0) Add instance numbers to page output on Android\n- [de5732d](https://github.com/appium/ruby_lib/commit/de5732d598ce9639dd18f4764971000f536833ab) Fix #224\n- [a206270](https://github.com/appium/ruby_lib/commit/a2062703fbcc2ebe0a80731034aee5d8bfb86108) Fix android device test\n- [9838d6a](https://github.com/appium/ruby_lib/commit/9838d6a5d910632a96df906c8d15a6084be97ea2) Move context tests to web_context.rb\n- [d6faefa](https://github.com/appium/ruby_lib/commit/d6faefaa2f18162076a0966b44b2b491f36a7504) Fix common/patch test\n- [414c4de](https://github.com/appium/ruby_lib/commit/414c4dea9de1404badf301c52142c75ba1125022) Update common/device test for Android L\n- [ccfb38d](https://github.com/appium/ruby_lib/commit/ccfb38d812d09cfbefcb77a404e9b3bbcbb6a237) Update android/helper for Android L\n- [24b75d7](https://github.com/appium/ruby_lib/commit/24b75d70f52cf5e2fe090086ed2ee5280cb572bd) Update alert tests for Android L\n- [8e9c7da](https://github.com/appium/ruby_lib/commit/8e9c7da4bf9ce44ab990da3ea9af9770aeac5c81) Fix #227\n- [596f6e0](https://github.com/appium/ruby_lib/commit/596f6e0e0cd6fe6e2b7f878517db46aedb45b716) Fix #223\n- [bcd9934](https://github.com/appium/ruby_lib/commit/bcd99340038fa30a3180e673757282b8e40b828f) Add predicate textfield test for iOS\n- [27732f4](https://github.com/appium/ruby_lib/commit/27732f4c6ebfbb0400419d90ca91528e0861bd68) Merge pull request #225 from appium/remove_complex_find\n- [3424d64](https://github.com/appium/ruby_lib/commit/3424d64bed8f641a67316c8a52e35f0b9ae7b75d) Remove complex_find. Update tests\n- [e2c82cc](https://github.com/appium/ruby_lib/commit/e2c82cc95d1443a31f73871fce96ae8aa4e99b6f) Add hide_keyboard for Android. Use custom for iOS\n- [27a25ba](https://github.com/appium/ruby_lib/commit/27a25baf936271203d13123386a2544b040d9a38) Update hide_keyboard for iOS\n- [e952bb0](https://github.com/appium/ruby_lib/commit/e952bb0d1287ebdd42254258e749136ed662b5f9) Test pull_folder on iOS & Android\n- [515e288](https://github.com/appium/ruby_lib/commit/515e28853607c729e6c58252dbe5e90e23b49e1d) available_contexts returns [] instead of nil on error\n- [86b378e](https://github.com/appium/ruby_lib/commit/86b378e7cf6cea86e2f88a342ab7b19f0cb455a8) Add pull_folder support\n- [0b3e0cf](https://github.com/appium/ruby_lib/commit/0b3e0cf2e4c5c8d674385e8a573a70d7c1ce3068) Add open_notifications. Fix #210\n- [05125b4](https://github.com/appium/ruby_lib/commit/05125b41dd4957c841fcb51566e07905b04bbd0c) Update migration.md\n- [235e1c0](https://github.com/appium/ruby_lib/commit/235e1c0dc9a93efb6defff27cfebf527784a3ba7) Replace keyevent with press_keycode. Add long_press_keycode\n- [64d9db1](https://github.com/appium/ruby_lib/commit/64d9db11152e46845b2a055bba97cc6d45edf413) Use one run.rb for all platforms\n- [335100e](https://github.com/appium/ruby_lib/commit/335100e8027a01bd46842111752d83f6fe3fe9de) Move iOS helpers to common.rb\n- [ab915cf](https://github.com/appium/ruby_lib/commit/ab915cfa92981afd628569cf7e85517c6e4aec97) Update driver opts\n- [b495c5e](https://github.com/appium/ruby_lib/commit/b495c5e0bf591c98c733d4636e3c31848857f8c2) Merge pull request #211 from kieferrm/patch-1\n- [543f8f3](https://github.com/appium/ruby_lib/commit/543f8f38763bec0d468dcadb3c4a6facf734e569) change require to lower case\n- [c54eaa1](https://github.com/appium/ruby_lib/commit/c54eaa1d78ed70bdf89405fac30d4129d9734a92) Remove global\n- [ee5a076](https://github.com/appium/ruby_lib/commit/ee5a07624314095148c6203bfe56454efc268891) Update docs.md\n- [a581424](https://github.com/appium/ruby_lib/commit/a5814249c8123c0309599847c0d0a9145c9ef819) Clean up cucumber doc\n\n\n#### v3.0.3 2014-06-02\n\n- [3ed875c](https://github.com/appium/ruby_lib/commit/3ed875cc01ba7f670e9b1b8ccfd7b7adb0af82c1) Release 3.0.3\n- [fab8ebe](https://github.com/appium/ruby_lib/commit/fab8ebe7245e28ad7628c91ba7766418a97521d0) Encode string to UTF-8 on iOS #208\n\n\n#### v3.0.2 2014-06-01\n\n- [08fe528](https://github.com/appium/ruby_lib/commit/08fe528887c33d64a3b06a5160859888cb92a9dd) Release 3.0.2\n- [a051b35](https://github.com/appium/ruby_lib/commit/a051b355b488db6d303e800451668a1d8cb7d3d0) Fix find by ids on Android\n- [84e3983](https://github.com/appium/ruby_lib/commit/84e39831d7d0c825c5c7ed44a512fb891e6efef3) Allow setting sauce_username/sauce_access_key to false\n\n\n#### v3.0.1 2014-06-01\n\n- [370b79c](https://github.com/appium/ruby_lib/commit/370b79c4b9f18fa615c145685256f543ee18debd) Release 3.0.1\n- [48cb878](https://github.com/appium/ruby_lib/commit/48cb87835076d6faa51f525c86ef0ed478eb0542) Default to UTF_8 encoding\n- [5b30ed5](https://github.com/appium/ruby_lib/commit/5b30ed563b98a9084e6cb89921efec1944e999af) Fix current_app\n\n\n#### v3.0.0 2014-05-30\n\n- [77d64af](https://github.com/appium/ruby_lib/commit/77d64af57b0e6a828c5d61008c444518e6597e4b) Release 3.0.0\n- [86f1655](https://github.com/appium/ruby_lib/commit/86f1655d51ee74ec32e720ff285c30175283d4fd) Rename mobile find to complex_find\n- [109139b](https://github.com/appium/ruby_lib/commit/109139bd6ff664e020609a5828ab755c9f6dbf2e) Merge pull request #207 from appium/no_xpath\n- [682797d](https://github.com/appium/ruby_lib/commit/682797d252a040ffcc225a43491842c3e0d6e2ad) Use uiselector instead of xpath\n- [0c51bca](https://github.com/appium/ruby_lib/commit/0c51bcab548826d125b9f90418079fc8af72071a) Update complex find constants\n\n\n#### v2.1.0 2014-05-21\n\n- [f0db091](https://github.com/appium/ruby_lib/commit/f0db0910ea077e04329d3e0cafb434f829760abb) Release 2.1.0\n- [189b99a](https://github.com/appium/ruby_lib/commit/189b99ab91625cc37414fe9aeb681949d4fd85be) Use io.appium.android.apis\n- [5b1e3d8](https://github.com/appium/ruby_lib/commit/5b1e3d8b014137cdd8f5a4f8af5d7019983aab9a) Fix current_app on Android\n- [aa6e93a](https://github.com/appium/ruby_lib/commit/aa6e93a0bb88ef31c596c5ac7352b159bc0ea53b) Fix wait\n- [c590996](https://github.com/appium/ruby_lib/commit/c5909961be059d715200ba58943e1b56e2dd8843) Move posix-spawn to dev dependency\n- [7a55892](https://github.com/appium/ruby_lib/commit/7a5589244db8f783f9a51b74809ff8fcb4354855) Fix typo\n- [2a1c009](https://github.com/appium/ruby_lib/commit/2a1c0096db8a4e53ae09a8c556b51b513eacfa74) Merge pull request #197 from xrd/patch-1\n- [9de20b7](https://github.com/appium/ruby_lib/commit/9de20b78f5dce29be874e727a027fd976703a0c1) Fix typo\n- [b306378](https://github.com/appium/ruby_lib/commit/b306378a9d54223e2b446a004a2c5a63574a9143) Merge pull request #196 from DylanLacey/master\n- [01dd97c](https://github.com/appium/ruby_lib/commit/01dd97ca63b6f8ff7ac65f170b8041241cad1271) Make wait and wait_true use the interval before it reexecutes\n- [9a138bb](https://github.com/appium/ruby_lib/commit/9a138bb6e2d1b0d836d3940f5e4b7e84d1fc0e3c) Merge pull request #195 from DylanLacey/master\n- [d85e292](https://github.com/appium/ruby_lib/commit/d85e292df723bcc9ff7227f8573581d44ef73c26) Don't continue to wait for crashed Appium server\n- [107a90c](https://github.com/appium/ruby_lib/commit/107a90c9137ef4ee7f8b7598c25adddedbdb34d4) Use __FILE__ instead of __dir__\n- [12d62bc](https://github.com/appium/ruby_lib/commit/12d62bcec3d8897089bd3045f564c0de271375bd) Merge pull request #194 from DylanLacey/master\n- [bcc7865](https://github.com/appium/ruby_lib/commit/bcc7865db8f65f5439cd60a983d1c45b80b97eb8) Quit driver before creating a new one.  Always.\n- [a52f215](https://github.com/appium/ruby_lib/commit/a52f215fb2246b35e17636ed9114fc977ad97511) Fix android test\n- [f43309c](https://github.com/appium/ruby_lib/commit/f43309ca716f5b140ef9370f4ebd4b45a500eb92) Fix #192\n- [4a97ba1](https://github.com/appium/ruby_lib/commit/4a97ba12684c7e49e8251305c47b8a3443a9ef98) Set sauce to empty so tests run local #191\n- [56d8a04](https://github.com/appium/ruby_lib/commit/56d8a04d8aa7e70f8e90a5e3cde79276bfb6158f) Fix #191\n- [ea0fe8e](https://github.com/appium/ruby_lib/commit/ea0fe8e2a9570e984a41fa424a908398694660de) Set empty sauce ENV to nil\n- [190f023](https://github.com/appium/ruby_lib/commit/190f0237fc94816e71e4327cbf8135913021688b) Update migration.md\n- [28aa754](https://github.com/appium/ruby_lib/commit/28aa7546b321950d704ba091a91c424a3cc4ac04) Update migration.md\n- [d9447a9](https://github.com/appium/ruby_lib/commit/d9447a97433b88afbc35c66264b1c67e175aef41) Merge pull request #190 from DylanLacey/xpath\n- [ac9f5eb](https://github.com/appium/ruby_lib/commit/ac9f5ebecf3a0e603cafc8ad4befda86050fc6d1) Parse HTML as HTML, not XML.\n- [a84163b](https://github.com/appium/ruby_lib/commit/a84163b113fb232068c9aa02bff61db8c11d374e) Output debug status only when enabled\n\n\n#### v2.0.0 2014-05-14\n\n- [2d7ab8b](https://github.com/appium/ruby_lib/commit/2d7ab8b6cc442f39f6171f8a27bc4923e4d4e2a4) Release 2.0.0\n- [84af3e9](https://github.com/appium/ruby_lib/commit/84af3e91dbdfb3781dc64dcf40a55f70ec023734) Merge pull request #189 from appium/update_api\n- [208ce67](https://github.com/appium/ruby_lib/commit/208ce67ddb34651460ad6a83cfef4eb0c3c97081) Add migration doc\n- [52b2c3a](https://github.com/appium/ruby_lib/commit/52b2c3a44b9b2af3cfb22579b3a51ca3713f0bd5) Enable page 'static'\n- [19a2cf8](https://github.com/appium/ruby_lib/commit/19a2cf8025bee2c93ed32168a586accc1c01c25f) Update tests\n- [5e10809](https://github.com/appium/ruby_lib/commit/5e10809c6bb87da7251d5c32ac5eb547cd97edd1) Format all .rb files\n- [3f41705](https://github.com/appium/ruby_lib/commit/3f41705636c7be9f994972e5a999bf10430dcf18) Rename s_text to text. Remove e_* methods\n- [7909daa](https://github.com/appium/ruby_lib/commit/7909daa46c4e8cdbcde9d223b008069335402ed0) Rename press_for_duration to long_press\n- [d63a58f](https://github.com/appium/ruby_lib/commit/d63a58ffafe12a6bf7e7897480c1eb3c4275076b) Update app_strings to take optional language arg\n- [71ab5db](https://github.com/appium/ruby_lib/commit/71ab5db00b832a049f9ed5dc544bd2a49afc42c1) Pass element reference, not element, when calling tap\n- [30b646f](https://github.com/appium/ruby_lib/commit/30b646fefe54830aea4a4e41dbf21471566ab489) Merge pull request #184 from DylanLacey/master\n- [6afc071](https://github.com/appium/ruby_lib/commit/6afc071921d263db13ead17cf7747e321b4a9487) Change current_context= to set_context.\n- [8f280ec](https://github.com/appium/ruby_lib/commit/8f280ec52e3bcfe7e917d910271fdfeb8a48562c) Fix page on iOS\n- [7088169](https://github.com/appium/ruby_lib/commit/7088169dc643b06a785247cfbcbde9c00daf2298) Update android/helper.rb\n- [537a8c3](https://github.com/appium/ruby_lib/commit/537a8c342d4977ab5e66765e05f69863a48a0fd6) Update Android common/device\n- [72ff02a](https://github.com/appium/ruby_lib/commit/72ff02a41673b113ecabeaa503e2f1702005d108) Restore strings.xml support on Android\n- [0dc4965](https://github.com/appium/ruby_lib/commit/0dc4965867cf089d87864401279176d5196a0caa) Update readme.md\n- [a5c2a1f](https://github.com/appium/ruby_lib/commit/a5c2a1f34b3c42f499dd9a78e90f02b135dd79b7) Update docs\n- [ca767f4](https://github.com/appium/ruby_lib/commit/ca767f425d3bd0ab763af09eb9065b7e2853ff0b) Improve page/page_class\n- [034a309](https://github.com/appium/ruby_lib/commit/034a309357ed5450cd977af5082669af2905cb47) Purge byte order marks\n- [3988ee3](https://github.com/appium/ruby_lib/commit/3988ee341972d2a42b00005ae7d2c694a572088a) Update readme.md\n- [f1e91a4](https://github.com/appium/ruby_lib/commit/f1e91a4d6cce813080dece73c5f80d06415b645a) Update readme.md\n\n\n#### v1.0.0 2014-04-29\n\n- [5a3ecbb](https://github.com/appium/ruby_lib/commit/5a3ecbb4147693ce3c2c6b693e64074022d03511) Release 1.0.0\n- [4b6989a](https://github.com/appium/ruby_lib/commit/4b6989a51c25b3b01398fe6bee2da908ab61a7e2) Merge pull request #172 from DylanLacey/flight\n- [0824188](https://github.com/appium/ruby_lib/commit/0824188043f76f5243de4d3753ef9e036fcb5ba6) Airline mode.\n- [7935fc0](https://github.com/appium/ruby_lib/commit/7935fc02afb7720306c7a273d205a2db9bdfb417) Prepare for release\n- [583a0a6](https://github.com/appium/ruby_lib/commit/583a0a6b7b67cdce4e533f06d98968021c0ed5d9) Update version helper\n- [982b102](https://github.com/appium/ruby_lib/commit/982b1021ed5e202ae2249791aa9ab091e7cb1b24) Update docs\n- [74f9e5e](https://github.com/appium/ruby_lib/commit/74f9e5ec97059f036c5c935bc9dcb5fb0000d813) Improve docs\n- [b5414b7](https://github.com/appium/ruby_lib/commit/b5414b7885804ccabddb53315a12c3b525924654) Update documentation for appium 1.0\n- [de25322](https://github.com/appium/ruby_lib/commit/de25322395c233e69c70cc2c9417913e8f393dbd) Fix ios test\n- [3943f19](https://github.com/appium/ruby_lib/commit/3943f194cd82bcc6880c13fd712041e111440aa5) Do not sort files\n- [e7bd82a](https://github.com/appium/ruby_lib/commit/e7bd82a133edcf27fa5c8d5cf850d1783ef4cd4c) Fix load_appium_txt\n- [fe792a5](https://github.com/appium/ruby_lib/commit/fe792a573ffb4ce5cfb3bd4f67cb0506a61dbf21) Fix comment\n- [bb9f44a](https://github.com/appium/ruby_lib/commit/bb9f44af04add6f4c1007f3641417f6366ae0b3e) Fix error message about missing platformName\n- [45e56b9](https://github.com/appium/ruby_lib/commit/45e56b9326d2ab9fad29d04626e34fdaf58f9659) Fix flaky android tests by using wait\n- [723b304](https://github.com/appium/ruby_lib/commit/723b30414719a2e728cfd32b0a43d09daa21c69b) Rename closeApp to close_app\n- [ec2f6ea](https://github.com/appium/ruby_lib/commit/ec2f6eab1f8f8ab40ef41a82d0c6de1a11705bf0) Improve android/patch test\n- [e3a7ad5](https://github.com/appium/ruby_lib/commit/e3a7ad5b4cb65a351bf2f61587fe35c0af465042) Merge pull request #169 from bootstraponline/master\n- [bbcd38b](https://github.com/appium/ruby_lib/commit/bbcd38b184ec047adc73188a1ec86e8cfb09de61) Fix complex find\n- [684aa0d](https://github.com/appium/ruby_lib/commit/684aa0df432e2c618637c873ca62f5a31626beb2) Merge pull request #168 from DylanLacey/master\n- [7475d38](https://github.com/appium/ruby_lib/commit/7475d38f069425e69bc81e9c7157734abfb780da) Remove unused error method\n- [6875a48](https://github.com/appium/ruby_lib/commit/6875a48705114d3d651f509d1e2f4f484e9650f3) Use new complex_find method.\n- [86371c3](https://github.com/appium/ruby_lib/commit/86371c3c74fd50666aee96bd575adefe3d4618e8) Fix common/helper\n- [e765488](https://github.com/appium/ruby_lib/commit/e765488f3dc3698092b8751ad400ba67bdcae220) Update Android common/device\n- [79de9b5](https://github.com/appium/ruby_lib/commit/79de9b59a604f7fc6c74fefb6743c5ede52b6193) Fix android common/helper\n- [7ac67e3](https://github.com/appium/ruby_lib/commit/7ac67e33655898446b75d4c7ca17bd26bf21fa35) Fix android/helper\n- [4754137](https://github.com/appium/ruby_lib/commit/47541378b4fdcf2daf36109be59b9e591d5f5666) Fix id resolution. Fix patch and helper\n- [38af1aa](https://github.com/appium/ruby_lib/commit/38af1aafb8525186f3ae10ee888ae52945753f6e) Fix android alert, text and textfield\n- [1f82df4](https://github.com/appium/ruby_lib/commit/1f82df4543e2de54564bd89e2ed8275612beb770) Fix page commnand on Android\n- [b3cd998](https://github.com/appium/ruby_lib/commit/b3cd9987f391447dc7bf86f97cc99b75f166b969) Fix android/element/button\n- [6e215ff](https://github.com/appium/ruby_lib/commit/6e215ff60752fbdc43b23829676215d10d0004d1) Reorder iOS text methods\n- [ead35f9](https://github.com/appium/ruby_lib/commit/ead35f99908ea5e9eac298308979a46dc0028751) Refactor iOS textfield xpath\n- [b26d77d](https://github.com/appium/ruby_lib/commit/b26d77d70967c14aef227dc651252f3ff675850e) Move iOS specific helpers out of common\n- [a97c1cd](https://github.com/appium/ruby_lib/commit/a97c1cdfa4b545283e463f5e792f7c413654043f) Merge pull request #163 from DylanLacey/master\n- [537099d](https://github.com/appium/ruby_lib/commit/537099d3afd5e950ef0a1042890c3134ee125578) Update tests to meet new code requirements.\n- [c7c6d10](https://github.com/appium/ruby_lib/commit/c7c6d10152dd61b856c1dfe828aa70dc4e4e48c3) Ensure elements on iOS are visible\n- [e0cb0c9](https://github.com/appium/ruby_lib/commit/e0cb0c911f831c4f8288d9c467b5546128c4e467) Update Rakefile\n- [6a174e2](https://github.com/appium/ruby_lib/commit/6a174e2a05fd6612f2592e0734122d60c2101d86) Modern ruby defaults to utf-8\n- [5540ffc](https://github.com/appium/ruby_lib/commit/5540ffc0f93abc85cefd7e397e39c8022071e171) Update ios_tests\n- [ecc7d02](https://github.com/appium/ruby_lib/commit/ecc7d0262e902f0e46e49f6395a00aa88558978c) Update iOS support\n- [8845a1e](https://github.com/appium/ruby_lib/commit/8845a1ed82d06ad3164dadc6fcc57c23482f5ca9) Rewrite iOS support for appium 1.0\n- [b0e0bfd](https://github.com/appium/ruby_lib/commit/b0e0bfd43edd011f2f628d588de7bef7829e0db6) Update textfield and flaky.txt\n- [7c40873](https://github.com/appium/ruby_lib/commit/7c40873ed4521c004b5033378fd87b44714264af) Fix ios[ios/element/textfield]\n- [ee0ccd2](https://github.com/appium/ruby_lib/commit/ee0ccd2f443c4f2ce80b1ea80f17b2d11d870a08) Fix ios[ios/element/alert]\n- [f439730](https://github.com/appium/ruby_lib/commit/f4397302cc9ffc42759fe946e0da643df2c89100) Fix ios[common/helper]\n- [3582d34](https://github.com/appium/ruby_lib/commit/3582d3495976bb724b39febf92d850dd5fd08508) Fix iOS common/element/button\n- [67f719e](https://github.com/appium/ruby_lib/commit/67f719eca1812f143e8b2445ceac154c87ec13c5) Add flaky.txt\n- [7847df2](https://github.com/appium/ruby_lib/commit/7847df21888ce5e089e81be24d035d4f8d1d7b92) Merge pull request #159 from DylanLacey/master\n- [4c816e2](https://github.com/appium/ruby_lib/commit/4c816e252a2e018e3db9730ea56a7a23eb7adbdd) Fix wait\n- [b58f283](https://github.com/appium/ruby_lib/commit/b58f283503af8ed3a16e054dd589b1662be533cb) Update one_test runner\n- [52b2a5c](https://github.com/appium/ruby_lib/commit/52b2a5cff30cae5c27e878071fd9a2c4ce16c48f) Enable running with flake\n- [9861a88](https://github.com/appium/ruby_lib/commit/9861a885b9bbdc45eaddf00589f854ec2355b24e) Update tag references\n- [326aeb5](https://github.com/appium/ruby_lib/commit/326aeb50375300662167f0f9f23211efa59fb052) Don't call mobile methods\n- [09329d1](https://github.com/appium/ruby_lib/commit/09329d1d0fb583733b7530d6fc1161611e2b16d3) Name before_first/after_last for better error messages\n- [5302418](https://github.com/appium/ruby_lib/commit/5302418d5180d02c87139662b7b97d53042faf24) Fix ios/element/generic\n- [9bf869f](https://github.com/appium/ruby_lib/commit/9bf869f889e80754132741bce4776d1e2bf0bf14) ios/element/text is passing\n- [2e10eb3](https://github.com/appium/ruby_lib/commit/2e10eb3407408c2979384c73a31c4ddbe8fc2dd3) Start updating for new XPath\n- [62c977a](https://github.com/appium/ruby_lib/commit/62c977a158ebb85bac2603be1321723d5c785931) Add note about source_window + appium 1.0\n- [2bb509f](https://github.com/appium/ruby_lib/commit/2bb509ff60733c950c4edba1754bddbfa1855003) Replace mobile methods for appium 1.0\n- [2c8142b](https://github.com/appium/ruby_lib/commit/2c8142b0026c0222d635c936448564002ca5eadb) Fix page_class to work with Appium 1.0\n- [265b658](https://github.com/appium/ruby_lib/commit/265b65833ed3971a1bf41b647edf0613786258bd) Use nokogiri to parse XML\n- [8c96eae](https://github.com/appium/ruby_lib/commit/8c96eaeab594d940ce30ede29f6253e1e5fd7370) Merge pull request #157 from appium/update_spec\n- [5c9e840](https://github.com/appium/ruby_lib/commit/5c9e840b7edafd083f3d5f3003086550baf3c242) Update tests to work with new spec gem\n- [0331fe0](https://github.com/appium/ruby_lib/commit/0331fe0f4c897b4cd41b67eecd6357416925d629) Merge pull request #155 from DylanLacey/keyevent\n- [3a9bebd](https://github.com/appium/ruby_lib/commit/3a9bebd48cc8ecc8a1d8e9c50d1db433e66bae1f) Add keyevent method\n- [758afbf](https://github.com/appium/ruby_lib/commit/758afbfee3beaf435ecc8c0f47584deb91b3ae2f) Merge pull request #154 from DylanLacey/master\n- [294ba49](https://github.com/appium/ruby_lib/commit/294ba49f4f98cce498f2b8217e639ab0c33c5036) Extend Appium::Device methods before promoting Appium methods.\n- [d432e36](https://github.com/appium/ruby_lib/commit/d432e365219914091f7a1bf532a758cfd2647aed) Merge pull request #149 from DylanLacey/chainz\n- [965ec7b](https://github.com/appium/ruby_lib/commit/965ec7bab13e8a92a4f5065ff1c4142ba58043d2) Add multi-touch actions, touch actions.\n- [d8cbacd](https://github.com/appium/ruby_lib/commit/d8cbacd938e41ce0ccc817f354ab6580f4742636) textfield_named to use chained find_element\n- [e76e6dd](https://github.com/appium/ruby_lib/commit/e76e6dd5f2046a73a2458a3bc03aa546c810ed20) Merge pull request #151 from DylanLacey/docs\n- [ecbbb18](https://github.com/appium/ruby_lib/commit/ecbbb18fa09b861a733f7b0071d2164e712697c2) Merge pull request #150 from DylanLacey/files\n- [7ef61e1](https://github.com/appium/ruby_lib/commit/7ef61e1cd1733217479646060c5131ef3235b852) Update doc\n- [6c97d17](https://github.com/appium/ruby_lib/commit/6c97d17ac177656c96a00ee29d64293e63a84c22) Add file methods\n- [aea8c5d](https://github.com/appium/ruby_lib/commit/aea8c5dd688778ba3cf076390a89455f5bec36cf) Update doc\n- [854d2c6](https://github.com/appium/ruby_lib/commit/854d2c689f9ea43701b4ae18fa83b121bf227f85) Fix invalid warnings Fix #147\n- [0408cc0](https://github.com/appium/ruby_lib/commit/0408cc0c7a99d3347cf6b762f28b1c4fa9339e2b) Fix driver docs\n- [e72c170](https://github.com/appium/ruby_lib/commit/e72c17094ff249f822346be9a62c135156d7758d) Remove Selendroid specific code\n- [4e9f3d6](https://github.com/appium/ruby_lib/commit/4e9f3d6f95fbd97c4db118e22de2741a49993d21) Validate platformName Fix #146\n- [38fc42e](https://github.com/appium/ruby_lib/commit/38fc42e599b02dcc17d007812cf9defbd21a6573) Clarify wait_true doc Fix #127\n- [285a97b](https://github.com/appium/ruby_lib/commit/285a97b0e15eb42034a91a2b59d8ba9bd8b0abe9) Fix ignore, wait, wait_true\n- [1b160b4](https://github.com/appium/ruby_lib/commit/1b160b46ecab5fccd45191f5af5f18eaf86a3188) Fix typing on iOS\n- [44eb53b](https://github.com/appium/ruby_lib/commit/44eb53b61c994dd16fd8636dd4bf43b70c98226e) Add comments to end\n- [a4d2c55](https://github.com/appium/ruby_lib/commit/a4d2c553a46b0cd64ecbc67193023e9802db2c0d) Add OpenStruct support to Awesome Print\n- [12b35a6](https://github.com/appium/ruby_lib/commit/12b35a612fcf7bb05173ef3e3ece66a0ecab4a0f) All tests passing\n- [01f4ecf](https://github.com/appium/ruby_lib/commit/01f4ecfdf5b5446c6eced06ca86cc85ff42edecd) Fix 'undefined' is not a function\n- [af76d4d](https://github.com/appium/ruby_lib/commit/af76d4daba1cc785325e62f4a1392895da7c7731) Fix broken ends\n- [9a214aa](https://github.com/appium/ruby_lib/commit/9a214aa7fb59042606956be1686c6c5a459a192c) Don't use add_to_path\n- [67a997c](https://github.com/appium/ruby_lib/commit/67a997c8396b4c8681f63be5d37f8055d39d220e) Clean up module syntax\n- [8be5b7c](https://github.com/appium/ruby_lib/commit/8be5b7c5b3dbdc1682a48b9ca85f2389c2a19502) Merge pull request #142 from appium/wip\n- [fb61522](https://github.com/appium/ruby_lib/commit/fb615225eae819eef70153a76e954ffa2991845e) Rename test folders\n- [8f2049f](https://github.com/appium/ruby_lib/commit/8f2049ff18e3dc20b7cd7a30cd15b0fcb1676341) Update capabilities and appium.txt\n- [62dc430](https://github.com/appium/ruby_lib/commit/62dc43030d047c3baaec28f524430893ac427ff9) Merge pull request #139 from DylanLacey/complex_find\n- [bc20a71](https://github.com/appium/ruby_lib/commit/bc20a7181b5159bbb8cd304e182a49765fec5b9d) Add complex find\n- [38a9429](https://github.com/appium/ruby_lib/commit/38a942973adc8768d7e5e1b270bad8d68323e33b) Merge pull request #140 from DylanLacey/hide\n- [f6d5987](https://github.com/appium/ruby_lib/commit/f6d598704f096dccfc0feedf28850d7059cd79f8) Add keyboard hidin'\n- [c0076e9](https://github.com/appium/ruby_lib/commit/c0076e92cdbeb3ce90fab536480a746c6acf933b) Merge pull request #138 from DylanLacey/noarg_methods\n- [23f24c9](https://github.com/appium/ruby_lib/commit/23f24c9193318c2cfb3432d01459aaf3b8121ab6) add current_activity, background_app, app_installed\n- [eb12171](https://github.com/appium/ruby_lib/commit/eb121710af6c7a3d128754a359640c36b7e73501) Merge pull request #135 from DylanLacey/contexts\n- [b8f3a91](https://github.com/appium/ruby_lib/commit/b8f3a919d11fc347b84ce4c1a38aab2705461553) Add context switching\n- [c13b877](https://github.com/appium/ruby_lib/commit/c13b877c75bd67390755720cc15842411a2d7218) Merge pull request #137 from DylanLacey/accessibility_id\n- [5c9d18f](https://github.com/appium/ruby_lib/commit/5c9d18f286c31f8ddbc6ad5cdd0b34a1041e775f) Add accessiblity_id finder\n- [5d1722f](https://github.com/appium/ruby_lib/commit/5d1722f965db7cac26eb7c14b3080f22ba5e1664) Merge pull request #136 from DylanLacey/uiauto_finders\n- [fdd14da](https://github.com/appium/ruby_lib/commit/fdd14daf4811aac740bdd7e1662f2d61aa43c359) Add uiautomat[ion|or] locators\n- [ef42569](https://github.com/appium/ruby_lib/commit/ef42569d2d0bc4bb741ed0132ba78371bb84b5f4) Merge pull request #133 from DylanLacey/master\n- [a6fbb15](https://github.com/appium/ruby_lib/commit/a6fbb15b1909df4d69c059a754fc7973123b17a3) Log warning when methods are added to Selenium\n- [6590e9f](https://github.com/appium/ruby_lib/commit/6590e9f5f30b7fa07c16390c965077a780116d44) All tests passing on master branch of appium\n- [cd5a25d](https://github.com/appium/ruby_lib/commit/cd5a25d395ec0d7f7361ce0a18a14aa4dc81f486) Update android tests\n- [7fc8c55](https://github.com/appium/ruby_lib/commit/7fc8c55b9c0866b14ce23f0c72fc5580d0935125) Update android tests\n- [6e32210](https://github.com/appium/ruby_lib/commit/6e3221015a028b184d0888d8d0281adc88c91d05) Add ruby_lib_ios and ruby_lib_android tests to ruby_lib\n- [b9b449a](https://github.com/appium/ruby_lib/commit/b9b449a1502db280728cf8b5d20ec36f7ae59a1d) Merge pull request #129 from DylanLacey/master\n- [f87a379](https://github.com/appium/ruby_lib/commit/f87a37906fe8cd66c549c351c8808d79586a1f79) Added calls to explicit endpoints for :install, :remove, :close, :launch, :lock, :shake.\n- [2ea9aa5](https://github.com/appium/ruby_lib/commit/2ea9aa598d38e2163a01a90ceee4473372999d67) Upgrade to SVG badges\n- [003bbe6](https://github.com/appium/ruby_lib/commit/003bbe6a92c2538c51dbea56f69fb525eec22db6) Status is in the official bindings\n- [d0b6198](https://github.com/appium/ruby_lib/commit/d0b619833457c974b500b00242ceb2fc7598f5d0) Document how to activate fast reset\n\n\n#### v0.24.1 2014-03-26\n\n- [a07da28](https://github.com/appium/ruby_lib/commit/a07da28de1e7133c77070859c2c35d7bd2635684) Release 0.24.1\n- [4718b0b](https://github.com/appium/ruby_lib/commit/4718b0b126748b14237ead15fd09812449512b12) Client should never send fastReset or skipUninstall\n\n\n#### v0.24.0 2014-03-25\n\n- [937f782](https://github.com/appium/ruby_lib/commit/937f7822bd5e248e2bdbc43a4602611d18df5d78) Release 0.24.0\n- [6e3fd72](https://github.com/appium/ruby_lib/commit/6e3fd720d90eda14f284c04ae4b8edb62ca7c010) fast_clear is no more\n\n\n#### v0.23.0 2014-03-21\n\n- [b6cda97](https://github.com/appium/ruby_lib/commit/b6cda9756f530d712f431df272cf5abdcd678131) Release 0.23.0\n- [8ce3009](https://github.com/appium/ruby_lib/commit/8ce3009ab6c8e957a7cee817df4a658b1ae3a834) Fix caps for new appium\n- [a6e7df2](https://github.com/appium/ruby_lib/commit/a6e7df258daf905c5dbaa6143aca9f5040e1308e) Remove device whitelist from appium.txt\n\n\n#### v0.22.1 2014-03-20\n\n- [82c40cd](https://github.com/appium/ruby_lib/commit/82c40cdd97eb7278d77b2b668cae554e55f1836d) Release 0.22.1\n- [c436daa](https://github.com/appium/ruby_lib/commit/c436daa916dfb7b3a824f498c98f4718d3aacca1) Disable device white list\n- [4cca152](https://github.com/appium/ruby_lib/commit/4cca152aa2519f5b3ae1292886c286f87d9fbbe8) Fix release rake task\n\n\n#### v0.22.0 2014-03-19\n\n- [4d88ecd](https://github.com/appium/ruby_lib/commit/4d88ecd87be7a2319dd0b7e437e230300269175f) Release 0.22.0\n- [347e81e](https://github.com/appium/ruby_lib/commit/347e81e2c3fae3b1b26bd707356c663a158198d4) Support all appium caps\n\n\n#### v0.21.0 2014-03-13\n\n- [db2df39](https://github.com/appium/ruby_lib/commit/db2df39eb6fc09e516e22334dd990699755c0509) Release 0.21.0\n- [bf74d7a](https://github.com/appium/ruby_lib/commit/bf74d7a70c0f7cab8e4cb115d53d86c3720e2df3) Remove webview. Update gemspec\n\n\n#### v0.20.0 2014-03-13\n\n- [e79923f](https://github.com/appium/ruby_lib/commit/e79923f731c0f7ba85f280b512f5d82d365fd619) Release 0.20.0\n- [9a6c6ea](https://github.com/appium/ruby_lib/commit/9a6c6eaf798938f8a483466e718e53483e3c0f02) Add bundle update to release rake task\n- [093ba77](https://github.com/appium/ruby_lib/commit/093ba7712275b009d66146bcd9429ed9bf2f8d7f) Update readme.md\n- [8dbe853](https://github.com/appium/ruby_lib/commit/8dbe853909a3a2691d3cc510d9751cfe8179dc76) Fix mainApp\n- [347ae13](https://github.com/appium/ruby_lib/commit/347ae13cc78101875bb223fdfee97898f50a791b) Update readme.md\n- [ba4d51c](https://github.com/appium/ruby_lib/commit/ba4d51c44329db8a849f59bfeedfa1eb99538d3a) Update location_rel to use center point\n\n\n#### v0.19.1 2014-02-25\n\n- [efa2e3f](https://github.com/appium/ruby_lib/commit/efa2e3feb74319a19d1fe3ef49d5a7fe3a2eb59a) Release 0.19.1\n- [1aee2fc](https://github.com/appium/ruby_lib/commit/1aee2fcc5773cc92b1f83a80188f6cac50d2e206) Add android coverage cap\n- [ccb213f](https://github.com/appium/ruby_lib/commit/ccb213f3866672f2be7ea526e6deb1656d497e6e) Update path logic\n- [9772383](https://github.com/appium/ruby_lib/commit/97723833f1d888fa809d704801d98bdff8a3e2a4) Fix load_appium_txt relative path\n\n\n#### v0.19.0 2014-02-20\n\n- [6fd332b](https://github.com/appium/ruby_lib/commit/6fd332b1715d7b8f4b3b3c99e7ca58e5d4d01b52) Release 0.19.0\n- [69f2058](https://github.com/appium/ruby_lib/commit/69f2058c3dffb60bb5040f920481da5fed571a6a) Merge pull request #119 from misttar/feature/appium_ruby_console_on_windows\n- [55ab536](https://github.com/appium/ruby_lib/commit/55ab536c8dfeafed43797675c82cc4c5d73d8454) Fix to enable appium ruby console (arc) on windows; Removed unnecessary ruby based absolute path conversion in load_appium_txt, as it is done later in Driver::initialize; Simplified absolute_app_path method for resolving windows paths;\n- [f529113](https://github.com/appium/ruby_lib/commit/f529113c3f54c351d668da9695b8a5a7e2377169) Merge pull request #118 from justingrammens/master\n- [297cdfc](https://github.com/appium/ruby_lib/commit/297cdfc8685c1752dbf9f6b2e07a9c4ac3f1ab87) Need to add the missing commas for the Android example in readme for it to work for me.\n- [d55a2f5](https://github.com/appium/ruby_lib/commit/d55a2f5beefb0b6e3068470769da64c8c47551ec) Fix webview\n- [da987f6](https://github.com/appium/ruby_lib/commit/da987f6b11b191ace34ea63764eb121c8ddae42e) Merge pull request #114 from misttar/app_path_on_windows\n- [488236e](https://github.com/appium/ruby_lib/commit/488236e8856e984f7d9285f33d7660d33fbd835d) Adding a small patch to fix loading the app with absolute windows paths;\n- [6e789d5](https://github.com/appium/ruby_lib/commit/6e789d54341979c412c9a6f3b956cf9b777c87ad) Fix tag_name\n- [af4517f](https://github.com/appium/ruby_lib/commit/af4517fa10a060e92c12bd49a93289ece709c0ac) Update MiniTest Expectations link\n- [8810bbe](https://github.com/appium/ruby_lib/commit/8810bbe640546f962325358d9ab763a0dc038057) Update name doc for iOS\n- [f08854a](https://github.com/appium/ruby_lib/commit/f08854a3cb498c12a00bdca8d0a3f9ffedf06bad) Escape single quotes for iOS JS selectors\n\n\n#### v0.18.2 2014-01-28\n\n- [f7a2e26](https://github.com/appium/ruby_lib/commit/f7a2e26b623404b83b2bbd9065aa7b57ab0fd62d) Release 0.18.2\n- [b123321](https://github.com/appium/ruby_lib/commit/b12332186befb84b7ef6107a27db035ca2b65400) Check ENV['DEVICE'] when :device isn't set.\n\n\n#### v0.18.1 2014-01-28\n\n- [d98aafc](https://github.com/appium/ruby_lib/commit/d98aafc1571c49d97f104ce5d275cf758f27e421) Release 0.18.1\n- [14bcd8f](https://github.com/appium/ruby_lib/commit/14bcd8fd50e6fc4f74c81d900c0c05a302d080b9) Fix device cap\n\n\n#### v0.18.0 2014-01-27\n\n- [e0ea2f2](https://github.com/appium/ruby_lib/commit/e0ea2f2d77875b9ffc88d8649b3652c39a1ab51a) Release 0.18.0\n- [c94bf57](https://github.com/appium/ruby_lib/commit/c94bf57dadf2049a3aace8ed35d978c1d4545be2) Update capabilities for Sauce\n- [2859c83](https://github.com/appium/ruby_lib/commit/2859c831916ef1541fe2a283c9afc6af55e43a25) Update session id example\n\n\n#### v0.17.0 2014-01-22\n\n- [8571197](https://github.com/appium/ruby_lib/commit/8571197b04ea923db6e375bae808bf84dea52c98) Release 0.17.0\n- [1134b87](https://github.com/appium/ruby_lib/commit/1134b878791c0abb23d11250ad185c34708d54be) Fix fast clear. Fix #110\n- [f0bc0b5](https://github.com/appium/ruby_lib/commit/f0bc0b5229dc21f736ab17c533e1d073c3b44a3c) Update api_19_webview.md\n- [94657b4](https://github.com/appium/ruby_lib/commit/94657b45394bcd823955270529aee79b305383f3) Update api_19_webview.md\n- [3b93375](https://github.com/appium/ruby_lib/commit/3b933752f560af6cf7cf976e8f2511222d255068) Create api_19_webview.md\n- [9b838f4](https://github.com/appium/ruby_lib/commit/9b838f4dc280126e4468a177fa4dd83eb2417512) First attempt at webview automation for Android API 19\n\n\n#### v0.16.0 2014-01-09\n\n- [b9264f6](https://github.com/appium/ruby_lib/commit/b9264f66b9dd04eb5221c3a4c4ea17c4eb9ef8aa) Release 0.16.0\n- [18466ea](https://github.com/appium/ruby_lib/commit/18466eae986647b27e3dbb041c591ce2dbc972a2) Hide invisible elements in iOS page output\n\n\n#### v0.15.2 2013-12-23\n\n- [35b84fd](https://github.com/appium/ruby_lib/commit/35b84fd4a0dcf37fe136451c9bcfa936e1017023) Release 0.15.2\n- [23504ea](https://github.com/appium/ruby_lib/commit/23504ea17c483650342832a204acac542a77b48b) Update selenium-webdriver for driver.manage.logs support\n\n\n#### v0.15.1 2013-12-13\n\n- [8340d99](https://github.com/appium/ruby_lib/commit/8340d993185ec22f02ca4ce3a3d24e65f367f3e3) Release 0.15.1\n- [ee39131](https://github.com/appium/ruby_lib/commit/ee391317b38f9dc7a0c13d148746401545a1f21e) Default to OS X 10.9 & iOS 7 on Sauce\n- [9627036](https://github.com/appium/ruby_lib/commit/962703617a3050dddb0be9f6ec757ca4b5070ff0) Fix promote_singleton_appium_methods\n- [81ce5d0](https://github.com/appium/ruby_lib/commit/81ce5d063b927d785cad3111b1ec7c50def6bfca) Fix docs\n- [fe60570](https://github.com/appium/ruby_lib/commit/fe6057045fd4d9ee1eb77ec57108755b4d445592) Error if we're generating an empty file\n- [0162656](https://github.com/appium/ruby_lib/commit/0162656e90e7db9f33c84fe1273ec96d8efc745f) Prevent duplicate tags\n\n\n#### v0.15.0 2013-11-25\n\n- [c27ac6f](https://github.com/appium/ruby_lib/commit/c27ac6fc37cb0c1b52aa2b15af480d17745adcf8) Release 0.15.0\n- [77a7736](https://github.com/appium/ruby_lib/commit/77a7736c3589db6ba2f029b97beae3e0d383cee9) wait and wait_true no longer use default_wait\n- [18a4b94](https://github.com/appium/ruby_lib/commit/18a4b9472be56b533d01c9b2758d365b3c3129fe) Fix exists\n- [dd885bf](https://github.com/appium/ruby_lib/commit/dd885bffc04e6306b6b70162e58e7149280bee0b) timeout(0) waits forever so default to 1 as the min wait\n\n\n#### v0.14.0 2013-11-22\n\n- [e7ed56b](https://github.com/appium/ruby_lib/commit/e7ed56b6304d7c9f6a24384915def1a3bc732c4e) Release 0.14.0\n- [eea5ef1](https://github.com/appium/ruby_lib/commit/eea5ef19bd7d52aac24e55e76544980b8c144a84) set_wait remembers the second to last wait\n- [7ef3406](https://github.com/appium/ruby_lib/commit/7ef34065982f4832584b12174fd491d5e1919c9b) Release 0.13.0\n- [e1632bc](https://github.com/appium/ruby_lib/commit/e1632bc88116996a5ed3983a0a9f3ec864d229d9) Release 0.13.0\n- [87c5e12](https://github.com/appium/ruby_lib/commit/87c5e120c51e3344241ca48ccb4ba4990dc76cbd) Release 0.13.0\n- [647cb94](https://github.com/appium/ruby_lib/commit/647cb942f344c635e067f2ae563f4fae12685148) Release 0.13.0\n\n\n#### v0.13.0 2013-11-22\n\n- [e1632bc](https://github.com/appium/ruby_lib/commit/e1632bc88116996a5ed3983a0a9f3ec864d229d9) Release 0.13.0\n- [87c5e12](https://github.com/appium/ruby_lib/commit/87c5e120c51e3344241ca48ccb4ba4990dc76cbd) Release 0.13.0\n- [647cb94](https://github.com/appium/ruby_lib/commit/647cb942f344c635e067f2ae563f4fae12685148) Release 0.13.0\n- [a235a2c](https://github.com/appium/ruby_lib/commit/a235a2c70d2c7dc1934c9fb403fb95cc3ae56e04) Update name_exact\n- [f1d2701](https://github.com/appium/ruby_lib/commit/f1d270120ae248beb6746a0149ebcbe4e34ebcca) names on Android will return the text values when no arg is passed\n- [7ac38c9](https://github.com/appium/ruby_lib/commit/7ac38c97b99178f6ae0bf8f7b5474a0cd3379e87) Fix return value of name_exact\n- [e6da4aa](https://github.com/appium/ruby_lib/commit/e6da4aa4937bfdc6f094f7895ecf172f8b96f32a) Add textfield_named for iOS\n- [789fc52](https://github.com/appium/ruby_lib/commit/789fc5276ad000dafd5a400f3d9aa8cfcd37e17d) Add ios_version method\n- [5447f4c](https://github.com/appium/ruby_lib/commit/5447f4cf3645459ddb4335b4a242b7639fc860f8) Rename password to ios_password\n- [a5b85de](https://github.com/appium/ruby_lib/commit/a5b85de11e413e301f94d41689658b01342bb1c8) Add scroll_to_exact for Android & more\n- [cc7e778](https://github.com/appium/ruby_lib/commit/cc7e778fd1532e5e15ea9933a300189ce8dc9e8a) Default to fastClear: false\n- [f54f145](https://github.com/appium/ruby_lib/commit/f54f14551e04517c71d9177fc0bd72797cd77781) Add link to minitest expectations\n\n\n#### v0.12.0 2013-11-07\n\n- [c92bd37](https://github.com/appium/ruby_lib/commit/c92bd3710be09731aa8ba4547a3e19af9eeaceab) Release 0.12.0\n- [f1b7633](https://github.com/appium/ruby_lib/commit/f1b7633e5dcfcd6d0d21f003ce0d98de1d093a13) Add s_texts_names. Fix alert_dismiss_text and alert_accept_text for iOS 7\n- [6f2d698](https://github.com/appium/ruby_lib/commit/6f2d6981b1f12443c4079dba455b16d1f331f903) Fix page on iOS 7\n- [70dbac3](https://github.com/appium/ruby_lib/commit/70dbac321688dfbec1d5f0a8efe6a7282678b88b) set_wait and no_wait now update @default_wait\n- [1f31754](https://github.com/appium/ruby_lib/commit/1f31754386dfd282e1143e3386ba18b1c656bb9d) Restore readme\n- [1e7a4c3](https://github.com/appium/ruby_lib/commit/1e7a4c36d1ea0df0ed87a2decbf8793406673774) Update Android page to always output resource-ids\n\n\n#### v0.11.1 2013-09-24\n\n- [0551d9a](https://github.com/appium/ruby_lib/commit/0551d9a4de2cb3d62efe63a87b01c15526202336) Release 0.11.1\n- [283040e](https://github.com/appium/ruby_lib/commit/283040e7227b7838124e835578d549fadc101cdc) Fix s_texts method overloading\n\n\n#### v0.11.0 2013-09-24\n\n- [948074c](https://github.com/appium/ruby_lib/commit/948074c44917029fb27b08ed582c90d7f73a7cde) Release 0.11.0\n- [a0dfe2c](https://github.com/appium/ruby_lib/commit/a0dfe2c5a99f9354b1c0f4fa766619505d4c85ae) Add s_texts, s_texts_exact\n- [5b3bb88](https://github.com/appium/ruby_lib/commit/5b3bb886951b8efe9845d423a4da310742a52bcb) wait and wait_true now respect default_wait\n- [5c3083b](https://github.com/appium/ruby_lib/commit/5c3083b819dc3dca66ee07fcb6e7aeadcfbc1d2c) Update Android tag maps\n- [c2b7098](https://github.com/appium/ruby_lib/commit/c2b70980ba80cefe82f776ac7c0e567a7dc93884) Sort page_class on Android\n\n\n#### v0.10.0 2013-09-20\n\n- [6ab8180](https://github.com/appium/ruby_lib/commit/6ab8180ca332239793c0abc5ee3a31b0b081b6c4) Release 0.10.0\n- [afb0b09](https://github.com/appium/ruby_lib/commit/afb0b09b54682fd497857a41affcdca531eb6911) Add promote_singleton_appium_methods(main_module)\n- [631c584](https://github.com/appium/ruby_lib/commit/631c5846373031a16cacb18bc0259663bd64b7b7) .location_rel now returns a fraction\n- [bf45140](https://github.com/appium/ruby_lib/commit/bf451407454853873305e25f7026e97a4119694d) page on iOS now takes window number\n- [cb38755](https://github.com/appium/ruby_lib/commit/cb38755ec824e139b40cf291eb0d3421cca3dfad) Fix Android fast duration\n- [c81bba8](https://github.com/appium/ruby_lib/commit/c81bba81bdba9a184b2fcc50fa1aabfdafd19e96) Sauce doesn't use dashes in the session id\n- [613c33e](https://github.com/appium/ruby_lib/commit/613c33ee22b389a3c42d96cb618a9858a6bc2e88) Add note about xpath index\n\n\n#### v0.9.1 2013-09-19\n\n- [cd9fc63](https://github.com/appium/ruby_lib/commit/cd9fc636c5fc1071ad95ea08a7ab5c077737e6a7) Release 0.9.1\n- [c5c2b83](https://github.com/appium/ruby_lib/commit/c5c2b832c5f535eacb657b4cfc5cb5d89e0ad8ee) XPath index starts at 1 for textfield\n- [511f76e](https://github.com/appium/ruby_lib/commit/511f76ea711516e5b2a95918343b8e903d17dc1a) Fix server_version path debug output\n\n\n#### v0.9.0 2013-09-19\n\n- [28f2161](https://github.com/appium/ruby_lib/commit/28f21615a435364246725e8f9adac62c0257dffa) Release 0.9.0\n- [25837ae](https://github.com/appium/ruby_lib/commit/25837aeccf47623c1e4055d51238ac7e443a2d4f) iOS textfields use xpath now\n\n\n#### v0.8.0 2013-09-19\n\n- [205e04a](https://github.com/appium/ruby_lib/commit/205e04a562e6606b583449cc285e5f4cc5ce9387) Release 0.8.0\n- [67f6361](https://github.com/appium/ruby_lib/commit/67f63614238507deac5e3d336f3217f7edc2cd62) Fix textfield methods on iOS\n\n\n#### v0.7.1 2013-09-09\n\n- [1e0f36e](https://github.com/appium/ruby_lib/commit/1e0f36e22833246873b6ecb8cc4d2bf3544de2c8) Release 0.7.1\n- [b611ac6](https://github.com/appium/ruby_lib/commit/b611ac6c361b7044d07d2501ae032784aa891c66) Fix typing on disabled textfield\n- [d887050](https://github.com/appium/ruby_lib/commit/d887050006dd4e18e8b558b542eb0a090fecf985) xml_keys, xml_values, resolve_id work on iOS\n- [e148f2a](https://github.com/appium/ruby_lib/commit/e148f2ad746795b7dcf3960ed8f837fad2b78f24) Allow custom URL. Fix #84\n- [8d6ae78](https://github.com/appium/ruby_lib/commit/8d6ae788006fd9430cc34fc0dc3e390876758a1a) Use our docs not rubydoc.info\n\n\n#### v0.7.0 2013-09-05\n\n- [c8f3041](https://github.com/appium/ruby_lib/commit/c8f3041049c2feb9ac85f67e85523118a6ce5a84) Release 0.7.0\n- [f98534d](https://github.com/appium/ruby_lib/commit/f98534dc92aa04a0afe05b6ed0e60c4be1d9394c) iOS page supports ids and defaults to 1st window\n- [ab6cb4f](https://github.com/appium/ruby_lib/commit/ab6cb4f66cb496a9c557b4c6246b8ecd7a3e06ed) strings.xml is now client side. compressed xml support\n- [e976552](https://github.com/appium/ruby_lib/commit/e9765527a8858d4d72e9372afdccbf0a2297f5c5) Add Android API 18 resource id to page output\n- [ddc5e36](https://github.com/appium/ruby_lib/commit/ddc5e3651e4920dab9198e33b77fcf570c7e5f8b) browserName is never used\n- [c5211e5](https://github.com/appium/ruby_lib/commit/c5211e52c51170653d85b9f2a249e4a346c17f7a) Print all matching ids in page\n- [8d19157](https://github.com/appium/ruby_lib/commit/8d1915732718864102cdfefcf4db0adb71377a74) Include strings.xml ids in page output on Android\n- [b615628](https://github.com/appium/ruby_lib/commit/b61562808624e1324be0934237dbef26a608aebf) Update readme.md\n- [adc4eba](https://github.com/appium/ruby_lib/commit/adc4ebaaade7778b975c166e1ab16f5c40cc2517) Add id example\n- [42d2a86](https://github.com/appium/ruby_lib/commit/42d2a860f8989a0d8df08815be1a5be4bd895ef6) Add more code examples\n- [fa45efd](https://github.com/appium/ruby_lib/commit/fa45efda445b7541f49f510ec08be9e99584ff72) Update docs.md\n\n\n#### v0.6.7 2013-08-23\n\n- [a1f5942](https://github.com/appium/ruby_lib/commit/a1f5942e907339f1c3968c5af03feb5bde6b1b7c) Release 0.6.7\n- [4a08dd6](https://github.com/appium/ruby_lib/commit/4a08dd63add2fd11e7cbb7aadaa086f6fb014ed2) Enable bundleid in app device cap\n- [caff218](https://github.com/appium/ruby_lib/commit/caff2187c378e619ee5b4e0524734df372354b69) Improve docs\n- [b579ca7](https://github.com/appium/ruby_lib/commit/b579ca7fd83c6673be1f04d745b9d6cbdaeb6504) Add iOS Jenkins Xcode note\n- [4fbf0fb](https://github.com/appium/ruby_lib/commit/4fbf0fbdea07120ebf4d270bfee2cf251ba312fb) Add landscape and portrait rotate examples\n- [c6d4353](https://github.com/appium/ruby_lib/commit/c6d43537c759342b1ceed72cf8a81573c5070c65) Allow setting device cap\n\n\n#### v0.6.6 2013-08-19\n\n- [5b84a0b](https://github.com/appium/ruby_lib/commit/5b84a0bd9d9273c704414bdb9a9857b503439b90) Release 0.6.6\n- [6f3b002](https://github.com/appium/ruby_lib/commit/6f3b0027757d8fbf62bc26d8a3497caab025c8c8) Add export session option.\n- [b05c07e](https://github.com/appium/ruby_lib/commit/b05c07e5ddcb6ba7dc79d20a38f1dae8567c52c6) Fix screenshot return value\n\n\n#### v0.6.5 2013-08-13\n\n- [8b7b4d6](https://github.com/appium/ruby_lib/commit/8b7b4d6d7836bfede93b6da99bdcac836d218481) Release 0.6.5\n- [8dadb52](https://github.com/appium/ruby_lib/commit/8dadb52e0bc0372cef575d5f1c82acdc9bec4c20) Add directory support to appium.txt require\n\n\n#### v0.6.4 2013-08-09\n\n- [94a9bbc](https://github.com/appium/ruby_lib/commit/94a9bbc595f42008d7fdb7ba6814efd38955294b) Release 0.6.4\n- [3b24fcd](https://github.com/appium/ruby_lib/commit/3b24fcd4c23941502eec22d99a3e3db7094b9401) Add optional $driver.global_webdriver_http_sleep\n- [dae3508](https://github.com/appium/ruby_lib/commit/dae3508b566de1a3eaae64483cd79d9502a71859) Add longClick example\n\n\n#### v0.6.3 2013-08-07\n\n- [ccf8e37](https://github.com/appium/ruby_lib/commit/ccf8e375283bd9038fcf6c1db576f7539065e6d0) Release 0.6.3\n- [d55c6fa](https://github.com/appium/ruby_lib/commit/d55c6faddcbfd42b1f500e617e38eaa18ddc6532) Fix device and rake uninstall\n- [8c704ee](https://github.com/appium/ruby_lib/commit/8c704eece569c37bcc491e8edf88b34e1310ee96) Support OpenStruct in Awesome Print\n- [898fe27](https://github.com/appium/ruby_lib/commit/898fe27a86056b5ec6931555ad778c04c3a3a342) Device is not case sensitive\n\n\n#### v0.6.2 2013-08-07\n\n- [509e7b8](https://github.com/appium/ruby_lib/commit/509e7b81f02c6b0c4cdcb07aca034c9dad260ff4) Release 0.6.2\n- [69a698b](https://github.com/appium/ruby_lib/commit/69a698b0ba7b3aa7bbe8846711eac8da0108552e) Add px_to_window_rel\n- [218185f](https://github.com/appium/ruby_lib/commit/218185fea68277537ed47dbc9312c874e26489b9) Add promote example\n- [b57772c](https://github.com/appium/ruby_lib/commit/b57772c48c409d981518d9aee7ab1b7accd3465a) Fix comments\n\n\n#### v0.6.1 2013-08-05\n\n- [44b4b29](https://github.com/appium/ruby_lib/commit/44b4b29596b59b1d8a7a7ab7485f176a84143ac3) Release 0.6.1\n- [a58228f](https://github.com/appium/ruby_lib/commit/a58228f728576be4bbe8325788ed28571b810bb4) Refactor promotion into a method\n\n\n#### v0.6.0 2013-08-05\n\n- [09aa23d](https://github.com/appium/ruby_lib/commit/09aa23d8c1b769b054c7d0e24ec86cf55d6bc027) Release 0.6.0\n- [cbaf19d](https://github.com/appium/ruby_lib/commit/cbaf19d9d607b00dde89aca3829f17808780c2f3) Add keyboard send_keys documentation\n- [25333d6](https://github.com/appium/ruby_lib/commit/25333d6d2871ba5009dcf4050185dbdf1d324ce9) Fix for Minitest 5\n- [1e047b0](https://github.com/appium/ruby_lib/commit/1e047b092740703083ed9e452f9e77d6086f8372) Minitest 5 only\n- [7ef93e9](https://github.com/appium/ruby_lib/commit/7ef93e99fbc373a6d4f2a75f1abc81a12a9688fa) Update usage example\n- [47f53f9](https://github.com/appium/ruby_lib/commit/47f53f9706d3aa302a431c2b91592ee8c72ba399) Device is now required\n- [62d5f2a](https://github.com/appium/ruby_lib/commit/62d5f2a258e927ee56e042466503c023c9138f6c) Patch only MiniTest\n- [6ce29df](https://github.com/appium/ruby_lib/commit/6ce29df7b9d7b144a750579faab9629741f64593) Fix release notes\n\n\n#### v0.5.16 2013-07-26\n\n- [bd71fb4](https://github.com/appium/ruby_lib/commit/bd71fb4e430608d32923c583c8d4d592f11a96fc) Release 0.5.16\n- [7b83b85](https://github.com/appium/ruby_lib/commit/7b83b85c41caf25376414d978ff63d49ab22f057) Only return files that exist\n- [1f0428d](https://github.com/appium/ruby_lib/commit/1f0428dca4e843a82de2d46be3c724e2dc7930c7) Fix keyboard race condition\n- [c99ed34](https://github.com/appium/ruby_lib/commit/c99ed341c779fb3eff4ab92a95a4a773a1ce212f) Update docs.md\n- [7103921](https://github.com/appium/ruby_lib/commit/71039210e1e0b7481df59210ce4addebcae7ba08) Fix link\n- [f76ea9b](https://github.com/appium/ruby_lib/commit/f76ea9b42a728aae247f88f732879cda94101624) Add require support to appium.txt\n- [12b8e59](https://github.com/appium/ruby_lib/commit/12b8e5938cb616015cb86d62e41ee9d29cace097) Update docs.md\n- [7d6a8f2](https://github.com/appium/ruby_lib/commit/7d6a8f2fa728e616e7fd459cdeef0d5cce9064b4) Add current_app to docs\n- [16ea945](https://github.com/appium/ruby_lib/commit/16ea9454941d84bb02ba4950aeea8df6d70cab26) Fix hide keyboard on iOS\n- [ad9263c](https://github.com/appium/ruby_lib/commit/ad9263cbabb4e1c56bbe9fafe85b048f2a285c11) Add Sauce wait req\n- [98ee244](https://github.com/appium/ruby_lib/commit/98ee244d460f6251c5c6cff8cc79ca8610cc6165) Add .clear example for textfield\n- [d373071](https://github.com/appium/ruby_lib/commit/d3730717faba192cc66f5346c2847ecf6cb60e16) Fix activity name example in readme\n- [50023f3](https://github.com/appium/ruby_lib/commit/50023f3a8201b0875025e5a94ec841fb23c35714) Fix Android version\n- [c4d281a](https://github.com/appium/ruby_lib/commit/c4d281a62d7923f9e6a65fbc870cb1dc6a959849) Add Android set version code\n- [5675f4a](https://github.com/appium/ruby_lib/commit/5675f4a03f8b20939e8cc1b5b13df795072d6553) Update readme.md\n\n\n#### v0.5.15 2013-07-03\n\n- [734fe68](https://github.com/appium/ruby_lib/commit/734fe6887f36aa1ad59ef7ce992ba2e2f4c8c7d3) Release 0.5.15\n- [0e203d7](https://github.com/appium/ruby_lib/commit/0e203d76610abd519ba9d2fe9c14b50c94df5bbd) Fix driver methods overriding object methods\n- [efc4602](https://github.com/appium/ruby_lib/commit/efc460278af5b6f2a24c290f704781be4e9b2d4b) Fix open struct\n\n\n#### v0.5.14 2013-07-03\n\n- [521f79b](https://github.com/appium/ruby_lib/commit/521f79b11497c0c963b7059347e02d81a08f665a) Release 0.5.14\n- [7831c7d](https://github.com/appium/ruby_lib/commit/7831c7d21bc6ae3c39d91c6903cb5e96ec066f16) Update current_app\n- [3009abc](https://github.com/appium/ruby_lib/commit/3009abc44624f58c2201ad881b918e79252c2a83) Add iOS version commands\n- [d224b6b](https://github.com/appium/ruby_lib/commit/d224b6b982d6ca7bc741ec9f92d597203081d4c6) Update readme.md\n- [89a43da](https://github.com/appium/ruby_lib/commit/89a43da27d3629d5a4f3dc521fefb6e00a97ad2e) Update docs.md\n- [85469de](https://github.com/appium/ruby_lib/commit/85469de2cb574722719e77809498319d948add15) Update readme.md\n- [95c5c3c](https://github.com/appium/ruby_lib/commit/95c5c3cccf7b038293c9b8bd8bb168edc5bdd6a2) Current app is only for Android\n- [460699c](https://github.com/appium/ruby_lib/commit/460699cce767339bf73efd8b5791464130681cb8) Update current_app\n\n\n#### v0.5.13 2013-06-19\n\n- [146e19a](https://github.com/appium/ruby_lib/commit/146e19a1b322d1bb625c6bb3ce1b80e67a7e80fa) Release 0.5.13\n- [2eb4bb0](https://github.com/appium/ruby_lib/commit/2eb4bb0c696f41c839227dd99256d77d52bf995f) Check method exists before calling\n- [8d48ca2](https://github.com/appium/ruby_lib/commit/8d48ca2c4463b54d5d68332b58e3ed8eff01edf0) Current app is in the lib now\n- [683ae29](https://github.com/appium/ruby_lib/commit/683ae2975fde08d069fefb731a342c7ddd9ebb92) Add current_app\n\n\n#### v0.5.12 2013-06-18\n\n- [89b0902](https://github.com/appium/ruby_lib/commit/89b0902ed94ed43d8a9f0e364463da77015dcfb7) Release 0.5.12\n- [7c4e8d1](https://github.com/appium/ruby_lib/commit/7c4e8d16d909112cebd2a80f0d8140723efd644a) search_id, search_value replaced with xml_keys, xml_values\n\n\n#### v0.5.11 2013-06-18\n\n- [891e003](https://github.com/appium/ruby_lib/commit/891e003748038a006121c8a4e0c702c12c405799) Release 0.5.11\n- [5e7f381](https://github.com/appium/ruby_lib/commit/5e7f381aa8fc4b64af9103beae67cfc2fc310484) WebView is not a widget\n- [830c3fb](https://github.com/appium/ruby_lib/commit/830c3fb07e01da64a6934a9a0868861a67326f4f) Add search value\n\n\n#### v0.5.10 2013-06-17\n\n- [16d696a](https://github.com/appium/ruby_lib/commit/16d696aa368bdce198b7ef7a1cc1370f6c5d2ac7) Release 0.5.10\n- [5cc0a7a](https://github.com/appium/ruby_lib/commit/5cc0a7a52d43af7690705f889860c2dc4788b892) Add search and resolve id\n\n\n#### v0.5.9 2013-06-11\n\n- [ac76a23](https://github.com/appium/ruby_lib/commit/ac76a23ca4c7f5bb89a833937cc726654fa2df82) Release 0.5.9\n- [b377791](https://github.com/appium/ruby_lib/commit/b3777911709538a230d1fd3be31ae21f72040b00) Update readme.md\n- [893737a](https://github.com/appium/ruby_lib/commit/893737a6033ed7c8e6f1c31f5b45f65b841320c2) Add current_activity\n\n\n#### v0.5.8 2013-06-04\n\n- [91f5c2f](https://github.com/appium/ruby_lib/commit/91f5c2f2bd388c1d4c4e771d2abea3772197de9c) Release 0.5.8\n- [b4e592c](https://github.com/appium/ruby_lib/commit/b4e592cc3d101a4ac9f7fa374ae8c75fcdc5218a) Fix call twice\n- [18e3f7d](https://github.com/appium/ruby_lib/commit/18e3f7d1c6869ba0d2c248b9c242d08c47390346) Prefer existing method before calling driver method\n- [1f72729](https://github.com/appium/ruby_lib/commit/1f727290c2452833df87a8b4d559bf5c51955a1e) switch_to.alert calls getAlertText so use bridge directly\n- [9752a3b](https://github.com/appium/ruby_lib/commit/9752a3bdf8173653f6d5c2d412bb7c70f0b5f023) Add tag method\n\n\n#### v0.5.7 2013-06-03\n\n- [669f734](https://github.com/appium/ruby_lib/commit/669f7345b7e8a92e8206b847d4a2263731df3c4b) Release 0.5.7\n- [bb5b7a5](https://github.com/appium/ruby_lib/commit/bb5b7a568dab38dc7044e3925274f9f7ee84a362) Add page_class for iOS\n\n\n#### v0.5.6 2013-05-31\n\n- [7c3335c](https://github.com/appium/ruby_lib/commit/7c3335c82e8b96e4a4cf74ae20faf98906b63770) Release 0.5.6\n- [b231d8f](https://github.com/appium/ruby_lib/commit/b231d8fbcdd35cc7a027e02a7733d10a616d2f7b) Fix finds\n\n\n#### v0.5.5 2013-05-31\n\n- [e061482](https://github.com/appium/ruby_lib/commit/e061482a0f712914c5fb21da92da357b79e07b87) Release 0.5.5\n- [82f9c58](https://github.com/appium/ruby_lib/commit/82f9c580d68189b669d3f5029914f00c8fd17c06) Fix value contains operator\n- [c5b8d84](https://github.com/appium/ruby_lib/commit/c5b8d849b29f46beebd1aea4ff59f2de6edd9dc6) Update readme.md\n- [c14fbb3](https://github.com/appium/ruby_lib/commit/c14fbb3c39b0c33a5d42dfe9da5427cebb9ec336) Add version badge\n\n\n#### v0.5.4 2013-05-28\n\n- [9e95106](https://github.com/appium/ruby_lib/commit/9e951061b9da6cee7b90ee310bbbef2b7c660fb1) Release 0.5.4\n- [d66020c](https://github.com/appium/ruby_lib/commit/d66020c66b02889d4a96809f41d02d4aa3e4b915) Fix gemspec. yard is required for docs task\n- [1c6509d](https://github.com/appium/ruby_lib/commit/1c6509ddea68305b47f251e0d0c1ff4a5c1493ee) Add dev task to install gems required for release task\n- [5106643](https://github.com/appium/ruby_lib/commit/51066439a4bacf7fea4a469044f6c3e2b60356c9) Add Sauce Storage support\n\n\n#### v0.5.3 2013-05-24\n\n- [b24565d](https://github.com/appium/ruby_lib/commit/b24565df67d4f0468ab5e3c1a700711a4c82b80d) Release 0.5.3\n- [5c7169a](https://github.com/appium/ruby_lib/commit/5c7169ae5fecc9adf0bd0a8f7fc6aea5a90495a2) Update appium_lib.gemspec\n- [1a03758](https://github.com/appium/ruby_lib/commit/1a03758dede749f9fd23f00db1be9199c159a6c8) Update readme.md\n\n\n#### v0.5.2 2013-05-24\n\n- [44ffbcb](https://github.com/appium/ruby_lib/commit/44ffbcb4715c8caac2770972c72ca498e751be34) Release 0.5.2\n- [61e92f8](https://github.com/appium/ruby_lib/commit/61e92f87e6870be06b34a20dc0dfc64ddfed7f13) Add get_page_class\n- [cca5db4](https://github.com/appium/ruby_lib/commit/cca5db4d98e00306f99110cd43398b0dc1f5980f) Update tag names\n\n\n#### v0.5.1 2013-05-24\n\n- [1a98819](https://github.com/appium/ruby_lib/commit/1a98819e93e739496f27a6ec2ad4197ca78c08a4) Release 0.5.1\n- [2003589](https://github.com/appium/ruby_lib/commit/2003589197a78d54f3d177abbf2335724c090e1e) Fix names on Android\n\n\n#### v0.5.0 2013-05-24\n\n- [de58f71](https://github.com/appium/ruby_lib/commit/de58f7164230d7551df8462d65d0e43a3d0cfdab) Release 0.5.0\n- [062a2a2](https://github.com/appium/ruby_lib/commit/062a2a21fc3768c0d19b33d317c7ba5828bcbc3e) Add page_class\n- [9e1e091](https://github.com/appium/ruby_lib/commit/9e1e091f1cc27d3330faa9c44b8241b720c10595) Add note\n- [1372009](https://github.com/appium/ruby_lib/commit/1372009afdd62c6c2f57ffa8d9fa4fce3de056b2) Fix method signature\n- [f0e0954](https://github.com/appium/ruby_lib/commit/f0e0954d8f2c8f941b4f95bf995890454e748c4f) Dynamic is Android only\n- [8a1a387](https://github.com/appium/ruby_lib/commit/8a1a387e1fe03e9a3e9d0fafd2064fb9cd3759c4) Update docs.md\n- [eaa5b79](https://github.com/appium/ruby_lib/commit/eaa5b79f6768f3fd0da0637fad46c3dec4cd4ad1) Rename s_first_text s_last_text\n- [edbd74f](https://github.com/appium/ruby_lib/commit/edbd74fb8a32b53f37c65dd3617afaf6c6bd5641) Add example for screenshot\n- [73fcb72](https://github.com/appium/ruby_lib/commit/73fcb72d78bf02cb0deaa9af3f65ce074518c4fa) Add params to exists\n- [558d4af](https://github.com/appium/ruby_lib/commit/558d4afc023243374eadf6187c5036c0ac8dd4ba) Fix opts\n- [adfdc18](https://github.com/appium/ruby_lib/commit/adfdc18f224dcb98e41630ed354bdc2ac61241d8) Fix gemspec\n- [299d0c8](https://github.com/appium/ruby_lib/commit/299d0c8085e5117d7cdb5084334fb8e35efad32d) Move appium.txt loading to appium_lib\n- [aaf54be](https://github.com/appium/ruby_lib/commit/aaf54be45c0b711c4c3a86d3b42a853f1bdc80d1) Fix code format\n- [9e3a3e9](https://github.com/appium/ruby_lib/commit/9e3a3e9c3321c1fb78d8ed8df9b98f7f99d8c258) Move default wait to init param\n- [ae9acb1](https://github.com/appium/ruby_lib/commit/ae9acb1fcea3dc2af32032ade35ee9263668e7a8) Update docs\n- [849594b](https://github.com/appium/ruby_lib/commit/849594bdd87bf6133cbb64c43d0a02f427f17467) Update method comments\n\n\n#### v0.4.2 2013-05-20\n\n- [be814c2](https://github.com/appium/ruby_lib/commit/be814c286bd55fb133f333738da9b0dcd6146b69) Release 0.4.2\n- [9d2cfe8](https://github.com/appium/ruby_lib/commit/9d2cfe86b3367fd3f4551962a042fe25da1e31bd) Add page_window for Apptentive\n- [e9b5e97](https://github.com/appium/ruby_lib/commit/e9b5e97baf7b6a417dc3865b7cc0c163c0165d70) Update docs\n\n\n#### v0.4.1 2013-05-20\n\n- [cd8dd73](https://github.com/appium/ruby_lib/commit/cd8dd73461d6bdb8903a8b3f5bba9ce554a44789) Release 0.4.1\n- [9e8cd0a](https://github.com/appium/ruby_lib/commit/9e8cd0a915e6c9c373ebd3a33a653c573f776636) Add status\n- [978d489](https://github.com/appium/ruby_lib/commit/978d48964361ca36267b866b1fe69d0b09b3f273) Update docs\n- [eb11923](https://github.com/appium/ruby_lib/commit/eb11923543a1e3e2fe8f19d2f09959cefd16fa05) Fix generic iOS methods\n\n\n#### v0.4.0 2013-05-16\n\n- [70a59fe](https://github.com/appium/ruby_lib/commit/70a59fefcaa4f16ba0e7629f16feaae3e5f8c424) Release 0.4.0\n- [b30548e](https://github.com/appium/ruby_lib/commit/b30548e58783bc6b20bd5c0f11e2ae9ddb5faa30) Translate mobile find on Android\n- [1ea8b85](https://github.com/appium/ruby_lib/commit/1ea8b85ebb7c7531c2791f3c41d0280d947edad0) Screenshot should work on iOS\n- [3797644](https://github.com/appium/ruby_lib/commit/3797644874ff1e56a8c35f9825e42c8486902984) Update docs\n- [0e2c119](https://github.com/appium/ruby_lib/commit/0e2c119199535a2e9a8e708453fa068c6445e6ca) Fix release notes\n- [5c28a2d](https://github.com/appium/ruby_lib/commit/5c28a2debcd8386aab62b48d0b087ed7dac84d8d) Next release will be 0.4.0\n- [b9e5044](https://github.com/appium/ruby_lib/commit/b9e5044ddf6f998c09f006d8a6d95a5560f2fdd3) Remove comment\n- [30c2ada](https://github.com/appium/ruby_lib/commit/30c2adaecb0bca734664192a805968a83f4b7a8b) Update doc links\n- [d08cd59](https://github.com/appium/ruby_lib/commit/d08cd5944aeda9fa3f3842fd5a259e0385b88166) Add JS doc gen\n- [61530fb](https://github.com/appium/ruby_lib/commit/61530fb908822cd32be6cb25d94ffb00f68ec87b) Update docs\n- [ebe6a2f](https://github.com/appium/ruby_lib/commit/ebe6a2fa91a748c0c823dbb969afa51ab3710acd) Update docs.md\n- [637fef7](https://github.com/appium/ruby_lib/commit/637fef7f7547e6e2b2fd8f70e19ef3f3870cc136) Use element.displayed? not visible\n\n\n#### v0.3.16 2013-05-14\n\n- [fb34a03](https://github.com/appium/ruby_lib/commit/fb34a03ceec0be552f218323bf266fda7f7e060b) Release 0.3.16\n- [6e552ae](https://github.com/appium/ruby_lib/commit/6e552ae0d9a66a03ac50caa38f73f3f3dbded317) Selendroid is boolean\n\n\n#### v0.3.15 2013-05-13\n\n- [cc56df8](https://github.com/appium/ruby_lib/commit/cc56df88825ac8e705e740eed7ac8ca42bcc9dd0) Release 0.3.15\n- [8613403](https://github.com/appium/ruby_lib/commit/8613403db07435908a149dc296fb92cad8af2e35) Use boolean for .visible on iOS\n\n\n#### v0.3.14 2013-05-13\n\n- [12aa291](https://github.com/appium/ruby_lib/commit/12aa29132a9a88076fbf8c76fbb65b1aa5e1fc96) Release 0.3.14\n- [a61b297](https://github.com/appium/ruby_lib/commit/a61b297d387b0c28865b050eaa3d7d59efae2a34) Add .visible for iOS\n- [6f6dda5](https://github.com/appium/ruby_lib/commit/6f6dda53fb12a483a524370c3d3c729fa1b87be4) Update gemspec\n\n\n#### v0.3.13 2013-05-10\n\n- [7badb99](https://github.com/appium/ruby_lib/commit/7badb998734ee4c4ae0781c5e8f3cfc4b862eeb3) Release 0.3.13\n- [efaa0ea](https://github.com/appium/ruby_lib/commit/efaa0eaebe5a045dba8370ec98aea8bdf31637ba) Fix #52\n\n\n#### v0.3.12 2013-05-10\n\n- [faf3e98](https://github.com/appium/ruby_lib/commit/faf3e98d0d745df9bbbfada93dcfd6b47a585793) Release 0.3.12\n- [7ff6b95](https://github.com/appium/ruby_lib/commit/7ff6b955cafc235a554d192cc09014c4400dc27a) Add scroll_to\n\n\n#### v0.3.11 2013-05-09\n\n- [14d705a](https://github.com/appium/ruby_lib/commit/14d705acd527f13e2962e2c04200b6d28fd36cbb) Release 0.3.11\n- [ebdae44](https://github.com/appium/ruby_lib/commit/ebdae448b108c76e586ad8f8ae86a1abc495e7e5) Search name and text when using textfield\n\n\n#### v0.3.10 2013-05-07\n\n- [db557df](https://github.com/appium/ruby_lib/commit/db557df9939fa44f2a6bf5d8afd950a2fa4b4178) Release 0.3.10\n- [c3adbc5](https://github.com/appium/ruby_lib/commit/c3adbc52f0b049e6b9292ac2ff328160d1820668) Fix name and textfield\n- [5c26137](https://github.com/appium/ruby_lib/commit/5c261370fd68f363f0ab2f4d70ad486c43dc46fb) Android can't get alert text\n- [36f68de](https://github.com/appium/ruby_lib/commit/36f68de51954de79754e8f377f4a6dad47361dc1) Add shown attribute to Selendroid page\n\n\n#### v0.3.9 2013-05-06\n\n- [3b4fbb4](https://github.com/appium/ruby_lib/commit/3b4fbb4e6957a92ac4236d5666d932ee9da238e7) Release 0.3.9\n- [98b1b1e](https://github.com/appium/ruby_lib/commit/98b1b1e8e0952244c1ca2c8738d7d33af7eb0f68) Fix extra slashes in path\n\n\n#### v0.3.8 2013-05-06\n\n- [e7bc45f](https://github.com/appium/ruby_lib/commit/e7bc45fd88f026dc51237d767da9f9dfa2e05b56) Release 0.3.8\n- [dc3a50f](https://github.com/appium/ruby_lib/commit/dc3a50f23ca6ba4978ddb9af1dadf6c6015eb9fb) Use 4.2 not 4.1\n- [f8042f1](https://github.com/appium/ruby_lib/commit/f8042f158f046815238463a9ea86cd66ea725942) Fix page Selendroid\n- [f9866e0](https://github.com/appium/ruby_lib/commit/f9866e034ea9a3744387fb15d5ca3ba221f27429) Load touch methods\n- [c3f9a2b](https://github.com/appium/ruby_lib/commit/c3f9a2b0300ee238acf4ce750f9b651ff39eb919) Don't set timeout on Selendroid until it's fixed\n- [d88245e](https://github.com/appium/ruby_lib/commit/d88245efe8fed5927e136719a9747b788dbd0fc2) Add page for Selendroid\n- [ff63433](https://github.com/appium/ruby_lib/commit/ff63433db6d68170ef135e151d6ac154c3504f4f) Add id method\n- [c59f7ce](https://github.com/appium/ruby_lib/commit/c59f7cefc76a9f172e6e6494aca275b5687d1a74) Improve debugging\n\n\n#### v0.3.7 2013-05-01\n\n- [edfd20a](https://github.com/appium/ruby_lib/commit/edfd20a6ffdef8484b9f7b5eddb9c21815241d42) Release 0.3.7\n- [9f8511c](https://github.com/appium/ruby_lib/commit/9f8511c1416867df606dfb3d058f83ee277ce39a) Remove puts\n\n\n#### v0.3.6 2013-05-01\n\n- [67e5c86](https://github.com/appium/ruby_lib/commit/67e5c867d38251687dc7ebd5de013db5712fcac3) Release 0.3.6\n- [a0a46f7](https://github.com/appium/ruby_lib/commit/a0a46f773a57c9ef7b92252afed467bd7cd01b96) Fix wait and add wait_true\n- [e7cde77](https://github.com/appium/ruby_lib/commit/e7cde775473bd3981cac5b356f78289f832091a9) Add wait example\n\n\n#### v0.3.5 2013-04-30\n\n- [a886ef4](https://github.com/appium/ruby_lib/commit/a886ef4722a902fdef15ecfc7164299399f1d524) Release 0.3.5\n- [193eb71](https://github.com/appium/ruby_lib/commit/193eb716023f52506cdf599cff6aae4f4a3c1119) Fix JSON.parse\n- [54ba323](https://github.com/appium/ruby_lib/commit/54ba323721a704d3ceb34f71dd8e1fcf9069dd78) Use upstream get name contains\n- [6f66b46](https://github.com/appium/ruby_lib/commit/6f66b46725ee397cc437901e95431ec95935d9c2) Name contains moved upstream\n- [2d33b5c](https://github.com/appium/ruby_lib/commit/2d33b5ce4078d784f7f6f0ac07651166a466b34c) Update readme.md\n- [4a1f87e](https://github.com/appium/ruby_lib/commit/4a1f87e1f0524595d7bd15027b4a009a42b5ff83) Update example\n- [6177c49](https://github.com/appium/ruby_lib/commit/6177c497f9c114203e624f530e51f4f54a61788a) Rename get_wait\n\n\n#### v0.3.4 2013-04-30\n\n- [ffdf104](https://github.com/appium/ruby_lib/commit/ffdf104ffdecb165cfe410976145134768756e30) Release 0.3.4\n- [4edc9f6](https://github.com/appium/ruby_lib/commit/4edc9f6097e29d2816dceef546a819fd6ee431d2) Add params to wait\n- [da1c042](https://github.com/appium/ruby_lib/commit/da1c0424873fa5f859b1ec558356a3ad0721097b) Add selendroid launch support\n- [f398041](https://github.com/appium/ruby_lib/commit/f398041369884d8068950ab9e703a8a2d750082c) Use symbols for driver opts\n- [cf09a0d](https://github.com/appium/ruby_lib/commit/cf09a0d1ca8de835043f855cbd74ced9abb5f1b0) Add expected server opts\n- [fe6c7d7](https://github.com/appium/ruby_lib/commit/fe6c7d71dbaf7f7b383d117918de2498945406d4) Fix os specific patches\n- [d9b9c1a](https://github.com/appium/ruby_lib/commit/d9b9c1a2fcc1857e0e7c78d250fd59b84726d69b) Improve logging\n- [3b831b0](https://github.com/appium/ruby_lib/commit/3b831b089e02c4a53585d90ed009f5ad3cb982a7) Return invisible match if no visible result\n\n\n#### v0.3.3 2013-04-27\n\n- [b0ca37c](https://github.com/appium/ruby_lib/commit/b0ca37cfe47318f029e1f2ad498a5c08338016d7) Release 0.3.3\n- [e7f55d9](https://github.com/appium/ruby_lib/commit/e7f55d92181660ea188a5123e6e4f447389c8d6d) Add driver method\n- [6d381fe](https://github.com/appium/ruby_lib/commit/6d381fe029bd9a5c11aa4d1a322d6afb603c6434) Update readme.md\n- [07da208](https://github.com/appium/ruby_lib/commit/07da208973ea4de64ec9605ef5dd38884771e8c6) Add troubleshooting steps\n\n\n#### v0.3.2 2013-04-26\n\n- [eee6632](https://github.com/appium/ruby_lib/commit/eee6632251c40c8b2d6be9a361f429d7c89762f8) Release 0.3.2\n- [b22d747](https://github.com/appium/ruby_lib/commit/b22d7473f03e1b13a1ffd9ddc2ea5ca1396c4642) Default to app_activity if app_wait_activity is not set\n- [76198ad](https://github.com/appium/ruby_lib/commit/76198ad4d169d836007a247b2ebe8cad5391f512) Fix reset clearing iOS JavaScript\n- [445519b](https://github.com/appium/ruby_lib/commit/445519b4528c9c253865f76fdac921a22c31fbd7) Use Appium's detailed error messages\n- [e00964f](https://github.com/appium/ruby_lib/commit/e00964fa7b9ccd047b06f1432ddd1e62170306df) Update readme.md\n- [ef0b626](https://github.com/appium/ruby_lib/commit/ef0b626940d86fd07dbb86ac16b40dd5b0b5ce4a) Avoid invisible elements\n\n\n#### v0.3.1 2013-04-26\n\n- [e00fc6e](https://github.com/appium/ruby_lib/commit/e00fc6efb8f0c94ac6e196e831980ee96676b645) Release 0.3.1\n- [81d762a](https://github.com/appium/ruby_lib/commit/81d762a92293a9d59600154f1f0a5944aee5b439) Check method exists before calling\n- [4b3f3dc](https://github.com/appium/ruby_lib/commit/4b3f3dc91714b08aae0acee51aa1137c58f59acb) Fix method dispatch\n- [fa8b679](https://github.com/appium/ruby_lib/commit/fa8b679b816bd1507c7c9de3f301a3b8a7742d8f) Fix iOS name\n- [5be26c4](https://github.com/appium/ruby_lib/commit/5be26c411fcf75154301749cd790487d3dd71ea9) Add sauce methods and find_name\n- [b3724d3](https://github.com/appium/ruby_lib/commit/b3724d36a85188c7c8c85dadc313c6c43c8bed59) Add session_id\n\n\n#### v0.3.0 2013-04-25\n\n- [e08e88c](https://github.com/appium/ruby_lib/commit/e08e88c40cc56e132c5db18d9d5862028861d5f2) Release 0.3.0\n- [3f4dd63](https://github.com/appium/ruby_lib/commit/3f4dd63ab2ab2e97b457bb188a347af6c74bc7df) Update code style\n- [9bbb17e](https://github.com/appium/ruby_lib/commit/9bbb17e4079c7db1c033284c3120611f11f33656) Update readme.md\n- [354bf19](https://github.com/appium/ruby_lib/commit/354bf19090ca6b1a7812d067321452094f7a62c0) Add new usage example\n- [9668450](https://github.com/appium/ruby_lib/commit/96684503b091af581a78067342106feef5769a92) Restore top level methods\n- [b095c4a](https://github.com/appium/ruby_lib/commit/b095c4a94109c508fc286801d957e4535e27462d) Rewrite as a real lib\n- [71628ff](https://github.com/appium/ruby_lib/commit/71628ff13fc84c3b15f0dc3986a75bd3fcb7a28e) Fix page for iOS\n- [fce0d67](https://github.com/appium/ruby_lib/commit/fce0d676cb78582703934872a0256c55ad55d225) Add force encoding check\n- [aed2607](https://github.com/appium/ruby_lib/commit/aed26079c25ee2f80c8a1462dde7d589d30e014b) Raise NoSuchElementError on find\n- [82dc953](https://github.com/appium/ruby_lib/commit/82dc953a302fc4505d6c7c2121da0ccbe71e053a) Add webview support to find\n- [151edde](https://github.com/appium/ruby_lib/commit/151edde563bb907b07c7896794ecbb81568c3e29) Define no args page for iOS\n- [b3227f7](https://github.com/appium/ruby_lib/commit/b3227f73175697782c5dbc8f62ad911fcae88965) Quote button name when string\n- [0c0073d](https://github.com/appium/ruby_lib/commit/0c0073d0785ff64606c7887ec4eb83a8bcc5cafd) Add grid and relative\n- [3b87251](https://github.com/appium/ruby_lib/commit/3b87251d9e749590873c1bb118c88dd4b8fdaea0) Add note about secure tag on Android\n- [494f0e3](https://github.com/appium/ruby_lib/commit/494f0e39d9b1ebbafd731b4d311e4cc1cee02266) Add window mapping for Android\n- [e4d63a5](https://github.com/appium/ruby_lib/commit/e4d63a569c6fede034a1fd411ba9047327389063) Replace classNameMatches with className\n- [dd82100](https://github.com/appium/ruby_lib/commit/dd821001ee333801a36f2b5c01e4793e47fd037e) Fix find_eles_attr\n- [de7a1bc](https://github.com/appium/ruby_lib/commit/de7a1bc1112aa3d1930647738d85ae54270685d2) Improve webdriver debug messages\n- [dff41da](https://github.com/appium/ruby_lib/commit/dff41dae4a0d67200336b3daa677ab73157c0464) Better webdriver debug messages\n- [d2ca728](https://github.com/appium/ruby_lib/commit/d2ca72880c9bdfb853a5dcd63e3db16fa03d3f1d) Use textContains to fetch first element only\n- [1cbb69d](https://github.com/appium/ruby_lib/commit/1cbb69d8b9b69cdacfdfef663ab8ff31d506ba50) Check for empty app path\n- [427e105](https://github.com/appium/ruby_lib/commit/427e105be7865c5a637e62fb597cc034b4cda2ad) Fix format\n- [40cd10b](https://github.com/appium/ruby_lib/commit/40cd10bf72a080a0a34f43d189befab1b1f953e4) Update get_inspect\n- [bc1cdb1](https://github.com/appium/ruby_lib/commit/bc1cdb120ccef4598333838cfaf35c54d84ad79a) Add find_eles_attr\n- [e89f8bd](https://github.com/appium/ruby_lib/commit/e89f8bdad8919471ae12c11343b82c2d04d88027) Use XPath last()\n- [133cf98](https://github.com/appium/ruby_lib/commit/133cf98bd27c26d1a5438bdf4534149f0f8aef89) Add xpath, xpaths\n- [435eac0](https://github.com/appium/ruby_lib/commit/435eac0bd8020dd5fc30a9ae163f72ab4fda1565) Fix name\n- [050734f](https://github.com/appium/ruby_lib/commit/050734f7a64e8d9386b5c2e2ccb0ce653f816437) Update first_ele to use XPath #15\n- [f89dcc3](https://github.com/appium/ruby_lib/commit/f89dcc361b8c6762cad541fc9b5a2e1955b1cd27) Update ele_index to use XPath #15\n- [763d086](https://github.com/appium/ruby_lib/commit/763d0862135bf9e06ad177c9e3e20a83819b1775) Use mobile method\n- [09035ab](https://github.com/appium/ruby_lib/commit/09035ab053df980baf43b8d1128f68fe52df37a4) Remove old comment\n- [2d07ed0](https://github.com/appium/ruby_lib/commit/2d07ed0d5868c734168b31fb47881eaa4c74af1c) Raise instead of puts\n\n\n#### v0.0.30 2013-04-16\n\n- [6d65a9c](https://github.com/appium/ruby_lib/commit/6d65a9c2895b1b66556b12fee4fc9649f558ede1) Release 0.0.30\n- [5692f96](https://github.com/appium/ruby_lib/commit/5692f9604a09b6198f8ada7823d8f74858b8af88) Fix quote\n- [ee17332](https://github.com/appium/ruby_lib/commit/ee173329758ea486d32d6887439de39a749ceba0) Use driver_quit\n\n\n#### v0.0.29 2013-04-15\n\n- [1c1e0ee](https://github.com/appium/ruby_lib/commit/1c1e0eeed8d636dc81d3b74612405722b1134071) Release 0.0.29\n- [2278c8e](https://github.com/appium/ruby_lib/commit/2278c8e662d32df86933a63f14dea4df431a95e5) Add wait param to start_driver\n- [f5f82c0](https://github.com/appium/ruby_lib/commit/f5f82c0f98291e0f8b8ae0baa6285ad4b62cc34e) Default to partial match\n- [2e7f8c6](https://github.com/appium/ruby_lib/commit/2e7f8c6b09aa433d3712685f6842a052dd4847b3) Update webdriver\n- [b7b6caa](https://github.com/appium/ruby_lib/commit/b7b6caa8ab0c2683626aed265ee6ec2feece37f0) Use gh_name\n\n\n#### v0.0.28 2013-04-11\n\n- [70606a4](https://github.com/appium/ruby_lib/commit/70606a43cebcd0c19b98a1876fb929f03db7bb0e) Release 0.0.28\n- [61d1943](https://github.com/appium/ruby_lib/commit/61d19439c8597ca3562028d6c985370a5d43fa26) Update docs.md\n- [7676a90](https://github.com/appium/ruby_lib/commit/7676a90af8a1951817fcc8c49ddef46577cf5726) Add iOS name, names, text, texts\n- [7bc936c](https://github.com/appium/ruby_lib/commit/7bc936c63fff14780595a9a9fd360670d6e00178) Update webdriver\n- [e3646d3](https://github.com/appium/ruby_lib/commit/e3646d311873f82287e2a14a8c699c2d097c5a6c) Add fast_duration\n- [22ac58a](https://github.com/appium/ruby_lib/commit/22ac58ab3f48cc51019fafde19efdc012d5b8c2b) Check that app path exists\n- [217bca9](https://github.com/appium/ruby_lib/commit/217bca9e85c5e5e4a21832c34cc715476b0dd181) Add page for iOS\n- [2abf365](https://github.com/appium/ruby_lib/commit/2abf365017555c37e95cfa57f0142b0a2fa944a8) Update docs.md\n- [a1d26ff](https://github.com/appium/ruby_lib/commit/a1d26ff13912e301079cc8ca222013850b660d21) Add link to docs.md\n- [e4d27c9](https://github.com/appium/ruby_lib/commit/e4d27c95e344ca7b25512044b65cbdbe4a9dce82) Update docs.md\n- [2cf20a0](https://github.com/appium/ruby_lib/commit/2cf20a026ef33e727b1da360634668ddda70518d) Create docs.md\n- [e1f470e](https://github.com/appium/ruby_lib/commit/e1f470e0a2b9a6cf94ffa20edbc244e31c0375e8) Add find for Android\n- [37bb4e9](https://github.com/appium/ruby_lib/commit/37bb4e90b29e5adb4438b287b6387a504c94b5c4) Update comment\n- [aaeba81](https://github.com/appium/ruby_lib/commit/aaeba817376dd8e3cadeab37d096abc0170b565b) Add order to find\n- [73b757c](https://github.com/appium/ruby_lib/commit/73b757cd28c5bc85b98d6e747f79f7ee33af5022) Define find and finds to search everything\n- [ebd6c1b](https://github.com/appium/ruby_lib/commit/ebd6c1bc7d3f8be01fdf5346786c2b5fb2da8deb) Fix text and texts on iOS\n\n\n#### v0.0.27 2013-04-05\n\n- [fb4af20](https://github.com/appium/ruby_lib/commit/fb4af206c114cf8f75fcb41cdbbea0ba728bf7e6) Release 0.0.27\n- [ca00d82](https://github.com/appium/ruby_lib/commit/ca00d82fb8e716d5941ec0ee6b38b207329b915e) Fix require\n- [ad00639](https://github.com/appium/ruby_lib/commit/ad006393ce8b6dc071c98b2edf73c32707d37762) Update readme.md\n\n\n#### v0.0.26 2013-04-04\n\n- [07fed25](https://github.com/appium/ruby_lib/commit/07fed259a743d9f3f3d72bfc8c8b9eac7b26d724) Release 0.0.26\n- [7c77faa](https://github.com/appium/ruby_lib/commit/7c77faa7087f9aa4bf2cc387a13b9bb0974d59a1) Add exists method\n- [27f4ccf](https://github.com/appium/ruby_lib/commit/27f4ccf19f0d4028baf634ccb9538a340c96ebb9) Add alert for Android\n- [4bb466f](https://github.com/appium/ruby_lib/commit/4bb466f8ed90cb0f015bb627423dba8c91574a4d) Add txt methods\n- [2d2704a](https://github.com/appium/ruby_lib/commit/2d2704a99318a21c292a636730bca94af87bcc55) Store default wait in var\n- [8a2bc8a](https://github.com/appium/ruby_lib/commit/8a2bc8aed39639e6c3d51c185d233be6f9760c59) Update release_notes.md\n- [c504873](https://github.com/appium/ruby_lib/commit/c504873582d4871650e02515ccb68e21bd1486ae) Create release_notes.md\n- [2e71e47](https://github.com/appium/ruby_lib/commit/2e71e477962c70113b556700cf08c74060d77370) Don't wait in Pry\n- [3416272](https://github.com/appium/ruby_lib/commit/341627269bf50497ebe4a6e388939d45d53e2032) Update readme.md\n\n\n#### v0.0.25 2013-03-28\n\n- [6a975a6](https://github.com/appium/ruby_lib/commit/6a975a6cc0e97866c3ef6248f0f7d1abbc934577) Release 0.0.25\n- [6a8fdce](https://github.com/appium/ruby_lib/commit/6a8fdcea4c8fdc308c7d107e958fbabed9719056) Rename inspect\n\n\n#### v0.0.24 2013-03-28\n\n- [d5bcb94](https://github.com/appium/ruby_lib/commit/d5bcb94966c4a7806a47ee892f3e5ff784a739e2) Release 0.0.24\n- [17f9a67](https://github.com/appium/ruby_lib/commit/17f9a67143720dbfc50b34783a11c7bf5c28ea3c) Add .lock to ignore\n- [9181cb8](https://github.com/appium/ruby_lib/commit/9181cb88f3d1180a16998f27e2236864809c6fcf) Add inspect using JSON dump\n- [e74dc46](https://github.com/appium/ruby_lib/commit/e74dc468a5d3d81f77c50d3fe41eb9dbebf3d404) Add get_source\n- [2444290](https://github.com/appium/ruby_lib/commit/24442908f9426b228dc760497ef98f9cf579d4d5) Add name methods\n\n\n#### v0.0.23 2013-03-27\n\n- [789634c](https://github.com/appium/ruby_lib/commit/789634c6b20d4030eaec4d385a85275b3fabfe76) Release 0.0.23\n- [6d58a33](https://github.com/appium/ruby_lib/commit/6d58a33bce0bf1ff3c6156717519a2db6a27bb84) Add app-wait-activity\n\n\n#### v0.0.22 2013-03-23\n\n- [bfd7761](https://github.com/appium/ruby_lib/commit/bfd7761c0f2b32e7ab0bbe8372228163181e60b9) Release 0.0.22\n\n\n#### v0.0.21 2013-03-22\n\n- [4066823](https://github.com/appium/ruby_lib/commit/40668230b89eaa66970889b20305279029048698) Release 0.0.21\n\n\n#### v0.0.20 2013-03-22\n\n- [ed588a1](https://github.com/appium/ruby_lib/commit/ed588a1ccc67d0efa0d8d56f4f9b08c23b261687) Release 0.0.20\n- [a4a7199](https://github.com/appium/ruby_lib/commit/a4a7199dfb609841310ad4e31ccbb56e3ecfa90d) Update readme.md\n\n\n#### v0.0.19 2013-03-22\n\n- [01f2d15](https://github.com/appium/ruby_lib/commit/01f2d150ae3d8e88970b361a8330c6ccc174097d) Release 0.0.19\n- [10eec2f](https://github.com/appium/ruby_lib/commit/10eec2f197899395978b73de049aed08ceda55cc) AppLib => AppiumLib\n- [c1e3b4f](https://github.com/appium/ruby_lib/commit/c1e3b4f0a08be3a0aef65218220f09f4198683bf) AppLib => AppiumLib"
  },
  {
    "path": "test/first_test.rb",
    "content": "# frozen_string_literal: true\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nrequire 'minitest/autorun'\nrequire 'minitest/reporters'\nrequire 'minitest'\n\nbegin\n  Minitest::Reporters.use! [Minitest::Reporters::ProgressReporter.new]\nrescue Errno::ENOENT\n  # Ignore since Minitest::Reporters::JUnitReporter.new fails in deleting files, sometimes\nend\n\nclass SampleTest < Minitest::Test\n  def test_test\n    assert(true)\n  end\nend\n"
  }
]