Repository: appium/ruby_lib Branch: master Commit: 47ac48a3aaac Files: 141 Total size: 579.2 KB Directory structure: gitextract_9jozq5zh/ ├── .github/ │ ├── CODEOWNERS │ ├── ISSUE_TEMPLATE.md │ ├── PULL_REQUEST_TEMPLATE.md │ ├── dependabot.yml │ └── workflows/ │ ├── functional-test.yml │ ├── pr-title.yml │ └── rubocop.yml ├── .gitignore ├── .rubocop.yml ├── CHANGELOG.md ├── Gemfile ├── LICENSE-2.0.txt ├── Rakefile ├── Thorfile ├── android_tests/ │ ├── Gemfile │ ├── LICENSE-2.0.txt │ ├── Rakefile │ ├── appium.txt │ ├── flaky.txt │ ├── lib/ │ │ ├── android/ │ │ │ └── specs/ │ │ │ ├── android/ │ │ │ │ ├── element/ │ │ │ │ │ ├── alert.rb │ │ │ │ │ ├── button.rb │ │ │ │ │ ├── generic.rb │ │ │ │ │ ├── text.rb │ │ │ │ │ └── textfield.rb │ │ │ │ ├── helper.rb │ │ │ │ └── patch.rb │ │ │ ├── common/ │ │ │ │ ├── device.rb │ │ │ │ ├── device_touchaction.rb │ │ │ │ ├── element/ │ │ │ │ │ └── window.rb │ │ │ │ ├── helper.rb │ │ │ │ ├── patch.rb │ │ │ │ ├── version.rb │ │ │ │ └── web_context.rb │ │ │ ├── driver.rb │ │ │ ├── install.rb │ │ │ └── sauce_labs.rb │ │ ├── format.rb │ │ └── run.rb │ └── readme.md ├── appium_lib.gemspec ├── contributing.md ├── docs/ │ ├── android_uiautomator.md │ ├── docs.md │ ├── ios_xcuitest.md │ ├── parallel.md │ └── w3c.md ├── grid/ │ ├── README.md │ ├── appium.txt.ios.example │ ├── config.json │ ├── hub_config.json │ └── hub_config_3.json ├── ios_tests/ │ ├── Gemfile │ ├── LICENSE-2.0.txt │ ├── Rakefile │ ├── appium.txt │ ├── data/ │ │ └── unicode.txt │ ├── flaky.txt │ ├── lib/ │ │ ├── common.rb │ │ ├── format.rb │ │ ├── ios/ │ │ │ └── specs/ │ │ │ ├── common/ │ │ │ │ ├── element/ │ │ │ │ │ └── window.rb │ │ │ │ ├── helper.rb │ │ │ │ ├── patch.rb │ │ │ │ ├── version.rb │ │ │ │ └── web_context.rb │ │ │ ├── device/ │ │ │ │ ├── device.rb │ │ │ │ └── image_comparison.rb │ │ │ ├── driver.rb │ │ │ └── ios/ │ │ │ ├── command/ │ │ │ │ ├── multi_app_handler.rb │ │ │ │ ├── pasteboard.rb │ │ │ │ └── source.rb │ │ │ ├── element/ │ │ │ │ ├── alert.rb │ │ │ │ ├── button.rb │ │ │ │ ├── generic.rb │ │ │ │ ├── text.rb │ │ │ │ └── textfield.rb │ │ │ ├── helper.rb │ │ │ ├── mobile_methods.rb │ │ │ ├── patch.rb │ │ │ └── xcuitest_gestures.rb │ │ └── run.rb │ ├── parallel/ │ │ └── test.rb │ └── readme.md ├── lib/ │ ├── appium_lib/ │ │ ├── android/ │ │ │ ├── android.rb │ │ │ ├── common/ │ │ │ │ ├── command/ │ │ │ │ │ └── command.rb │ │ │ │ └── helper.rb │ │ │ ├── element/ │ │ │ │ ├── alert.rb │ │ │ │ ├── button.rb │ │ │ │ ├── generic.rb │ │ │ │ ├── text.rb │ │ │ │ └── textfield.rb │ │ │ ├── espresso/ │ │ │ │ ├── bridge.rb │ │ │ │ ├── element/ │ │ │ │ │ ├── button.rb │ │ │ │ │ └── generic.rb │ │ │ │ ├── element.rb │ │ │ │ └── helper.rb │ │ │ ├── espresso.rb │ │ │ ├── uiautomator2/ │ │ │ │ ├── bridge.rb │ │ │ │ ├── element/ │ │ │ │ │ └── button.rb │ │ │ │ ├── element.rb │ │ │ │ └── helper.rb │ │ │ └── uiautomator2.rb │ │ ├── appium.rb │ │ ├── common/ │ │ │ ├── command.rb │ │ │ ├── device.rb │ │ │ ├── helper.rb │ │ │ ├── http_client.rb │ │ │ ├── log.rb │ │ │ └── wait.rb │ │ ├── driver.rb │ │ ├── error.rb │ │ ├── ios/ │ │ │ ├── common/ │ │ │ │ ├── errors.rb │ │ │ │ └── helper.rb │ │ │ ├── element/ │ │ │ │ ├── alert.rb │ │ │ │ ├── button.rb │ │ │ │ ├── generic.rb │ │ │ │ ├── text.rb │ │ │ │ └── textfield.rb │ │ │ ├── ios.rb │ │ │ ├── xcuitest/ │ │ │ │ ├── bridge.rb │ │ │ │ ├── command/ │ │ │ │ │ ├── certificate.rb │ │ │ │ │ ├── gestures.rb │ │ │ │ │ ├── get_context.rb │ │ │ │ │ ├── multi_app_handler.rb │ │ │ │ │ ├── pasteboard.rb │ │ │ │ │ └── source.rb │ │ │ │ ├── command.rb │ │ │ │ ├── element/ │ │ │ │ │ ├── button.rb │ │ │ │ │ ├── generic.rb │ │ │ │ │ ├── text.rb │ │ │ │ │ └── textfield.rb │ │ │ │ ├── element.rb │ │ │ │ └── helper.rb │ │ │ └── xcuitest.rb │ │ ├── sauce_labs.rb │ │ └── version.rb │ └── appium_lib.rb ├── readme.md ├── release_notes.md ├── test/ │ └── first_test.rb └── test_apps/ ├── VodQA.apk └── api.apk ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/CODEOWNERS ================================================ * @KazuCocoa ================================================ FILE: .github/ISSUE_TEMPLATE.md ================================================ ## This is a * [ ] Bug report * [ ] Question * [ ] Freature Request ## Summary ## Environment * Appium version (or git revision): * `ruby_lib` version: * Mobile platform/version/device under test: ## Actual behaviour and steps to reproduce ## Expected behaviour ## Link to Appium/Ruby logs Create a [GIST](https://gist.github.com) which is a paste of your _full_ Appium logs, and link them here. ## Any additional comments ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ # Summary Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. Closes # (issue) # How Has This Been Tested? Please describe the tests that you ran to verify your changes. If the change has test code, it can be alternative. - [ ] Test A - [ ] Test B # Checklist - [ ] `bundle exec rake rubocop` ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: - package-ecosystem: bundler directory: "/" schedule: interval: weekly time: "11:00" open-pull-requests-limit: 10 - package-ecosystem: github-actions directory: "/" schedule: interval: weekly time: "11:00" open-pull-requests-limit: 10 ================================================ FILE: .github/workflows/functional-test.yml ================================================ name: Functional Tests on: # Run by manual at this time workflow_dispatch: push: branches: [ master ] pull_request: branches: [ master ] concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: ios_test: runs-on: macos-15 timeout-minutes: 90 env: XCODE_VERSION: 16.4 IOS_VERSION: 18.5 IOS_DEVICE_NAME: iPhone 16 Plus steps: - uses: actions/checkout@v6 - name: Install Node.js uses: actions/setup-node@v6 with: node-version: 'lts/*' - name: Select Xcode uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: ${{ env.XCODE_VERSION }} - run: defaults write com.apple.iphonesimulator PasteboardAutomaticSync -bool false - uses: futureware-tech/simulator-action@v5 with: # https://github.com/actions/runner-images/blob/main/images/macos/macos-14-arm64-Readme.md model: ${{ env.IOS_DEVICE_NAME }} os_version: ${{ env.IOS_VERSION }} - name: Preparing other environment run: | brew install ffmpeg brew tap wix/brew brew install applesimutils # Start Appium - name: Install appium and mjpeg-consumer run: | npm install -g appium npm install -g mjpeg-consumer - run: | appium driver install xcuitest appium plugin install images appium plugin install execute-driver nohup appium --use-plugins=images,execute-driver --relaxed-security --log-timestamp --log-no-colors > appium.log & - run: | npx appium driver run xcuitest download-wda-sim --platform=ios --outdir=${{ github.workspace }}/wda name: Downloading prebuilt WDA - name: Set up Ruby uses: ruby/setup-ruby@v1 with: ruby-version: 4.0 - run: | bundle install bundle exec rake ios name: Run tests timeout-minutes: 60 working-directory: ios_tests env: LOCAL_PREBUILT_WDA: ${{ github.workspace }}/wda/WebDriverAgentRunner-Runner.app - name: Save server output if: ${{ always() }} uses: actions/upload-artifact@master with: name: appium-ios_test_with_other_deps.log path: | appium.log test/report/ android_test: runs-on: ubuntu-latest timeout-minutes: 90 env: API_LEVEL: 35 ARCH: x86_64 steps: - uses: actions/checkout@v6 - name: Set up Java uses: actions/setup-java@v5 with: distribution: temurin java-version: '17' - name: Install Node.js uses: actions/setup-node@v6 with: node-version: 'lts/*' - name: Set up Ruby uses: ruby/setup-ruby@v1 with: ruby-version: 4.0 - name: Install appium run: | npm install -g appium npm install -g mjpeg-consumer - name: Start appium run: | appium driver install uiautomator2 appium plugin install images appium plugin install execute-driver nohup appium --use-plugins=images,execute-driver --relaxed-security --log-timestamp --log-no-colors > appium.log & - name: Enable KVM group perms run: | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules sudo udevadm control --reload-rules sudo udevadm trigger --name-match=kvm - name: AVD cache uses: actions/cache@v5 id: avd-cache with: path: | ~/.android/avd/* ~/.android/adb* key: avd-${{ env.API_LEVEL }} - name: Create AVD snapshot for cache if: steps.avd-cache.outputs.cache-hit != 'true' uses: reactivecircus/android-emulator-runner@v2 with: api-level: ${{ env.API_LEVEL }} arch: ${{ env.ARCH }} target: google_apis force-avd-creation: false emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none disable-animations: false script: echo "Generated AVD snapshot for caching." - name: run tests uses: reactivecircus/android-emulator-runner@v2 with: api-level: ${{ env.API_LEVEL }} arch: ${{ env.ARCH }} script: cd android_tests;bundle install;bundle exec rake --tasks;bundle exec rake android target: google_apis profile: Nexus 5X disable-spellchecker: true disable-animations: true - name: Save server output if: ${{ always() }} uses: actions/upload-artifact@master with: name: appium-android_test_with_other_deps.log path: | appium.log test/report/ ================================================ FILE: .github/workflows/pr-title.yml ================================================ name: Conventional Commits on: pull_request: types: [opened, edited, synchronize, reopened] jobs: lint: uses: appium/appium-workflows/.github/workflows/pr-title.yml@main with: config-preset: angular ================================================ FILE: .github/workflows/rubocop.yml ================================================ name: rubocop on: push: branches: [ master ] pull_request: branches: [ master ] jobs: test: strategy: fail-fast: false matrix: ruby: [3.1, 3.2, 3.3] runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} - name: Install dependencies run: bundle install - name: Run rubocop run: bundle exec rake rubocop - name: Run tests run: bundle exec rake test ================================================ FILE: .gitignore ================================================ *.gem *.lock .DS_Store ================================================ FILE: .rubocop.yml ================================================ AllCops: TargetRubyVersion: 3.1 Layout/LineLength: Max: 128 Metrics/MethodLength: Enabled: false Metrics/ModuleLength: Enabled: false Metrics/ClassLength: Enabled: false Metrics/CyclomaticComplexity: Enabled: false Metrics/PerceivedComplexity: Enabled: false Metrics/AbcSize: Enabled: false Metrics/BlockLength: Enabled: false Style/Documentation: Enabled: false Style/RegexpLiteral: Enabled: false # blocked on https://github.com/appium/ruby_lib/issues/312. Already removed from core part Style/GlobalVars: Enabled: false Style/PercentLiteralDelimiters: Enabled: false Style/CommentedKeyword: Enabled: false Naming/AccessorMethodName: Enabled: false Naming/RescuedExceptionsVariableName: Enabled: false Layout/HeredocIndentation: Enabled: false Layout/RescueEnsureAlignment: Enabled: false Layout/HashAlignment: Enabled: false Style/ExplicitBlockArgument: Enabled: false Style/OptionalBooleanParameter: Enabled: false Naming/MethodParameterName: Enabled: false Style/KeywordParametersOrder: Enabled: false Style/AccessorGrouping: Enabled: false Style/StringConcatenation: Enabled: false Lint/NonDeterministicRequireOrder: Enabled: false Gemspec/DeprecatedAttributeAssignment: Enabled: true Layout/LineEndStringConcatenationIndentation: Enabled: true Layout/SpaceBeforeBrackets: Enabled: true Lint/AmbiguousAssignment: Enabled: true Lint/AmbiguousOperatorPrecedence: Enabled: false Lint/AmbiguousRange: Enabled: true Lint/DeprecatedConstants: Enabled: true Lint/DuplicateBranch: Enabled: true Lint/DuplicateRegexpCharacterClassElement: Enabled: true Lint/EmptyBlock: Enabled: true Lint/EmptyClass: Enabled: false Lint/EmptyInPattern: Enabled: true Lint/IncompatibleIoSelectWithFiberScheduler: Enabled: true Lint/LambdaWithoutLiteralBlock: Enabled: true Lint/NoReturnInBeginEndBlocks: Enabled: true Lint/NumberedParameterAssignment: Enabled: true Lint/OrAssignmentToConstant: Enabled: true Lint/RedundantDirGlobSort: Enabled: true Lint/RequireRelativeSelfPath: Enabled: true Lint/SymbolConversion: Enabled: true Lint/ToEnumArguments: Enabled: true Lint/TripleQuotes: Enabled: true Lint/UnexpectedBlockArity: Enabled: true Lint/UnmodifiedReduceAccumulator: Enabled: true Security/IoMethods: Enabled: true Style/ArgumentsForwarding: Enabled: true Style/CollectionCompact: Enabled: true Style/DocumentDynamicEvalDefinition: Enabled: true Style/EndlessMethod: Enabled: true Style/HashConversion: Enabled: false Style/HashExcept: Enabled: true Style/IfWithBooleanLiteralBranches: Enabled: true Style/InPatternThen: Enabled: true Style/MultilineInPatternThen: Enabled: true Style/NegatedIfElseCondition: Enabled: true Style/NilLambda: Enabled: true Style/NumberedParameters: Enabled: true Style/NumberedParametersLimit: Enabled: true Style/QuotedSymbols: Enabled: true Style/RedundantArgument: Enabled: true Style/RedundantSelfAssignmentBranch: Enabled: true Style/SelectByRegexp: Enabled: true Style/StringChars: Enabled: true Style/SwapValues: Enabled: true Gemspec/DevelopmentDependencies: # new in 1.44 Enabled: true Layout/LineContinuationLeadingSpace: # new in 1.31 Enabled: true Layout/LineContinuationSpacing: # new in 1.31 Enabled: true Lint/ConstantOverwrittenInRescue: # new in 1.31 Enabled: true Lint/DuplicateMagicComment: # new in 1.37 Enabled: true Lint/NonAtomicFileOperation: # new in 1.31 Enabled: false Lint/RefinementImportMethods: # new in 1.27 Enabled: true Lint/RequireRangeParentheses: # new in 1.32 Enabled: true Lint/UselessRescue: # new in 1.43 Enabled: true Metrics/CollectionLiteralLength: # new in 1.47 Enabled: true Naming/BlockForwarding: # new in 1.24 Enabled: true Security/CompoundHash: # new in 1.28 Enabled: true Style/ArrayIntersect: # new in 1.40 Enabled: true Style/ComparableClamp: # new in 1.44 Enabled: true Style/ConcatArrayLiterals: # new in 1.41 Enabled: true Style/DirEmpty: # new in 1.48 Enabled: true Style/EmptyHeredoc: # new in 1.32 Enabled: true Style/EnvHome: # new in 1.29 Enabled: true Style/FetchEnvVar: # new in 1.28 Enabled: true Style/FileEmpty: # new in 1.48 Enabled: true Style/FileRead: # new in 1.24 Enabled: true Style/FileWrite: # new in 1.24 Enabled: true Style/MagicCommentFormat: # new in 1.35 Enabled: true Style/MapCompactWithConditionalBlock: # new in 1.30 Enabled: true Style/MapToHash: # new in 1.24 Enabled: true Style/MapToSet: # new in 1.42 Enabled: true Style/MinMaxComparison: # new in 1.42 Enabled: true Style/NestedFileDirname: # new in 1.26 Enabled: true Style/ObjectThen: # new in 1.28 Enabled: true Style/OperatorMethodCall: # new in 1.37 Enabled: true Style/RedundantConstantBase: # new in 1.40 Enabled: false Style/RedundantDoubleSplatHashBraces: # new in 1.41 Enabled: true Style/RedundantEach: # new in 1.38 Enabled: true Style/RedundantHeredocDelimiterQuotes: # new in 1.45 Enabled: true Style/RedundantInitialize: # new in 1.27 Enabled: true Style/RedundantStringEscape: # new in 1.37 Enabled: true Gemspec/RequireMFA: # new in 1.23 Enabled: true Lint/UselessRuby2Keywords: # new in 1.23 Enabled: true Style/OpenStructUse: # new in 1.23 Enabled: false Lint/RedundantStringCoercion: Enabled: false Gemspec/AddRuntimeDependency: # new in 1.65 Enabled: true Lint/ConstantReassignment: # new in 1.70 Enabled: true Lint/DuplicateMatchPattern: # new in 1.50 Enabled: true Lint/DuplicateSetElement: # new in 1.67 Enabled: true Lint/HashNewWithKeywordArgumentsAsDefault: # new in 1.69 Enabled: true Lint/ItWithoutArgumentsInBlock: # new in 1.59 Enabled: true Lint/LiteralAssignmentInCondition: # new in 1.58 Enabled: true Lint/MixedCaseRange: # new in 1.53 Enabled: true Lint/NumericOperationWithConstantResult: # new in 1.69 Enabled: true Lint/RedundantRegexpQuantifiers: # new in 1.53 Enabled: true Lint/SharedMutableDefault: # new in 1.70 Enabled: true Lint/UnescapedBracketInRegexp: # new in 1.68 Enabled: true Lint/UselessDefined: # new in 1.69 Enabled: true Lint/UselessNumericOperation: # new in 1.66 Enabled: true Style/AmbiguousEndlessMethodDefinition: # new in 1.68 Enabled: true Style/BitwisePredicate: # new in 1.68 Enabled: true Style/CombinableDefined: # new in 1.68 Enabled: true Style/DataInheritance: # new in 1.49 Enabled: true Style/DigChain: # new in 1.69 Enabled: true Style/ExactRegexpMatch: # new in 1.51 Enabled: true Style/FileNull: # new in 1.69 Enabled: true Style/FileTouch: # new in 1.69 Enabled: true Style/ItAssignment: # new in 1.70 Enabled: true Style/KeywordArgumentsMerging: # new in 1.68 Enabled: true Style/MapIntoArray: # new in 1.63 Enabled: true Style/RedundantArrayConstructor: # new in 1.52 Enabled: true Style/RedundantCurrentDirectoryInPath: # new in 1.53 Enabled: true Style/RedundantFilterChain: # new in 1.52 Enabled: true Style/RedundantInterpolationUnfreeze: # new in 1.66 Enabled: true Style/RedundantLineContinuation: # new in 1.49 Enabled: true Style/RedundantRegexpArgument: # new in 1.53 Enabled: true Style/RedundantRegexpConstructor: # new in 1.52 Enabled: true Style/ReturnNilInPredicateMethodDefinition: # new in 1.53 Enabled: true Style/SafeNavigationChainLength: # new in 1.68 Enabled: false Style/SendWithLiteralMethodName: # new in 1.64 Enabled: true Style/SingleLineDoEndBlock: # new in 1.57 Enabled: true Style/SuperArguments: # new in 1.64 Enabled: true Style/SuperWithArgsParentheses: # new in 1.58 Enabled: true Style/YAMLFileRead: # new in 1.53 Enabled: true ================================================ FILE: CHANGELOG.md ================================================ # Changelogs Commit based release not is [release_notes.md](./release_notes.md) Release tags are https://github.com/appium/ruby_lib/releases . ## [16.2.0] - 2026-04-19 - Define device methods (`lock`, `unlock`, `hide_keyboard`, `push_file`, `pull_file`, `background_app`, `shake`, etc.) natively on `Appium::Driver` via `def_delegators :driver`, replacing the implicit delegation previously set up by `extend ::Appium::Core::Device`. Paves the way for `ruby_lib_core` to drop its static compatibility list (appium/ruby_lib_core#97). ## 16.1.1 - 2025-12-28 - Add deprecated mark for start_logs_broadcast/stop_logs_broadcast to use BiDi instead ## 16.1.0 - 2025-03-37 - Relaxed usable the appium_lib_core deps version to `> 11` ## 16.0.1 - 2025-03-16 - Update appium_lib_core deps version condition ## 16.0.0 - 2025-02-16 - Use `http://127.0.0.1:4723` as the default url destination instead of `http://127.0.0.1:4723/wd/hub` - `--base-path` in appium server may need to drop the `/wd/hub` if configured ## 15.2.2 - 2024-08-06 - Fix non `app` capability behavior ## 15.2.1 - 2024-08-03 - Fix client side timeout in the default http client - Bump appium_lib_core 9.2.1+ to apply the fix ## 15.2.0 - 2024-07-20 - Raise defined errors instead of Ruby general errors by appium_lib's own errors ## 15.1.0 - 2024-05-19 - Use appium_lib_core 9.0.0 ## 15.0.1 - 2024-04-26 - Bump release module (internal only) ## 15.0.0 - 2024-04-11 - Breaking - Use appium_lib_core 8.0.0 and up - Please refer to [the diff](https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#800---2024-03-08) about the details. - Remove `Appium::MultiTouch` and `Appium::TouchAction` - `swipe` could use `mobile:swipe`, or w3c actions. Multi-touch actions such as zoom/pinch can be written in w3c actions. - Please use [w3c actions](https://github.com/appium/ruby_lib/blob/master/docs/w3c.md) instead. Several resources such as [test code in ruby_lib_core](https://github.com/appium/ruby_lib_core/blob/master/test/functional/common_w3c_actions.rb) also would help to check the syntax. ## 14.0.0 - 2024-01-25 - Use appium_lib_core 7.4.0 and up - Removed deprecated `export_session` and `export_session_path` - Please get the session id via `driver.session_id` instead ## 13.0.2 - 2024-01-25 - Allow up to appium_lib_core 7.3 ## 13.0.1 - 2023-06-19 - Ruby 3.0+ is required ## 12.3.3 - 2023-04-27 ### Bug fixes - Fix start_driver ## 12.2.1 - 2023-04-24 ### 1. Enhancements ### 2. Bug fixes - fixed the `default_wait` value as zero (regression) `set_wait` will set `0` if no `appium_lib: {wait: 0}` is not given. ### 3. Deprecations ## 12.2.0 - 2022-12-25 ### 1. Enhancements ### 2. Bug fixes ### 3. Deprecations - Defaults to XCUITest modulefor iOS ## 12.1.3 - 2022-12-13 ### 1. Enhancements - Minor internal update ### 2. Bug fixes ### 3. Deprecations ## 12.1.2 - 2022-11-13 ### 1. Enhancements ### 2. Bug fixes - Fix `app` capability handling in parsing a toml file ### 3. Deprecations ## 12.1.1 - 2022-10-19 ### 1. Enhancements ### 2. Bug fixes - Fix undefined `.warning` method call ### 3. Deprecations ## 12.1.0 - 2022-10-11 ### 1. Enhancements - Bump minimal ruby_lib_core version ### 2. Bug fixes ### 3. Deprecations - Deprecate `Appium::Driver.absolute_app_path`, instead, please set proper `app` capability - This aims to reduce client side validation as same as other clients. ## 12.0.1 - 2022-04-02 ### 1. Enhancements ### 2. Bug fixes - Fixes `promote_appium_methods` ### 3. Deprecations ## 12.0.0 - 2021-11-06 ### 1. Enhancements - Update ruby_lib_core version from v4 to v5. The change affects this library. - [Migration from v4 to v5 in ruby_lib_core client](https://github.com/appium/ruby_lib_core#migration-from-v4-to-v5) - Base Selenium Ruby binding is now v4 - Support only W3C WebDriver spec (and a few Appium specific commands) - Support Ruby 2.6+ - `element.id` returns the element id instead of `element.ref` - `element.ref` now returns an array - Removed `forceMjsonwp` to send only MJSONWP capabilities since Selenium cleint v4 no longer supports MJSONWP - No longer set default `timeouts` as `0` - ruby_lib_core will call `/timeouts` endpoint only when `appium_lib: { wait: 5 }` is provided explicitly - Raises `::Appium::Core::Error::ArgumentError` instead of `ArgumentError` for this library specific argument errors ### 2. Deprecations - `TouchAction` and `MultiTouch` are deprecated - Please use W3C actions instead https://github.com/appium/ruby_lib/blob/master/docs/w3c.md - Other examples - https://github.com/appium/ruby_lib/pull/909 - https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#deprecations-1 - `launch_app`, `close_app` and `reset` are deprecated. Please read [issues#15807](https://github.com/appium/appium/issues/15807) for more details. - `activate_app` or a new session request can be alternatives of `launch_app` - `terminate_app` or close the session request can be alternatives of `close_app` - Close current session and creating a new session, or `terminate_app` and `launch_app` can be alternatives of `reset` - Global driver (`$driver`) is `false` by default. Please provide `true` as `Appium::Driver.new(opts, true)` to enable it as previously logged as a deprecation warning message. ## 11.1.0 - 2020-12-29 (11.2.0 is the same as this version) Support Ruby 3 ### 1. Enhancements ### 2. Bug fixes ### 3. Deprecations - Rename `Appium::Ios::Xcuitest::Guesture#tap` to `Appium::Ios::Xcuitest::Guesture#one_finger_tap` to prevent conflicts with `tap` in Ruby ## 11.0.0 - 2020-12-19 Bump supported Ruby version to 2.4+ [related changes](https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#400---2020-12-19) in ruby_lib_core. ## 10.6.0 ### 1. Enhancements ### 2. Bug fixes ### 3. Deprecations - Remove auto `Pry.config.pager` off - Please turn it off if you needed. https://github.com/pry/pry/wiki/Customization-and-configuration#Config_pager ## v10.5.0 ### 1. Enhancements - Added `driver.log_event` to post an event - Added `driver.log_events` to get the events ### 2. Bug fixes ### 3. Deprecations ## v10.4.1 ### 1. Enhancements ### 2. Bug fixes - Fix iOS `page` in native context ### 3. Deprecations ## v10.4.0 ### 1. Enhancements - Add `execute_driver` support ### 2. Bug fixes - Fix wrong warning message in create session ### 3. Deprecations ## v10.3.1 ### 1. Enhancements ### 2. Bug fixes - Fix `scroll_to` and `scroll_to_exact` for Android [#859](https://github.com/appium/ruby_lib/pull/859) ### 3. Deprecations ## v10.3.0 ### 1. Enhancements - Add `tvOS` support - Requires Appium 1.13 ### 2. Bug fixes ### 3. Deprecations ## v10.2.0 ### 1. Enhancements ### 2. Bug fixes - **Breaking changes** - `find_element/s_by_image` no longer need arguments except for a file path - `find_element/s_by_image(file_to_image)` instead of `find_element/s_by_image(file_to_image, match_threshold:, visualize:)` ### 3. Deprecations ## v10.1.0 ### 1. Enhancements ### 2. Bug fixes - `*_exact` methods handle value as case sensitive - This might break test cases if it calls `*_exact` as case insensitive ### 3. Deprecations ## v10.0.0 This change has a breaking change about implicit wait. ### 1. Enhancements - **Breaking changes** - Set implicit wait zero by default following [WebDriver spec in Selenium](https://www.seleniumhq.org/docs/04_webdriver_advanced.jsp) - The change potentially break your `find_element/s` - You can wrap it with `wait` method to avoid the error explicitly - Or you also can configure `wait: 20` as `appium_lib` capability to keep the behaviour - [Experimental] - Add `direct_connect` capability - How to use: `{ caps: {...}, appium_lib: { direct_connect: true }}` - Read [here](https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#enhancements-1) for more details ### 2. Bug fixes ### 3. Deprecations ## v9.18.0 ### 1. Enhancements - Enhance Espresso automation name adaptation - Call `xpath` locator strategy instead of `uiautomator` locator strategy in various wrapper methods like `text/s`, `button/s`, etc - [#884](https://github.com/appium/ruby_lib/pull/844/) ### 2. Bug fixes ### 3. Deprecations ## v9.17.0 ### 1. Enhancements - Add `action` wrapping _ruby_lib_core_ for [W3C actions](https://github.com/appium/ruby_lib_core/blob/master/lib/appium_lib_core/common/base/bridge/w3c.rb#L39) - Returns `TouchAction.new` if the driver works as _MJSONWP_ ### 2. Bug fixes ### 3. Deprecations - `:offset_x` and `:offset_y` in `TouchAction#swipe` is deprecated in favor of `:end_x` and `:end_y` - [internal] Remove `check_server_version_xcuitest` ## v9.16.1 ### 1. Enhancements ### 2. Bug fixes - Fix failing Appium version comparison [#836](https://github.com/appium/ruby_lib/issues/836) ### 3. Deprecations ## v9.16.0 ### 1. Enhancements - Introduce `appium_thor` in order to automate release ### 2. Bug fixes - `:app` can be non-path capability like [Windows](https://github.com/Microsoft/WinAppDriver) ```ruby { caps: { platformName: :windows, app: 'Microsoft.WindowsCalculator_8wekyb3d8bbwe!App' } } # `:app` is bundle id. { caps: { platformName: :windows, app: 'relative/path/to/app' } } # `:app` will be alsolute path to the `:app` if the path exists ``` ### 3. Deprecations ## v9.15.2 ### 1. Enhancements - Wrap selenium-webdriver apis via `Appium::Driver` through Appium Core Bridge [#827](https://github.com/appium/ruby_lib/pull/827/files) ### 2. Bug fixes ### 3. Deprecations ## v9.15.1 ### 1. Enhancements - [Internal] Use [ruby_lib_core](https://github.com/appium/ruby_lib_core) 2.0 - The change shouldn't affect this version since the change influence `Core.new`. ### 2. Bug fixes ### 3. Deprecations ## v9.15.0 ### 1. Enhancements - Requires `appium_lib_core` 1.9.0+ - Requires `selenium-webdriver 3.14+` - Support `find_element :image, image` [appium-base-driver#235](https://github.com/appium/appium-base-driver/pull/235) - Requires Appium1.8.2 - Read [changelog](https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#190---2018-08-05) for more details - Add `distance` option in `scroll` for XCUITest [#805](https://github.com/appium/ruby_lib/pull/805). Thanks [@saim80](https://github.com/saim80) ### 2. Bug fixes ### 3. Deprecations ## v9.14.3 ### 1. Enhancements - Add Tizen - Use [ruby_lib_core](https://github.com/appium/ruby_lib_core) 1.8.0 ### 2. Bug fixes ### 3. Deprecations ## v9.14.2 ### 1. Enhancements - add `mobile: installCertificate` shortcut for XCUITest - add `mobile: getContexts` shortcut for XCUITest - Add `find_element_by_image` and `find_elements_by_image` to handle `ImageElement` - Read a [PR](https://github.com/appium/ruby_lib/pull/795/files) and [Core](https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#enhancements-1) for more details - Experimental feature ### 2. Bug fixes ### 3. Deprecations ## v9.14.1 ### 1. Enhancements ### 2. Bug fixes - Fix an initialisation error for iOS with `appium_lib_core 1.7.0` [#785](https://github.com/appium/ruby_lib/issues/785) ### 3. Deprecations ## v9.14.0 ### 1. Enhancements - Breaking changes for `press_keycode` and `long_press_keycode` - Detail: https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#170---2018-05-28 ### 2. Bug fixes ### 3. Deprecations ## v9.13.0 ### 1. Enhancements - Requires `appium_lib_core` 1.6.0+ - Breaking change for `app_state`: https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#160---2018-05-08 ### 2. Bug fixes ### 3. Deprecations ## v9.12.1 ### 1. Enhancements - Support `start_logs_broadcast` and `stop_logs_broadcast` for iOS ### 2. Bug fixes - Back compatible for `wait(number) {}` and `wait_true(number) {}` ### 3. Deprecations ## v9.12.0 ### 1. Enhancements ### 2. Bug fixes ### 3. Deprecations - Changed the name of arguments - `swipe(start_x:, start_y:, end_x:, end_y:)` instead of `swipe(start_x:, start_y:, offset_x:, offset_y:)` ## v9.11.1 ### 1. Enhancements - Apply `ruby_lib_core ~> 1.4.2` - Support image comparison features - http://www.rubydoc.info/gems/appium_lib_core/Appium/Core/Device/ImageComparison ### 2. Bug fixes - Fix `wait` compatibility for `ruby_lib_core ~> 1.4.1` ### 3. Deprecations ## v9.11.0 ### 1. Enhancements - Add `start_logs_broadcast` and `stop_logs_broadcast` which use WebSocket to get logcat. - Include https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#140---2018-04-15 ### 2. Bug fixes ### 3. Deprecations ## v9.10.0 ### 1. Enhancements - Some changes for Appium 1.8.0 - Read also: - https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#131---2018-02-14 - https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#130---2018-01-28 ### 2. Bug fixes ### 3. Deprecations ## v9.9.2 ### 1. Enhancements - Fix Security Vulnerability(Nokogiri)[#761](https://github.com/appium/ruby_lib/pull/761) ### 2. Bug fixes ### 3. Deprecations ## v9.9.1 ### 1. Enhancements ### 2. Bug fixes - fix `Minitest`'s revert: [URL](http://docs.seattlerb.org/minitest/History_rdoc.html#label-5.11.2+-2F+2018-01-25) ### 3. Deprecations ## v9.9.0 ### 1. Enhancements - Bump the core library to 1.3.0 - The change have one breaking change for `start_recording_screen`(Android) ### 2. Bug fixes ### 3. Deprecations ## v9.8.5 ### 1. Enhancements ### 2. Bug fixes - Fix _Bug: NameError: uninitialized constant Minitest::VERSION [#750](https://github.com/appium/ruby_lib/issues/750)_ ### 3. Deprecations ## v9.8.4 ### 1. Enhancements ### 2. Bug fixes - Fix `TypeError: superclass mismatch for class Test` for minitest `5.11.0`+ [PR](https://github.com/appium/ruby_lib/pull/748) ### 3. Deprecations ## v9.8.3 ### 1. Enhancements - Bump the core library to 1.2.5 - The changelog is [here](https://github.com/appium/ruby_lib_core/blob/master/CHANGELOG.md#124---2018-01-03) ### 2. Bug fixes ### 3. Deprecations ## v9.8.2 ### 1. Enhancements - add `shell` command wrapped `mobile: shell` for Android [#732](https://github.com/appium/ruby_lib/pull/732) - add handling multiple apps for iOS [#729](https://github.com/appium/ruby_lib/issues/729) - Adapt W3C commands and make sure to work Appium 1.7.2+ - Which module, msjsonwp or w3c, used depends on server side's response. ### 2. Bug fixes ### 3. Deprecations ## v9.8.1 ### 1. Enhancements ### 2. Bug fixes - Fix creating session for the new W3C createSession - https://github.com/appium/appium/pull/9791 ### 3. Deprecations ## v9.8.0 ### 1. Enhancements - Add start/stop recording screen [#674](https://github.com/appium/ruby_lib/issues/674) - replace core directory to core library [#665](https://github.com/appium/ruby_lib/issues/665), [#718](https://github.com/appium/ruby_lib/pull/718) - No change for users ### 2. Bug fixes ### 3. Deprecations - `ap_` prefixed logging - `source_window`: use `get_source` instead - `ios_version`: use `platform_version` instead - `current_app`: use `current_activity`, for example to know current app. ## v9.7.5 ### 1. Enhancements ### 2. Bug fixes - [fix: take care capybara case #716](https://github.com/appium/ruby_lib/pull/716) ### 3. Deprecations ## v9.7.4 ### 1. Enhancements - Add unlock command: [PR](https://github.com/appium/ruby_lib/pull/710/files) - Be able to call `source` command from any `automationName` ### 2. Bug fixes ### 3. Deprecations ## v9.7.3 ### 1. Enhancements - Get source from XCUITest with `xcuitest_source format: :json` - https://github.com/appium/ruby_lib/pull/699 - `:espresso` support ### 2. Bug fixes ### 3. Deprecations ## v9.7.2 ### 1. Enhancements - Raise error if capability is wrong - [validate `caps` and `appium_lib` #684](https://github.com/appium/ruby_lib/issues/684) ### 2. Bug fixes - `Bug: NoMethodError: undefined method 'write_session_id' for #` [#686](https://github.com/appium/ruby_lib/issues/686) - undefined local variable or method `patch_webdriver_element' [#687](https://github.com/appium/ruby_lib/issues/687) ### 3. Deprecations ## v9.7.1 Hot-fix for v9.7.0: [uninitialized constant Appium::VERSION #680](https://github.com/appium/ruby_lib/issues/680) ## v9.7.0 _v9.7.0_ has [a bunch of refactoring](https://github.com/appium/ruby_lib/issues/602#issuecomment-331140219) but the behaviours must be the same as well as previous versions. I've checked the behaviour and confirmed test cases in this repository. So, please create issues if you have any issues against this version. ### 1. Enhancements - Refactoring ``` lib/appium_lib # root directory /core # Minumul driver files for the Appium server and dependencies for Selenium Driver. /common # Appium related(some methods to make ruby_lib useful) /android # for Android /ios # for iOS ``` - The `core` directory will separate as the other gem in [separate core as core ruby gem #665](https://github.com/appium/ruby_lib/issues/665) - Logs - `get_available_log_types`: To get a list of available log types - `get_log(type)`: To get logs associated with `type` ### 2. Bug fixes ### 3. Deprecations - [refactor: Reduce patch_webdriver_element and some DEPRECATIONs #663](https://github.com/appium/ruby_lib/pull/663) - Remove deprecated methods: - Android - `client_xpath/client_xpaths` - Please use `xpath` or `find_element/s(:xpath, "xpaths")` - iOS - `get_page` - Please use `source` instead - Deprecated - iOS - `ios_version`, `source_window`, `page_window` - Please use `source` instead ## v9.6.1 ### 1. Enhancements - Refactor `XCUItest` for iOS and `uiautomator2` for Android a bit ### 2. Bug fixes - missing extending `button` methods for `uiautomator2`, Android ### 3. Deprecations ## v9.6.0 ### 1. Enhancements - Reduce Global Driver - We'll stop defining global scope driver by default. So, if you'd like to continue to define global scope, please call `start_driver` as the following. ```ruby Appium::Driver.new(opts, true).start_driver # $driver is defined. Appium::Driver.new(opts, false).start_driver # $driver isn't defined. ``` - [link](https://github.com/appium/ruby_lib/blob/master/docs/ios_docs.md#initialize) - We need to provide `driver` to work `TouchAction` and `MultiAction` without global driver - `TouchAction` ```ruby driver = Appium::Driver.new(opts, false).start_driver action = TouchAction.new.press(x: 45, y: 100).wait(5).release action.perform(driver) action = TouchAction.new.swipe(....) action.perform(driver) ``` - `MultiAction` ```ruby driver = Appium::Driver.new(opts, false).start_driver pinch 200, true, driver ``` - Add example to run multiple iOS Simulators [doc](https://github.com/appium/ruby_lib/blob/master/docs/ios_xcuitest.md#run-tests-on-multiple-simulators-with-xcode-9) - Require Xcode 9 and Appium 1.6.6 ### 2. Bug fixes - `scroll_to` is failed on some Android 5.0 and 5.1 devices - https://github.com/appium/ruby_lib/pull/638 ### 3. Deprecations ### Special Thanks - Fixing `acroll_to` - [@emen](https://github.com/emen) - Add alias `quit_driver` - [@DylanLacey ](https://github.com/DylanLacey) ## v9.5.0 ### 1. Enhancements - Support `selenium-webdriver3.4.1+` - Support new `createSession` ### 2. Bug fixes ### 3. Deprecations - Drop `selenium-webdriver` `3.0 ~ 3.4.0` since some methods depends on `selenium-webdriver3.4.1+` ## v9.4.10 ### 1. Enhancements - some refactoring - add some documentations ### 2. Bug fixes ### 3. Deprecations ## v9.4.9 ### 1. Enhancements ### 2. Bug fixes - fix handling a tap gesture in xcuitest [#611](https://github.com/appium/ruby_lib/pull/611) ### 3. Deprecations ## v9.4.8 ### 1. Enhancements - within_context swallowing block return value [#311](https://github.com/appium/ruby_lib/issues/311) - get current_package for Android [#604](https://github.com/appium/ruby_lib/issues/604) - Show visibility on iOS page command [#609](https://github.com/appium/ruby_lib/pull/609) - related: allow showing all elements on ios page command [#310](https://github.com/appium/ruby_lib/issues/310) ### 2. Bug fixes ### 3. Deprecations - Android: mark deprecated for client side xpath strategy [#608](https://github.com/appium/ruby_lib/pull/608) - iOS: get_page method [#609](https://github.com/appium/ruby_lib/pull/609) ## v9.4.7 ### 1. Enhancements ### 2. Bug fixes - fix raise 500 error by `driver.remote_status` in `appium_server_version` [#599](https://github.com/appium/ruby_lib/issues/599) ### 3. Deprecations ## v9.4.6 ### 1. Enhancements ### 2. Bug fixes - reduce gemfile size [#591](https://github.com/appium/ruby_lib/issues/591) - Exclude `ios_tests`, `android_tests` and `grid` from gem ### 3. Deprecations ## v9.4.5 ### 1. Enhancements - add `touch_and_hols` for `mobile:` command in XCUITest [#581](https://github.com/appium/ruby_lib/pull/581) - Driver disables Pry pager without asking [#582](https://github.com/appium/ruby_lib/issues/582) - add grid environments in this repository. ### 2. Bug fixes ### 3. Deprecations ## v9.4.4 ### 1. Enhancements - add mobile gesture, `mobile: alert` - Required over https://github.com/appium/appium-xcuitest-driver/releases/tag/v2.28.6 - add travis example for ios [#573](https://github.com/appium/ruby_lib/pull/573) - remove some redundant code [#572](https://github.com/appium/ruby_lib/pull/572), [#571](https://github.com/appium/ruby_lib/pull/571) - update api-demos [#569](https://github.com/appium/ruby_lib/issues/569) ### 2. Bug fixes ### 3. Deprecations ## v9.4.3 ### 1. Enhancements - Use uiautomator for uiautomator2 [#561](https://github.com/appium/ruby_lib/pull/561) - improve stability for some methods - don't use selenium-webdriver 3.5+ [#559](https://github.com/appium/ruby_lib/pull/559) - Auto link bug # from release notes [#239](https://github.com/appium/ruby_lib/issues/239) ### 2. Bug fixes ### 3. Deprecations ### Special Thanks - Thanks for checking uiautomator2 - [@Edouard-chin](https://github.com/Edouard-chin), [@rajdeepv](https://github.com/rajdeepv) ## v9.4.2 ### 1. Enhancements ### 2. Bug fixes - fix drag_from_to_for_duration gets server error [#552](https://github.com/appium/ruby_lib/issues/552) ### 3. Deprecations ## v9.4.1 ### 1. Enhancements ### 2. Bug fixes - fix 9.4.0 release sudden failures [#546](https://github.com/appium/ruby_lib/issues/546) - XPath strategy for find_element/s sudden fail than uiautomator strategy. - Use `:xpath` strategy only for uiautomator2 ### 3. Deprecations ## v9.4.0 ### 1. Enhancements - update mobile gesture APIs for XCUITest(WDA) [#514](https://github.com/appium/ruby_lib/pull/514) - For XCUITest(WebDriverAgent) - Users can call some [`mobile:` methods](https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/ios-xctest-mobile-gestures.md) without `execute_script('mobile: tap', args)`. - Users can write test code without `.ref` method for elements in `execute_script`. - Example: https://github.com/appium/ruby_lib/pull/537 - Support UIAutomator2 strategy for Android[#505](https://github.com/appium/ruby_lib/issues/505) - Fix some find elemenet methods[#544](https://github.com/appium/ruby_lib/pull/544) ### 2. Bug fixes ### 3. Deprecations ## v9.3.8 ### 1. Enhancements - allow using TestObject server [#538](https://github.com/appium/ruby_lib/pull/538) ### 2. Bug fixes ### 3. Deprecations ## v9.3.7 ### 1. Enhancements - Remove appium suffix from find element [#532](https://github.com/appium/ruby_lib/pull/532) - rename `@driver.find_element/s_with_appium` to `@driver.find_element/s` - fix documentations ### 2. Bug fixes ### 3. Deprecations - `@driver.find_element/s_with_appium` - use `@driver.find_element/s` instead ## v9.3.6 ### 1. Enhancements - Add toggle touch id enrollment [#521](https://github.com/appium/ruby_lib/pull/521) ### 2. Bug fixes ### 3. Deprecations ## v9.3.5 ### 1. Enhancements - add some commands for Android and class chain for iOS [#513](https://github.com/appium/ruby_lib/issues/513) - iOS - `find_element :class_chain, 'XCUIElementTypeWindow/*/*/XCUIElementTypeStaticText'` - Android - `get_system_bars` - `get_display_density` - `is_keyboard_shown` - add scrollable index parameter into scroll methods [#506](https://github.com/appium/ruby_lib/issues/506) - `scroll_to(text, scrollable_index = 0)` - `scroll_to_exact(text, scrollable_index = 0)` - clear `@actions` in Appium::TouchAction if `perform` is called [#511](https://github.com/appium/ruby_lib/issues/511) ### 2. Bug fixes ### 3. Deprecations ## v9.3.4 ### 1. Enhancements - [remove workaround](https://github.com/appium/ruby_lib/pull/474/commits/57cc95264e83e14862f729683b93c1f020a30ce5) to pass CI - document uiautomator events logging command [#319](https://github.com/appium/ruby_lib/issues/319) - use predicate for XCUITest to improve performance [#493](https://github.com/appium/ruby_lib/issues/493) - `text/s`, `button/s`, `textfield/s`, `tags_exact`, `tags_include` - new: `find_ele/s_by_predicate`, `find_ele/s_by_predicate_include` ### 2. Bug fixes ### 3. Deprecations ## v9.3.3 ### 1. Enhancements - add tags_include/tags_exact to be able to find elements of arbitrary classes such as XCUIElementTypeTextView [#488](https://github.com/appium/ruby_lib/issues/488) ### 2. Bug fixes ### 3. Deprecations ## v9.3.2 ### 1. Enhancements - allow SAUCE_ENDPOINT env var to override sauce server url/path [#485](https://github.com/appium/ruby_lib/pull/485) - Read [readme](https://github.com/appium/ruby_lib/blob/89c7c89be058153d119d517eab22ccc318d33649/readme.md#sauce-labs-env-vars)'s `SAUCE_ENDPOINT` section. ### 2. Bug fixes ### 3. Deprecations ## v9.3.1 ### 1. Enhancements - Clarify disabling Sauce Labs. [#471](https://github.com/appium/ruby_lib/pull/471) - add getting performance [#479](https://github.com/appium/ruby_lib/issues/479) - **require appium-base-driver@2.1.7** ### 2. Bug fixes - Fix missed var rename [#481](https://github.com/appium/ruby_lib/pull/481) ### 3. Deprecations ## v9.3.0 ### 1. Enhancements - wait / wait_true need global defaults [#250](https://github.com/appium/ruby_lib/issues/250) - You can set default value in `appium_lib` - e.g.: [lib/appium_lib/driver.rb](https://github.com/appium/ruby_lib/blob/34803ef6b7b94df9ef4e147ba8fec5c1d2cfaada/lib/appium_lib/driver.rb#L341-L351) - Problem with delta_x/delta_y in swipe method [#461](https://github.com/appium/ruby_lib/issues/461) - Revert _fix arguments for `move_to` in `swipe` method._ in Appium v8.2.1 - `delta_x/delta_y` replace to `offset_*` for iOS - e.g.: `swipe start_x: start_x, start_y: start_y, end_offset_x: 0, offset_y: -100` - `delta_x/delta_y` replace to `end_*` for Android - e.g.: `swipe start_x: start_x, start_y: start_y, end_x: start_x, end_y: start_y - 100` - The reason why there are two kind of arguments is the following issue. - [Difference behaviour between iOS and Android regarding with `swipe` action #7702](https://github.com/appium/appium/issues/7702) - Clarify disabling Sauce Labs. #471 - update documentations ### 2. Bug fixes - REQUIRED_VERSION_XCUITEST [#463](https://github.com/appium/ruby_lib/issues/463) - find elements except for name attributes in text/s, button/s [#462](https://github.com/appium/ruby_lib/issues/462) - Return only **visible** elements - Previously, these methods return **all** elements. ### 3. Deprecations - Problem with delta_x/delta_y in swipe method [#461](https://github.com/appium/ruby_lib/issues/461) - `delta_x/delta_y` are replaced to `offset_*` for iOS and `end_*` for Android. ## v9.2.0 ### 1. Enhancements - update set_wait / no_wait logic #249 - `no_wait` just set `implicit_wait = 0` - `set_wait` just set `@default_wait` or arbitrary time as `implicit_wait` - remove `last_waits` attribute ### 2. Bug fixes - automationName always nil if set automationName in server side #450 ### 3. Deprecations ## v9.1.3 Support selenium-webdriver 3.0.4+ ### 1. Enhancements - Improve performance for button/s and text/s #442 - Should use `open_timeout` or `read_timeout` instead of `timeout` #436 - add documentation for alternative long_press method #440 ### 2. Bug fixes ### 3. Deprecations ## v9.1.2 ### 1. Enhancements - add `appium_client_version`: https://github.com/appium/ruby_lib/issues/260 - add some tests and fix some rubocop syntax errors ### 2. Bug fixes - fix `set_immediate_value`: https://github.com/appium/ruby_lib/issues/263 ### 3. Deprecations ## v9.1.1 ### 1. Enhancements ### 2. Bug fixes - fix Finds exact in ios does not return an array #423 ### 3. Deprecations Thanks @slipy12 ## v9.1.0 ### 1. Enhancements - update dependencies - Support selenium-webdriver 3.0.2+ - If you'd like to use `selenium-webdriver2.x`, please use `appium_lib9.0.0` ### 2. Bug fixes ### 3. Deprecations - Drop Ruby 1.9.3, 2.0, 2.1 support - Because these ruby versions have already stop updating. ## v9.0.0 ### 1. Enhancements - Support `XCUITest` strategy for iOS - Basically, `XCUITest` strategy is compatible with `Appium` strategy in this library. - But users who use XPath should be check [this document](https://github.com/appium/ruby_lib/blob/master/docs/ios_xcuitest.md) since XPath has performance issue - Users who use `find_element/s` should work fine. - tests for elements are [here](https://github.com/appium/ruby_lib/tree/master/ios_tests/lib/ios/specs/ios/element) Special thanks to @montdidier ### 2. Bug fixes ### 3. Deprecations ## v8.2.1 - fix arguments for `move_to` in `swipe` method. - https://github.com/appium/ruby_lib/pull/405 - Please set `:delta_x` and `:delta_y` as the distance from start to move. ================================================ FILE: Gemfile ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. source 'https://rubygems.org' gemspec gem 'appium_thor', '~> 2.0' gem 'hashdiff', '~> 1.2.0' gem 'minitest', '~> 5.0' gem 'minitest-reporters', '~> 1.1' gem 'pry' gem 'rake', '~> 13.0' gem 'rubocop', '1.86.1' gem 'yard', '~> 0.9.11' ================================================ FILE: LICENSE-2.0.txt ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: Rakefile ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'bundler/gem_tasks' require 'rubocop/rake_task' require 'rake/testtask' desc 'Execute RuboCop static code analysis' RuboCop::RakeTask.new(:rubocop) do |t| t.patterns = %w(lib ios_tests android_tests) t.options = %w(-D) t.fail_on_error = true end desc('Run all unit tests in test directory') Rake::TestTask.new(:test) do |t| t.libs << 'test' t.libs << 'lib' t.test_files = FileList[ENV['TESTS'] ? ENV['TESTS'].split(',') : 'test/**/*_test.rb'] end ================================================ FILE: Thorfile ================================================ require 'appium_thor' Appium::Thor::Config.set do gem_name 'appium_lib' github_name 'ruby_lib' version_file 'lib/appium_lib/version.rb' end ================================================ FILE: android_tests/Gemfile ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. source 'https://rubygems.org' eval_gemfile File.join(File.expand_path('..', __dir__), 'Gemfile') ================================================ FILE: android_tests/LICENSE-2.0.txt ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: android_tests/Rakefile ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'rubygems' require 'rake' require 'rubocop/rake_task' task default: :android # Run sh and ignore exception def run_sh(cmd) sh cmd rescue StandardError # ignored end # Run cmd. On failure run install and try again. def bash(cmd) sh cmd do |successful, result| # exitstatus 7 means bundle install failed # non-zero (except 7 retry path) means the test failed if !successful && result.exitstatus == 7 Rake::Task['install'].execute sh cmd elsif !successful raise "Command failed with status #{result.exitstatus}: #{cmd}" end end end # rake android['single_text_name'] # rake android def run_android(test_file = nil) cmd = 'bundle exec ruby ./lib/run.rb android' cmd = %(#{cmd} "#{test_file}") if test_file bash cmd end # Run a single test with: # rake android['android/element/generic'] # # Run all tests with: # rake android desc 'Run the Android tests' task :android, :args, :test_file do |_args, test_file| run_android test_file[:args] end desc 'Run the Android tests without uninstalling' task :droid, :args, :test_file do |_args, test_file| run_android test_file[:args] end desc 'Run bundle install' task :install do sh 'bundle install' end desc 'Execute RuboCop static code analysis' RuboCop::RakeTask.new(:rubocop) do |t| t.patterns = %w(**/*.rb) t.options = %w(-D) t.fail_on_error = false end ================================================ FILE: android_tests/appium.txt ================================================ [caps] automationName = "uiautomator2" platformName = "android" deviceName = "Android emulator" app = "../test_apps/api.apk" appPackage = "io.appium.android.apis" appActivity = "io.appium.android.apis.ApiDemos" some_capability = "some_capability" [appium_lib] sauce_username = "" sauce_access_key = "" ================================================ FILE: android_tests/flaky.txt ================================================ android = "lib/android/specs/" ================================================ FILE: android_tests/lib/android/specs/android/element/alert.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake "android[android/element/alert]" class AndroidTest class Element class Alert < Minitest::Test def open_alert # trigger the alert wait { button('OK Cancel dialog with a message').click } end def test_01_alert_click # nav to alert activity wait { find('app').click } wait { find('alert').click } # test wait { open_alert } wait { alert_click('OK') } end def test_02_alert_accept wait { open_alert } wait { alert_accept } end def test_03_alert_accept_text wait { open_alert } wait { assert_equal alert_accept_text, 'OK' } wait { alert_accept } end def test_04_alert_dismiss wait { open_alert } wait { alert_dismiss } end def test_05_alert_dismiss_text wait { open_alert } # alert dialog button placement changed: # 'OK Cancel dialog with a long message' # Android L: 'Something, Cancel, Ok' # Android 19: 'Cancel, Something, Ok' wait { assert_equal alert_dismiss_text.downcase, 'cancel' } wait { alert_dismiss } # nav to start activity 2.times { back } end end end end ================================================ FILE: android_tests/lib/android/specs/android/element/button.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake "android[android/element/button]" class AndroidTest class Element class Button < Minitest::Test def before_first # nav to buttons activity wait { find('App').click } wait { find('Activity').click } wait { find('Animation').click } end def after_last # nav back to home activity 3.times { back } end def fade_in 'Fade in' end def test_01_before_first before_first end def test_02_button # by index 2.times { wait { assert_equal button(1).text.upcase, fade_in.upcase } } # by name contains wait { assert_equal button('ade').text.upcase, fade_in.upcase } end def test_03_buttons exp = ['ZOOM IN', 'MODERN ZOOM IN', 'THUMBNAIL ZOOM'] wait { assert_equal buttons('zoom').map(&:text).map(&:upcase), exp } wait { assert_equal buttons.length, 6 } end def test_04_first_button wait { assert_equal first_button.text.upcase, fade_in.upcase } end def test_05_last_button wait { assert_equal last_button.text.upcase, 'THUMBNAIL ZOOM' } end def test_06_button_exact wait { assert_equal button_exact(fade_in).text.upcase, fade_in.upcase } end def test_07_buttons_exact 2.times { wait { assert_equal buttons_exact(fade_in).first.text.upcase, fade_in.upcase } } end def test_08_after_last after_last end end end end ================================================ FILE: android_tests/lib/android/specs/android/element/generic.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake "android[android/element/generic]" class AndroidTest class Element class Generic < Minitest::Test def content 'Content' end def partial 'tent' end def test_01_find_works_before_and_after_get_source wait { assert_equal find(partial).text, content } wait { assert_equal get_source.class, String } wait { assert_equal find(partial).text, content } end def test_01_find wait { assert_equal find(partial).text, content } end def test_01_finds wait { assert_equal finds(partial).first.text, content } end def test_01_find_exact wait { assert_equal find_exact(content).text, content } end def test_01_finds_exact wait { assert_equal finds_exact(content).first.text, content } end # scroll_to is broken def test_01_scroll_to wait { scroll_to('Views').click } wait { assert_equal scroll_to('scrollbars').text, 'ScrollBars' } wait { find('ScrollBars').click } wait { text('style').click } wait { assert scroll_to('Developers', 1).text.include? 'What would it take to build a better mobile phone?' } back back # back to start activity back end def test_01_scroll_to_exact wait { scroll_to('Views').click } wait { assert_equal scroll_to_exact('ScrollBars').text, 'ScrollBars' } wait { find('ScrollBars').click } wait { text('style').click } back back # back to start activity back end end end end ================================================ FILE: android_tests/lib/android/specs/android/element/text.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake "android[android/element/text]" class AndroidTest class Element class Text < Minitest::Test def must_raise_no_element assert_raises Selenium::WebDriver::Error::NoSuchElementError do yield end end def test_01_text wait { assert ['API Demos', "Access'ibility"].include? text(1).text } wait { assert_equal text('mos').text, 'API Demos' } end def test_02_texts wait { assert_equal texts('i').length, 7 } wait { assert_equal texts.length, 13 } end def test_03_first_text wait { assert ['API Demos', "Access'ibility"].include? first_text.text } end def test_04_last_text wait { assert ['API Demos', 'Views'].include? last_text.text } end def test_05_text_exact must_raise_no_element { text_exact 'mos' } # should pass wait { assert_equal text_exact('API Demos').text, 'API Demos' } end def test_06_texts_exact wait { assert_equal texts_exact('API Demos').length, 1 } end end end end ================================================ FILE: android_tests/lib/android/specs/android/element/textfield.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake "android[android/element/textfield]" class AndroidTest class Element class TextField < Minitest::Test def must_raise_no_element assert_raises Selenium::WebDriver::Error::NoSuchElementError do yield end end def left 'Left is best' end def right 'Right is always right' end def before_first # nav to activity wait { find('app').click } wait { find('activity').click } wait { find('custom title').click } end def after_last # back to start 3.times { back } end def test_01_before_test before_first end def test_02_textfield wait { assert_equal textfield(1).text, left } wait { assert_equal textfield('right').text, right } end def test_03_textfields wait { assert_equal textfields('right').first.text, right } wait { assert_equal textfields.length, 2 } end def test_04_first_textfield wait { assert_equal first_textfield.text, left } end def test_05_last_textfield wait { assert_equal last_textfield.text, right } end def test_06_textfield_exact must_raise_no_element { textfield_exact 'zz' } wait { assert_equal textfield_exact(left).text, left } end def test_07_textfields_exact wait { assert_equal textfields_exact('zz'), [] } wait { assert_equal textfields_exact(left).first.text, left } end def test_08_hide_keyboard first_textfield.click hide_keyboard end def test_09_after_last after_last end end end end ================================================ FILE: android_tests/lib/android/specs/android/helper.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake "android[android/helper]" class AndroidTest class Helper < Minitest::Test def test_01_tags wait { assert_equal tags('android.widget.TextView').length, 13 } end def test_01_get_page_class # digit values change based on screen size # larger screens have more elements act = get_page_class assert act.split("\n").length >= 5 assert act.include? '13x android.widget.TextView' if automation_name_is_espresso? # 13x android.widget.TextView # 1x android.widget.ActionMenuView # 1x android.widget.Toolbar # 1x com.android.internal.widget.ActionBarContainer # 1x com.android.internal.widget.ActionBarContextView # 1x android.widget.ListView # 1x android.widget.FrameLayout # 1x com.android.internal.widget.ActionBarOverlayLayout # 1x com.android.internal.policy.DecorView assert act.include? '1x android.widget.ActionMenuView' else assert act.include? '3x android.widget.FrameLayout' assert act.include? '2x android.view.ViewGroup' assert act.include? '1x android.widget.ListView' assert act.include? '1x hierarchy' end end # def test_01_page_class' do # tested by get_page_c def test_02_get_android_inspect # line count changes based on screen size wait { assert get_android_inspect.split("\n").length >= 40 } end # def test_01_get_inspect' do # tested by get_android_ins # def test_01_page' do # tested by get_android_ins def id_key 'animation_2_instructions' end def id_value 'Select an animation:' end def test_03_xml_keys wait do id_pair = xml_keys id_key id_pair = id_pair.to_a[0] assert_equal id_pair.length, 2 assert_equal id_pair.first, id_key assert_equal id_pair.last, id_value end end def test_04_resolve_id wait do str = resolve_id id_key assert_equal str, id_value end end def test_05_xml_values wait do value = xml_values(id_value).first.last assert_equal value, id_value end end def test_06_find_by_id wait { find('accessibility').click } wait { find('accessibility node provider').click } if automation_name_is_uiautomator2? || automation_name_is_espresso? wait { text 'Accessibility/Accessibility Node Provider' } else # With string.xml # Only for uiautomator1 wait { id 'accessibility_node_provider' } end 2.times { back } end def test_07_ids wait { assert_equal ids('android:id/text1').length, 12 } end end end ================================================ FILE: android_tests/lib/android/specs/android/patch.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake "android[android/patch]" class AndroidTest class Patch < Minitest::Test def test_type # nav to textfield wait { find('app').click } wait { find('Search').click } wait { find('Invoke Search').click } wait { first_textfield.type 'ok' } wait { assert_equal first_textfield.text, 'ok' } # TODO: how to invoke random am start commands? # nav to start activity # io.appium.android.apis/io.appium.android.apis.ApiDemos # keyboard may exist, if it doesn't then an error will raise ignore { hide_keyboard } # return to app start back wait { find('Invoke Search') } back wait { find_exact('Search') } back wait { find('app') } end end end ================================================ FILE: android_tests/lib/android/specs/common/device.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake "android[common/device]" class AndroidTest class Common class Device < Minitest::Test def test_01_get_performance_data_types expected = %w(batteryinfo cpuinfo memoryinfo networkinfo) assert_equal get_performance_data_types.sort, expected assert_equal get_performance_data( package_name: 'io.appium.android.apis', data_type: 'cpuinfo' )[0], %w(user kernel) end def test_02_start_activity wait { assert_equal current_activity, '.ApiDemos' } start_activity( app_package: 'io.appium.android.apis', app_activity: '.accessibility.AccessibilityNodeProviderActivity' ) wait { assert_equal current_activity.include?('Node'), true } start_activity( app_package: 'com.android.settings', app_activity: '.Settings', app_wait_package: 'com.android.settings', app_wait_activity: '.Settings' ) wait { assert_equal current_activity.include?('Settings'), true } end def test_03_current_package start_activity( app_package: 'io.appium.android.apis', app_activity: '.accessibility.AccessibilityNodeProviderActivity' ) wait { assert_equal current_package, 'io.appium.android.apis' } end def test_04_app_strings wait_true { app_strings.key? 'activity_save_restore' } end def test_05_press_keycode # http://developer.android.com/reference/android/view/KeyEvent.html press_keycode 176 end def test_06_long_press_keycode # http://developer.android.com/reference/android/view/KeyEvent.html long_press_keycode 176 end end end end ================================================ FILE: android_tests/lib/android/specs/common/device_touchaction.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake "android[common/device_touchaction]" class AndroidTest class Common class DeviceTouchAction < Minitest::Test def test_01_before_test wait { text('Accessibility') } end def test_02_action_chain_press_release wait do e = text('Accessibility') action.click(e).perform end wait { text('Custom View') } back wait { text_exact 'NFC' } end def test_03_action_chain_tap wait do e = text('Accessibility') action.click(e).perform end wait { text('Custom View') } back wait { text_exact 'NFC' } end def test_04_swipe wait { text('Animation').click } wait { text_exact('Bouncing Balls').click } driver.action .move_to_location(0.75, 0.25).pointer_down(:left) .move_to_location(0.75, 50) .release.perform 3.times { back } wait { text_exact 'NFC' } end def test_05_pinch_zoom wait { text_exact 'NFC' } wait { text_exact('Graphics').click } wait { scroll_to('Touch Paint').click } # multiple action chains f1 = driver.action.add_pointer_input(:touch, 'finger1') f1.create_pointer_move( duration: 0.5, x: 500, y: 800, origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT ) f1.create_pointer_down(:left) f1.create_pause(0.5) f1.create_pointer_move( duration: 3, x: 500, y: 700, origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT ) f1.create_pointer_up(:left) f2 = driver.action.add_pointer_input(:touch, 'finger2') f2.create_pointer_move( duration: 0.5, x: 500, y: 800, origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT ) f2.create_pointer_down(:left) f1.create_pause(0.5) f2.create_pointer_move( duration: 3, x: 500, y: 900, origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT ) f2.create_pointer_up(:left) driver.perform_actions [f1, f2] wait { text('Graphics/Touch Paint') } 2.times { back } wait { text_exact 'NFC' } end end end end ================================================ FILE: android_tests/lib/android/specs/common/element/window.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake "android[common/element/window]" class AndroidTest class Common class Element class Window < Minitest::Test def test_window_size wait do size = window_size assert_equal size.width.class, Integer assert_equal size.height.class, Integer end end end end end end ================================================ FILE: android_tests/lib/android/specs/common/helper.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake "android[common/helper]" class AndroidTest class Common class Helper < Minitest::Test def wait_opts { timeout: 0.2, interval: 0.2 } # max_wait, interval end # There's no `must_not_raise` as the opposite of must_raise # By default code is expected to not raise exceptions. # must_not_raise is a no-op. # wait is a success unless an error is raised # max_wait=0 is infinity to use 0.1 def test_01_wait # successful wait should not raise error wait(wait_opts) { true } wait(wait_opts) { false } wait(wait_opts) { nil } # failed wait should error assert_raises ::Appium::Core::Wait::TimeoutError do wait(wait_opts) { raise } end # regular rescue will not handle exceptions outside of StandardError hierarchy # must rescue Exception explicitly to rescue everything assert_raises ::Appium::Core::Wait::TimeoutError do wait(wait_opts) { raise NoMemoryError } end assert_raises ::Appium::Core::Wait::TimeoutError do wait(timeout: 0.2, interval: 0.0) { raise NoMemoryError } end e = assert_raises ArgumentError do wait_true(invalidkey: 2) { true } end assert_equal 'unknown keyword: :invalidkey', e.message end def test_02_ignore # ignore should rescue all exceptions ignore { true } ignore { false } ignore { nil } ignore { raise } ignore { raise NoMemoryError } end # wait_true is a success unless the value is not true def test_03_wait_true # successful wait should not error wait_true(wait_opts) { true } # failed wait should error assert_raises ::Appium::Core::Wait::TimeoutError do wait_true(wait_opts) { false } end assert_raises ::Appium::Core::Wait::TimeoutError do wait_true(wait_opts) { nil } end # raise should error assert_raises ::Appium::Core::Wait::TimeoutError do wait_true(wait_opts) { raise } end # regular rescue will not handle exceptions outside of StandardError hierarchy # must rescue Exception explicitly to rescue everything assert_raises ::Appium::Core::Wait::TimeoutError do wait_true(wait_opts) { raise NoMemoryError } end assert_raises ::Appium::Core::Wait::TimeoutError do wait_true(timeout: 0.2, interval: 0.0) { raise NoMemoryError } end e = assert_raises ArgumentError do wait_true(invalidkey: 2) { true } end assert_equal 'unknown keyword: :invalidkey', e.message end def test_04_back # start page wait { assert_equal texts.length, 13 } # nav to new page. # ele 0 is the title and can't be clicked. wait { text(2).click } wait { assert_equal texts.length, 5 } # go back back # start page wait { find 'NFC' } end def test_05_session_id wait { assert_match(/\h{8}-\h{4}-\h{4}-\h{4}-\h{12}/, session_id) } end def test_06_xpath # Access'ibility is for Espresso wait { assert ['API Demos', "Access'ibility"].include? xpath('//android.widget.TextView').text } end def test_07_xpaths wait { assert_equal xpaths('//android.widget.TextView').length, 13 } end def test_08_ele_index # Animation is for Espresso wait { assert %w(Accessibility Animation).include? ele_index('android.widget.TextView', 3).text } end def test_09_tags wait { assert_equal tags('android.widget.TextView').length, 13 } end def test_10_first_ele wait do # Access'ibility is for Espresso assert ['API Demos', "Access'ibility"].include? first_ele('android.widget.TextView').text end end def test_11_last_ele wait do # "API Demos" is for Espresso assert ['API Demos', 'Views'].include? last_ele('android.widget.TextView').text end end # def test_01_source' do # tested by get_so def test_12_get_source wait do assert_equal get_source.class, String end end end end end ================================================ FILE: android_tests/lib/android/specs/common/patch.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Skip: # status # status patches are already tested in driver.rb # execute # debug output for Pry # rake "android[common/patch]" class AndroidTest class Common class Patch < Minitest::Test # Attributes are busted in Android. # Blocked on https://github.com/appium/appium/issues/628 # Android supports exactly two string Attributes # .name and .text # https://github.com/appium/appium/blob/ea3450e7f78d1794bab42fa396a387e7b86fd3b3/android/bootstrap/src/io/appium/android/bootstrap/handler/GetAttribute.java#L43 # def test_01_value' do; end # Doesn't work on And def test_01_element_method_name wait { assert_equal first_text.text, 'API Demos' } end # def test_01_tag_name' do; end # Doesn't work on And def test_02_element_method_location_rel wait do loc = first_text.location_rel($driver) assert_equal loc.x.class, String assert_equal loc.y.class, String end end # By default, the webdriver gem will return message instead of origValue def test_03_common_patch_id_error_message value = '' begin set_wait 0 find_element(:id, 'ok') rescue StandardError => e value = e.message ensure set_wait 30 end exp = 'An element could not be located on the page using the given search parameters.' assert value.start_with? exp end def test_04_id_common_patch_success if automation_name_is_uiautomator2? wait do el = text 'text' # TextText assert_equal el.text, 'Text' end end end def test_05_find_many_elements_by_resource_id wait do value = find_elements(:id, 'android:id/text1').length assert_equal value, 12 end end def test_06_find_single_element_by_resource_id wait do value = id('android:id/text1').text assert_equal value, "Access'ibility" end end end end end ================================================ FILE: android_tests/lib/android/specs/common/version.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake "android[common/version]" class AndroidTest class Common class Version < Minitest::Test def test_appium_version assert_match(/(\d+)\.(\d+).(\d+)/, ::Appium::VERSION) end def test_appium_date assert_match(/(\d+)-(\d+)-(\d+)/, ::Appium::DATE) end end end end ================================================ FILE: android_tests/lib/android/specs/common/web_context.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Tests specifically for areas where the web_context differs in behaviour # rake "android[common/web_context]" class AndroidTest class Common class WebContext < Minitest::Test # appium's context support is broken on android def test_01_available_contexts wait_true { available_contexts.include? 'NATIVE_APP' } end def test_02_current_context wait { assert_equal current_context, 'NATIVE_APP' } end def undo_setcontext_nav back wait { find('WebView') } back wait { find 'Views' } end def test_03_set_context wait { scroll_to('Views').click } wait { scroll_to('WebView').click } wait_true { !available_contexts.detect { |e| e.start_with?('WEBVIEW') }.nil? } webview_context = available_contexts.detect { |e| e.start_with?('WEBVIEW') } if webview_context.nil? undo_setcontext_nav raise "No webview context found. contexts are: #{contexts}" end wait { set_context webview_context } wait { assert_equal current_context, webview_context } # verify inspect within webview works assert get_android_inspect.split("\n").length >= 3 wait { set_context 'NATIVE_APP' } wait { assert_equal current_context, 'NATIVE_APP' } undo_setcontext_nav end end end end ================================================ FILE: android_tests/lib/android/specs/driver.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'tmpdir' # rake "android[driver]" class AndroidTest class Driver < Minitest::Test def sauce? ENV.fetch('UPLOAD_FILE', nil) && ENV.fetch('SAUCE_USERNAME', nil) end def test_01_load_settings appium_txt = File.join(Dir.pwd, 'appium.txt') parsed = Appium.load_settings file: appium_txt, verbose: true apk_name = File.basename parsed[:caps][:app] assert_equal apk_name, 'api.apk' end def test_02_attributes_no_wait no_wait assert_raises Selenium::WebDriver::Error::NoSuchElementError do button('zz') end set_wait end # attr_reader :default_wait, :app_path, :app_name, # :app_package, :app_activity, :app_wait_activity, # :sauce_username, :sauce_access_key, :port, :os, :debug def test_03_attributes_default_wait_attr set_wait 1 assert_equal default_wait, 1 set_wait # restore default end def test_04_attributes_app_path_attr apk_name = File.basename driver_attributes[:caps][:app] assert_equal apk_name, 'api.apk' end def test_05_attributes_verify_all_attributes actual = driver_attributes expected_app = File.absolute_path('../test_apps/api.apk') expected = { automation_name: :uiautomator2, custom_url: 'http://127.0.0.1:4723', default_wait: 1, sauce_username: nil, sauce_access_key: nil, sauce_endpoint: 'ondemand.saucelabs.com:443/wd/hub', port: 4723, device: :android, debug: true, listener: nil, wait_timeout: 30, # default wait_interval: 0.5 # default } # actual[:caps].to_json send to Appium server caps_with_json = JSON.parse(actual[:caps].to_json) assert_equal caps_with_json['platformName'], 'android' assert_equal caps_with_json['app'], expected_app assert_equal caps_with_json['appPackage'], 'io.appium.android.apis' assert_equal caps_with_json['appActivity'], 'io.appium.android.apis.ApiDemos' assert_equal caps_with_json['deviceName'], 'Android emulator' assert_equal caps_with_json['someCapability'], 'some_capability' assert_equal actual[:caps][:platformName], 'android' assert_equal actual[:caps][:app], expected_app assert_equal actual[:caps][:appPackage], 'io.appium.android.apis' assert_equal actual[:caps][:appActivity], 'io.appium.android.apis.ApiDemos' assert !actual[:caps][:deviceName].nil? assert_equal actual[:caps][:some_capability], 'some_capability' dup_actual = actual.dup dup_actual.delete(:caps) raise "\n\nactual:\n\n: #{dup_actual}expected:\n\n#{expected}" if dup_actual != expected end def test_06_driver_class assert_equal $driver.class, Appium::Driver end def absolute_app_path(path) $driver.class.absolute_app_path(caps: { app: path }) end def validate_path(path) assert_equal absolute_app_path(path), path end def test_07_absolute_app_path validate_path 'sauce-storage:some_storage_suffix' validate_path 'http://www.saucelabs.com' Dir.mktmpdir do |tmp_dir| existing_path = File.join(tmp_dir, 'myapp.app') FileUtils.mkdir_p existing_path validate_path existing_path end # bundle id test validate_path 'my.bundle.id' # relative path test relative_path = File.join __FILE__, ('..' + File::SEPARATOR) * 5, 'test_apps/api.apk' expected_path = File.expand_path relative_path assert_equal absolute_app_path(relative_path), expected_path # invalid path test assert_equal absolute_app_path('../../does_not_exist.apk'), '../../does_not_exist.apk' end def test_08_methods_status appium_server_version['build'].keys.sort.include? 'version' end def test_09_methods_server_version server_version = appium_server_version['build']['version'] if sauce? assert_match 'Sauce OnDemand', server_version else assert_match(/(\d+)\.(\d+).(\d+)/, server_version) end end def test_10_methods_client_version client_version = appium_client_version expected = { version: ::Appium::VERSION } assert_equal client_version, expected end def test_11_methods_restart set_wait 1 # ensure wait is 1 before we restart. restart assert_equal current_activity, '.ApiDemos' end def test_12_methods_driver assert_equal driver.browser, 'unknown' end # Skip: # screenshot # this is slow and already tested by Appium # driver_quit # tested by restart # start_driver # tested by restart # no_wait # posts value to server, it's not stored locally # set_wait # posts value to server, it's not stored locally # execute_script # 'mobile: ' is deprecated and plain execute_script unsupported def test_13_methods_default_wait set_wait 1 assert_equal default_wait, 1 end # returns true unless an error is raised def test_14_methods_exists assert_equal exists(0, 0) { true }, true assert_equal exists(0, 0) { raise 'error' }, false end # any elements def test_15_methods_find_elements wait do assert_equal find_elements(:class_name, 'android.widget.TextView').length, 13 end end # any element def test_16_methods_find_element wait do assert_equal find_element(:class_name, 'android.widget.TextView').class, ::Appium::Core::Element end end # simple integration sanity test to check for unexpected exceptions def test_17_methods_set_location set_location latitude: 55, longitude: -72, altitude: 33 rescue Selenium::WebDriver::Error::UnknownError => e # on android this method is expected to raise with this message when running # on a regular device, or on genymotion. # error could be many messages, including: # ERROR running Appium command: port should be a number or string # ERROR running Appium command: port should be > 0 and < 65536 raise unless e.message.include?('ERROR running Appium command: port should be') end # settings def test_18_methods_get_settings assert !get_settings.nil? end def test_19_methods_update_settings update_settings allowInvisibleElements: true assert_equal get_settings['allowInvisibleElements'], true end # Skip: x # x is only used in Pry end end ================================================ FILE: android_tests/lib/android/specs/install.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake "android[install]" class AndroidTest class Install < Minitest::Test # To Do: Blocked on https://github.com/appium/appium/issues/3032 def pkg 'io.appium.android.apis' end def installed assert_equal app_installed?(pkg), true end def not_installed assert_equal app_installed?(pkg), false end def test_install_uninstall installed remove_app 'io.appium.android.apis' not_installed install_app caps[:app] installed end # no way to launch apk after it's uninstalled/installed # blocked on: https://github.com/appium/appium/issues/2969 # launch_app end end ================================================ FILE: android_tests/lib/android/specs/sauce_labs.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake "android[sauce_labs]" class AndroidTest class SauceLabs < Minitest::Test def test_sauce_settings opt = {} sauce_username = 'sauce_name' sauce_access_key = 'abcdefghijklmn' sauce_endpoint = 'ondemand.saucelabs.com:443/wd/hub' opt[:sauce_username] = sauce_username opt[:sauce_access_key] = sauce_access_key opt[:sauce_endpoint] = sauce_endpoint sauce = Appium::SauceLabs.new(opt) assert_equal sauce.username, sauce_username assert_equal sauce.access_key, sauce_access_key assert_equal sauce.endpoint, sauce_endpoint assert_equal sauce.sauce_server_url?, true assert_equal sauce.server_url, 'https://sauce_name:abcdefghijklmn@ondemand.saucelabs.com:443/wd/hub' end def test_no_sauce_settings opt = {} sauce = Appium::SauceLabs.new(opt) assert_equal sauce.sauce_server_url?, false assert_equal sauce.server_url, 'http://127.0.0.1:4723/wd/hub' end end end ================================================ FILE: android_tests/lib/format.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # helper code useful for writing and verifying tests using Pry list = <<-TXT find text texts name names scroll_to TXT list.split("\n").each do |method| puts "t '#{method}' do" puts puts 'end' puts end # -- # Format AndroidElementClassMap from # https://github.com/appium/appium/blob/master/android/bootstrap/src/io/appium/android/bootstrap/AndroidElementClassMap.java # for ruby_lib android/helper.rb tag_name_to_android list = <= 9.2.1', '< 13.0' s.add_dependency 'nokogiri', '~> 1.8', '>= 1.8.1' s.add_dependency 'tomlrb', '>= 1.1', '< 3.0' s.files = `git ls-files`.split("\n").reject { |v| v.match(/\A^(ios_tests|android_tests|grid|test_apps)\/.+/) } s.metadata['rubygems_mfa_required'] = 'true' end ================================================ FILE: contributing.md ================================================ # Contributing For features or bug fixes, please submit a pull request. Ideally there would be a test as well. The remainder of this doc details how to run the tests. If you'd like to adding new driver commands, please refer to https://github.com/appium/ruby_lib_core ## Tests - Tests are run against [appium's master branch](https://github.com/appium/appium/blob/master/docs/en/contributing-to-appium/appium-from-source.md) - The tests are run using the [flaky gem](https://github.com/appium/flaky) on OS X - The `arc` command can be run from within the `ios_tests` or `android_tests` folder to open an interactive console ### Run iOS tests iOS tests are run on the iPhone 6 / iOS 9.3 simulator. - `cd ios_tests` - `flake 3 ios` - Run all the iOS tests up to 3 times ### Run Android tests Android tests require running on physical hardware with Android 5.0 (API 21). The emulator is unreliable. - `cd android_tests` - `flake 3 android` - Run all the Android tests up to 3 times ## Publishing 0. Ensure you have `~/.gem/credentials` If not run [the following command](http://guides.rubygems.org/make-your-own-gem/) (replace username with your rubygems user) > $ curl -u username https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials; chmod 0600 ~/.gem/credentials 1. Bump the version number: `thor bump` (`bumpy`, `bumpz`) 2. Update `CHANGELOG.md` 3. Generate release note, publish release gem and push the tag to this repository: `thor release` ================================================ FILE: docs/android_uiautomator.md ================================================ # Help debugging - `adb shell uiautomator events` - Prints out accessibility events to the console until the connection to the device is terminated - [URL](https://stuff.mit.edu/afs/sipb/project/android/docs/tools/help/uiautomator/index.html) - **notice** - If Appium is started then it terminates the other `uiautomator` processes # uiautomator2 ## difference between uiautomator1 and uiautomator2 - `find_element/s :id, "ids"` - uiautomator1 - Find elements with `resource_id` - Find elements with string id resource(string.xml based) - uiautomator2 - Find elements with `resource_id` - from: Does not appium-uiautomator2-server support finding string ids with "id" strategy? [issue](https://github.com/appium/appium/issues/8349) ================================================ FILE: docs/docs.md ================================================ # Documentation ## API Doc of Ruby Client - This library: http://www.rubydoc.info/github/appium/ruby_lib - Core: http://www.rubydoc.info/github/appium/ruby_lib_core - [Ruby selenium-webdriver](https://github.com/SeleniumHQ/selenium/wiki/Ruby-Bindings) ### General - [Appium](https://github.com/appium/appium/blob/master/README.md) - [Supported platforms](https://github.com/appium/appium/blob/master/docs/en/about-appium/platform-support.md) - [All methods supported by Appium](https://github.com/appium/appium-base-driver/blob/master/docs/mjsonwp/protocol-methods.md) - Fundamental Commands: http://appium.io/docs/en/commands/status/ etc - [MiniTest Expectations](http://docs.seattlerb.org/minitest/Minitest/Expectations.html) ### Driver types in Ruby Client ```ruby # Appium specific driver with helpers available extending Standard Appium Driver. @appium_driver = Appium::Driver.new @options, false # Standard Appium Driver extends Selenium WebDriver. @selenium_driver = @appium_driver.start_driver ``` ### Example Example of automating the built in Android settings. ```ruby # run Pry, and paste the following apk = { platformName: 'android', deviceName: :nexus, appPackage: 'com.android.settings', appActivity: '.Settings', appWaitActivity: '.Settings' } Appium::Driver.new({caps: apk}, false).start_driver ``` Example use of Appium's mobile gesture. Long click on an ImageView in Android. ``` last_image = find_elements(:class, 'ImageView').last long_press(element: last_image) ``` Rotate examples. The behaviour is depends on devices. ```ruby driver.rotate :landscape driver.rotate :portrait ``` - `appium_server_version` Discover the Appium rev running on the server. - `element.send_keys "msg"` Sends keys to currently active element ### APIs ```ruby e.name # button, text e.value # secure, textfield e.type 'some text' # type text into textfield e.clear # clear textfield e.tag_name # calls .type (patch.rb) e.text e.size e.location e.location_rel e.click e.send_keys 'keys to send' e.displayed? # true or false depending if the element is visible e.selected? # is the tab selected? e.attribute('checked') # is the checkbox checked? # alert example without helper methods alert = @driver.switch_to.alert alert.text alert.accept alert.dismiss # Secure textfield example. # # Find using default value s = textfield 'Password' # Enter password s.send_keys 'hello' # Check value s.value == ios_password('hello'.length) ``` -- #### Driver - `start_driver` will restart the driver. - `x` will quit the driver and exit Pry. - `execute_script` calls `@driver.execute_script` - `find_element` calls `@driver.find_element` - `find_elements` calls `@driver.find_elements` - `no_wait` will set implicit wait to 0. `@driver.manage.timeouts.implicit_wait = 0` - `set_wait` will set implicit wait to default seconds. `@driver.manage.timeouts.implicit_wait = default` - `set_wait(timeout_seconds)` will set implicit wait to desired timeout. `@driver.manage.timeouts.implicit_wait = timeout` - `.click` to tap an element. - `.send_keys` or `.type` to type on an element. #### Cucumber Sauce Integration Reset after each test and when done report the result to Sauce after quiting the driver. ```ruby require 'rest_client' # https://github.com/archiloque/rest-client require 'json' # for .to_json require 'sauce_whisk' After do |scenario| # end the test session, ignoring any exceptions. ignore { $driver.driver_quit } user = ENV['SAUCE_USERNAME'] key = ENV['SAUCE_ACCESS_KEY'] if user && !user.empty? && key && !key.empty? passed = ! scenario.failed? SauceWhisk::Jobs.change_status $driver.driver.session_id, passed end end ``` ================================================ FILE: docs/ios_xcuitest.md ================================================ ## XCUITest - Over Appium1.6.0 provides `XCUITest` automation name based on WebDriverAgent. - [appium-xcuitest-driver](https://github.com/appium/appium-xcuitest-driver) - [WebDriverAgent](https://github.com/facebook/WebDriverAgent) - How to migrate XCUITest from UIAutomation - [Migrating your iOS tests from UIAutomation](https://github.com/appium/appium/blob/v1.6.2/docs/en/advanced-concepts/migrating-to-xcuitest.md) - Mobile gestures for XCUITest - [ios-xctest-mobile-gestures](https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/ios/ios-xctest-mobile-gestures.md) - Required Appium1.6.4+ ## find elements - supported elements by find_element are: - [appium-xcuitest-driver](https://github.com/appium/appium-xcuitest-driver/blob/master/lib/commands/find.js#L17) - [locatorStrategies](https://github.com/appium/appium-xcuitest-driver/blob/95886f1118d71fe950768f8262179d3608b40fc7/lib/driver.js#L81) - [WebDriverAgent](https://github.com/facebook/WebDriverAgent/blob/8346199212bffceab24192e81bc0118d65132466/WebDriverAgentLib/Commands/FBFindElementCommands.m#L111) - Mapping - https://github.com/facebook/WebDriverAgent/blob/master/WebDriverAgentLib/Utilities/FBElementTypeTransformer.m#L19 ### with except for XPath and Predicate #### examples - [button_class](https://github.com/appium/ruby_lib/blob/master/lib/appium_lib/ios/element/button.rb#L8), [static_text_class](https://github.com/appium/ruby_lib/blob/master/lib/appium_lib/ios/element/text.rb#L8), [text_field_class](https://github.com/appium/ruby_lib/blob/master/lib/appium_lib/ios/element/textfield.rb#L10) and [secure_text_field_class](https://github.com/appium/ruby_lib/blob/master/lib/appium_lib/ios/element/textfield.rb#L15) provide class name. - If `automationName` is `Appium` or `nil`, then they provide `UIAxxxx` - If `automationName` is `XCUITest`, then they provide `XCUIElementTypexxx` ```ruby find_element(:class, button_class) # Return a element of XCUIElementTypeButton for XCUITest ``` - [tag/s](https://github.com/appium/ruby_lib/blob/ac03116756a72fbd624fa32ea886123b955d7089/lib/appium_lib/android/helper.rb#L238) is alias of `find_element :class, element` - `accessibility_id` ```ruby find_element(:accessibility_id, element) # Return a element which has accessibilityIdentifier, `element`. ``` - `button/s(value)`, `button_exact/buttons_exact`, `text/s(value)`, `text_exact/texts_exact` ```ruby buttons(value) # Return button elements include `value` as its name attributes. ``` ### with Predicate - We recommend to use predicate strategy instead of XPath strategy. - e.g. `find_ele_by_predicate/find_eles_by_predicate`, `find_ele_by_predicate_include/find_eles_by_predicate_include` - A helpful cheatsheet for predicate - https://realm.io/news/nspredicate-cheatsheet/ - For XCUITest(WebDriverAgent), without 'wd' prefixes are supported. - https://github.com/facebook/WebDriverAgent/wiki/Queries - For example, `%(name ==[c] "#{value}" || label ==[c] "#{value}" || value ==[c] "#{value}")` is equal to `%(wdName ==[c] "#{value}" || wdLabel ==[c] "#{value}" || wdValue ==[c] "#{value}")` in WebDriverAgent. #### examples - `textfield/s(value)`, `find/s`, `find_exact/finds_exact`, `find_ele_by_predicate/find_eles_by_predicate` and `find_ele_by_predicate_include/find_eles_by_predicate_include` use predicate strategy in their method. ```ruby textfield(value) # Return a XCUIElementTypeSecureTextField or XCUIElementTypeTextField element which has `value` text. finds_exact(value) # Return any elements include `value` as its name attributes. ``` ### with Class Chain - require Appium 1.6.4+ - https://github.com/appium/appium-xcuitest-driver/pull/391 - https://github.com/appium/java-client/pull/599/files - WebDriverAgent - https://github.com/facebook/WebDriverAgent/wiki/Queries ### with XPath - It is better to avoid XPath strategy. - https://github.com/appium/appium/blob/v1.6.2/docs/en/advanced-concepts/migrating-to-xcuitest.md#xpath-locator-strategy - > Try not to use XPath locators unless there are absolutely no other alternatives. In general, XPath locators might be times slower, than other types of locators like accessibility id, class name and predicate (up to 100 times slower in some special cases). They are so slow because XPath location is not natively supported by Apple's XCTest framework. - Improved performance a bit - https://github.com/appium/appium/issues/6842 - https://github.com/facebook/WebDriverAgent/issues/306 - XPath in WebDriverAgent - https://github.com/facebook/WebDriverAgent/blob/2158a8d0f305549532f1338fe1e4628cfbd53cd9/WebDriverAgentLib/Categories/XCElementSnapshot%2BFBHelpers.m#L57 #### examples ```ruby xpaths("//some xpaths") ``` ## Gesture - `mobile:` commands are provided by WDA. - Documentations - https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/ios/ios-xctest-mobile-gestures.md - Specs by test code - https://github.com/appium/appium-xcuitest-driver/blob/master/test/functional/basic/gesture-e2e-specs.js ### Workaround - `mobile:` commands depends on WDA and Apple's framework and the behaviour depends on them. - Sometimes issues occur such as "doubleTap isn't tapping #548" - workaround for it: - with `selenium-webdriver >= 3.4.0` ```ruby def double_tap(element) rect = element.rect execute_script 'mobile: doubleTap', x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 end ``` - with `selenium-webdriver < 3.4.0` ```ruby def double_tap(element) size = element.size location = element.location execute_script 'mobile: doubleTap', x: location.x + size.width / 2, y: location.y + size.height / 2 end ``` ## Other actions Basically, other actions such as `type` are compatible with `automationName = Appium`. ## Pasteboard - Simulator only - https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/ios-xctest-pasteboard.md ================================================ FILE: docs/parallel.md ================================================ Appium 1.7.0+ supports single server and multiple sessions, and it requires Xcode 9 for iOS. # Example ## Run tests on Multiple Simulators with Xcode 9 - https://github.com/appium/appium-xcuitest-driver/tree/master/test/functional/parallel - https://github.com/appium/ruby_lib/tree/master/ios_tests/parallel - Thread programming: TestParallelRunThread - Process programming: TestParallelRunProcess ================================================ FILE: docs/w3c.md ================================================ Perform touch actions for W3C module. Generate `touch` pointer action here and users can use this via `driver.action` [Documentation](http://www.rubydoc.info/github/appium/ruby_lib_core/Appium%2FCore%2FBase%2FCoreBridgeW3C:action) # Example ```ruby dialect #=> :w3c # then el = find_element(:name, 'Pickers') driver.action.click(el).perform #=> work # Scroll/Swipe driver.action .move_to_location(500, 500).pointer_down(:left) .move_to_location(0, 700) .release.perform # Zoom in # multiple action chains f1 = driver.action.add_pointer_input(:touch, 'finger1') f1.create_pointer_move(duration: 1, x: 200, y: 500, origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT) f1.create_pointer_down(:left) f1.create_pause(0.5) f1.create_pointer_move(duration: 1, x: 200, y: 200, origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT) f1.create_pointer_up(:left) f2 = driver.action.add_pointer_input(:touch, 'finger2') f2.create_pointer_move(duration: 1, x: 200, y: 500, origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT) f2.create_pointer_down(:left) f2.create_pause(0.5) f2.create_pointer_move(duration: 1, x: 200, y: 800, origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT) f2.create_pointer_up(:left) driver.perform_actions [f1, f2] ``` # Note ## Coordinate points - jsonwp - Relative action coordinates are counted relatively to the **top left point** of element's rectangle - W3C - Relative action coordinates are counted relatively to the **center** of element's rectangle ## Limitations - WebDriverAgent support only `touch` as a `pointer type`. - By default, [ruby_lib_core](https://github.com/appium/ruby_lib_core/blob/ab5d7c5ed31f318a9395e5aeafe1d0d655d3cff4/lib/appium_lib_core/common/base/w3c_bridge.rb#L26) generate `touch` based actions. - About `pointer type` => [W3C](https://www.w3.org/TR/webdriver/#perform-actions) and [Simple WD Spec](https://github.com/jlipps/simple-wd-spec#perform-actions) ================================================ FILE: grid/README.md ================================================ # Run Grid ```bash $ java -jar selenium-server-standalone-2.53.1.jar -role hub -hubConfig hub_config.json ``` **note** Selenium Grid 3.4.0 is failed to establish sessions: # Run Appium ```bash $ node . --nodeconfig ~/GitHub/ruby_lib/grid/config.json # or $ appium --nodeconfig ~/GitHub/ruby_lib/grid/config.json ``` # Run Ruby Script ```bash $ rake ios # for example ``` ================================================ FILE: grid/appium.txt.ios.example ================================================ [caps] platformName = "ios" platformVersion = "11.4" deviceName ="iPhone 11" automationName = 'XCUITest' app = "/absolute/path/to/UICatalog.app.zip" some_capability = "some_capability" [appium_lib] server_url = "http://localhost:4444/wd/hub" sauce_username = "" sauce_access_key = "" sauce_endpoint = "" wait = 30 wait_timeout = 20 wait_interval = 1 ================================================ FILE: grid/config.json ================================================ { "capabilities": [ { "browserName": "iPhone 11", "version":"11.4", "platform":"ios", "maxInstances": 1 } ], "configuration": { "cleanUpCycle": 2000, "timeout": 60000, "proxy": "org.openqa.grid.selenium.proxy.DefaultRemoteProxy", "url": "http://localhost:4723", "host": "localhost", "port": 4723, "maxSession": 1, "register": true, "registerCycle": 5000, "hubPort": 4444, "hubHost": "localhost" } } ================================================ FILE: grid/hub_config.json ================================================ { "port": 4444, "newSessionWaitTimeout": -1, "servlets" : [], "withoutServlets": [], "custom": {}, "capabilityMatcher": "org.openqa.grid.internal.utils.DefaultCapabilityMatcher", "throwOnCapabilityNotPresent": true, "cleanUpCycle": 5000, "role": "hub", "debug": false, "browserTimeout": 0, "timeout": 1800 } ================================================ FILE: grid/hub_config_3.json ================================================ { "capabilities": [ { "browserName": "iPhone 11", "version":"11.4", "maxInstances": 1, "seleniumProtocol": "WebDriver" } ], "proxy": "org.openqa.grid.selenium.proxy.DefaultRemoteProxy", "maxSession": 5, "port": 4444, "register": true, "registerCycle": 5000, "hub": "http://localhost:4444", "nodeStatusCheckTimeout": 5000, "nodePolling": 5000, "role": "hub", "unregisterIfStillDownAfter": 60000, "downPollingLimit": 2, "debug": true, "servlets" : [], "withoutServlets": [], "custom": {} } ================================================ FILE: ios_tests/Gemfile ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. source 'https://rubygems.org' eval_gemfile File.join(File.expand_path('..', __dir__), 'Gemfile') gem 'parallel_tests' ================================================ FILE: ios_tests/LICENSE-2.0.txt ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: ios_tests/Rakefile ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'rubygems' require 'rake' require 'rubocop/rake_task' task default: :ios # Run sh and ignore exception def run_sh(cmd) sh cmd rescue StandardError # Ignored end # Run cmd. On failure run install and try again. def bash(cmd) sh cmd do |successful, result| # exitstatus 7 means bundle install failed # non-zero (except 7 retry path) means the test failed if !successful && result.exitstatus == 7 Rake::Task['install'].execute sh cmd elsif !successful raise "Command failed with status #{result.exitstatus}: #{cmd}" end end end # Run a single test with: # rake ios['ios/element/generic'] # # rake ios['driver'] # # Run all tests with: # rake ios desc 'Run the iOS tests' task :ios, :args, :test_file do |_args, test_file| # rake android['ok'] # args = android # test_file = {:args=>"ok"} test_file = test_file[:args] cmd = 'bundle exec ruby ./lib/run.rb ios' cmd = %(#{cmd} "#{test_file}") if test_file bash cmd end desc 'Run bundle install' task :install do sh 'bundle install' end desc 'Execute RuboCop static code analysis' RuboCop::RakeTask.new(:rubocop) do |t| t.patterns = %w(**/*.rb) t.options = %w(-D) t.fail_on_error = false end class Device def self.one { automationName: 'xcuitest', platformName: 'ios', platformVersion: '11.0', deviceName: 'iPhone 6', app: "#{Dir.pwd}/../test_apps/UICatalog.app.zip", wdaLocalPort: 8100, isCommandsQueueEnabled: false } end def self.two { automationName: 'xcuitest', platformName: 'ios', platformVersion: '11.0', deviceName: 'iPhone 6s', app: "#{Dir.pwd}/../test_apps/UICatalog.app.zip", wdaLocalPort: 8200, isCommandsQueueEnabled: false } end end desc 'Run tests with parallel thread' task :run_parallel_t do require_relative 'parallel/test' threads = [] [Device.one, Device.two].map do |capability| threads << Thread.new do TestParallelRunThread.new(capability).test_run end end threads.each(&:join) end desc 'Run tests with parallel processes' task :run_parallel_p do require_relative 'parallel/test' [Device.one, Device.two].each do |capability| fork do TestParallelRunProcess.new(capability).test_run end end Process.waitall end ================================================ FILE: ios_tests/appium.txt ================================================ [caps] platformName = "ios" platformVersion = "18.5" deviceName ="iPhone 16 Plus" automationName = 'XCUITest' app = "../test_apps/UICatalog.app.zip" someCapability = "some_capability" simulatorStartupTimeout = 600000 wdaLaunchTimeout = 600000 [appium_lib] wait = 30 wait_timeout = 20 wait_interval = 1 ================================================ FILE: ios_tests/data/unicode.txt ================================================ ® ================================================ FILE: ios_tests/flaky.txt ================================================ ios = "lib/ios/specs/" ================================================ FILE: ios_tests/lib/common.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # common methods def back_click back end def leave_textfields back_click assert screen == catalog end def go_to_textfields assert screen == catalog wait_true do find_element(:name, 'Text Fields').click screen == 'Text Fields' # wait for screen transition end end def screen $driver.find_element(:class, ui_ios.navbar).name end def catalog 'UICatalog' end def target_bundle_id 'com.example.apple-samplecode.UICatalog' end def ui_ios UI.new($driver) end class UI def initialize(driver) @driver = driver end def navbar 'XCUIElementTypeNavigationBar' end def button 'XCUIElementTypeButton' end def static_text 'XCUIElementTypeStaticText' end def text_field 'XCUIElementTypeTextField' end def secure_text_field 'XCUIElementTypeSecureTextField' end def picker 'XCUIElementTypePicker' end def picker_wheel 'XCUIElementTypePickerWheel' end def action_sheet 'XCUIElementTypeActionSheet' end def table 'XCUIElementTypeTable' end def table_cell 'XCUIElementTypeCell' end def other 'XCUIElementTypeOther' end def status_bar 'XCUIElementTypeStatusBar' end end ================================================ FILE: ios_tests/lib/format.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # helper code useful for writing and verifying tests using Pry list = <= 7) assert_includes act, '25x XCUIElementTypeOther' assert_includes act, '24x XCUIElementTypeStaticText' assert_includes act, '12x XCUIElementTypeCell' assert_includes act, '1x XCUIElementTypeTable' assert_includes act, '1x XCUIElementTypeNavigationBar' assert_includes act, '1x XCUIElementTypeWindow' assert_includes act, '1x XCUIElementTypeApplication' end # TODO: write tests # page_class # px_to_window_rel # lazy_load_strings # xml_keys # xml_values # resolve_id # string_visible_contains # xpath_visible_contains # xpaths_visible_contains # string_visible_exact # xpath_visible_exact # xpaths_visible_exact # raise_no_element_error end end end ================================================ FILE: ios_tests/lib/ios/specs/common/patch.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Skip: # status # status patches are already tested in driver.rb # execute # debug output for Pry # # bundle exec rake "ios[common/patch]" class IosTest class Common class Patch < Minitest::Test def test_01_before_first driver.terminate_app target_bundle_id driver.activate_app target_bundle_id assert_equal screen, catalog end def test_02_appium_core_element_method_name assert_equal first_text.name, 'UICatalog' end def test_03_appium_core_element_method_location_rel loc = first_text.location_rel($driver) assert_equal loc.x.class, String assert_equal loc.y.class, String end end end end ================================================ FILE: ios_tests/lib/ios/specs/common/version.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. class IosTest class Common class Version < Minitest::Test def test_01_before_first assert_equal screen, catalog end def test_02_appium_version assert_match(/(\d+)\.(\d+).(\d+)/, ::Appium::VERSION) end def test_03_appium_date assert_match(/(\d+)-(\d+)-(\d+)/, ::Appium::DATE) end end end end ================================================ FILE: ios_tests/lib/ios/specs/common/web_context.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Tests specifically for areas where the web_context differs in behaviour # rake "ios[common/web_context]" class IosTest class Common class WebContext < Minitest::Test def test_01_before_first driver.terminate_app target_bundle_id driver.activate_app target_bundle_id assert_equal screen, catalog end def test_02_get_ios_inspect find_eles_by_predicate_include(value: 'Web').first.click wait_true { available_contexts.size >= 2 } web_view_context = available_contexts.find { |c| c.start_with? 'WEBVIEW' } # Get WEBVIEW_59153.1 for example. set_context web_view_context assert_equal current_context, web_view_context sleep 1 # Give a chance to load assert_equal page.start_with?("\nhtml\n"), true end def test_03_xcuitest_get_contexts context = xcuitest_get_contexts assert_equal({ 'id' => 'NATIVE_APP' }, context.first) assert context[1]['id'].include?('WEBVIEW_') end def test_04_after_last set_context 'NATIVE_APP' back_click end end end end ================================================ FILE: ios_tests/lib/ios/specs/device/device.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # $ rake "ios[device/device]" class IosTest class Device class Device < Minitest::Test # go back to the main page def go_back back wait { find_ele_by_predicate_include(class_name: ui_ios.navbar, value: 'UICatalog') } end def test_01_before_first driver.terminate_app target_bundle_id driver.activate_app target_bundle_id assert_equal screen, catalog end def test_02_app_installed installed = app_installed? 'Derrp' assert_equal installed, false end def test_03_background_app_homescreen bundle_id = 'com.example.apple-samplecode.UICatalog' background_app(-1) # background_app(nil) should work as same. # The app goes to background and never come back wait do assert_equal driver.app_state(bundle_id), :running_in_background_suspended end driver.activate_app bundle_id end def test_04_app_strings assert_includes app_strings, 'A Short Title Is Best' assert_includes app_strings('en'), 'A Short Title Is Best' end def test_05_action_chain element = text('Buttons') one_finger_tap x: 0, y: 0, element: element wait { button 'UICatalog' } # successfully transitioned to buttons page go_back end def test_06_swipe action.move_to_location(75, 500).pointer_down(:left) .move_to_location(75, 20).release.perform end end end end ================================================ FILE: ios_tests/lib/ios/specs/device/image_comparison.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # $ rake ios[device/image_comparison] class IosTest class Device class ImageComparison < Minitest::Test def test_image_comparison image1 = File.read './data/test_normal.png' image2 = File.read './data/test_has_blue.png' # Equal to `$driver.driver.find_image_occurrence` # Equal to `driver.find_image_occurrence` find_result = find_image_occurrence full_image: image1, partial_image: image2 rect = find_result['rect'] assert_equal({ 'x' => 0, 'y' => 0, 'width' => 750, 'height' => 1334 }, rect) end end end end ================================================ FILE: ios_tests/lib/ios/specs/driver.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # bundle exec rake "ios[driver]" class IosTest class Driver < Minitest::Test def test_01_before_first driver.terminate_app target_bundle_id driver.activate_app target_bundle_id assert_equal screen, catalog end def test_02_unicode_defaults data = File.read File.expand_path('../../../data/unicode.txt', __dir__) assert_equal data.strip, 174.chr('UTF-8') end def test_03_load_settings appium_txt = File.join(Dir.pwd, 'appium.txt') opts = Appium.load_settings file: appium_txt, verbose: true actual = '' actual = File.basename opts[:caps][:app] if opts && opts[:caps] expected = 'UICatalog.app.zip' assert_equal expected, actual end def test_04_verify_all_attributes actual = driver_attributes caps_app_for_teardown = actual[:caps][:app] expected_app = File.absolute_path('../test_apps/UICatalog.app.zip') # actual[:caps].to_json send to Appium server caps_with_json = JSON.parse(actual[:caps].to_json) assert_equal caps_with_json['platformName'], 'ios' assert !caps_with_json['platformVersion'].nil? assert_equal caps_with_json['app'], expected_app assert_equal caps_with_json['automationName'], 'XCUITest' assert !caps_with_json['deviceName'].nil? assert_equal caps_with_json['someCapability'], 'some_capability' assert_equal actual[:caps][:platformName], 'ios' assert !actual[:caps][:platformVersion].nil? assert_equal actual[:caps][:app], expected_app assert_equal actual[:caps][:automationName], 'XCUITest' assert !actual[:caps][:deviceName].nil? assert_equal actual[:caps][:someCapability], 'some_capability' actual_selenium_caps = actual[:caps][:automationName] assert_equal actual_selenium_caps, 'XCUITest' actual[:caps][:app] = caps_app_for_teardown end def test_05_verify_attributes_are_immutable assert_equal driver_attributes[:custom_url], 'http://127.0.0.1:4723' driver_attributes[:custom_url] = true assert_equal driver_attributes[:custom_url], 'http://127.0.0.1:4723' end def test_06_verify_attribute_of_caps_are_not_immutable_because_it_depends_on_selenium # immutability depends on Selenium for_clean_up = driver_attributes[:caps][:app].dup driver_attributes[:caps][:app] = 'fake' expected = 'fake' assert_equal driver_attributes[:caps][:app], expected # clean up driver_attributes[:caps][:app] = for_clean_up end def test_07_no_wait no_wait assert_raises Selenium::WebDriver::Error::NoSuchElementError do find_element(:accessibility_id, 'zz') end set_wait end def test_08_app_path_attr apk_name = File.basename driver_attributes[:caps][:app] assert_equal apk_name, 'UICatalog.app.zip' end def test_09_driver_class assert_equal $driver.class, Appium::Driver end def test_10_status assert appium_server_version['build'].keys.member?('version') end def test_11_server_version server_version = appium_server_version['build']['version'] assert_match(/(\d+)\.(\d+).(\d+)/, server_version) end def test_12_client_version client_version = appium_client_version expected = { version: ::Appium::VERSION } assert_equal client_version, expected end def test_13_restart restart text 'buttons' end def test_14_driver assert driver.browser.empty? end def test_15_automation_name_is_xcuitest? assert_equal automation_name_is_xcuitest?, true end # # Skip: # screenshot # this is slow and already tested by Appium # driver_quit # tested by restart # start_driver # tested by restart # def test_16_set_wait # fill the @last_waits array with: [30, 30] assert_equal set_wait(30), 30 assert_equal set_wait(30), 30 # verify set_wait with no args works correctly assert_equal set_wait, 30 assert_equal set_wait(30), 30 assert_equal set_wait, 30 assert_equal set_wait(2), 2 assert_equal set_wait, 30 assert_equal set_wait(3), 3 assert_equal set_wait, 30 assert_equal set_wait(2), 2 assert_equal set_wait(3), 3 assert_equal set_wait, 30 end def test_17_default_wait set_wait 30 assert_equal default_wait, 30 # set in run.rb end # returns true unless an error is raised def test_18_exists assert_equal exists(0, 0) { true }, true assert_equal exists(0, 0) { raise 'error' }, false end # simple integration sanity test to check for unexpected exceptions def test_19_set_location set_location latitude: 55, longitude: -72, altitude: 33 end # any elements def test_20_find_elements assert_equal find_elements(:class, ui_ios.table_cell).length, 18 end # any element def test_21_find_element assert_equal find_element(:class, ui_ios.static_text).class, ::Appium::Core::Element end # settings def test_22_get_settings assert !get_settings.nil? end def test_23_update_settings update_settings allowInvisibleElements: true assert_equal get_settings['allowInvisibleElements'], true end def test_24_events log_event vendor: 'appium', event: 'funEvent' log_events end def test_25_device_is_ios assert_equal device_is_ios?, true end end end ================================================ FILE: ios_tests/lib/ios/specs/ios/command/multi_app_handler.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake "ios[ios/command/multi_app_handler]" class IosTest class Ios class Command class MultiAppHandler < Minitest::Test # Only for Xcode 9+ def test_multip_app_handler driver.terminate_app target_bundle_id driver.activate_app target_bundle_id test_app_bundle = target_bundle_id assert_equal xcuitest_query_app_status(bundle_id: test_app_bundle), :running_in_foreground assert_equal xcuitest_terminate_app(bundle_id: test_app_bundle), true assert_equal xcuitest_query_app_status(bundle_id: test_app_bundle), :not_running assert xcuitest_activate_app(bundle_id: test_app_bundle).nil? assert_equal xcuitest_query_app_status(bundle_id: test_app_bundle), :running_in_foreground assert xcuitest_activate_app(bundle_id: 'com.apple.Preferences').nil? wait(timeout: 5) do assert_equal xcuitest_query_app_status(bundle_id: test_app_bundle), :running_in_background_suspended end assert xcuitest_activate_app(bundle_id: test_app_bundle).nil? wait(timeout: 5) do assert_equal xcuitest_query_app_status(bundle_id: test_app_bundle), :running_in_foreground end end end end end end ================================================ FILE: ios_tests/lib/ios/specs/ios/command/pasteboard.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake "ios[ios/command/pasteboard]" class IosTest class Ios class Command class Pasteboard < Minitest::Test def test_pasteboard driver.terminate_app target_bundle_id driver.activate_app target_bundle_id # set blank before testing because pasteboard is remaining during launching simulators set_pasteboard content: 'before' assert_equal get_pasteboard, 'before' set_pasteboard content: 'sample content' assert_equal get_pasteboard, 'sample content' end end end end end ================================================ FILE: ios_tests/lib/ios/specs/ios/command/source.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake ios[ios/command/source] class IosTest class Ios class Command class Source < Minitest::Test def test_source assert_equal xcuitest_source(format: :json).is_a?(Hash), true assert_equal xcuitest_source(format: :xml).is_a?(String), true end end end end end ================================================ FILE: ios_tests/lib/ios/specs/ios/element/alert.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake "ios[ios/element/alert]" class IosTest class Ios class Element class Alert < Minitest::Test def open_alert wait_true do find_element(:name, 'Okay / Cancel').click find_element(:name, 'A Short Title Is Best').displayed? end end def test_01_before driver.terminate_app target_bundle_id driver.activate_app target_bundle_id assert_equal screen, catalog wait_true do find_element(:name, 'Alert Views').click tag(ui_ios.navbar).name == 'Alert Views' # wait for true end end def test_02_alert_accept open_alert alert_accept end def test_03_alert_dismiss open_alert alert_dismiss end def test_04_after_last back_click assert screen == catalog sleep 1 end end end end end ================================================ FILE: ios_tests/lib/ios/specs/ios/element/button.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # FIXME: The order is broken in Ruby 3. # rake "ios[ios/element/button]" class IosTest class Ios class Element class Button < Minitest::Test def before_first assert_equal screen, catalog # nav to buttons activity wait { find_element(:name, 'Buttons').click } end def after_last # nav back to start back_click end def test_01_before_first driver.terminate_app target_bundle_id driver.activate_app target_bundle_id before_first end def test_02_button # by index assert_equal button(3).name, 'UIAccessoryButtonPlus' # by name contains assert_equal button('Plus').name, 'UIAccessoryButtonPlus' end def test_03_buttons exp = %w(UICatalog UIAccessoryButtonPlus) target_buttons = buttons('a') assert_equal target_buttons.map(&:name), exp assert_equal target_buttons.length, exp.length end def test_04_first_button assert_equal first_button.name, 'UICatalog' end def test_05_last_button expected = 'Button' assert_equal last_button.name, expected end def test_06_button_exact assert_equal button_exact('UIAccessoryButtonPlus').name, 'UIAccessoryButtonPlus' end def test_07_buttons_exact assert_equal buttons_exact('UIAccessoryButtonPlus').first.name, 'UIAccessoryButtonPlus' end def test_08_after_last after_last end end end end end ================================================ FILE: ios_tests/lib/ios/specs/ios/element/generic.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake "ios[ios/element/generic]" class IosTest class Ios class Element class Generic < Minitest::Test def uibutton_text 'Buttons' end def verify(element) element = element.first if element.is_a? Array assert_equal element.name, uibutton_text end def test_01_before_first driver.terminate_app target_bundle_id driver.activate_app target_bundle_id assert_equal screen, catalog end def test_02_find verify find 'tons' end def test_03_finds verify finds 'tons' end def test_04_find_exact verify find_exact uibutton_text end def test_05_finds_exact elements = finds_exact uibutton_text assert_equal elements.is_a?(Array), true verify elements end end end end end ================================================ FILE: ios_tests/lib/ios/specs/ios/element/text.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake "ios[ios/element/text]" class IosTest class Ios class Element class Text < Minitest::Test def ui_catalog 'UICatalog' end def uiview_steppers 'Steppers' end def test_01_before_first driver.terminate_app target_bundle_id driver.activate_app target_bundle_id assert_equal screen, catalog end def test_02_first_text assert_equal first_text.text, ui_catalog end def test_03_last_text expected = 'Steppers' assert_equal last_text.text, expected assert_equal last_text.name, expected end def test_04_text assert_equal text('epp').text, uiview_steppers assert_equal text(1).text, ui_catalog assert_equal text('epp').name, uiview_steppers end def test_05_texts exp = ['Date Picker', 'AAPLDatePickerController', 'Picker View', 'AAPLPickerViewController'] assert_equal texts.length, 24 assert_equal texts('icker').map(&:name), exp assert_equal texts('AAPL').length, 11 end def test_06_text_exact # should fail set_wait 0 act = begin text_exact 'mos' rescue StandardError # nop end assert act.nil? set_wait # should pass assert_equal text_exact(ui_catalog).text, ui_catalog end def test_07_texts_exact assert_equal texts_exact('UICatalog').length, 1 end end end end end ================================================ FILE: ios_tests/lib/ios/specs/ios/element/textfield.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake "ios[ios/element/textfield]" class IosTest class Element class Textfield < Minitest::Test def enter_text 'Placeholder text' end def enter_password 'Placeholder text' end def test_01_before_first driver.terminate_app target_bundle_id driver.activate_app target_bundle_id assert_equal screen, catalog go_to_textfields end def test_02_textfield assert_equal textfield(1).text, enter_text assert_equal textfield(enter_text).text, enter_text assert_equal textfield('holder').value, enter_password end def test_03_textfields values = textfields('text').map(&:value) assert_equal values.include?(enter_text), true assert_equal values.include?(enter_password), true # secure as well assert_equal textfields.length, 5 end def test_04_predicate_textfields textfields = find_elements(:predicate, "type contains[c] 'textfield'") assert_equal textfields.length, 5 end def test_05_first_textfield assert_equal first_textfield.text, enter_text end def test_06_last_textfield assert_equal last_textfield.text, enter_text end def test_07_textfield_exact assert_equal textfield_exact(enter_password).value, enter_password end def test_08_textfields_exact assert_equal textfields_exact(enter_password).first.value, enter_password end def test_09_textfield_type textfield(1).send_keys "o'k" assert_equal find_exact("o'k").text, "o'k" end def test_10_hide_keyboard first_textfield.click hide_keyboard end # test textfield methods with no textfields def test_11_leave_textfields set_wait 1 leave_textfields end def test_12_no_textfield assert_raises(Selenium::WebDriver::Error::NoSuchElementError) { textfield(1) } assert_raises(Selenium::WebDriver::Error::NoSuchElementError) { textfield('does not exist') } end def test_13_no_textfields assert_equal textfields('does not exist').length, 0 end def test_14_no_first_textfield assert_raises(Selenium::WebDriver::Error::NoSuchElementError) { first_textfield } end def test_15_no_last_textfield assert_raises(Selenium::WebDriver::Error::NoSuchElementError) { last_textfield } end def test_16_no_textfield_exact assert_raises(Selenium::WebDriver::Error::NoSuchElementError) { textfield_exact('does not exist') } end def test_17_no_textfields_exact assert_equal textfields_exact('does not exist').length, 0 end def test_18_after_last set_wait 30 end end end end ================================================ FILE: ios_tests/lib/ios/specs/ios/helper.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake "ios[ios/helper]" class IosTest class Ios class Helper < Minitest::Test def test_01_before_first driver.terminate_app target_bundle_id driver.activate_app target_bundle_id assert_equal screen, catalog end def test_02_ios_password assert_equal ios_password, 8226.chr('UTF-8') assert_equal ios_password(2), 8226.chr('UTF-8') * 2 end def test_03_page page # writes to std out end def test_04_id id 'Buttons' # 'Various uses of UIButton' end def test_05_platform_version assert !platform_version.empty? end def test_06_tags_include elements = tags_include class_names: %w(XCUIElementTypeTextView) assert_equal elements.length, 0 elements = tags_include class_names: %w(XCUIElementTypeTextView XCUIElementTypeStaticText) assert_equal elements.length, 24 elements = tags_include class_names: %w(XCUIElementTypeTextView XCUIElementTypeStaticText), value: 'u' assert_equal elements.length, 3 end def test_07_tags_exact elements = tags_exact class_names: %w() assert_equal elements.length, 0 elements = tags_exact class_names: %w(XCUIElementTypeStaticText) assert_equal elements.length, 24 elements = tags_exact class_names: %w(XCUIElementTypeTextView XCUIElementTypeStaticText) assert_equal elements.length, 24 elements = tags_exact class_names: %w(XCUIElementTypeTextView XCUIElementTypeStaticText), value: 'Buttons' assert_equal elements.length, 1 assert_equal elements.first.value, 'Buttons' end end end end ================================================ FILE: ios_tests/lib/ios/specs/ios/mobile_methods.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake ios[ios/mobile_methods] class IosTest class Ios class MobileMethods < Minitest::Test def test_01_before_first driver.terminate_app target_bundle_id driver.activate_app target_bundle_id assert_equal screen, catalog end def test_02_an_element_with_class_chain element = find_element :class_chain, '**/XCUIElementTypeStaticText' assert_equal element.name, catalog end def test_03_elements_with_class_chain elements = find_elements :class_chain, 'XCUIElementTypeWindow/*/*' assert_equal elements.size, 2 assert_equal elements[0].name, catalog assert elements[1].name.nil? end end end end ================================================ FILE: ios_tests/lib/ios/specs/ios/patch.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake "ios[ios/patch]" class IosTest class Ios class Patch < Minitest::Test def test_01_before_first driver.terminate_app target_bundle_id driver.activate_app target_bundle_id assert_equal screen, catalog go_to_textfields end def test_02_label assert_equal textfields[0].label, '' end def test_03_type text('text fields').click ele = first_textfield ele.clear ele.type 'ok' assert_equal ele.text, 'ok' end def test_04_after_last leave_textfields end end end end ================================================ FILE: ios_tests/lib/ios/specs/ios/xcuitest_gestures.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # rake "ios[ios/xcuitest_gestures]" class IosTest class Ios class XcuitestGestures < Minitest::Test def open_alert_ok_cancel wait_true do find_element(:name, 'Okay / Cancel').click find_element(:name, 'A Short Title Is Best').displayed? end end def open_alert_custom wait_true do find_element(:name, 'Other').click find_element(:name, 'A Short Title Is Best').displayed? end end def test_01_before_first driver.terminate_app target_bundle_id driver.activate_app target_bundle_id assert_equal screen, catalog end def test_02_tap element = text('controls') one_finger_tap x: 0, y: 0, element: element back_click element = text('controls') rect = element.rect one_finger_tap x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 end def test_03_double_tap element = button('Search') double_tap(element: element) end def test_04_touch_and_hold element = button('Tools') touch_and_hold(element: element, duration: 4.0) touch_and_hold(x: 100, y: 100) end def test_05_swipe swipe direction: 'down' swipe direction: 'down' assert_raises Selenium::WebDriver::Error::NoSuchElementError do text('Toolbars') end end def test_06_drag_from_to_for_duration drag_from_to_for_duration from_x: 100, from_y: 100, to_x: 100, to_y: 400 end def test_07_pinch pinch(scale: 0.5, velocity: -1) end def test_08_back_to_top back_click end def test_09_select_picker_wheel element = text('Picker View') one_finger_tap x: 0, y: 0, element: element e = find_element :class, ui_ios.picker_wheel previous_value = e.text select_picker_wheel(element: e, order: 'next') current_element = find_element(:class, ui_ios.picker_wheel) assert_equal current_element.displayed?, true assert current_element.text != previous_value end def test_10_back_to_top back_click end def test_11_alert wait_true do find_element(:name, 'Alert Views').click tag(ui_ios.navbar).name == 'Alert Views' end open_alert_ok_cancel alert action: 'accept' open_alert_ok_cancel alert action: 'dismiss' open_alert_custom list = alert action: 'getButtons' assert_equal list, ['Choice One', 'Choice Two', 'Cancel'] alert action: 'accept', button_label: 'Choice Two' end def test_12_back_to_top back_click end def test_13_after_last assert_equal screen, catalog end end end end ================================================ FILE: ios_tests/lib/run.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ios tests have a set of core helper methods require_relative 'common' # run file is identical to android require_relative '../../android_tests/lib/run' ================================================ FILE: ios_tests/parallel/test.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require_relative '../../lib/appium_lib' def des_server_caps { debug: true, server_url: ENV['appium_server'] ||= 'http://127.0.0.1:4723', wait: 25, wait_timeout: 20, wait_interval: 0.3 } end class TestParallelRunThread def initialize(capability) @capability = capability end def setup @appium = Appium::Driver.new({ caps: @capability, appium_lib: des_server_caps }, false) @appium.start_driver end def teardown @appium.quit_driver puts "finish: #{@capability}" end def test_run setup # tap alert @appium.find_element(:name, 'Alerts').click @appium.wait_true do @appium.find_element(:name, 'Show OK-Cancel').click @appium.find_element(:name, 'UIActionSheet ').displayed? end @appium.alert action: 'accept' @appium.back sleep 5 # TODO: fixme text_elem = @appium.text(@appium.app_strings['ButtonsExplain']) @appium.driver.action.click(text_elem).perform @appium.back teardown end end class TestParallelRunProcess def initialize(capability) @capability = capability end def setup @appium = Appium::Driver.new({ caps: @capability, appium_lib: des_server_caps }, false) Appium.promote_appium_methods TestParallelRunProcess, @appium start_driver end def teardown quit_driver puts "finish: #{@capability}" end def test_run setup # tap alert find_element(:name, 'Alerts').click wait_true do find_element(:name, 'Show OK-Cancel').click find_element(:name, 'UIActionSheet <title>').displayed? end alert action: 'accept' back sleep 5 # TODO: fixme # TouchAction text_elem = text(app_strings['ButtonsExplain']) driver.action.click(text_elem).perform back teardown end end ================================================ FILE: ios_tests/readme.md ================================================ ruby_lib_ios ===================== ruby_lib's iOS tests. Requires `Ruby 2.2+` or better. - `rake install` Install gems required to run the tests. - `rake ios` Run all tests. - `rake` Run all the test. Same as `rake ios` - `rake ios['ios/element/generic']` Run a single test. - `rake run_parallel_t` Run a test in parallel with thread model. - `rake run_parallel_p` Run a test in parallel with process model. - `arc` Opens the Appium Ruby Console (arc). Enables interactive testing. - `gem install appium_console` if it's not installed already. `UICatalog6.1` is from [appium/appium](https://github.com/appium/appium/blob/master/assets/UICatalog6.1.app.zip) There 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. By default, the tests are now run against `iPhone 6 Simulator 10.1 (14A345)` -- ```ruby Finished in 1 min 57 secs 123 runs, 164 assertions, 0 failures, 0 errors, 0 skips ``` ### Tips for parallel - https://github.com/grosser/parallel_tests - Usage: https://github.com/appium/ruby_lib_core#run-parallel-tests-with-parallel_tests-gem ================================================ FILE: lib/appium_lib/android/android.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require_relative 'common/helper' require_relative 'common/command/command' require_relative 'element/alert' require_relative 'element/button' require_relative 'element/generic' require_relative 'element/textfield' require_relative 'element/text' # android - uiautomator2 require_relative 'uiautomator2' # android - espresso require_relative 'espresso' module Appium module Android class Bridge def self.for(target) target.extend Appium::Android target.extend Appium::Android::Command end end end end ================================================ FILE: lib/appium_lib/android/common/command/command.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Android module Command # Conduct an adb shell script on Appium server. # Require `--relaxed-security` arguments when run Appium server as server side arguments. # # @param [String] command Command for "adb shell" # @param [Array] arguments Arguments for the adb command # # @example # # shell "echo", "list" #=> "list" # def shell(command, arguments) args = { command: command, args: arguments } # --relaxed-security @driver.execute_script 'mobile: shell', args end end end end ================================================ FILE: lib/appium_lib/android/common/helper.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Android # @private # http://nokogiri.org/Nokogiri/XML/SAX.html class AndroidElements < Nokogiri::XML::SAX::Document attr_reader :result, :keys, :filter # convert to string to support symbols def filter=(value) # nil and false disable the filter return @filter = false unless value # rubocop:disable Lint/ReturnInVoidContext @filter = value.to_s.downcase end def initialize # rubocop:disable Lint/MissingSuper reset @filter = false end def reset @result = '' @keys = %w(text resource-id content-desc) end # http://nokogiri.org/Nokogiri/XML/SAX/Document.html def start_element(name, attrs = [], driver = $driver) return if filter && !name.downcase.include?(filter) attributes = {} attrs.each do |key, value| attributes[key] = value if keys.include?(key) && !value.empty? end # scoped to: text resource-id content-desc attributes_values = attributes.values strings = driver.lazy_load_strings id_matches = strings.empty? ? [] : strings.select { |_key, value| attributes_values.include? value } string_ids = nil if id_matches && !id_matches.empty? space_suffix = ' ' * 15 # 15 is ' strings.xml: '.length string_ids = '' # add first string_ids += "#{id_matches.shift[0]}\n" # use padding for remaining values # [0] = key, [1] = value id_matches.each do |match| string_ids += "#{space_suffix}#{match[0]}\n" end end string = '' text = attributes['text'] desc = attributes['content-desc'] id = attributes['resource-id'] if !text.nil? && text == desc string += " text, desc: #{text}\n" else string += " text: #{text}\n" unless text.nil? string += " desc: #{desc}\n" unless desc.nil? end string += " id: #{id}\n" unless id.nil? string += " strings.xml: #{string_ids}" unless string_ids.nil? @result += "\n#{name}\n#{string}" unless attributes.empty? end end # class AndroidElements # Android only. # Returns a string containing interesting elements. # The text, content description, and id are returned. # @param class_name [String] the class name to filter on. # if false (default) then all classes will be inspected # @return [String] def get_android_inspect(class_name = false) source = get_source doctype_string = '<!doctyp' source_header = source[0..doctype_string.length].downcase source_is_html = source_header.start_with?(doctype_string, '<html') parser = if source_is_html # parse html from webview @android_html_parser ||= Nokogiri::HTML::SAX::Parser.new(Appium::Common::HTMLElements.new) else @android_native_parser ||= Nokogiri::XML::SAX::Parser.new(AndroidElements.new) end parser.document.reset # ensure document is reset before parsing parser.document.filter = class_name parser.parse source result = parser.document.result parser.document.reset # clean up any created objects after parsing result end # Intended for use with console. # Inspects and prints the current page. # Will return XHTML for Web contexts because of a quirk with Nokogiri. # @option class [Symbol] the class name to filter on. case insensitive include match. # if nil (default) then all classes will be inspected # @return [void] def page(opts = {}) class_name = opts.is_a?(Hash) ? opts.fetch(:class, nil) : opts puts get_android_inspect class_name nil end # Find the first matching element by id # @param id [String] the id to search for # @return [Element] def id(id) # Android auto resolves strings.xml ids find_element :id, id end # Find all matching elements by id # @param id [String] the id to search for # @return [Element] def ids(id) # Android auto resolves strings.xml ids find_elements :id, id end # Find the element of type class_name at matching index. # @param class_name [String] the class name to find # @param index [Integer] the index # @return [Element] the found element of type class_name def ele_index(class_name, index) results = tags(class_name) if index == 'last()' index = results.length index -= 1 if index >= 0 else raise ArgumentError, 'Index must be >= 1' unless index >= 1 index -= 1 if index >= 1 end # uiautomator has issues with index/instance so calculate the index # client side. results[index] end # Find the first element that matches class_name # @param class_name [String] the tag to match # @return [Element] def first_ele(class_name) tag(class_name) end # Find the last element that matches class_name # @param class_name [String] the tag to match # @return [Element] def last_ele(class_name) ele_index class_name, 'last()' end # Find the first element of type class_name # # @param class_name [String] the class_name to search for # @return [Element] def tag(class_name) find_element :class, class_name end # Find all elements of type class_name # # @param class_name [String] the class_name to search for # @return [Element] def tags(class_name) find_elements :class, class_name end # @private # Detects if the string represents a resourceId # resourceId is only supported on API >= 18 devices # # @param string [String] the string check for a resourceId # value will be auto unquoted # @param on_match [String] the string to return on resourceId match # # @return [String] empty string on failure, on_match on successful match def resource_id(string, on_match) return '' unless string # unquote the string # "com.example.Test:id/enter" -> com.example.Test:id/enter unquote = string.match(/"(.+)"/) string = unquote[1] if unquote # java_package : type / name # # com.example.Test:id/enter # # ^[a-zA-Z_] - Java package must start with letter or underscore # [a-zA-Z0-9\._]* - Java package may contain letters, numbers, periods and underscores # : - : ends the package and starts the type # [^\/]+ - type is made up of at least one non-/ characters # \\/ - / ends the type and starts the name # [\S]+$ - the name contains at least one non-space character and then the line is ended resource_id = /^[a-zA-Z_][a-zA-Z0-9._]*:[^\/]+\/\S+$/ string.match(resource_id) ? on_match : '' end # Returns a string that matches the first element that contains value # For automationName is uiautomator2 # example: string_visible_contains_xpath 'UIATextField', 'sign in' # note for XPath: https://github.com/appium/ruby_lib/pull/561 # # @param class_name [String] the class name for the element # @param value [String] the value to search for # @return [String] def string_visible_contains_xpath(class_name, value) r_id = resource_id(value, " or @resource-id='#{value}'") if class_name == '*' return "//*[contains(translate(@text,'#{value.upcase}', '#{value}'), '#{value}') " \ "or contains(translate(@content-desc,'#{value.upcase}', '#{value}'), '#{value}')" + r_id + ']' end "//#{class_name}[contains(translate(@text,'#{value.upcase}', '#{value}'), '#{value}') " \ "or contains(translate(@content-desc,'#{value.upcase}', '#{value}'), '#{value}')" + r_id + ']' end # Returns a string that matches the first element that contains value # For automationName is Appium # example: string_visible_contains 'UIATextField', 'sign in' # note for XPath: https://github.com/appium/ruby_lib/pull/561 # # @param class_name [String] the class name for the element # @param value [String] the value to search for # @return [String] def string_visible_contains(class_name, value) value = %("#{value}") if class_name == '*' return (resource_id(value, "new UiSelector().resourceId(#{value});") + "new UiSelector().descriptionContains(#{value});" \ "new UiSelector().textContains(#{value});") end class_name = %("#{class_name}") resource_id(value, "new UiSelector().className(#{class_name}).resourceId(#{value});") + "new UiSelector().className(#{class_name}).descriptionContains(#{value});" \ "new UiSelector().className(#{class_name}).textContains(#{value});" end # Find the first element that contains value # @param class_name [String] the class name for the element # @param value [String] the value to search for # @return [Element] def complex_find_contains(class_name, value) find_element :uiautomator, string_visible_contains(class_name, value) end # Find all elements containing value # @param class_name [String] the class name for the element # @param value [String] the value to search for # @return [Array<Element>] def complex_finds_contains(class_name, value) find_elements :uiautomator, string_visible_contains(class_name, value) end # @private # Create an string to exactly match the first element with target value # For automationName is uiautomator2 # @param class_name [String] the class name for the element # @param value [String] the value to search for # @return [String] def string_visible_exact_xpath(class_name, value) r_id = resource_id(value, " or @resource-id='#{value}'") return "//*[@text='#{value}' or @content-desc='#{value}'" + r_id + ']' if class_name == '*' "//#{class_name}[@text='#{value}' or @content-desc='#{value}'" + r_id + ']' end # @private # Create an string to exactly match the first element with target value # @param class_name [String] the class name for the element # @param value [String] the value to search for # @return [String] def string_visible_exact(class_name, value) value = %("#{value}") if class_name == '*' return (resource_id(value, "new UiSelector().resourceId(#{value});") + "new UiSelector().description(#{value});" \ "new UiSelector().text(#{value});") end class_name = %("#{class_name}") resource_id(value, "new UiSelector().className(#{class_name}).resourceId(#{value});") + "new UiSelector().className(#{class_name}).description(#{value});" \ "new UiSelector().className(#{class_name}).text(#{value});" end # Find the first element exactly matching value # @param class_name [String] the class name for the element # @param value [String] the value to search for # @return [Element] def complex_find_exact(class_name, value) find_element :uiautomator, string_visible_exact(class_name, value) end # Find all elements exactly matching value # @param class_name [String] the class name for the element # @param value [String] the value to search for # @return [Element] def complex_finds_exact(class_name, value) find_elements :uiautomator, string_visible_exact(class_name, value) end end # module Android end # module Appium ================================================ FILE: lib/appium_lib/android/element/alert.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Android # Click the first alert button that contains value or by index. # @param value [Integer, String] either an integer index of the button or the button's name # @return [void] def alert_click(value) button(value).click end # Accept the alert. # The last button is considered "accept." # @return [void] def alert_accept last_button.click end # Get the text of the alert's accept button. # The last button is considered "accept." # @return [String] def alert_accept_text last_button.text end # Dismiss the alert. # The first button is considered "dismiss." # @return [void] def alert_dismiss first_button.click end # Get the text of the alert's dismiss button. # The first button is considered "dismiss." # @return [String] def alert_dismiss_text first_button.text end end # module Android end # module Appium ================================================ FILE: lib/appium_lib/android/element/button.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Android BUTTON = 'android.widget.Button' Button = BUTTON # backward compatibility IMAGE_BUTTON = 'android.widget.ImageButton' ImageButton = IMAGE_BUTTON # backward compatibility # Find the first button that contains value or by index. # @param value [String, Integer] the value to exactly match. # If int then the button at that index is returned. # @return [BUTTON] def button(value) # Don't use ele_index because that only works on one element type. # Android needs to combine button and image button to match iOS. if value.is_a? Numeric index = value raise ArgumentError, "#{index} is not a valid index. Must be >= 1" if index <= 0 # 1 indexed return find_element :uiautomator, _button_visible_selectors(index: index) end find_element :uiautomator, _button_contains_string(value) end # Find all buttons containing value. # If value is omitted, all buttons are returned. # @param value [String] the value to search for # @return [Array<BUTTON>] def buttons(value = false) return find_elements :uiautomator, _button_visible_selectors unless value find_elements :uiautomator, _button_contains_string(value) end # Find the first button. # @return [BUTTON] def first_button find_element :uiautomator, _button_visible_selectors(button_index: 0, image_button_index: 0) end # Find the last button. # @return [BUTTON] def last_button # uiautomator index doesn't support last # and it's 0 indexed button_index = tags(BUTTON).length button_index -= 1 if button_index.positive? image_button_index = tags(IMAGE_BUTTON).length image_button_index -= 1 if image_button_index.positive? find_element :uiautomator, _button_visible_selectors(button_index: button_index, image_button_index: image_button_index) end # Find the first button that exactly matches value. # @param value [String] the value to match exactly # @return [BUTTON] def button_exact(value) find_element :uiautomator, _button_exact_string(value) end # Find all buttons that exactly match value. # @param value [String] the value to match exactly # @return [Array<BUTTON>] def buttons_exact(value) find_elements :uiautomator, _button_exact_string(value) end private # @private def raise_no_such_element_if_empty(elements) raise _no_such_element if elements.empty? elements.first end def _button_visible_selectors(opts = {}) button_index = opts.fetch :button_index, false image_button_index = opts.fetch :image_button_index, false if button_index && image_button_index "new UiSelector().className(#{BUTTON}).instance(#{button_index});" \ "new UiSelector().className(#{IMAGE_BUTTON}).instance(#{image_button_index});" else "new UiSelector().className(#{BUTTON});" \ "new UiSelector().className(#{IMAGE_BUTTON});" end end def _button_exact_string(value) button = string_visible_exact BUTTON, value image_button = string_visible_exact IMAGE_BUTTON, value button + image_button end def _button_contains_string(value) button = string_visible_contains BUTTON, value image_button = string_visible_contains IMAGE_BUTTON, value button + image_button end end # module Android end # module Appium ================================================ FILE: lib/appium_lib/android/element/generic.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Android # Find the first element containing value # @param value [String] the value to search for # @return [Element] def find(value) complex_find_contains '*', value end # Find all elements containing value # @param value [String] the value to search for # @return [Array<Element>] def finds(value) complex_finds_contains '*', value end # Find the first element exactly matching value # @param value [String] the value to search for # @return [Element] def find_exact(value) complex_find_exact '*', value end # Find all elements exactly matching value # @param value [String] the value to search for # @return [Array<Element>] def finds_exact(value) complex_finds_exact '*', value end # @private def scroll_uiselector(content, index = 0) "new UiScrollable(new UiSelector().scrollable(true).instance(#{index})).scrollIntoView(#{content}.instance(0));" end # Scroll to the first element containing target text or description. # @param text [String] the text or resourceId to search for in the text value and content description # @param scrollable_index [Integer] the index for scrollable views. # @return [Element] the element scrolled to def scroll_to(text, scrollable_index = 0) text = %("#{text}") rid = resource_id(text, "new UiSelector().resourceId(#{text})") args = rid.empty? ? ["new UiSelector().textContains(#{text})", "new UiSelector().descriptionContains(#{text})"] : [rid] args.each_with_index do |arg, index| elem = find_element :uiautomator, scroll_uiselector(arg, scrollable_index) return elem rescue StandardError => e raise e if index == args.size - 1 end end # Scroll to the first element with the exact target text or description. # @param text [String] the text or resourceId to search for in the text value and content description # @param scrollable_index [Integer] the index for scrollable views. # @return [Element] the element scrolled to def scroll_to_exact(text, scrollable_index = 0) text = %("#{text}") rid = resource_id(text, "new UiSelector().resourceId(#{text})") args = rid.empty? ? ["new UiSelector().text(#{text})", "new UiSelector().description(#{text})"] : [rid] args.each_with_index do |arg, index| elem = find_element :uiautomator, scroll_uiselector(arg, scrollable_index) return elem rescue StandardError => e raise e if index == args.size - 1 end end end # module Android end # module Appium ================================================ FILE: lib/appium_lib/android/element/text.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # TextView methods module Appium module Android TEXT_VIEW = 'android.widget.TextView' TextView = TEXT_VIEW # Find the first TextView that contains value or by index. # @param value [String, Integer] the value to find. # If int then the TextView at that index is returned. # @return [TextView] def text(value) return ele_index TEXT_VIEW, value if value.is_a? Numeric complex_find_contains TEXT_VIEW, value end # Find all TextViews containing value. # If value is omitted, all texts are returned. # @param value [String] the value to search for # @return [Array<TEXT_VIEW>] def texts(value = false) return tags TEXT_VIEW unless value complex_finds_contains TEXT_VIEW, value end # Find the first TextView. # @return [TEXT_VIEW] def first_text first_ele TEXT_VIEW end # Find the last TextView. # @return [TEXT_VIEW] def last_text last_ele TEXT_VIEW end # Find the first TextView that exactly matches value. # @param value [String] the value to match exactly # @return [TEXT_VIEW] def text_exact(value) complex_find_exact TEXT_VIEW, value end # Find all TextViews that exactly match value. # @param value [String] the value to match exactly # @return [Array<TEXT_VIEW>] def texts_exact(value) complex_finds_exact TEXT_VIEW, value end end # module Android end # module Appium ================================================ FILE: lib/appium_lib/android/element/textfield.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Android EDIT_TEXT = 'android.widget.EditText' EditText = EDIT_TEXT # Find the first EditText that contains value or by index. # @param value [String, Integer] the text to match exactly. # If int then the EditText at that index is returned. # @return [EDIT_TEXT] def textfield(value) return ele_index EDIT_TEXT, value if value.is_a? Numeric complex_find_contains EDIT_TEXT, value end # Find all EditTexts containing value. # If value is omitted, all EditTexts are returned. # @param value [String] the value to search for # @return [Array<EDIT_TEXT>] def textfields(value = false) return tags EDIT_TEXT unless value complex_finds_contains EDIT_TEXT, value end # Find the first EditText. # @return [EDIT_TEXT] def first_textfield first_ele EDIT_TEXT end # Find the last EditText. # @return [EDIT_TEXT] def last_textfield last_ele EDIT_TEXT end # Find the first EditText that exactly matches value. # @param value [String] the value to match exactly # @return [EDIT_TEXT] def textfield_exact(value) complex_find_exact EDIT_TEXT, value end # Find all EditTexts that exactly match value. # @param value [String] the value to match exactly # @return [Array<EDIT_TEXT>] def textfields_exact(value) complex_finds_exact EDIT_TEXT, value end end # module Android end # module Appium ================================================ FILE: lib/appium_lib/android/espresso/bridge.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require_relative '../android' module Appium module Android module Espresso class Bridge def self.for(target) target.extend Appium::Android target.extend Appium::Android::Command target.extend Appium::Android::Espresso target.extend Appium::Android::Espresso::Helper target.extend Appium::Android::Espresso::Element end end end end end ================================================ FILE: lib/appium_lib/android/espresso/element/button.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Android module Espresso module Element # Find the first button that contains value or by index. # @param value [String, Integer] the value to exactly match. # If int then the button at that index is returned. # @return [Button] def button(value) # Don't use ele_index because that only works on one element type. # Android needs to combine button and image button to match iOS. if value.is_a? Numeric index = value raise ArgumentError, "#{index} is not a valid index. Must be >= 1" if index <= 0 # zero index _button_visible_selectors_xpath(index: index - 1) end i = find_elements :xpath, _button_contains_string_xpath(BUTTON, value) e = find_elements :xpath, _button_contains_string_xpath(IMAGE_BUTTON, value) raise_no_such_element_if_empty(i + e) (i + e)[0] end # Find all buttons containing value. # If value is omitted, all buttons are returned. # @param value [String] the value to search for # @return [Array<Button>] def buttons(value = false) return _button_visible_selectors_xpath unless value i = find_elements :xpath, _button_contains_string_xpath(BUTTON, value) e = find_elements :xpath, _button_contains_string_xpath(IMAGE_BUTTON, value) i + e end # Find the first button. # @return [Button] def first_button _button_visible_selectors_xpath(button_index: 0, image_button_index: 0) end # Find the last button. # @return [Button] def last_button # uiautomator index doesn't support last # and it's 0 indexed button_index = tags(::Appium::Android::BUTTON).length button_index -= 1 if button_index.positive? image_button_index = tags(::Appium::Android::IMAGE_BUTTON).length image_button_index -= 1 if image_button_index.positive? _button_visible_selectors_xpath(button_index: button_index, image_button_index: image_button_index) end # Find the first button that exactly matches value. # @param value [String] the value to match exactly # @return [Button] def button_exact(value) i = find_elements :xpath, _button_exact_string_xpath(BUTTON, value) e = find_elements :xpath, _button_exact_string_xpath(IMAGE_BUTTON, value) raise_no_such_element_if_empty(i + e) (i + e)[0] end # Find all buttons that exactly match value. # @param value [String] the value to match exactly # @return [Array<Button>] def buttons_exact(value) i = find_elements :xpath, _button_exact_string_xpath(BUTTON, value) e = find_elements :xpath, _button_exact_string_xpath(IMAGE_BUTTON, value) i + e end private # @private def raise_no_such_element_if_empty(elements) raise _no_such_element if elements.empty? elements.first end def _button_visible_selectors_xpath(opts = {}) button_index = opts.fetch :button_index, false image_button_index = opts.fetch :image_button_index, false index = opts.fetch :index, false b = find_elements :xpath, "//#{BUTTON}" i = find_elements :xpath, "//#{IMAGE_BUTTON}" if index raise_no_such_element_if_empty(b + i) (b + i)[index] elsif button_index && image_button_index raise_no_such_element_if_empty(b + i) b_index = button_index + image_button_index (b + i)[b_index] else b + i end end def _button_exact_string_xpath(class_name, value) r_id = resource_id(value, " or @resource-id='#{value}'") "//#{class_name}[@text='#{value}' or @content-desc='#{value}'#{r_id}]" end def _button_contains_string_xpath(class_name, value) r_id = resource_id(value, " or @resource-id='#{value}'") "//#{class_name}[contains(translate(@text,'#{value.upcase}', '#{value}'), '#{value}') " \ "or contains(translate(@content-desc,'#{value.upcase}', '#{value}'), '#{value}')#{r_id}]" end end # module Element end # module Espresso end # module Android end # module Appium ================================================ FILE: lib/appium_lib/android/espresso/element/generic.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Android module Espresso module Element # Scroll to the first element containing target text or description. # Scroll happens upto 30 times in centre of device width. # @param text [String] the text or resourceId to search for in the text value and content description # @return [Element] the element scrolled to def scroll_to(text) err = nil w_s = window_rect (1..30).each do |_count| action .move_to_location(w_s.width / 2, (w_s.height * 2) / 5) # pointer based magic number .pointer_down(:left) .move_to_location(0, w_s.height / 5) .release .perform sleep 1 # we must wait finish scrolling return text(text) rescue StandardError => e err = e end raise err end # Scroll to the first element with the exact target text or description. # Scroll happens upto 30 times in centre of device width. # @param text [String] the text or resourceId to search for in the text value and content description # @return [Element] the element scrolled to def scroll_to_exact(text) err = nil w_s = window_rect (1..30).each do |_count| action .move_to_location(w_s.width / 2, (w_s.height * 2) / 5) # pointer based magic number .pointer_down(:left) .move_to_location(0, w_s.height / 5) .release .perform sleep 1 # we must wait finish scrolling return text_exact(text) rescue StandardError => e err = e end raise err end end # module Element end # module Espresso end # module Android end # module Appium ================================================ FILE: lib/appium_lib/android/espresso/element.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require_relative 'element/generic' require_relative 'element/button' module Appium module Android module Espresso module Element end # module Element end # module Espresso end # module Android end # module Appium ================================================ FILE: lib/appium_lib/android/espresso/helper.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Android module Espresso module Helper # Find the first element that contains value # @param class_name [String] the class name for the element # @param value [String] the value to search for # @return [Element] def complex_find_contains(class_name, value) find_element :xpath, string_visible_contains_xpath(class_name, value) end # Find all elements containing value # @param class_name [String] the class name for the element # @param value [String] the value to search for # @return [Array<Element>] def complex_finds_contains(class_name, value) find_elements :xpath, string_visible_contains_xpath(class_name, value) end # Find the first element exactly matching value # @param class_name [String] the class name for the element # @param value [String] the value to search for # @return [Element] def complex_find_exact(class_name, value) find_element :xpath, string_visible_exact_xpath(class_name, value) end # Find all elements exactly matching value # @param class_name [String] the class name for the element # @param value [String] the value to search for # @return [Element] def complex_finds_exact(class_name, value) find_elements :xpath, string_visible_exact_xpath(class_name, value) end end # module Helper end # module Espresso end # module Android end # module Appium ================================================ FILE: lib/appium_lib/android/espresso.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require_relative 'espresso/helper' require_relative 'espresso/element' require_relative 'espresso/bridge' module Appium module Android module Espresso # parent end # module Espresso end # module Android end # module Appium ================================================ FILE: lib/appium_lib/android/uiautomator2/bridge.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require_relative '../android' module Appium module Android module Uiautomator2 class Bridge def self.for(target) target.extend Appium::Android target.extend Appium::Android::Command target.extend Appium::Android::Uiautomator2 target.extend Appium::Android::Uiautomator2::Helper target.extend Appium::Android::Uiautomator2::Element end end end end end ================================================ FILE: lib/appium_lib/android/uiautomator2/element/button.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Android module Uiautomator2 module Element # Find the first button that contains value or by index. # @param value [String, Integer] the value to exactly match. # If int then the button at that index is returned. # @return [Button] def button(value) # Don't use ele_index because that only works on one element type. # Android needs to combine button and image button to match iOS. if value.is_a? Numeric index = value raise ArgumentError, "#{index} is not a valid index. Must be >= 1" if index <= 0 result = find_elements :uiautomator, _button_visible_selectors(index: index) raise _no_such_element if result.empty? return result[value - 1] end elements = find_elements :uiautomator, _button_contains_string(value) raise_no_such_element_if_empty(elements) end # Find all buttons containing value. # If value is omitted, all buttons are returned. # @param value [String] the value to search for # @return [Array<Button>] def buttons(value = false) return find_elements :uiautomator, _button_visible_selectors unless value find_elements :uiautomator, _button_contains_string(value) end # Find the first button. # @return [Button] def first_button elements = find_elements :uiautomator, _button_visible_selectors(button_index: 0, image_button_index: 0) raise_no_such_element_if_empty(elements) end # Find the last button. # @return [Button] def last_button # uiautomator index doesn't support last # and it's 0 indexed button_index = tags(::Appium::Android::Button).length button_index -= 1 if button_index.positive? image_button_index = tags(::Appium::Android::ImageButton).length image_button_index -= 1 if image_button_index.positive? elements = find_elements :uiautomator, _button_visible_selectors(button_index: button_index, image_button_index: image_button_index) raise_no_such_element_if_empty(elements) end # Find the first button that exactly matches value. # @param value [String] the value to match exactly # @return [Button] def button_exact(value) elements = find_elements :uiautomator, _button_exact_string(value) raise_no_such_element_if_empty(elements) end # Find all buttons that exactly match value. # @param value [String] the value to match exactly # @return [Array<Button>] def buttons_exact(value) find_elements :uiautomator, _button_exact_string(value) end private # @private def raise_no_such_element_if_empty(elements) raise _no_such_element if elements.empty? elements.first end # @private def _button_visible_selectors(opts = {}) button_index = opts.fetch :button_index, false image_button_index = opts.fetch :image_button_index, false if button_index && image_button_index "new UiSelector().className(#{::Appium::Android::Button}).instance(#{button_index});" \ "new UiSelector().className(#{::Appium::Android::ImageButton}).instance(#{image_button_index});" else "new UiSelector().className(#{::Appium::Android::Button});" \ "new UiSelector().className(#{::Appium::Android::ImageButton});" end end # @private def _button_exact_string(value) button = string_visible_exact ::Appium::Android::Button, value image_button = string_visible_exact ::Appium::Android::ImageButton, value button + image_button end # @private def _button_contains_string(value) button = string_visible_contains ::Appium::Android::Button, value image_button = string_visible_contains ::Appium::Android::ImageButton, value button + image_button end end # module Element end # module Uiautomator2 end # module Android end # module Appium ================================================ FILE: lib/appium_lib/android/uiautomator2/element.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require_relative 'element/button' module Appium module Android module Uiautomator2 module Element end # module Element end # module Uiautomator2 end # module Android end # module Appium ================================================ FILE: lib/appium_lib/android/uiautomator2/helper.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Android module Uiautomator2 module Helper # Returns a string that matches the first element that contains value # For automationName is Appium # example: string_visible_contains 'UIATextField', 'sign in' # note for XPath: https://github.com/appium/ruby_lib/pull/561 # # @param class_name [String] the class name for the element # @param value [String] the value to search for # @return [String] def string_visible_contains(class_name, value) value = %("#{value}") if class_name == '*' return (resource_id(value, "new UiSelector().resourceId(#{value});") + "new UiSelector().descriptionContains(#{value});" \ "new UiSelector().textContains(#{value});") end class_name = %("#{class_name}") resource_id(value, "new UiSelector().className(#{class_name}).resourceId(#{value});") + "new UiSelector().className(#{class_name}).descriptionContains(#{value});" \ "new UiSelector().className(#{class_name}).textContains(#{value});" end # Find the first element that contains value # @param class_name [String] the class name for the element # @param value [String] the value to search for # @return [Element] def complex_find_contains(class_name, value) elements = find_elements :uiautomator, string_visible_contains(class_name, value) raise _no_such_element if elements.empty? elements.first end # Find all elements containing value # @param class_name [String] the class name for the element # @param value [String] the value to search for # @return [Array<Element>] def complex_finds_contains(class_name, value) find_elements :uiautomator, string_visible_contains(class_name, value) end # @private # Create an string to exactly match the first element with target value # @param class_name [String] the class name for the element # @param value [String] the value to search for # @return [String] def string_visible_exact(class_name, value) value = %("#{value}") if class_name == '*' return (resource_id(value, "new UiSelector().resourceId(#{value});") + "new UiSelector().description(#{value});" \ "new UiSelector().text(#{value});") end class_name = %("#{class_name}") resource_id(value, "new UiSelector().className(#{class_name}).resourceId(#{value});") + "new UiSelector().className(#{class_name}).description(#{value});" \ "new UiSelector().className(#{class_name}).text(#{value});" end # Find the first element exactly matching value # @param class_name [String] the class name for the element # @param value [String] the value to search for # @return [Element] def complex_find_exact(class_name, value) elements = find_elements :uiautomator, string_visible_exact(class_name, value) raise _no_such_element if elements.empty? elements.first end # Find all elements exactly matching value # @param class_name [String] the class name for the element # @param value [String] the value to search for # @return [Element] def complex_finds_exact(class_name, value) find_elements :uiautomator, string_visible_exact(class_name, value) end end # module Helper end # module Uiautomator2 end # module Android end # module Appium ================================================ FILE: lib/appium_lib/android/uiautomator2.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require_relative 'uiautomator2/helper' require_relative 'uiautomator2/element' require_relative 'uiautomator2/bridge' module Appium module Android module Uiautomator2 # parent end # module Uiautomator2 end # module Android end # module Appium ================================================ FILE: lib/appium_lib/appium.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'rubygems' require 'selenium-webdriver' require 'nokogiri' require 'appium_lib_core' # base require_relative 'driver' require_relative 'sauce_labs' # common require_relative 'common/wait' require_relative 'common/log' require_relative 'common/helper' require_relative 'common/http_client' require_relative 'common/device' require_relative 'common/command' # ios require_relative 'ios/ios' # android require_relative 'android/android' module Appium class << self # Load arbitrary text ([toml format](https://github.com/toml-lang/toml)) # The toml is parsed by https://github.com/fbernier/tomlrb . # # ``` # [caps] # app = "path/to/app" # # [appium_lib] # port = 8080 # ``` # # :app is expanded # :require is expanded # all keys are converted to symbols # # @param opts [Hash] file: '/path/to/appium.txt', verbose: true # @return [hash] the symbolized hash with updated :app and :require keys def load_settings(opts = {}) raise ArgumentError, 'opts must be a hash' unless opts.is_a? Hash raise ArgumentError, 'opts must not be empty' if opts.empty? toml = opts[:file] raise ArgumentError, 'Must pass a capability file which has [caps] and [appium_lib]' unless toml verbose = opts.fetch :verbose, false Appium::Logger.info "appium settings path: #{toml}" if verbose toml_exists = File.exist? toml Appium::Logger.info "Exists? #{toml_exists}" if verbose raise ArgumentError, "toml doesn't exist #{toml}" unless toml_exists require 'tomlrb' Appium::Logger.info "Loading #{toml}" if verbose data = Tomlrb.load_file(toml, symbolize_keys: true) Appium::Logger.info data if verbose && !data.empty? # FIXME: Deprecated. Will remove when we remove 'Appium::Driver.absolute_app_path' if data if data['caps'] if data['caps'][:app] && !data['caps'][:app].empty? data['caps'][:app] = Appium::Driver.absolute_app_path data elsif data['caps']['app'] && !data['caps']['app'].empty? data['caps']['app'] = Appium::Driver.absolute_app_path data end elsif data[:caps] if data[:caps][:app] && !data[:caps][:app].empty? data[:caps][:app] = Appium::Driver.absolute_app_path data elsif data[:caps]['app'] && !data[:caps]['app'].empty? data[:caps]['app'] = Appium::Driver.absolute_app_path data end end end if data && data[:appium_lib] && data[:appium_lib][:require] parent_dir = File.dirname toml data[:appium_lib][:require] = expand_required_files(parent_dir, data[:appium_lib][:require]) end data end # @see load_settings alias load_appium_txt load_settings # @param [String] base_dir parent directory of loaded appium.txt (toml) # @param [String] file_paths # @return [Array] list of require files as an array, nil if require doesn't exist def expand_required_files(base_dir, file_paths) # ensure files are absolute Array(file_paths).map! do |f| file = File.exist?(f) ? f : File.join(base_dir, f) file = File.expand_path file File.exist?(file) ? file : nil end file_paths.compact! # remove nils files = [] # now expand dirs file_paths.each do |item| unless File.directory? item # save file files << item next # only look inside folders end Dir.glob(File.expand_path(File.join(item, '**', '*.rb'))) do |f| # do not add folders to the file list files << File.expand_path(f) unless File.directory? f end end files end # This method is intended to work with page objects that share # a common module. For example, Page::HomePage, Page::SignIn # those could be promoted on with Appium.promote_singleton_appium_methods Page # # If you are promoting on an individual class then you should use # Appium.promote_appium_methods instead. The singleton method is intended # only for the shared module use case. # # if modules is a module instead of an array, then the constants of # that module are promoted on. # otherwise, the array of modules will be used as the promotion target. # # @param [Array<Module>] modules An array of modules # @param [Driver] driver A driver to extend for def promote_singleton_appium_methods(modules, driver = $driver) raise ArgumentError, 'Global $driver is nil' if driver.nil? target_modules = [] if modules.is_a? Module modules.constants.each do |sub_module| target_modules << modules.const_get(sub_module) end else raise ArgumentError, 'modules must be a module or an array' unless modules.is_a? Array target_modules = modules end target_modules.each do |const| # noinspection RubyResolve driver.public_methods(false).each do |m| # override unless there's an existing method with matching arity next if const.respond_to?(m) && const.method(m).arity == driver.method(m).arity const.send(:define_singleton_method, m) do |*args, &block| super(*args, &block) # promote.rb rescue NoMethodError, ArgumentError driver.send m, *args, &block if driver.respond_to?(m) end end end end ## # Promote appium methods to class instance methods # # @param [Array<Class>] class_array An array of classes # @param [Driver] driver A driver to extend for # # To promote methods to all classes: # # @example # # Appium.promote_appium_methods Object # # It's better to promote on specific classes instead of Object # # @example # # # promote on rspec # Appium.promote_appium_methods RSpec::Core::ExampleGroup # # @example # # # promote on minispec # Appium.promote_appium_methods Minitest::Spec # def promote_appium_methods(class_array, driver = $driver) raise ArgumentError, 'Driver is nil' if driver.nil? # Wrap single class into an array class_array = [class_array] unless class_array.instance_of? Array # Promote Appium driver methods to class instance methods. class_array.each do |klass| driver.public_methods(false).each do |method| klass.class_eval do # NOTE: Do not skip re-definding methods to not keep old instance information. # Probably the global driver ($driver) stuff needs to override (re-defined) # every time to not keep unexpected state. # https://github.com/appium/ruby_lib/issues/917 # Remove the method before adding it. remove_method method if method_defined? method define_method method do |*args, &block| # Prefer existing method. # super will invoke method missing on driver super(*args, &block) # minitest also defines a name method, # so rescue argument error # and call the name method on $driver rescue NoMethodError, ArgumentError if args.size == 1 && args.first.is_a?(Hash) # To prevent warnings by keyword arguments (for Ruby 2.7 and 3) driver.send method, **args.first, &block if driver.respond_to?(method) else ::Appium::Logger.warn "Should fix this '#{args}' for Ruby 2.7 (and 3)" if args.first.is_a?(Hash) driver.send method, *args, &block if driver.respond_to?(method) end end end end end nil # return nil end end # class << self end # module Appium ================================================ FILE: lib/appium_lib/common/command.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Common module Command # parent end end end ================================================ FILE: lib/appium_lib/common/device.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Device extend Forwardable end # module Device end # module Appium ================================================ FILE: lib/appium_lib/common/helper.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Generic helper methods not specific to a particular tag name module Appium module Common # iOS .name returns the accessibility attribute if it's set. if not set, the string value is used. # Android .name returns the accessibility attribute and nothing if it's not set. # # .text should be cross platform so prefer that over name, unless both # Android and iOS have proper accessibility attributes. # .text and .value should be the same so use .text over .value. # # secure class_name is iOS only because it can't be implemented using uiautomator for Android. # # find_element :text doesn't work so use XPath to find by text. # Return yield and ignore any exceptions. def ignore yield rescue Exception # rubocop:disable Lint/RescueException # Ignored end # Navigate back. # @return [void] def back @driver.navigate.back end # For Sauce Labs reporting. Returns the current session id. # @return [String] # # @example # # @driver.session_id #=> "some-session-ids" # def session_id @driver.session_id end # Returns the first element that matches the provided xpath. # # @param xpath_str [String] the XPath string # @return [Element] def xpath(xpath_str) @driver.find_element :xpath, xpath_str end # Returns all elements that match the provided xpath. # # @param xpath_str [String] the XPath string # @return [Array<Element>] def xpaths(xpath_str) @driver.find_elements :xpath, xpath_str end # json and ap are required for the source method. require 'json' # @private # http://nokogiri.org/Nokogiri/XML/SAX.html class CountElements < Nokogiri::XML::SAX::Document attr_reader :result def initialize(platform) # rubocop:disable Lint/MissingSuper reset @platform = platform end def reset @result = Hash.new 0 end # http://nokogiri.org/Nokogiri/XML/SAX/Document.html def start_element(name, attrs = []) element_visible = case @platform.to_sym when :android true else # :ios, :windows Hash[attrs]['visible'] == 'true' end @result[name] += 1 if element_visible end def formatted_result @result .sort_by { |_element, count| count } .reverse .reduce('') { |acc, element| "#{acc}#{element[1]}x #{element[0]}\n" } .strip end end # class CountElements # Returns a string of class counts of visible elements. # @return [String] # # @example # # get_page_class #=> "24x XCUIElementTypeStaticText\n12x XCUIElementTypeCell\n8x XCUIElementTypeOther\n # # 2x XCUIElementTypeWindow\n1x XCUIElementTypeStatusBar\n1x XCUIElementTypeTable\n1 # # x XCUIElementTypeNavigationBar\n1x XCUIElementTypeApplication" # def get_page_class parser = @count_elements_parser ||= Nokogiri::XML::SAX::Parser.new(CountElements.new(@core.device)) parser.document.reset parser.parse get_source parser.document.formatted_result end # Count all classes on screen and print to stdout. # Useful for appium_console. # @return [nil] # # @example # # page_class # # 24x XCUIElementTypeStaticText # # 12x XCUIElementTypeCell # # 8x XCUIElementTypeOther # # 2x XCUIElementTypeWindow # # 1x XCUIElementTypeStatusBar # # 1x XCUIElementTypeTable # # 1x XCUIElementTypeNavigationBar # # 1x XCUIElementTypeApplication # def page_class puts get_page_class nil end # Prints xml of the current page # @return [void] def source _print_source get_source end # Returns XML string for the current page # Same as driver.page_source # @return [String] def get_source @driver.page_source end # Converts pixel values to window relative values # # @example # # px_to_window_rel x: 50, y: 150 #=> #<OpenStruct x="50.0 / 375.0", y="150.0 / 667.0"> # def px_to_window_rel(opts = {}, driver = $driver) w = driver.window_size x = opts.fetch :x, 0 y = opts.fetch :y, 0 OpenStruct.new(x: "#{x.to_f} / #{w.width.to_f}", y: "#{y.to_f} / #{w.height.to_f}") end # @private def lazy_load_strings # app strings only works on local apps. # on disk apps (ex: com.android.settings) will error @lazy_load_strings ||= ignore { app_strings } || {} end # Search strings.xml's values for target. # @param target [String] the target to search for in strings.xml values # @return [Array] def xml_keys(target) lazy_load_strings @lazy_load_strings.select { |key, _value| key.downcase.include? target.downcase } end # Search strings.xml's keys for target. # @param target [String] the target to search for in strings.xml keys # @return [Array] def xml_values(target) lazy_load_strings @lazy_load_strings.select { |_key, value| value.downcase.include? target.downcase } end # Resolve id in strings.xml and return the value. # @param id [String] the id to resolve # @return [String] def resolve_id(id) lazy_load_strings @lazy_load_strings[id] end # @private class HTMLElements < Nokogiri::XML::SAX::Document attr_reader :filter # convert to string to support symbols def filter=(value) # nil and false disable the filter return @filter = false unless value # rubocop:disable Lint/ReturnInVoidContext @filter = value.to_s.downcase end def initialize # rubocop:disable Lint/MissingSuper reset @filter = false end def reset @element_stack = [] @elements_in_order = [] @skip_element = false end def result @elements_in_order.reduce('') do |r, e| name = e.delete :name attr_string = e.reduce('') do |string, attr| attr1 = attr[1] ? attr[1].strip : attr[1] "#{string} #{attr[0]}: #{attr1}\n" end return r if attr_string.nil? || attr_string.empty? "#{r}\n#{name}\n#{attr_string}" end end def start_element(name, attrs = []) @skip_element = filter && !filter.include?(name.downcase) return if @skip_element element = { name: name } attrs.each { |a| element[a[0]] = a[1] } @element_stack.push element @elements_in_order.push element end def end_element(name) return if filter && !filter.include?(name.downcase) element_index = @element_stack.rindex { |e| e[:name] == name } @element_stack.delete_at element_index end def characters(chars) return if @skip_element element = @element_stack.last element[:text] = chars end end # @private def _no_such_element error_message = 'An element could not be located on the page using the given search parameters.' raise Selenium::WebDriver::Error::NoSuchElementError, error_message end # @private def _print_source(source) opts = Nokogiri::XML::ParseOptions::NOBLANKS | Nokogiri::XML::ParseOptions::NONET doc = if source.start_with? '<html' Nokogiri::HTML(source) { |cfg| cfg.options = opts } else Nokogiri::XML(source) { |cfg| cfg.options = opts } end puts doc.to_xml indent: 2 end end end ================================================ FILE: lib/appium_lib/common/http_client.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'appium_lib_core' require_relative '../version' module Appium module Http class Default < ::Appium::Core::Base::Http::Default # Default HTTP client inherit Appium::Core::Base::Http::Default, but has different DEFAULT_HEADERS DEFAULT_HEADERS = { 'Accept' => CONTENT_TYPE, 'User-Agent' => "appium/ruby_lib/#{::Appium::VERSION}" }.freeze end end end ================================================ FILE: lib/appium_lib/common/log.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Common # @param [String|Hash] type You can get particular type's logs. # @return [[Selenium::WebDriver::LogEntry]] A list of logs data. # # @example # # @driver.get_log("syslog") #=> [[Selenium::WebDriver::LogEntry]] # @driver.get_log(:syslog) #=> [[Selenium::WebDriver::LogEntry]] # def get_log(type) @driver.logs.get type end # Get a list of available log types # # @return [[String]] A list of available log types. # # @example # # @driver.get_available_log_types #=> [:syslog, :crashlog, :performance] # def get_available_log_types @driver.logs.available_types end end # module Common end # module Appium ================================================ FILE: lib/appium_lib/common/wait.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'appium_lib_core' module Appium module Common class Wait include ::Appium::Core::Waitable end # Check every interval seconds to see if yield returns a truthy value. # Note this isn't a strict boolean true, any truthy value is accepted. # false and nil are considered failures. # Give up after timeout seconds. # # Wait code from the selenium Ruby gem # https://github.com/SeleniumHQ/selenium/blob/cf501dda3f0ed12233de51ce8170c0e8090f0c20/rb/lib/selenium/webdriver/common/wait.rb # # If only a number is provided then it's treated as the timeout value. # # @param [Hash|Numeric] opts Options. If the value is _Numeric_, the value is set as `{ timeout: value }` # @option opts [Numeric] :timeout Seconds to wait before timing out. Set default by `appium_wait_timeout` (30). # @option opts [Numeric] :interval Seconds to sleep between polls. Set default by `appium_wait_interval` (0.5). # @option opts [String] :message Exception message if timed out. # @option opts [Array, Exception] :ignore Exceptions to ignore while polling (default: Exception) # # @example # # wait_true(timeout: 20, interval: 0.2, message: 'custom message') { button_exact('Back') }.click # wait_true(20) { button_exact('Back') }.click # def wait_true(opts = {}) opts = { timeout: opts } if opts.is_a? Numeric if opts.is_a? Hash opts.empty? ? @core.wait_true { yield } : @core.wait_true(**opts) { yield } else ::Appium::Logger.warn('Arguments should be Hash like {timeout: 100}') end end # Check every interval seconds to see if yield doesn't raise an exception. # Give up after timeout seconds. # # Wait code from the selenium Ruby gem # https://github.com/SeleniumHQ/selenium/blob/cf501dda3f0ed12233de51ce8170c0e8090f0c20/rb/lib/selenium/webdriver/common/wait.rb # # If only a number is provided then it's treated as the timeout value. # # @param [Hash|Numeric] opts Options. If the value is _Numeric_, the value is set as `{ timeout: value }` # @option opts [Numeric] :timeout Seconds to wait before timing out. Set default by `appium_wait_timeout` (30). # @option opts [Numeric] :interval Seconds to sleep between polls. Set default by `appium_wait_interval` (0.5). # @option opts [String] :message Exception message if timed out. # @option opts [Array, Exception] :ignore Exceptions to ignore while polling (default: Exception) # # @example # # wait(timeout: 20, interval: 0.2, message: 'custom message') { button_exact('Back') }.click # wait(20) { button_exact('Back') }.click # def wait(opts = {}) opts = { timeout: opts } if opts.is_a? Numeric if opts.is_a? Hash opts.empty? ? @core.wait { yield } : @core.wait(**opts) { yield } else ::Appium::Logger.warn('Arguments should be Hash like {timeout: 100}') end end end end ================================================ FILE: lib/appium_lib/driver.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Load only Minitest is loaded if defined?(Minitest::VERSION) # Fix uninitialized constant Minitest (NameError) module Minitest # Fix superclass mismatch for class Spec class Runnable end begin class Test < Runnable end rescue TypeError => te # http://docs.seattlerb.org/minitest/History_rdoc.html#label-5.11.0+-2F+2018-01-01 # for 5.11.0/5.11.1 # `Minitest::Test` became a subclass of `Minitest::Result` raise TypeError, te.message unless te.message == 'superclass mismatch for class Test' class Test < Result end end end end require 'appium_lib_core' require 'uri' module Appium class Driver extend Forwardable # Methods forwarded to the underlying Appium::Core::Base::Driver instance # (exposed via `#driver`). Previously these were wired up implicitly by # `extend ::Appium::Core::Device` through a static compatibility list in # `ruby_lib_core` (see appium/ruby_lib_core#97). Defining them here lets # `ruby_lib_core` eventually drop that list. CORE_BRIDGE_METHODS = %i[ take_element_screenshot save_viewport_screenshot lock device_locked? unlock hide_keyboard is_keyboard_shown ime_activate ime_available_engines ime_active_engine ime_activated ime_deactivate get_settings update_settings within_context current_context available_contexts set_context push_file pull_file pull_folder keyevent press_keycode long_press_keycode match_images_features find_image_occurrence get_images_similarity compare_images app_strings background_app install_app remove_app app_installed? activate_app terminate_app app_state stop_recording_screen stop_and_save_recording_screen shake device_time execute_cdp ].freeze def_delegators :driver, *CORE_BRIDGE_METHODS # @private class << self def convert_to_symbol(value) if value.nil? value else value.to_sym end end # @private def get_cap(caps, name) name_with_prefix = "#{::Appium::Core::Base::Bridge::APPIUM_PREFIX}#{name}" caps[convert_to_symbol name] || caps[name] || caps[convert_to_symbol name_with_prefix] || caps[name_with_prefix] end end # attr readers are promoted to global scope. To avoid clobbering, they're # made available via the driver_attributes method # # attr_accessor is repeated for each one so YARD documents them properly. # The amount to sleep in seconds before every webdriver http call. attr_accessor :global_webdriver_http_sleep # SauceLab's settings attr_reader :sauce # Username for use on Sauce Labs. Set `false` to disable Sauce, even when SAUCE_USERNAME is in ENV. # same as @sauce.username attr_reader :sauce_username # Access Key for use on Sauce Labs. Set `false` to disable Sauce, even when SAUCE_ACCESS_KEY is in ENV. # same as @sauce.access_key attr_reader :sauce_access_key # Override the Sauce Appium endpoint to allow e.g. TestObject tests # same as @sauce.endpoint attr_reader :sauce_endpoint # from Core # read http://www.rubydoc.info/github/appium/ruby_lib_core/Appium/Core/Driver attr_reader :caps attr_reader :custom_url attr_reader :default_wait attr_reader :appium_port attr_reader :appium_device attr_reader :automation_name attr_reader :listener attr_reader :http_client attr_reader :appium_wait_timeout attr_reader :appium_wait_interval # Appium's server version attr_reader :appium_server_status # Boolean debug mode for the Appium Ruby bindings attr_reader :appium_debug # Returns the driver # @return [Driver] the driver attr_reader :driver # Instance of Appium::Core::Driver attr_reader :core # Creates a new driver. The driver is defined as global scope by default. # We can avoid defining global driver. # # @example # # require 'rubygems' # require 'appium_lib' # # # platformName takes a string or a symbol. # # Start iOS driver with global scope # opts = { # caps: { # platformName: :ios, # app: '/path/to/MyiOS.app' # }, # appium_lib: { # server_url: 'http://127.0.0.1:4723' # wait_timeout: 30 # } # } # appium_driver = Appium::Driver.new(opts, true) # appium_driver.start_driver # # # Start Android driver with global scope # opts = { # caps: { # platformName: :android, # app: '/path/to/my.apk' # }, # appium_lib: { # wait_timeout: 30, # wait_interval: 1 # } # } # appium_driver = Appium::Driver.new(opts, true) # appium_driver.start_driver # # # Start iOS driver without global scope # opts = { # caps: { # platformName: :ios, # app: '/path/to/MyiOS.app' # }, # appium_lib: { # wait_timeout: 30 # } # } # appium_driver = Appium::Driver.new(opts, false) # appium_driver.start_driver # # # Start iOS driver without global scope # opts = { # caps: { # platformName: :ios, # app: '/path/to/MyiOS.app' # }, # appium_lib: { # wait_timeout: 30 # }, # global_driver: false # } # appium_driver = Appium::Driver.new(opts) # appium_driver.start_driver # # @param opts [Object] A hash containing various options. # @param global_driver [Bool] A bool require global driver before initialize. # @return [Driver] def initialize(opts = {}, global_driver = false) # Capybara can't put `global_driver` as the 2nd argument. global_driver = opts.delete :global_driver if global_driver.nil? $driver&.driver_quit if global_driver raise ArgumentError, 'opts must be a hash' unless opts.is_a? Hash @core = ::Appium::Core.for(opts) extend ::Appium::Core::Device opts = Appium.symbolize_keys opts appium_lib_opts = opts[:appium_lib] || {} @caps = @core.caps @custom_url = @core.custom_url @default_wait = @core.default_wait || 0 @appium_port = @core.port @appium_wait_timeout = @core.wait_timeout @appium_wait_interval = @core.wait_interval @listener = @core.listener @appium_device = @core.device @automation_name = @core.automation_name # Arrange the app capability. This must be after @core = ::Appium::Core.for(opts) set_app_path(opts) # enable debug patch @appium_debug = appium_lib_opts.fetch :debug, !!defined?(Pry) # rubocop:disable Style/DoubleNegation set_sauce_related_values(appium_lib_opts) # Extend Common methods extend Appium::Common extend Appium::Device # Extend each driver's methods extend_for(device: @core.device, automation_name: @core.automation_name) # for command if @appium_debug Appium::Logger.debug opts unless opts.empty? Appium::Logger.debug "Debug is: #{@appium_debug}" Appium::Logger.debug "Device is: #{@core.device}" end # Save global reference to last created Appium driver for top level methods. $driver = self if global_driver self # rubocop:disable Lint/Void # return newly created driver end private # @private def extend_for(device:, automation_name:) case device when :android case automation_name when :uiautomator2 ::Appium::Android::Uiautomator2::Bridge.for(self) when :espresso ::Appium::Android::Espresso::Bridge.for(self) else # default and UiAutomator ::Appium::Android::Bridge.for(self) end when :ios, :tvos # default and XCUITest ::Appium::Ios::Xcuitest::Bridge.for(self) when :mac # no Mac specific extentions Appium::Logger.debug('mac') when :windows # no windows specific extentions Appium::Logger.debug('windows') when :tizen # https://github.com/Samsung/appium-tizen-driver Appium::Logger.debug('tizen') when :youiengine # https://github.com/YOU-i-Labs/appium-youiengine-driver Appium::Logger.debug('YouiEngine') else case automation_name when :youiengine # https://github.com/YOU-i-Labs/appium-youiengine-driver Appium::Logger.debug('YouiEngine') else Appium::Logger.debug('no device matched') # core also shows warning message end end end # @private # Deprecated. TODO: remove def set_app_path(opts) return unless @core.caps # return the path exists on the local app_path = Driver.get_cap(@core.caps, 'app') return if app_path.nil? return if File.exist?(app_path) @core.caps['app'] = self.class.absolute_app_path opts end # @private def set_sauce_related_values(appium_lib_opts) @sauce = Appium::SauceLabs.new(appium_lib_opts) @sauce_username = @sauce.username @sauce_access_key = @sauce.access_key @sauce_endpoint = @sauce.endpoint end public # Returns a hash of the driver attributes def driver_attributes { caps: @core.caps, automation_name: @core.automation_name, custom_url: @core.custom_url, default_wait: @default_wait, sauce_username: @sauce.username, sauce_access_key: @sauce.access_key, sauce_endpoint: @sauce.endpoint, port: @core.port, device: @core.device, debug: @appium_debug, listener: @listener, wait_timeout: @core.wait_timeout, wait_interval: @core.wait_interval } end def device_is_android? @core.device == :android end def device_is_ios? @core.device == :ios end def device_is_windows? @core.device == :windows end # Return true if automationName is 'uiautomator2' # @return [Boolean] def automation_name_is_uiautomator2? !@core.automation_name.nil? && @core.automation_name == :uiautomator2 end # Return true if automationName is 'Espresso' # @return [Boolean] def automation_name_is_espresso? !@core.automation_name.nil? && @core.automation_name == :espresso end # Return true if automationName is 'XCUITest' # @return [Boolean] def automation_name_is_xcuitest? !@core.automation_name.nil? && @core.automation_name == :xcuitest end # An entry point to chain W3C actions # Read https://www.rubydoc.info/github/appium/ruby_lib_core/Appium/Core/Base/Bridge/W3C#action-instance_method # # @return [Selenium::WebDriver::PointerActions] # # @example # # element = find_element(:id, "some id") # action.click(element).perform # The `click` is a part of `PointerActions` # def action @driver&.action end # Returns the server's version info # # @example # { # "build" => { # "version" => "0.18.1", # "revision" => "d242ebcfd92046a974347ccc3a28f0e898595198" # } # } # # @return [Hash] def appium_server_version @core.appium_server_version rescue Selenium::WebDriver::Error::WebDriverError => ex raise ::Appium::Core::Error::ServerError unless ex.message.include?('content-type=""') # server (TestObject for instance) does not respond to status call {} end alias remote_status appium_server_version # Return the platform version as an array of integers # @return [Array<Integer>] def platform_version return [] if @driver.nil? p_version = @driver.capabilities['platformVersion'] p_version.split('.').map(&:to_i) end # Returns the client's version info # # @example # # { # "version" => "9.1.1" # } # # @return [Hash] def appium_client_version { version: ::Appium::VERSION } end # [Deprecated] Converts app_path to an absolute path. # # opts is the full options hash (caps and appium_lib). If server_url is set # then the app path is used as is. # # if app isn't set then an error is raised. # # @return [String] APP_PATH as an absolute path def self.absolute_app_path(opts) raise ArgumentError, 'opts must be a hash' unless opts.is_a? Hash caps = opts[:caps] || opts['caps'] || {} app_path = get_cap(caps, 'app') raise ArgumentError, 'absolute_app_path invoked and app is not set!' if app_path.nil? || app_path.empty? # Sauce storage API. http://saucelabs.com/docs/rest#storage return app_path if app_path.start_with? 'sauce-storage:' return app_path if app_path =~ URI::DEFAULT_PARSER.make_regexp # public URL for Sauce ::Appium::Logger.warn('[Deprecation] Converting the path to absolute path will be removed. ' \ 'Please specify the full path which can be accessible from the appium server') absolute_app_path = File.expand_path app_path if File.exist? absolute_app_path absolute_app_path else ::Appium::Logger.info("Use #{app_path}") app_path end end # Get the server url # @return [String] the server url def server_url return @core.custom_url if @core.custom_url return @sauce.server_url if @sauce.sauce_server_url? "http://127.0.0.1:#{@core.port}" end # Restarts the driver # @return [Driver] the driver def restart driver_quit start_driver end # Takes a png screenshot and saves to the target path. # # @example # # screenshot '/tmp/hi.png' # # @param png_save_path [String] the full path to save the png # @return [File] def screenshot(png_save_path) @driver&.save_screenshot png_save_path end # Takes a png screenshot of particular element's area # # @example # # el = find_element :accessibility_id, zzz # element_screenshot el, '/tmp/hi.png' # # @param [String] element Element take a screenshot # @param [String] png_save_path the full path to save the png # @return [File] def element_screenshot(element, png_save_path) @driver&.take_element_screenshot element, png_save_path nil end # Quits the driver # @return [void] def driver_quit @driver&.quit @driver = nil rescue Selenium::WebDriver::Error::WebDriverError nil end alias quit_driver driver_quit # Get the device window's size. # @return [Selenium::WebDriver::Dimension] # # @example # # size = @driver.window_size # size.width #=> Integer # size.height #=> Integer # def window_size # maybe exception is expected as no driver created raise NoDriverInstanceError if @driver.nil? @driver.window_size end # Get the device window's rect. # @return [Selenium::WebDriver::Rectangle] # # @example # # size = @driver.window_size # size.width #=> Integer # size.height #=> Integer # size.x #=> Integer # size.y #=> Integer # def window_rect raise NoDriverInstanceError if @driver.nil? @driver.window_rect end # Creates a new global driver and quits the old one if it exists. # You can customise http_client as the following # # Read http://www.rubydoc.info/github/appium/ruby_lib_core/Appium/Core/Device to understand more what the driver # can call instance methods. # # @example # # require 'rubygems' # require 'appium_lib' # # # platformName takes a string or a symbol. # # Start iOS driver # opts = { # caps: { # platformName: :ios, # app: '/path/to/MyiOS.app' # }, # appium_lib: { # wait_timeout: 30 # } # } # appium_driver = Appium::Driver.new(opts) #=> return an Appium::Driver instance # appium_driver.start_driver #=> return an Appium::Core::Base::Driver # # @option http_client_ops [Hash] :http_client Custom HTTP Client # @option http_client_ops [Hash] :open_timeout Custom open timeout for http client. # @option http_client_ops [Hash] :read_timeout Custom read timeout for http client. # @return [Selenium::WebDriver] the new global driver def start_driver(http_client_ops = { http_client: nil, open_timeout: 999_999, read_timeout: 999_999 }) if http_client_ops[:http_client].nil? http_client = ::Appium::Http::Default.new(open_timeout: http_client_ops[:open_timeout], read_timeout: http_client_ops[:read_timeout]) end # TODO: do not kill the previous session in the future version. if $driver.nil? driver_quit else $driver.driver_quit end # If automationName is set only in server side, then the following automation_name should be nil before # starting driver. automation_name = @core.automation_name @driver = @core.start_driver(server_url: server_url, http_client_ops: { http_client: http_client, open_timeout: 999_999, read_timeout: 999_999 }) @http_client = @core.http_client # if automation_name was nil before start_driver, then re-extend driver specific methods # to be able to extend correctly. extend_for(device: @core.device, automation_name: @core.automation_name) if automation_name.nil? @appium_server_status = appium_server_version @driver end # To ignore error for Espresso Driver def set_implicit_wait(wait) @driver.manage.timeouts.implicit_wait = wait rescue Selenium::WebDriver::Error::UnknownError => e unless e.message.include?('The operation requested is not yet implemented by Espresso driver') raise ::Appium::Core::Error::ServerError end {} end # Set implicit wait to zero. def no_wait @driver&.manage&.timeouts&.implicit_wait = 0 end # Set implicit wait. Default to @default_wait. # # @example # # set_wait 2 # set_wait # @default_wait # # # @param timeout [Integer] the timeout in seconds # @return [void] def set_wait(timeout = nil) timeout = @default_wait if timeout.nil? @driver&.manage&.timeouts&.implicit_wait = timeout end # Returns existence of element. # # Example: # # exists { button('sign in') } ? puts('true') : puts('false') # # @param [Integer] pre_check The amount in seconds to set the # wait to before checking existence # @param [Integer] post_check The amount in seconds to set the # wait to after checking existence # @yield The block to call # @return [Boolean] def exists(pre_check = 0, post_check = @default_wait) # do not uset set_wait here. # it will cause problems with other methods reading the default_wait of 0 # which then gets converted to a 1 second wait. @driver&.manage&.timeouts&.implicit_wait = pre_check # the element exists unless an error is raised. exists = true begin yield # search for element rescue StandardError exists = false # error means it's not there end # restore wait @driver&.manage&.timeouts&.implicit_wait = post_check if post_check != pre_check exists end # The same as @driver.execute_script # @param [String] script The script to execute # @param [*args] args The args to pass to the script # @return [Object] def execute_script(script, *args) raise NoDriverInstanceError if @driver.nil? @driver.execute_script script, *args end ### # Wrap calling selenium webdrier APIs via ruby_core ### # Get the window handles of open browser windows def execute_async_script(script, *args) raise NoDriverInstanceError if @driver.nil? @driver.execute_async_script script, *args end # Run a set of script against the current session, allowing execution of many commands in one Appium request. # Supports {https://webdriver.io/docs/api.html WebdriverIO} API so far. # Please read {http://appium.io/docs/en/commands/session/execute-driver command API} for more details # about acceptable scripts and the output. # # @param [String] script The string consisting of the script itself # @param [String] type The name of the script type. # Defaults to 'webdriverio'. Depends on server implementation which type is supported. # @param [Integer] timeout_ms The number of `ms` Appium should wait for the script to finish # before killing it due to timeout. # # @return [Appium::Core::Base::Device::ExecuteDriver::Result] The script result parsed by # Appium::Core::Base::Device::ExecuteDriver::Result. # # @raise [::Selenium::WebDriver::Error::UnknownError] If something error happens in the script. # It has the original message. # # @example # script = <<~SCRIPT # const status = await driver.status(); # console.warn('warning message'); # return [status]; # SCRIPT # r = @@driver.execute_driver(script: script, type: 'webdriverio', timeout: 10_000) # r #=> An instance of Appium::Core::Base::Device::ExecuteDriver::Result # r.result #=> The `result` key part as the result of the script # r.logs #=> The `logs` key part as `{'log' => [], 'warn' => [], 'error' => []}` # def execute_driver(script: '', type: 'webdriverio', timeout_ms: nil) raise NoDriverInstanceError if @driver.nil? @driver.execute_driver(script: script, type: type, timeout_ms: timeout_ms) end def window_handles raise NoDriverInstanceError if @driver.nil? @driver.window_handles end # Get the current window handle def window_handle raise NoDriverInstanceError if @driver.nil? @driver.window_handle end def navigate raise NoDriverInstanceError if @driver.nil? @driver.navigate end def manage raise NoDriverInstanceError if @driver.nil? @driver.manage end def get(url) raise NoDriverInstanceError if @driver.nil? @driver.get(url) end def current_url raise NoDriverInstanceError if @driver.nil? @driver.current_url end def title raise NoDriverInstanceError if @driver.nil? @driver.title end # @return [TargetLocator] # @see TargetLocator def switch_to raise NoDriverInstanceError if @driver.nil? @driver.switch_to end ### # End core ### # Calls @driver.find_elements_with_appium # # @example # # @driver = Appium::Driver.new(opts, false) # @driver.start_driver # @driver.find_elements :predicate, yyy # # If you call `Appium.promote_appium_methods`, you can call `find_elements` directly. # # @example # # @driver = Appium::Driver.new(opts, false) # @driver.start_driver # @driver.find_elements :predicate, yyy # # If you call `Appium.promote_appium_methods`, you can call `find_elements` directly. # # @param [*args] args The args to use # @return [Array<Element>] Array is empty when no elements are found. def find_elements(*args) raise NoDriverInstanceError if @driver.nil? @driver.find_elements(*args) end # Calls @driver.find_element # # @example # # @driver = Appium::Driver.new(opts, false) # @driver.start_driver # @driver.find_element :accessibility_id, zzz # # If you call `Appium.promote_appium_methods`, you can call `find_element` directly. # # @param [*args] args The args to use # @return [Element] def find_element(*args) raise NoDriverInstanceError if @driver.nil? @driver.find_element(*args) end # Return ImageElement if current view has a partial image # # @param [String] png_img_path A path to a partial image you'd like to find # # @return [::Appium::Core::ImageElement] # @raise [::Appium::Core::Error::NoSuchElementError|::Appium::Core::Error::CoreError] No such element # # @example # # @driver.find_element_by_image './test/functional/data/test_element_image.png' # def find_element_by_image(png_img_path) raise NoDriverInstanceError if @driver.nil? @driver.find_element_by_image(png_img_path) end # Return ImageElement if current view has partial images # # @param [[String]] png_img_paths Paths to a partial image you'd like to find # # @return [[::Appium::Core::ImageElement]] # @return [::Appium::Core::Error::CoreError] # # @example # # @driver.find_elements_by_image ['./test/functional/data/test_element_image.png'] # def find_elements_by_image(png_img_paths) raise NoDriverInstanceError if @driver.nil? @driver.find_elements_by_image(png_img_paths) end # Calls @driver.set_location # # @note This method does not work on real devices. # # @param [Hash] opts consisting of: # @option opts [Float] :latitude the latitude in degrees (required) # @option opts [Float] :longitude the longitude in degees (required) # @option opts [Float] :altitude the altitude, defaulting to 75 # @return [Selenium::WebDriver::Location] the location constructed by the selenium webdriver def set_location(opts = {}) raise NoDriverInstanceError if @driver.nil? latitude = opts.fetch(:latitude) longitude = opts.fetch(:longitude) altitude = opts.fetch(:altitude, 75) @driver.set_location(latitude, longitude, altitude) end # @since Appium 1.16.0 # # Logs a custom event. The event is available via {::Appium::Core::Events#get}. # # @param [String] vendor The vendor prefix for the event # @param [String] event The name of event # @return [nil] # # @example # # log_event vendor: 'appium', event: 'funEvent' # # log_event = { vendor: 'appium', event: 'anotherEvent' } # log_events #=> {...., 'appium:funEvent' => [1572957315, 1572960305], # # 'appium:anotherEvent' => 1572959315} # def log_event(vendor:, event:) raise NoDriverInstanceError if @driver.nil? @driver.logs.event vendor: vendor, event: event end def log_event=(log_event) raise if @driver.nil? unless log_event.is_a?(Hash) raise ::Appium::Core::Error::ArgumentError('log_event should be Hash like { vendor: "appium", event: "funEvent"}') end @driver.logs.event vendor: log_event[:vendor], event: log_event[:event] end # @since Appium 1.16.0 # Returns events with filtering with 'type'. Defaults to all available events. # # @param [String] type The type of events to get # @return [Hash] # # @example # # log_events #=> {} # log_events #=> {'commands' => [{'cmd' => 123455, ....}], 'startTime' => 1572954894127, } # def log_events(type = nil) raise NoDriverInstanceError if @driver.nil? @driver.logs.events(type) end # Quit the driver and Pry. # quit and exit are reserved by Pry. # @return [void] def x driver_quit exit # exit pry end end # class Driver end # module Appium ================================================ FILE: lib/appium_lib/error.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium class Error < StandardError; end # Driver instance hasn't been created yet. class NoDriverInstanceError < Appium::Error; end class ArgumentError < ArgumentError; end end ================================================ FILE: lib/appium_lib/ios/common/errors.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Ios class CommandError < RuntimeError end end end ================================================ FILE: lib/appium_lib/ios/common/helper.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Ios # @private class UITestElementsPrinter < Nokogiri::XML::SAX::Document attr_accessor :filter def start_element(type, attrs = []) return if filter && !filter.eql?(type) page = attrs.each_with_object({}) do |attr, hash| hash[attr[0]] = attr[1] if %w(name label value hint visible).include?(attr[0]) hash end _print_attr(type, page['name'], page['label'], page['value'], page['hint'], page['visible']) end # @private def _print_attr(type, name, label, value, hint, visible) # rubocop:disable Metrics/ParameterLists puts type.to_s if name || label || value || hint || visible if name == label && name == value puts " name, label, value: #{name}" if name elsif name == label puts " name, label: #{name}" if name puts " value: #{value}" if value elsif name == value puts " name, value: #{name}" if name puts " label: #{label}" if label else puts " name: #{name}" if name puts " label: #{label}" if label puts " value: #{value}" if value end puts " hint: #{hint}" if hint puts " visible: #{visible}" if visible end end # iOS only. On Android uiautomator always returns an empty string for EditText password. # # Password character returned from value of UIASecureTextField # @param length [Integer] the length of the password to generate # @return [String] the returned string is of size length def ios_password(length = 1) 8226.chr('UTF-8') * length end # Prints a string of interesting elements to the console. # # @example # ```ruby # page class: :UIAButton # filter on buttons # page class: :UIAButton, window: 1 # ``` # # @option visible [Symbol] visible value to filter on # @option class [Symbol] class name to filter on # # @return [void] def page(opts = {}) class_name = opts.is_a?(Hash) ? opts.fetch(:class, nil) : opts source = get_source # current_context may be nil which breaks start_with if current_context&.start_with?('WEBVIEW') parser = @android_html_parser ||= Nokogiri::HTML::SAX::Parser.new(Appium::Common::HTMLElements.new) parser.document.reset parser.document.filter = class_name parser.parse source result = parser.document.result puts result result else parser = Nokogiri::XML::SAX::Parser.new(UITestElementsPrinter.new) if class_name parser.document.filter = class_name.is_a?(Symbol) ? class_name.to_s : class_name end parser.parse source nil end end # Find by id # @param id [String] the id to search for # @return [Element] def id(id) find_element(:id, id) end # Get the element of type class_name at matching index. # @param class_name [String] the class name to find # @param index [Integer] the index # @return [Element] def ele_index(class_name, index) raise ArgumentError, 'Index must be >= 1' unless index == 'last()' || (index.is_a?(Integer) && index >= 1) elements = tags(class_name) if index == 'last()' result = elements.last else # elements array is 0 indexed index -= 1 result = elements[index] end raise _no_such_element if result.nil? result end # @private def string_attr_exact(class_name, attr, value) %(//#{class_name}[@visible="true" and @#{attr}="#{value}"]) end # Find the first element exactly matching class and attribute value. # Note: Uses XPath # Note: For XCUITest, this method return ALL elements include displayed or not displayed elements. # @param class_name [String] the class name to search for # @param attr [String] the attribute to inspect # @param value [String] the expected value of the attribute # @return [Element] def find_ele_by_attr(class_name, attr, value) @driver.find_element :xpath, string_attr_exact(class_name, attr, value) end # Find all elements exactly matching class and attribute value. # Note: Uses XPath # Note: For XCUITest, this method return ALL elements include displayed or not displayed elements. # @param class_name [String] the class name to match # @param attr [String] the attribute to compare # @param value [String] the value of the attribute that the element must have # @return [Array<Element>] def find_eles_by_attr(class_name, attr, value) @driver.find_elements :xpath, string_attr_exact(class_name, attr, value) end # @private def string_attr_include(class_name, attr, value) %(//#{class_name}[@visible="true" and contains(translate(@#{attr},"#{value.upcase}", "#{value}"), "#{value}")]) end # Find the first element exactly matching attribute case insensitive value. # Note: Uses Predicate # @param value [String] the expected value of the attribute # @return [Element] def find_ele_by_predicate(class_name: '*', value:) elements = find_eles_by_predicate(class_name: class_name, value: value) raise _no_such_element if elements.empty? elements.first end # Find all elements exactly matching attribute case insensitive value. # Note: Uses Predicate # @param value [String] the value of the attribute that the element must have # @param class_name [String] the tag name to match # @return [Array<Element>] def find_eles_by_predicate(class_name: '*', value:) predicate = if class_name == '*' %(name == "#{value}" || label == "#{value}" || value == "#{value}") else %(type == "#{class_name}" && ) + %((name == "#{value}" || label == "#{value}" || value == "#{value}")) end @driver.find_elements :predicate, predicate end # Get the first tag by attribute that exactly matches value. # Note: Uses XPath # @param class_name [String] the tag name to match # @param attr [String] the attribute to compare # @param value [String] the value of the attribute that the element must include # @return [Element] the element of type tag who's attribute includes value def find_ele_by_attr_include(class_name, attr, value) @driver.find_element :xpath, string_attr_include(class_name, attr, value) end # Get tags by attribute that include value. # Note: Uses XPath # @param class_name [String] the tag name to match # @param attr [String] the attribute to compare # @param value [String] the value of the attribute that the element must include # @return [Array<Element>] the elements of type tag who's attribute includes value def find_eles_by_attr_include(class_name, attr, value) @driver.find_elements :xpath, string_attr_include(class_name, attr, value) end # Get the first elements that include insensitive value. # Note: Uses Predicate # @param value [String] the value of the attribute that the element must include # @return [Element] the element of type tag who's attribute includes value def find_ele_by_predicate_include(class_name: '*', value:) elements = find_eles_by_predicate_include(class_name: class_name, value: value) raise _no_such_element if elements.empty? elements.first end # Get elements that include case insensitive value. # Note: Uses Predicate # @param value [String] the value of the attribute that the element must include # @param class_name [String] the tag name to match # @return [Array<Element>] the elements of type tag who's attribute includes value def find_eles_by_predicate_include(class_name: '*', value:) predicate = if class_name == '*' %(name contains[c] "#{value}" || label contains[c] "#{value}" || value contains[c] "#{value}") else %(type == "#{class_name}" && ) + %((name contains[c] "#{value}" || label contains[c] "#{value}" || value contains[c] "#{value}")) end @driver.find_elements :predicate, predicate end # Get the first tag that matches class_name # @param class_name [String] the tag to match # @return [Element] def first_ele(class_name) ele_index class_name, 1 end # Get the last tag that matches class_name # @param class_name [String] the tag to match # @return [Element] def last_ele(class_name) ele_index class_name, 'last()' end # Returns the first **visible** element matching class_name # # @param class_name [String] the class_name to search for # @return [Element] def tag(class_name) ele_by_json(typeArray: [class_name], onlyVisible: true) end # Returns all visible elements matching class_name # # @param class_name [String] the class_name to search for # @return [Element] def tags(class_name) eles_by_json(typeArray: [class_name], onlyVisible: true) end # Returns all visible elements matching class_names and value # This method calls find_element/s and element.value/text many times. # So, if you set many class_names, this method's performance become worse. # # @param class_names [Array[String]] the class_names to search for # @param value [String] the value to search for # @return [Array[Element]] def tags_include(class_names:, value: nil) return unless class_names.is_a? Array class_names.flat_map do |class_name| value ? eles_by_json_visible_contains(class_name, value) : tags(class_name) end end # Returns all visible elements matching class_names and value. # This method calls find_element/s and element.value/text many times. # So, if you set many class_names, this method's performance become worse. # # @param class_names [Array[String]] the class_names to search for # @param value [String] the value to search for # @return [Array[Element]] def tags_exact(class_names:, value: nil) return unless class_names.is_a? Array class_names.flat_map do |class_name| value ? eles_by_json_visible_exact(class_name, value) : tags(class_name) end end # @private # Returns an object that matches the first element that contains value # # example: ele_by_json_visible_contains 'UIATextField', 'sign in' # # @param element [String] the class name for the element # @param value [String] the value to search for # @return [String] def string_visible_contains(element, value) contains = { target: value, substring: true, insensitive: true } { typeArray: [element], onlyVisible: true, name: contains, label: contains, value: contains } end # Find the first element that contains value. # For Appium(automation name), not XCUITest # @param element [String] the class name for the element # @param value [String] the value to search for # @return [Element] def ele_by_json_visible_contains(element, value) ele_by_json string_visible_contains element, value end # Find all elements containing value # For Appium(automation name), not XCUITest # @param element [String] the class name for the element # @param value [String] the value to search for # @return [Array<Element>] def eles_by_json_visible_contains(element, value) eles_by_json string_visible_contains element, value end # @private # Create an object to exactly match the first element with target value # @param element [String] the class name for the element # @param value [String] the value to search for # @return [String] def string_visible_exact(element, value) exact = { target: value, substring: false, insensitive: false } { typeArray: [element], onlyVisible: true, name: exact, label: exact, value: exact } end # Find the first element exactly matching value # For Appium(automation name), not XCUITest # @param element [String] the class name for the element # @param value [String] the value to search for # @return [Element] def ele_by_json_visible_exact(element, value) ele_by_json string_visible_exact element, value end # Find all elements exactly matching value # For Appium(automation name), not XCUITest # @param element [String] the class name for the element # @param value [String] the value to search for # @return [Element] def eles_by_json_visible_exact(element, value) eles_by_json string_visible_exact element, value end # # predicate - the predicate to evaluate on the main app # # visible - if true, only visible elements are returned. default true # def _all_pred(opts) predicate = opts[:predicate] raise ArgumentError, 'predicate must be provided' unless predicate visible = opts.fetch :visible, true %($.mainApp().getAllWithPredicate("#{predicate}", #{visible});) end # returns element matching predicate contained in the main app # # predicate - the predicate to evaluate on the main app # # visible - if true, only visible elements are returned. default true # @return [Element] def ele_with_pred(opts) # true = return only visible find_element(:uiautomation, _all_pred(opts)) end # returns elements matching predicate contained in the main app # # predicate - the predicate to evaluate on the main app # # visible - if true, only visible elements are returned. default true # @return [Array<Element>] def eles_with_pred(opts) find_elements(:uiautomation, _all_pred(opts)) end def _validate_object(*objects) raise ArgumentError, 'objects must be an array' unless objects.is_a? Array objects.each do |obj| next unless obj # obj may be nil. if so, ignore. valid_keys = %i[target substring insensitive] unknown_keys = obj.keys - valid_keys raise ArgumentError, "Unknown keys: #{unknown_keys}" unless unknown_keys.empty? target = obj[:target] raise ArgumentError, 'target must be a string' unless target.is_a? String substring = obj[:substring] raise ArgumentError, 'substring must be a boolean' unless [true, false].include? substring insensitive = obj[:insensitive] raise ArgumentError, 'insensitive must be a boolean' unless [true, false].include? insensitive end end # For Appium(automation name), not XCUITest # typeArray - array of string types to search for. Example: ["UIAStaticText"] # onlyFirst - boolean. returns only the first result if true. Example: true # onlyVisible - boolean. returns only visible elements if true. Example: true # target - string. the target value to search for. Example: "Buttons, Various uses of UIButton" # substring - boolean. matches on substrings if true otherwise an exact mathc is required. Example: true # insensitive - boolean. ignores case sensitivity if true otherwise it's case sensitive. Example: true # # opts = { # typeArray: ["UIAStaticText"], # onlyFirst: true, # onlyVisible: true, # name: { # target: "Buttons, Various uses of UIButton", # substring: false, # insensitive: false, # }, # label: { # target: "Buttons, Various uses of UIButton", # substring: false, # insensitive: false, # }, # value: { # target: "Buttons, Various uses of UIButton", # substring: false, # insensitive: false, # } # } # def _by_json(opts) valid_keys = %i(typeArray onlyFirst onlyVisible name label value) unknown_keys = opts.keys - valid_keys raise ArgumentError, "Unknown keys: #{unknown_keys}" unless unknown_keys.empty? type_array = opts[:typeArray] raise ArgumentError, 'typeArray must be an array' unless type_array.is_a? Array only_first = opts[:onlyFirst] raise ArgumentError, 'onlyFirst must be a boolean' unless [true, false].include? only_first only_visible = opts[:onlyVisible] raise ArgumentError, 'onlyVisible must be a boolean' unless [true, false].include? only_visible # name/label/value are optional. when searching for class only, then none # will be present. _validate_object opts[:name], opts[:label], opts[:value] # NOTE: that mainWindow is sometimes nil so it's passed as a param # $._elementOrElementsByType will validate that the window isn't nil element_or_elements_by_type = <<-JS (function() { var opts = #{opts.to_json}; var result = false; try { result = $._elementOrElementsByType($.mainWindow(), opts); } catch (e) { } return result; })(); JS res = execute_script element_or_elements_by_type res || raise(Appium::Ios::CommandError, 'mainWindow is nil') end # For Appium(automation name), not XCUITest # example usage: # # eles_by_json({ # typeArray: ["UIAStaticText"], # onlyVisible: true, # name: { # target: "Buttons, Various uses of UIButton", # substring: false, # insensitive: false, # }, # }) def eles_by_json(opts) opts[:onlyFirst] = false _by_json opts end # see eles_by_json def ele_by_json(opts) opts[:onlyFirst] = true result = _by_json(opts).first raise _no_such_element if result.nil? result end end # module Ios end # module Appium ================================================ FILE: lib/appium_lib/ios/element/alert.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Ios # Accept the alert. # @return [void] def alert_accept # @driver.switch_to.alert.accept # ".switch_to.alert" calls alert_text so use bridge directly driver.send(:bridge).accept_alert end # Dismiss the alert. # @return [void] def alert_dismiss # @driver.switch_to.alert.dismiss # ".switch_to.alert" calls alert_text so use bridge directly driver.send(:bridge).dismiss_alert end end # module Ios end # module Appium ================================================ FILE: lib/appium_lib/ios/element/button.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # XCUIElementTypeButton methods module Appium module Ios UIA_BUTTON = 'UIAButton' UIAButton = UIA_BUTTON XCUIELEMENT_TYPE_BUTTON = 'XCUIElementTypeButton' XCUIElementTypeButton = XCUIELEMENT_TYPE_BUTTON # @return [String] Class name for button def button_class UIA_BUTTON end # Find the first UIAButton|XCUIElementTypeButton that contains value or by index. # @param value [String, Integer] the value to exactly match. # If int then the UIAButton|XCUIElementTypeButton at that index is returned. # @return [UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON] def button(value) # return button at index. return ele_index button_class, value if value.is_a? Numeric ele_by_json_visible_contains button_class, value end # Find all UIAButtons|XCUIElementTypeButtons containing value. # If value is omitted, all UIAButtons|XCUIElementTypeButtons are returned. # @param value [String] the value to search for # @return [Array<UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON>] def buttons(value = false) return tags button_class unless value eles_by_json_visible_contains button_class, value end # Find the first UIAButton|XCUIElementTypeButton. # @return [UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON] def first_button first_ele button_class end # TODO: add documentation regarding previous element. # Previous UIAElement is differ from UIAButton|XCUIElementTypeButton. So, the results are different. # Find the last UIAButton|XCUIElementTypeButton. # @return [UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON] def last_button last_ele button_class end # Find the first UIAButton|XCUIElementTypeButton that exactly matches value. # @param value [String] the value to match exactly # @return [UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON] def button_exact(value) ele_by_json_visible_exact button_class, value end # Find all UIAButtons|XCUIElementTypeButtons that exactly match value. # @param value [String] the value to match exactly # @return [Array<UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON>] def buttons_exact(value) eles_by_json_visible_exact button_class, value end end # module Ios end # module Appium ================================================ FILE: lib/appium_lib/ios/element/generic.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Ios # Find the first element containing value # @param value [String] the value to search for # @return [Element] def find(value) ele_by_json_visible_contains '*', value end # Find all elements containing value # @param value [String] the value to search for # @return [Array<Element>] def finds(value) eles_by_json_visible_contains '*', value end # Find the first element exactly matching value # @param value [String] the value to search for # @return [Element] def find_exact(value) ele_by_json_visible_exact '*', value end # Find all elements exactly matching value # @param value [String] the value to search for # @return [Array<Element>] def finds_exact(value) eles_by_json_visible_exact '*', value end private def raise_error_if_no_element(element) error_message = 'An element could not be located on the page using the given search parameters.' raise(::Selenium::WebDriver::Error::NoSuchElementError, error_message) if element.nil? element end # Return visible elements. def select_visible_elements(elements) elements.select(&:displayed?) end end # module Ios end # module Appium ================================================ FILE: lib/appium_lib/ios/element/text.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # UIAStaticText|XCUIElementTypeStaticText methods module Appium module Ios UIA_STATIC_TEXT = 'UIAStaticText' UIAStaticText = UIA_STATIC_TEXT XCUIELEMENT_TYPE_STATIC_TEXT = 'XCUIElementTypeStaticText' XCUIElementTypeStaticText = XCUIELEMENT_TYPE_STATIC_TEXT # @return [String] Class name for text def static_text_class UIA_STATIC_TEXT end # Find the first UIAStaticText|XCUIElementTypeStaticText that contains value or by index. # @param value [String, Integer] the value to find. # If int then the UIAStaticText|XCUIElementTypeStaticText at that index is returned. # @return [UIA_STATIC_TEXT|XCUIELEMENT_TYPE_STATIC_TEXT] def text(value) return ele_index static_text_class, value if value.is_a? Numeric ele_by_json_visible_contains static_text_class, value end # Find all UIAStaticTexts|XCUIElementTypeStaticTexts containing value. # If value is omitted, all UIAStaticTexts|XCUIElementTypeStaticTexts are returned # @param value [String] the value to search for # @return [Array<UIA_STATIC_TEXT|XCUIELEMENT_TYPE_STATIC_TEXT>] def texts(value = false) return tags static_text_class unless value eles_by_json_visible_contains static_text_class, value end # Find the first UIAStaticText|XCUIElementTypeStaticText. # @return [UIA_STATIC_TEXT|XCUIELEMENT_TYPE_STATIC_TEXT] def first_text first_ele static_text_class end # Find the last UIAStaticText|XCUIElementTypeStaticText. # @return [UIA_STATIC_TEXT|XCUIELEMENT_TYPE_STATIC_TEXT] def last_text last_ele static_text_class end # Find the first UIAStaticText|XCUIElementTypeStaticText that exactly matches value. # @param value [String] the value to match exactly # @return [UIA_STATIC_TEXT|XCUIElementTypeStaticText] def text_exact(value) ele_by_json_visible_exact static_text_class, value end # Find all UIAStaticTexts|XCUIElementTypeStaticTexts that exactly match value. # @param value [String] the value to match exactly # @return [Array<UIA_STATIC_TEXT|XCUIElementTypeStaticText>] def texts_exact(value) eles_by_json_visible_exact static_text_class, value end end # module Ios end # module Appium ================================================ FILE: lib/appium_lib/ios/element/textfield.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Ios UIA_TEXT_FIELD = 'UIATextField' UIATextField = UIA_TEXT_FIELD UIA_SECURE_TEXT_FIELD = 'UIASecureTextField' UIASecureTextField = UIA_SECURE_TEXT_FIELD XCUIELEMENT_TYPE_TEXT_FIELD = 'XCUIElementTypeTextField' XCUIElementTypeTextField = XCUIELEMENT_TYPE_TEXT_FIELD XCUIELEMENT_TYPE_SECURE_TEXT_FIELD = 'XCUIElementTypeSecureTextField' XCUIElementTypeSecureTextField = XCUIELEMENT_TYPE_SECURE_TEXT_FIELD # @return [String] Class name for text field def text_field_class UIA_TEXT_FIELD end # @return [String] Class name for secure text field def secure_text_field_class UIA_SECURE_TEXT_FIELD end # Find the first TextField that contains value or by index. # Note: Uses XPath # @param value [String, Integer] the text to match exactly. # If int then the TextField at that index is returned. # @return [TextField] def textfield(value) if value.is_a? Numeric index = value raise ArgumentError, "#{index} is not a valid index. Must be >= 1" if index <= 0 index -= 1 # eles_by_json and _textfields_with_predicate is 0 indexed. result = eles_by_json(_textfield_visible)[index] raise _no_such_element if result.nil? return result end ele_by_json _textfield_contains_string value end # Find all TextFields containing value. # If value is omitted, all TextFields are returned. # @param value [String] the value to search for # @return [Array<TextField>] def textfields(value = false) return eles_by_json _textfield_visible unless value eles_by_json _textfield_contains_string value end # Find the first TextField. # @return [TextField] def first_textfield ele_by_json _textfield_visible end # Find the last TextField. # @return [TextField] def last_textfield result = eles_by_json(_textfield_visible).last raise _no_such_element if result.nil? result end # Find the first TextField that exactly matches value. # @param value [String] the value to match exactly # @return [TextField] def textfield_exact(value) ele_by_json _textfield_exact_string value end # Find all TextFields that exactly match value. # @param value [String] the value to match exactly # @return [Array<TextField>] def textfields_exact(value) eles_by_json _textfield_exact_string value end private # Appium def _textfield_visible { typeArray: [UIA_TEXT_FIELD, UIA_SECURE_TEXT_FIELD], onlyVisible: true } end # Appium def _textfield_exact_string(value) exact = { target: value, substring: false, insensitive: false } exact_obj = { name: exact, label: exact, value: exact } _textfield_visible.merge(exact_obj) end # Appium def _textfield_contains_string(value) contains = { target: value, substring: true, insensitive: true } contains_obj = { name: contains, label: contains, value: contains } _textfield_visible.merge(contains_obj) end end # module Ios end # module Appium ================================================ FILE: lib/appium_lib/ios/ios.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require_relative 'common/helper' require_relative 'common/errors' require_relative 'element/alert' require_relative 'element/button' require_relative 'element/generic' require_relative 'element/textfield' require_relative 'element/text' require_relative 'xcuitest' module Appium module Ios class Bridge def self.for(target) target.extend Appium::Ios end end end end ================================================ FILE: lib/appium_lib/ios/xcuitest/bridge.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require_relative '../ios' module Appium module Ios module Xcuitest class Bridge def self.for(target) target.extend Appium::Ios target.extend Appium::Ios::Xcuitest target.extend Appium::Ios::Xcuitest::PasteBoard target.extend Appium::Ios::Xcuitest::Source target.extend Appium::Ios::Xcuitest::Helper target.extend Appium::Ios::Xcuitest::Gesture target.extend Appium::Ios::Xcuitest::MultiAppHandler target.extend Appium::Ios::Xcuitest::Element target.extend Appium::Ios::Xcuitest::GetContext end end end end end ================================================ FILE: lib/appium_lib/ios/xcuitest/command/certificate.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'base64' module Appium module Ios module Xcuitest module Certificate # Generates Apple's over-the-air configuration profile for certificate deployment # based on the given PEM certificate content. # https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/iPhoneOTAConfiguration/Introduction/Introduction.html # https://github.com/appium/appium-xcuitest-driver/pull/652 # # @param [string] cer_file The content of the certificate file. # # @example # # install_certificate cer_file: "path/to/cert.cer" # def install_certificate(cer_file:) args = { content: Base64.encode64(cer_file) } @driver.execute_script 'mobile: installCertificate', args end end end # module Xcuitest end # module Ios end # module Appium ================================================ FILE: lib/appium_lib/ios/xcuitest/command/gestures.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Ios module Xcuitest module Gesture # @param [string] direction Either 'up', 'down', 'left' or 'right'. # @option opts [Element] :element Element to swipe on # # ```ruby # swipe direction: "down" # ``` def swipe(direction:, element: nil) args = { direction: direction } args[:element] = element.id if element @driver.execute_script 'mobile: swipe', args end # @param [string] direction Either 'up', 'down', 'left' or 'right'. # @option opts [Double] :distance scroll distance, proportional to scroll view height. # the value is supposed to be in between 0.0 and 1.0. # @option opts [String] :name the accessibility id of the child element, to which scrolling is performed. # @option opts [Element] :element Element id to long tap on. # @option opts [bool] :to_visible Boolean parameter. If set to true then asks to scroll to the first visible # element in the parent container. Has no effect if element is not set # @option opts [String] :predicate_string the NSPredicate locator of the child element, # to which the scrolling should be performed. Has no effect if element is not a container # # ```ruby # scroll direction: "down" # ``` # rubocop:disable Metrics/ParameterLists def scroll(direction:, distance: nil, name: nil, element: nil, to_visible: nil, predicate_string: nil) return 'Set "up", "down", "left" or "right" for :direction' unless %w(up down left right).include?(direction) args = { direction: direction } args[:element] = element.id if element args[:distance] = distance if distance args[:name] = name if name args[:toVisible] = to_visible if to_visible args[:predicateString] = predicate_string if predicate_string @driver.execute_script 'mobile: scroll', args end # rubocop:enable Metrics/ParameterLists # @param scale [scale] X tap coordinate of type float. Mandatory parameter # @param velocity [float] Y tap coordinate of type float. Mandatory parameter # @option opts [Element] :element Element id to long tap on. # # ```ruby # pinch scale: 0.5, velocity: -1 # ``` def pinch(scale:, velocity: 1.0, element: nil) args = { scale: scale, velocity: velocity } args[:element] = element.id if element @driver.execute_script 'mobile: pinch', args end # @param x [float] X Screen x tap coordinate of type float. Mandatory parameter only if element is not set # @param y [float] Y Screen y tap coordinate of type float. Mandatory parameter only if element is not set # @option opts [Element] :element Element to long tap on. # # ```ruby # double_tap x: 100, y: 100 # double_tap element: find_element(:accessibility_id, "some item") # ``` def double_tap(x: nil, y: nil, element: nil) return 'Set x, y or element' if (x.nil? || y.nil?) && element.nil? args = element.nil? ? { x: x, y: y } : { element: element.id } @driver.execute_script 'mobile: doubleTap', args end # @param x [float] Screen x long tap coordinate of type float. Mandatory parameter only if element is not set # @param y [float] Screen y long tap coordinate of type float. Mandatory parameter only if element is not set # @param duration [Float] The float duration of press action in seconds. Mandatory parameter # @option opts [Element] :element The internal element identifier (as hexadecimal hash string) to long tap on # # ```ruby # touch_and_hold x: 100, y: 100 # touch_and_hold x: 100, y: 100, duration: 2.0 # touch_and_hold element: find_element(:accessibility_id, "some item") # ``` def touch_and_hold(x: nil, y: nil, element: nil, duration: 1.0) return 'Set x, y or element' if (x.nil? || y.nil?) && element.nil? args = element.nil? ? { x: x, y: y } : { element: element.id } args[:duration] = duration @driver.execute_script 'mobile: touchAndHold', args end # @param [Element] element Element to long tap on. # # ```ruby # two_finger_tap element: find_element(:accessibility_id, "some item") # ``` def two_finger_tap(element:) args = { element: element.id } @driver.execute_script 'mobile: twoFingerTap', args end # @param x [float] X tap coordinate of type float. Mandatory parameter # @param y [float] Y tap coordinate of type float. Mandatory parameter # @option opts [Element] :element Element id to long tap on. x and y tap coordinates will be calculated # relatively to the current element position on the screen if this argument is provided. # Otherwise they should be calculated relatively to screen borders. # # ```ruby # one_finger_tap x: 100, y: 100 # one_finger_tap x: 100, y: 100, element: find_element(:accessibility_id, "some item") # ``` def one_finger_tap(x:, y:, element: nil) args = { x: x, y: y } args[:element] = element.id if element @driver.execute_script 'mobile: tap', args end # rubocop:disable Metrics/ParameterLists # @param duration [float] Float number of seconds in range [0.5, 60]. How long the tap gesture at starting # drag point should be before to start dragging. Mandatory parameter # @param from_x [float] The x coordinate of starting drag point (type float). Mandatory parameter # @param from_y [float] The y coordinate of starting drag point (type float). Mandatory parameter # @param to_x [float] The x coordinate of ending drag point (type float). Mandatory parameter # @param to_y [float] The y coordinate of ending drag point (type float). Mandatory parameter # @option opts [Element] :element Element id to perform drag on. All the coordinates will be calculated # relatively this this element position on the screen. Absolute screen coordinates are expected # if this argument is not set # # ```ruby # drag_from_to_for_duration from_x: 100, from_y: 100, to_x: 150, to_y: 150 # ``` def drag_from_to_for_duration(from_x:, from_y:, to_x:, to_y:, duration: 1.0, element: nil) args = { fromX: from_x, fromY: from_y, toX: to_x, toY: to_y, duration: duration } args[:element] = element.id if element @driver.execute_script 'mobile: dragFromToForDuration', args end # rubocop:enable Metrics/ParameterLists # https://github.com/facebook/WebDriverAgent/pull/523 # https://github.com/appium/appium-xcuitest-driver/pull/420 # @param order [String] The order to move picker to. "next" or "previous". # @param element [Element] Element id to perform select picker wheel on. # @option opts [Integer] :offset The value in range [0.01, 0.5]. Default is 0.2 in server side. # https://github.com/facebook/WebDriverAgent/pull/549/files # # ```ruby # select_picker_wheel order: "next", element: find_element(:accessibility_id, "some picker") # ``` def select_picker_wheel(element:, order:, offset: nil) return 'Set "next" or "previous" for :order' unless %w(next previous).include?(order) args = { element: element.id, order: order } args[:offset] = offset if offset @driver.execute_script 'mobile: selectPickerWheelValue', args end # @param action [String] The following actions are supported: accept, dismiss and getButtons. Mandatory parameter # @param button_label [String] The label text of an existing alert button to click on. # This is an optional parameter and is only valid in combination with accept and dismiss actions. # @return {} or Selenium::WebDriver::Error::NoSuchAlertError if no action sheet or alert # or button labels if action is equal to getButtons. # # ```ruby # alert action: "accept" # alert action: "dismiss" # ``` def alert(action:, button_label: nil) return 'Set "accept", "dismiss" or "getButtons" for :action' unless %w(accept dismiss getButtons).include?(action) args = { action: action } args[:button_label] if button_label @driver.execute_script 'mobile: alert', args end end # module Gesture end # module Xcuitest end # module Ios end # module Appium ================================================ FILE: lib/appium_lib/ios/xcuitest/command/get_context.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Ios module Xcuitest # Get the contexts available, with information about the url and title of each webview module GetContext # # Get contexts # # @example # # xcuitest_get_contexts #=> [{ 'id' => 'NATIVE_APP' }, # # { 'id' => 'WEBVIEW_41467.1', 'title' => 'Apple', 'url' => 'https://www.apple.com/' }] # def xcuitest_get_contexts @driver.execute_script 'mobile: getContexts', {} end end # module GetContext end # module Xcuitest end # module Ios end # module Appium ================================================ FILE: lib/appium_lib/ios/xcuitest/command/multi_app_handler.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Ios module Xcuitest # **Note** Works only for Xcode 9+. # Instance methods have `xcuitest_` prefix to prevent conflicts for core commands. # see: https://github.com/appium/ruby_lib_core/blob/82e2526de95b05e8a49872e0b69835e99acc66e5/lib/appium_lib_core/common/command.rb#L39 module MultiAppHandler # Installs given application to the device under test. If the same application is already installed # then it's going to be installed over it, which allows to test upgrades. # Be careful while reinstalling the main application under test - make sure you called terminateApp # for it first, otherwise WebDriverAgent will detect it as a potential application crash. # # @param [String] app The path to an existing .ipa/.app file on the server file system, zipped .app file # or an URL pointing to a remote .ipa/.zip file. Mandatory argument. # @return {} # # @example # # xcuitest_install_app(app: "path/to/app.app") # def xcuitest_install_app(app:) @driver.install_app app end # Verifies whether the application with given bundle identifier is installed on the device. # # @param [String] bundle_id The bundle identifier of the application, which is going to be verified. # @return [boolean] # # @example # # xcuitest_app_installed?(bundle_id: "io.appium.bundle") #=> true or false # def xcuitest_app_installed?(bundle_id:) @driver.app_installed? bundle_id end # Uninstalls an existing application from the device under test. This endpoint does not verify # whether the application is already installed or not before uninstalling it. # # @param [String] bundle_id The bundle identifier of the application, which is going to be uninstalled. # @return {} # # @example # # xcuitest_remove_app(bundle_id: "io.appium.bundle") #=> 1 # def xcuitest_remove_app(bundle_id:) @driver.remove_app bundle_id end # Executes an existing application on the device. If the application is already running then # it will be brought to the foreground. # # @param [String] bundle_id The bundle identifier of the application, which is going to be executed. # @return {} # # @example # # xcuitest_launch_app(bundle_id: "io.appium.bundle") #=> 1 # def xcuitest_launch_app(bundle_id:) args = { bundleId: bundle_id } @driver.execute_script 'mobile: launchApp', args end # Terminates an existing application on the device. If the application is not running then # the returned result will be false, otherwise true. # # @param [String] bundle_id The bundle identifier of the application, which is going to be terminated. # @return {} # # @example # # xcuitest_terminate_app(bundle_id: "io.appium.bundle") #=> 1 # def xcuitest_terminate_app(bundle_id:) @driver.terminate_app bundle_id end # Get the status of an existing application on the device. # State: # 0: The current application state cannot be determined/is unknown # 1: The application is not running # 2: The application is running in the background and is suspended # 3: The application is running in the background and is not suspended # 4: The application is running in the foreground # # For more details: https://developer.apple.com/documentation/xctest/xcuiapplicationstate # # @param [String] bundle_id A target app's bundle id # @return [0|1|2|3|4] A number of the state # # @example # # xcuitest_query_app_status(bundle_id: "io.appium.bundle") #=> 1 # def xcuitest_query_app_status(bundle_id:) @driver.app_state bundle_id end # Activates an existing application on the device under test and moves it to the foreground. # The application should be already running in order to activate it. # The call is ignored if the application is already in foreground. # # @param [String] bundle_id The bundle identifier of the application, which is going to be brought to the foreground. # @return {} # # @example # # xcuitest_activate_app(bundle_id: "io.appium.bundle") #=> 1 # def xcuitest_activate_app(bundle_id:) @driver.activate_app bundle_id end end end # module Xcuitest end # module Ios end # module Appium ================================================ FILE: lib/appium_lib/ios/xcuitest/command/pasteboard.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Ios module Xcuitest module PasteBoard # @param [string] content The content of the pasteboard. The previous content is going to be overridden. # The parameter is mandatory # @option opts [string] :encoding Encoding of the given content. UTF-8 by default. # # ```ruby # set_pasteboard content: "sample content" # ``` def set_pasteboard(content:, encoding: nil) args = { content: content } args[:encoding] = encoding if encoding @driver.execute_script 'mobile: setPasteboard', args end # @option opts [string] :encoding Encoding of the received pasteboard content. UTF-8 by default. # # ```ruby # get_pasteboard encoding: "shift-jis" # ``` def get_pasteboard(encoding: nil) args = {} args[:encoding] = encoding if encoding @driver.execute_script 'mobile: getPasteboard', args end end end # module Xcuitest end # module Ios end # module Appium ================================================ FILE: lib/appium_lib/ios/xcuitest/command/source.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Ios module Xcuitest # Instance method have `xcuitest_` prefix to prevent conflicts for core commands. module Source # @param [String|Symbol] format :xml or :json. :xml is by default. # # ```ruby # xcuitest_source format: :json # ``` def xcuitest_source(format: :xml) format = format.to_s if format.is_a? Symbol args = { format: format } @driver.execute_script 'mobile: source', args end end # module Gesture end # module Xcuitest end # module Ios end # module Appium ================================================ FILE: lib/appium_lib/ios/xcuitest/command.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require_relative 'command/pasteboard' require_relative 'command/gestures' require_relative 'command/source' require_relative 'command/multi_app_handler' require_relative 'command/get_context' ================================================ FILE: lib/appium_lib/ios/xcuitest/element/button.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # XCUIElementTypeButton methods module Appium module Ios module Xcuitest module Element # XCUIElementTypeButton = 'XCUIElementTypeButton' # @return [String] Class name for button def button_class ::Appium::Ios::XCUIELEMENT_TYPE_BUTTON end # Find the first UIAButton|XCUIElementTypeButton that contains value or by index. # @param value [String, Integer] the value to exactly match. # If int then the UIAButton|XCUIElementTypeButton at that index is returned. # @return [UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON] def button(value) # return button at index. return ele_index button_class, value if value.is_a? Numeric raise_error_if_no_element buttons(value).first end # Find all UIAButtons|XCUIElementTypeButtons containing value. # If value is omitted, all UIAButtons|XCUIElementTypeButtons are returned. # @param value [String] the value to search for # @return [Array<UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON>] def buttons(value = false) return tags button_class unless value elements = find_eles_by_predicate_include(class_name: button_class, value: value) select_visible_elements elements end # Find the first UIAButton|XCUIElementTypeButton. # @return [UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON] def first_button first_ele button_class end # TODO: add documentation regarding previous element. # Previous UIAElement is differ from UIAButton|XCUIElementTypeButton. So, the results are different. # Find the last UIAButton|XCUIElementTypeButton. # @return [UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON] def last_button last_ele button_class end # Find the first UIAButton|XCUIElementTypeButton that exactly matches value. # @param value [String] the value to match exactly # @return [UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON] def button_exact(value) raise_error_if_no_element buttons_exact(value).first end # Find all UIAButtons|XCUIElementTypeButtons that exactly match value. # @param value [String] the value to match exactly # @return [Array<UIA_BUTTON|XCUIELEMENT_TYPE_BUTTON>] def buttons_exact(value) elements = find_eles_by_predicate(class_name: button_class, value: value) select_visible_elements elements end end # moudule button end # module Xcuitest end # module Ios end # module Appium ================================================ FILE: lib/appium_lib/ios/xcuitest/element/generic.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Ios module Xcuitest module Element # Find the first element containing value # @param value [String] the value to search for # @return [Element] def find(value) raise_error_if_no_element finds(value).first end # Find all elements containing value # @param value [String] the value to search for # @return [Array<Element>] def finds(value) elements = find_eles_by_predicate_include value: value select_visible_elements elements end # Find the first element exactly matching value # @param value [String] the value to search for # @return [Element] def find_exact(value) raise_error_if_no_element finds_exact(value).first end # Find all elements exactly matching value # @param value [String] the value to search for # @return [Array<Element>] def finds_exact(value) elements = find_eles_by_predicate value: value select_visible_elements elements end private def raise_error_if_no_element(element) error_message = 'An element could not be located on the page using the given search parameters.' raise(::Selenium::WebDriver::Error::NoSuchElementError, error_message) if element.nil? element end # Return visible elements. def select_visible_elements(elements) elements.select(&:displayed?) end end # module Element end # module Xcuitest end # module Ios end # module Appium ================================================ FILE: lib/appium_lib/ios/xcuitest/element/text.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # UIAStaticText|XCUIElementTypeStaticText methods module Appium module Ios module Xcuitest module Element # XCUIELEMENT_TYPE_STATIC_TEXT = 'XCUIElementTypeStaticText' # @return [String] Class name for text def static_text_class ::Appium::Ios::XCUIELEMENT_TYPE_STATIC_TEXT end # Find the first UIAStaticText|XCUIElementTypeStaticText that contains value or by index. # @param value [String, Integer] the value to find. # If int then the UIAStaticText|XCUIElementTypeStaticText at that index is returned. # @return [UIA_STATIC_TEXT|XCUIELEMENT_TYPE_STATIC_TEXT] def text(value) return ele_index static_text_class, value if value.is_a? Numeric raise_error_if_no_element texts(value).first end # Find all UIAStaticTexts|XCUIElementTypeStaticTexts containing value. # If value is omitted, all UIAStaticTexts|XCUIElementTypeStaticTexts are returned # @param value [String] the value to search for # @return [Array<UIA_STATIC_TEXT|XCUIELEMENT_TYPE_STATIC_TEXT>] def texts(value = false) return tags static_text_class unless value elements = find_eles_by_predicate_include(class_name: static_text_class, value: value) select_visible_elements elements end # Find the first UIAStaticText|XCUIElementTypeStaticText. # @return [UIA_STATIC_TEXT|XCUIELEMENT_TYPE_STATIC_TEXT] def first_text first_ele static_text_class end # Find the last UIAStaticText|XCUIElementTypeStaticText. # @return [UIA_STATIC_TEXT|XCUIELEMENT_TYPE_STATIC_TEXT] def last_text last_ele static_text_class end # Find the first UIAStaticText|XCUIElementTypeStaticText that exactly matches value. # @param value [String] the value to match exactly # @return [UIA_STATIC_TEXT|XCUIELEMENT_TYPE_STATIC_TEXT] def text_exact(value) raise_error_if_no_element texts_exact(value).first end # Find all UIAStaticTexts|XCUIElementTypeStaticTexts that exactly match value. # @param value [String] the value to match exactly # @return [Array<UIA_STATIC_TEXT|XCUIELEMENT_TYPE_STATIC_TEXT>] def texts_exact(value) elements = find_eles_by_predicate(class_name: static_text_class, value: value) select_visible_elements elements end end # module Text end # module XCUITest end # module Ios end # module Appium ================================================ FILE: lib/appium_lib/ios/xcuitest/element/textfield.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Ios module Xcuitest module Element # XCUIElementTypeTextField = 'XCUIElementTypeTextField' # XCUIElementTypeSecureTextField = 'XCUIElementTypeSecureTextField' # @return [String] Class name for text field def text_field_class ::Appium::Ios::XCUIELEMENT_TYPE_TEXT_FIELD end # @return [String] Class name for secure text field def secure_text_field_class ::Appium::Ios::XCUIELEMENT_TYPE_SECURE_TEXT_FIELD end # Find the first TextField that contains value or by index. # Note: Uses XPath # @param value [String, Integer] the text to match exactly. # If int then the TextField at that index is returned. # @return [TextField] def textfield(value) if value.is_a? Numeric index = value raise ArgumentError, "#{index} is not a valid index. Must be >= 1" if index <= 0 index -= 1 # eles_by_json and _textfields_with_predicate is 0 indexed. result = _textfields_with_predicate[index] raise _no_such_element if result.nil? return result end raise_error_if_no_element textfields(value).first end # Find all TextFields containing value. # If value is omitted, all TextFields are returned. # @param value [String] the value to search for # @return [Array<TextField>] def textfields(value = false) return tags_include(class_names: [text_field_class, secure_text_field_class]) unless value elements = tags_include class_names: [text_field_class, secure_text_field_class], value: value select_visible_elements elements end # Find the first TextField. # @return [TextField] def first_textfield _textfield_with_predicate end # Find the last TextField. # @return [TextField] def last_textfield result = _textfields_with_predicate.last raise _no_such_element if result.nil? result end # Find the first TextField that exactly matches value. # @param value [String] the value to match exactly # @return [TextField] def textfield_exact(value) raise_error_if_no_element textfields_exact(value).first end # Find all TextFields that exactly match value. # @param value [String] the value to match exactly # @return [Array<TextField>] def textfields_exact(value) elements = tags_exact class_names: [text_field_class, secure_text_field_class], value: value select_visible_elements elements end private # @private # for XCUITest def _textfield_with_predicate raise_error_if_no_element _textfields_with_predicate.first end # @private # for XCUITest def _textfields_with_predicate elements = tags_include(class_names: [text_field_class, secure_text_field_class]) select_visible_elements elements end end # module TextField end # module XCUITest end # module Ios end # module Appium ================================================ FILE: lib/appium_lib/ios/xcuitest/element.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require_relative 'element/text' require_relative 'element/textfield' require_relative 'element/generic' require_relative 'element/button' module Appium module Ios module Xcuitest module Element # no end # module Element end # module Xcuitest end # module Ios end # module Appium ================================================ FILE: lib/appium_lib/ios/xcuitest/helper.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium module Ios module Xcuitest module Helper # @private def string_attr_exact(class_name, attr, value) if attr == '*' %((//#{class_name})[@*[.="#{value}"]]) else %((//#{class_name})[@#{attr}="#{value}"]) end end # @private def string_attr_include(class_name, attr, value) if attr == '*' %((//#{class_name})[@*[contains(translate(., "#{value.upcase}", "#{value}"), "#{value}")]]) else %((//#{class_name})[contains(translate(@#{attr}, "#{value.upcase}", "#{value}"), "#{value}")]) end end # Get the last tag that matches class_name # @param class_name [String] the tag to match # @return [Element] def last_ele(class_name) visible_elements = tags class_name raise _no_such_element if visible_elements.empty? visible_elements.last end # Returns the first **visible** element matching class_name # # @param class_name [String] the class_name to search for # @return [Element] def tag(class_name) raise_error_if_no_element tags(class_name).first end # Returns all visible elements matching class_name # # @param class_name [String] the class_name to search for # @return [Element] def tags(class_name) elements = @driver.find_elements :class, class_name select_visible_elements elements end # Returns all visible elements matching class_names and value # This method calls find_element/s and element.value/text many times. # So, if you set many class_names, this method's performance become worse. # # @param class_names [Array[String]] the class_names to search for # @param value [String] the value to search for # @return [Array[Element]] def tags_include(class_names:, value: nil) return unless class_names.is_a? Array c_names = class_names.map { |class_name| %(type == "#{class_name}") }.join(' || ') predicate = if value %((#{c_names}) && (name contains[c] "#{value}" || label contains[c] "#{value}" || value contains[c] "#{value}")) # rubocop:disable Layout/LineLength else c_names end elements = @driver.find_elements :predicate, predicate select_visible_elements elements end # Returns all visible elements matching class_names and value. # This method calls find_element/s and element.value/text many times. # So, if you set many class_names, this method's performance become worse. # # @param class_names [Array[String]] the class_names to search for # @param value [String] the value to search for # @return [Array[Element]] def tags_exact(class_names:, value: nil) return unless class_names.is_a? Array c_names = class_names.map { |class_name| %(type == "#{class_name}") }.join(' || ') predicate = if value %((#{c_names}) && (name ==[c] "#{value}" || label ==[c] "#{value}" || value ==[c] "#{value}")) else c_names end elements = @driver.find_elements :predicate, predicate select_visible_elements elements end end # module Helper end # module Xcuitest end # module Ios end # module Appium ================================================ FILE: lib/appium_lib/ios/xcuitest.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require_relative 'xcuitest/element' require_relative 'xcuitest/command' require_relative 'xcuitest/helper' require_relative 'xcuitest/bridge' module Appium module Ios module Xcuitest # parent end # module Xcuitest end # module Ios end # module Appium ================================================ FILE: lib/appium_lib/sauce_labs.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium class SauceLabs # Username for use on Sauce Labs. Set `false` to disable Sauce, even when SAUCE_USERNAME is in ENV. attr_reader :username # Access Key for use on Sauce Labs. Set `false` to disable Sauce, even when SAUCE_ACCESS_KEY is in ENV. attr_reader :access_key # Override the Sauce Appium endpoint to allow e.g. TestObject tests. Default is 'ondemand.saucelabs.com:443/wd/hub'. attr_reader :endpoint # # Create a SauceLabs instance to manage sauce labs related attributes. # # @param [Hash] appium_lib_opts Appium library parameter # @return [Appium::SauceLabs] # # @example # # opts_blank = {} # sauce_labs_blank = Appium::SauceLabs.new(opts_blank) # sauce_labs_blank.username #=> nil # sauce_labs_blank.access_key #=> nil # sauce_labs_blank.endpoint #=> "ondemand.saucelabs.com:443/wd/hub" # # opts = { sauce_username: "user-name", # sauce_access_key: "access-key-to-sauce-labs", # sauce_endpoint: "ondemand.other_saucelabs.com:443/wd/hub", # } # sauce_labs = Appium::SauceLabs.new(opts) # sauce_labs.username #=> "user-name" # sauce_labs.access_key #=> "access-key-to-sauce-labs" # sauce_labs.endpoint #=> "ondemand.other-saucelabs.com:443/wd/hub" # def initialize(appium_lib_opts) @username = appium_lib_opts.fetch :sauce_username, ENV.fetch('SAUCE_USERNAME', nil) @username = nil if !@username || (@username.is_a?(String) && @username.empty?) @access_key = appium_lib_opts.fetch :sauce_access_key, ENV.fetch('SAUCE_ACCESS_KEY', nil) @access_key = nil if !@access_key || (@access_key.is_a?(String) && @access_key.empty?) @endpoint = appium_lib_opts.fetch :sauce_endpoint, ENV.fetch('SAUCE_ENDPOINT', nil) @endpoint = 'ondemand.saucelabs.com:443/wd/hub' if !@endpoint || (@endpoint.is_a?(String) && @endpoint.empty?) end # # Return true if an instance of Appium::SauceLabs has sauce_username and sauce_access_key. # @return [Boolean] # # @example # # sauce_labs_blank.sauce_server_url? #=> false # sauce_labs.sauce_server_url? #=> true # def sauce_server_url? !username.nil? && !access_key.nil? end # # Return a particular server url to access to. Default is the local address. # @return [String] # # @example # # sauce_labs_blank.server_url #=> "http://127.0.0.1:4723/wd/hub" # sauce_labs.server_url #=> "https://user-name:access-key-to-sauce-labs@ondemand.other-saucelabs.com:443/wd/hub" # def server_url sauce_server_url? ? "https://#{username}:#{access_key}@#{endpoint}" : 'http://127.0.0.1:4723/wd/hub' end end end ================================================ FILE: lib/appium_lib/version.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Appium # Version and Date are defined on the 'Appium' module, not 'Appium::Common' VERSION = '16.2.0' unless defined? ::Appium::VERSION DATE = '2026-04-19' unless defined? ::Appium::DATE end ================================================ FILE: lib/appium_lib.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Enforce UTF-8 Encoding Encoding.default_external = Encoding::UTF_8 Encoding.default_internal = Encoding::UTF_8 require 'forwardable' unless defined? Forwardable # Init global driver $driver = nil require_relative 'appium_lib/appium' ================================================ FILE: readme.md ================================================ # appium_lib [![Gem Version](https://badge.fury.io/rb/appium_lib.svg)](http://badge.fury.io/rb/appium_lib) [![Downloads](https://img.shields.io/gem/dt/appium_lib.svg)](https://rubygems.org/gems/appium_lib) - [appium_lib on RubyGems](https://rubygems.org/gems/appium_lib) - [Documentation for appium_lib](https://www.rubydoc.info/github/appium/ruby_lib) - [Documentation for core lib](http://www.rubydoc.info/github/appium/ruby_lib_core) - Especially [driver method for Appium](http://www.rubydoc.info/github/appium/ruby_lib_core/Appium/Core/Device) Helper 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. **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. Ordinary, `ruby_lib` worked with class driver, `$driver`, mainly. We 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. # Setup ## Requirement - [Appium](https://github.com/appium/appium#requirements) - Ruby: 3.0+ ### Ruby Lib and Appium - Ruby library version over `12.0.0` is based on Selenium v4 - Please read [changelog of 12.0.0](CHANGELOG.md#1200---2021-11-06) for more details to migrate from v11 to v12 - Ruby library version over `9.8.0` requires Appium over `1.8` - Ruby library version under `9.7.5` can work with Appium under `1.7` ## Start appium server ### Appium 2 ```bash $ npm install --location=global appium $ appium driver install xcuitest # proper driver name to install $ appium server ``` > **Note** Please set `server_url` properly like the below for Appium v1. > ``` > opts = { > caps: { > automationName: 'xcuitest' > platformName: 'ios', > app: '/path/to/MyiOS.app' > }, > appium_lib: { > server_url: 'http://127.0.0.1:4723/wd/hub' > } > } > appium_driver = Appium::Driver.new(opts) > appium_driver.start_driver > ``` ### Appium 1 ```bash $ npm install -g appium $ appium ``` ## Install / Upgrade ```bash gem install appium_lib ``` ## [Sauce Labs env vars](https://github.com/appium/ruby_lib/blob/master/lib/appium_lib/sauce_labs.rb) - `SAUCE_USERNAME` Sauce username - `SAUCE_ACCESS_KEY` Sauce API key - `SAUCE_ENDPOINT` Alternative Sauce Appium Server endpoint (only use if directed) (Note: If these variables are set, all tests will use Sauce Labs unless over-ridden in configuration.) # Documentation - [Getting started](https://github.com/appium/appium) - [Overview](https://github.com/appium/ruby_lib/blob/master/docs/docs.md) - [Ruby Android methods](https://github.com/appium/ruby_lib/blob/master/docs/android_docs.md) - [Ruby iOS methods](https://github.com/appium/ruby_lib/blob/master/docs/ios_docs.md) - [Tips for XCUITest for iOS](https://github.com/appium/ruby_lib/blob/master/docs/ios_xcuitest.md) # Related libraries - [ruby_lib_core](https://github.com/appium/ruby_lib_core): Bridged commands, WebDriver dependencies - We add new endpoints for Appium in the core library, and `ruby_lib` call the methods. - [ruby_console](https://github.com/appium/ruby_console): Appium Ruby Console - [appium_capybara](https://github.com/appium/appium_capybara): Gem enabling appium support in capybara # Load Pry `Pry.config.pager = false` is set if you have no `.pryrc` files and `Pry` is defined. # Run tests in parallel This repository has examples for running tests in parallel. Read [ios_tests](https://github.com/appium/ruby_lib/tree/master/ios_tests) to see them. # Contribute ## How to add new commands for `driver` - 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) ## How to add new helpful methods - Add the new methods in this library ================================================ FILE: release_notes.md ================================================ #### v16.2.0 2026-04-19 - [939a204](https://github.com/appium/ruby_lib/commit/939a20461738c80f9a19bb9ee8fe41030ab6c91e) Release 16.2.0 - [324b646](https://github.com/appium/ruby_lib/commit/324b646adcf182b92cad66bd53ec8f7b1892b34f) feat: define device methods natively on Appium::Driver (#1109) - [5e60d97](https://github.com/appium/ruby_lib/commit/5e60d973ca74fe25af3b58ad7dcf9ce46d209b08) chore: Update rubocop requirement from 1.86.0 to 1.86.1 (#1108) - [76a85fd](https://github.com/appium/ruby_lib/commit/76a85fde1c05b5a479179d07e062a2ca9b18d48d) chore: Bump actions/cache from 4 to 5 (#1107) - [555767c](https://github.com/appium/ruby_lib/commit/555767cf885f49705cfeea8be4688f7bddb08cd7) ci: add android (#1106) - [59a27af](https://github.com/appium/ruby_lib/commit/59a27af6c3c2bbfd37664e59d2a9e3322250199c) feat: drop deprecated start_logs_broadcast/stop_logs_broadcast methods (#1105) - [4bd31dc](https://github.com/appium/ruby_lib/commit/4bd31dc1b15de6dccb80a5eb2f70e5c592af7293) chore: Update rubocop requirement from 1.85.1 to 1.86.0 (#1104) - [070e4e3](https://github.com/appium/ruby_lib/commit/070e4e34294e1d2a6bf57519493e4f47d96a7fae) chore: Update rubocop requirement from 1.85.0 to 1.85.1 (#1103) - [e624cea](https://github.com/appium/ruby_lib/commit/e624cea7ab88fd543f77d63517eb0fc4b3d138fe) chore: Bump futureware-tech/simulator-action from 4 to 5 (#1102) - [6192589](https://github.com/appium/ruby_lib/commit/6192589e4379e4405d6dbf0c99fb583544be996c) chore: Update rubocop requirement from 1.84.2 to 1.85.0 (#1101) - [211cb0b](https://github.com/appium/ruby_lib/commit/211cb0bfb746b51db6f24d27a7d1ae8153fc6937) chore: Update rubocop requirement from 1.84.1 to 1.84.2 (#1100) - [56e092d](https://github.com/appium/ruby_lib/commit/56e092de3ff7c4c29a2cf9f63672563f60f5457f) chore: Update rubocop requirement from 1.84.0 to 1.84.1 (#1099) - [858cacb](https://github.com/appium/ruby_lib/commit/858cacb2675dcfd7935bee7c8fc9dbfd6eae60c1) chore: Update rubocop requirement from 1.82.1 to 1.84.0 (#1098) - [0451b50](https://github.com/appium/ruby_lib/commit/0451b50e15723b649d92f4f1476d5b575ed92482) ci: add pr title check - [d5a27a8](https://github.com/appium/ruby_lib/commit/d5a27a8de9fcca37accd851686c6a8a90a40b374) chore: Update rubocop requirement from 1.82.0 to 1.82.1 (#1097) #### v16.1.1 2025-12-28 - [2efaf09](https://github.com/appium/ruby_lib/commit/2efaf0937dfaf3759d370607fdea05c890df634a) Release 16.1.1 - [121316f](https://github.com/appium/ruby_lib/commit/121316f8c74cbcdab6073c7b7cb8ef5b46f28bb6) chore: add deprecated in docstrings for start_logs_broadcast/stop_logs_broadcast (#1095) - [2736ab2](https://github.com/appium/ruby_lib/commit/2736ab2cb77cf7a149bd2e933f1c5af5e5e6c8cc) ci: use ruby v4 (#1094) - [0fe4fbc](https://github.com/appium/ruby_lib/commit/0fe4fbce26f71211e15eea11ff624b1fbeb23767) chore: Update rubocop requirement from 1.81.7 to 1.82.0 (#1093) - [5676f33](https://github.com/appium/ruby_lib/commit/5676f338c399cddc41f3b830d82eccd7a955466c) chore: Bump futureware-tech/simulator-action from 3 to 4 (#1092) - [9b7b69b](https://github.com/appium/ruby_lib/commit/9b7b69b26c20b0dd23a218d4994cac634504fb08) chore: Bump actions/setup-node from 3 to 6 (#1091) - [00d640d](https://github.com/appium/ruby_lib/commit/00d640dd460a013a924b27a2865d605563f44e2d) chore: Bump actions/checkout from 3 to 6 (#1090) - [2272004](https://github.com/appium/ruby_lib/commit/2272004b6127b49bc555bdf13a61fd8370f0adec) ci: add github actions dependabot config - [0ffe7d4](https://github.com/appium/ruby_lib/commit/0ffe7d48eddf59817686cf72b2811af11d7b34c3) chore: Update rubocop requirement from 1.81.6 to 1.81.7 (#1089) - [1b9628c](https://github.com/appium/ruby_lib/commit/1b9628c0098499e5c0c763f2f1e63578ce1a3dae) chore: Update rubocop requirement from 1.81.1 to 1.81.6 (#1088) - [99d15ca](https://github.com/appium/ruby_lib/commit/99d15ca8e0339da425f2cc93c360fbd1e4231453) chore: Update rubocop requirement from 1.81.0 to 1.81.1 (#1087) - [94f8d72](https://github.com/appium/ruby_lib/commit/94f8d72e251b3513db7c1ddd6009cef76c6b620f) chore: Update rubocop requirement from 1.80.2 to 1.81.0 (#1086) - [31a7747](https://github.com/appium/ruby_lib/commit/31a77475ce32fe1cfb61e8a9e5b8c9c4671603fb) chore: Update rubocop requirement from 1.80.1 to 1.80.2 (#1084) - [38c0dcb](https://github.com/appium/ruby_lib/commit/38c0dcb248a5cd8e458027304c6a3fb11f97cf95) ci: use newer dependencies (#1085) - [e925497](https://github.com/appium/ruby_lib/commit/e925497539a5cfa374a1855642bcf524f3cbdb0d) chore: Update rubocop requirement from 1.80.0 to 1.80.1 (#1083) - [a3b6a09](https://github.com/appium/ruby_lib/commit/a3b6a09bf6faf9ac870704b6430412113d2d9262) chore: Update rubocop requirement from 1.79.2 to 1.80.0 (#1082) - [dfa1010](https://github.com/appium/ruby_lib/commit/dfa10104bcd8f1e477f8aa8da5437ae89df2a330) chore: Update rubocop requirement from 1.79.1 to 1.79.2 (#1081) - [454dcfb](https://github.com/appium/ruby_lib/commit/454dcfb4cea592a7e295b787f2c6f9c8d78a53b1) chore: Update rubocop requirement from 1.79.0 to 1.79.1 (#1080) - [facc0db](https://github.com/appium/ruby_lib/commit/facc0db652c1f5d4c82d7b5be7dfdf80fba4d509) chore: Update rubocop requirement from 1.78.0 to 1.79.0 (#1079) - [d9df353](https://github.com/appium/ruby_lib/commit/d9df35303244433576026b17db1388a1b1135b05) chore: Update rubocop requirement from 1.77.0 to 1.78.0 (#1078) - [8d3b64c](https://github.com/appium/ruby_lib/commit/8d3b64c09ff623791255f93910f16f2d4c26d132) chore: Update rubocop requirement from 1.76.2 to 1.77.0 (#1077) - [83283a9](https://github.com/appium/ruby_lib/commit/83283a98f0e396d25d4c9b6d9eb65a14a1b043e1) chore: Update rubocop requirement from 1.76.1 to 1.76.2 (#1076) - [f92405a](https://github.com/appium/ruby_lib/commit/f92405a943139284ab189a50f189714e56244e9b) chore: Update rubocop requirement from 1.76.0 to 1.76.1 (#1075) - [a8cf9da](https://github.com/appium/ruby_lib/commit/a8cf9daa6e1703a9adef7c62e3f061ecdf345101) chore: Update rubocop requirement from 1.75.8 to 1.76.0 (#1074) - [1e3c2f6](https://github.com/appium/ruby_lib/commit/1e3c2f6bec7e84be3f05095ac09421be25c5f940) chore: Update rubocop requirement from 1.75.7 to 1.75.8 (#1073) - [48c869e](https://github.com/appium/ruby_lib/commit/48c869e660c0701cf659ca2965286070629b2cf7) chore: Update rubocop requirement from 1.75.6 to 1.75.7 (#1072) - [a7dbd63](https://github.com/appium/ruby_lib/commit/a7dbd63df5c19f8d0a03d8f35a22d64ac95550bf) chore: Update hashdiff requirement from ~> 1.1.0 to ~> 1.2.0 (#1071) - [710884d](https://github.com/appium/ruby_lib/commit/710884d4eaffa7a2d62615907934ab35e19e3639) chore: Update rubocop requirement from 1.75.5 to 1.75.6 (#1070) - [6e58d17](https://github.com/appium/ruby_lib/commit/6e58d17499371b8e4bfed9a57922ba9f94ca0c9f) chore: Update rubocop requirement from 1.75.4 to 1.75.5 (#1069) - [0398421](https://github.com/appium/ruby_lib/commit/039842150019d0e844542551ada80256ebaf18ab) chore: Update rubocop requirement from 1.75.3 to 1.75.4 (#1068) - [2f73e58](https://github.com/appium/ruby_lib/commit/2f73e5810cb9f4430a8baa39bfd2d959a333819a) chore: Update rubocop requirement from 1.75.2 to 1.75.3 (#1067) - [17b591b](https://github.com/appium/ruby_lib/commit/17b591b1e78a092431b597ba43bb7085616391ed) chore: Update rubocop requirement from 1.75.1 to 1.75.2 (#1066) - [b49421a](https://github.com/appium/ruby_lib/commit/b49421a28dfaa40f22e6dc45a59b85de2b27cad0) chore: Update rubocop requirement from 1.74.0 to 1.75.1 (#1065) #### v16.1.0 2025-03-27 - [caca559](https://github.com/appium/ruby_lib/commit/caca559c1fb70d0376860a5b8590c71e33eb453f) Release 16.1.0 - [1673d38](https://github.com/appium/ruby_lib/commit/1673d38e38fab8f510f494564810723508ff8ff7) feat: allow including ruby lib core 11 (#1064) #### v16.0.1 2025-03-16 - [97de309](https://github.com/appium/ruby_lib/commit/97de309bd6a60b22e2937b51086f7e7491e035cc) Release 16.0.1 - [8a0bc17](https://github.com/appium/ruby_lib/commit/8a0bc17f0352f158cbb80c44676f90ec1b57e287) chore: allow appium lib core to use 10 - [ea9f6ab](https://github.com/appium/ruby_lib/commit/ea9f6ab852896a43e01c57ea608334806cc8834f) chore: Update rubocop requirement from 1.73.2 to 1.74.0 (#1062) - [7ed65df](https://github.com/appium/ruby_lib/commit/7ed65dfbbacba5093476139629bd828e1b9f67a9) chore: Update rubocop requirement from 1.73.0 to 1.73.2 (#1061) - [7c1f16c](https://github.com/appium/ruby_lib/commit/7c1f16c7f3441879c7c1836c4a63336e276da066) chore: Update rubocop requirement from 1.72.2 to 1.73.0 (#1059) - [2524c42](https://github.com/appium/ruby_lib/commit/2524c42c626473bdfac846905e42eabf889570bd) chore: Update rubocop requirement from 1.72.1 to 1.72.2 (#1058) - [7294b88](https://github.com/appium/ruby_lib/commit/7294b887dd744e107217840144ead4e4a137f9bc) chore: Update rubocop requirement from 1.71.2 to 1.72.1 (#1056) #### v16.0.0 2025-02-16 - [f260936](https://github.com/appium/ruby_lib/commit/f26093663056bee2c170d74283928b517d5071dc) Release 16.0.0 - [134af92](https://github.com/appium/ruby_lib/commit/134af92efc674377940c82d7f819b4eb98816653) feat: drop `/wd/hub` from the default url config (#1055) - [1f7f8cb](https://github.com/appium/ruby_lib/commit/1f7f8cb82ad6499421125d1ca1aabb601af5a869) chore: Update rubocop requirement from 1.71.1 to 1.71.2 (#1054) - [fcfc777](https://github.com/appium/ruby_lib/commit/fcfc777eef0b4909896506b83ceeef02702e9811) chore: Update rubocop requirement from 1.71.0 to 1.71.1 (#1053) - [34f0695](https://github.com/appium/ruby_lib/commit/34f069526befbd9d449bea27aae0bd2172557abe) chore: Update rubocop requirement from 1.70.0 to 1.71.0 (#1052) - [c48681c](https://github.com/appium/ruby_lib/commit/c48681cdc6ccceda612b735457b4496946eab8c6) chore: Update fakefs requirement from ~> 2.8.0 to ~> 3.0.0 (#1050) #### v15.3.0 2025-01-22 - [030f83b](https://github.com/appium/ruby_lib/commit/030f83ba4d48480f3ac664d0029dc1aae7b90d7d) Release 15.3.0 - [8befdbe](https://github.com/appium/ruby_lib/commit/8befdbe07d9d415ee04a09096326e670e901be20) feat: bump mini Ruby version to 3.1 by following core (#1051) - [35edaf4](https://github.com/appium/ruby_lib/commit/35edaf4b9cfdda5b0f18b91189cf04d6c714356c) chore: Update rubocop requirement from = 1.69.2 to = 1.70.0 (#1049) - [c45abdf](https://github.com/appium/ruby_lib/commit/c45abdfc2423e3fc0fb9d7b347751cc61dc65295) chore: Update rubocop requirement from = 1.69.1 to = 1.69.2 (#1048) - [9776747](https://github.com/appium/ruby_lib/commit/97767471108d7270e74255fcc1ffc1bd04c1a895) chore: Update fakefs requirement from ~> 2.7.1 to ~> 2.8.0 (#1047) - [961bc02](https://github.com/appium/ruby_lib/commit/961bc02c359ff05c75802e6d313e08cb4d24e09e) chore: Update fakefs requirement from ~> 2.5.0 to ~> 2.7.1 (#1046) - [93cffb5](https://github.com/appium/ruby_lib/commit/93cffb5547756dc76ba6897350877446410464ec) chore: Update rubocop requirement from = 1.69.0 to = 1.69.1 (#1045) - [304f953](https://github.com/appium/ruby_lib/commit/304f953f8eb0514a145360ea885722860791ac36) chore: Update rubocop requirement from = 1.68.0 to = 1.69.0 (#1044) - [e47c764](https://github.com/appium/ruby_lib/commit/e47c764fe6d581006731549dce49f5e0cd2312c1) chore: Update rubocop requirement from = 1.67.0 to = 1.68.0 (#1043) - [40db502](https://github.com/appium/ruby_lib/commit/40db502c68586af5c9acac988fdbbb04e9a5899b) chore: Update rubocop requirement from = 1.66.1 to = 1.67.0 (#1042) - [87da90b](https://github.com/appium/ruby_lib/commit/87da90b00bb98e5a76b4a7fb3312965fe7abb644) chore: Update rubocop requirement from = 1.66.0 to = 1.66.1 (#1041) - [57a1e79](https://github.com/appium/ruby_lib/commit/57a1e7903ca31ee5a7ff3d37f98d51f9abf591d1) chore: Update rubocop requirement from = 1.65.1 to = 1.66.0 (#1040) #### v15.2.2 2024-08-06 - [08ac85a](https://github.com/appium/ruby_lib/commit/08ac85ace5a451886431f10367f544708a792954) Release 15.2.2 - [b741383](https://github.com/appium/ruby_lib/commit/b74138352b7f274d89e0af36efe3d65a574ed502) fix: non-app capability handling (#1039) #### v15.2.1 2024-08-03 - [693dc16](https://github.com/appium/ruby_lib/commit/693dc167cbbcbe1ab08d1142958207d635c480a3) Release 15.2.1 - [d98126c](https://github.com/appium/ruby_lib/commit/d98126c47e04d7d152f85a2a75c3fdcb3011ae96) ci: add ci (#1037) - [fd2e639](https://github.com/appium/ruby_lib/commit/fd2e639b62e9b5c533915e7e860621391479c4aa) chore: modify rubocop.yml a bit - [0d1c2b8](https://github.com/appium/ruby_lib/commit/0d1c2b87b8f2ac456372bf4cbb2441fffae5cf27) chore: Update rubocop requirement from = 1.65.0 to = 1.65.1 (#1036) #### v15.2.0 2024-07-20 - [d73525e](https://github.com/appium/ruby_lib/commit/d73525eec584c3c31690dcd55a6c52d641d43f9f) Release 15.2.0 - [6b5d969](https://github.com/appium/ruby_lib/commit/6b5d9693f10e64a521f6ac5d31c78d71e5f0f6be) feat: raise its own defined errors (#1035) - [4a74c60](https://github.com/appium/ruby_lib/commit/4a74c60937e66bf028a66e4f05a324ce8b2077ce) chore: Update rubocop requirement from = 1.64.1 to = 1.65.0 (#1034) - [fa4cea4](https://github.com/appium/ruby_lib/commit/fa4cea4e5bea0aa4e3ed7052ba77812c82684fe0) chore: Update rubocop requirement from = 1.64.0 to = 1.64.1 (#1033) - [96ce262](https://github.com/appium/ruby_lib/commit/96ce26264d985b5260e99573486e8f712bfb12e3) chore: Update rubocop requirement from = 1.63.5 to = 1.64.0 (#1032) - [14590cc](https://github.com/appium/ruby_lib/commit/14590cce6f6cbef8c20e12ae10b00bf3f7b5ab3a) chore: tweak changelog format #### v15.1.0 2024-05-19 - [b1534cc](https://github.com/appium/ruby_lib/commit/b1534cc8e781e37f9632fa1cbaa6e2422b6a768d) Release 15.1.0 - [f6cc482](https://github.com/appium/ruby_lib/commit/f6cc482e6bcf75cd4388911355700e31da74b578) chore: tweak deps - [c034ec5](https://github.com/appium/ruby_lib/commit/c034ec5cb74e442db6db4cfc8365a43c903cbbfc) feat: update ruby lib core to v9 (#1030) - [50bca8f](https://github.com/appium/ruby_lib/commit/50bca8f8acd2c4c144684cd33dd0ea9787a40bf5) chore: Update rubocop requirement from = 1.63.4 to = 1.63.5 (#1028) - [415b3c6](https://github.com/appium/ruby_lib/commit/415b3c6b52e28f3b43cdd95a0684b1e9aadc0ae8) chore: Update rubocop requirement from = 1.63.3 to = 1.63.4 (#1027) - [7461e6a](https://github.com/appium/ruby_lib/commit/7461e6a44569245b6dbd1b352f3ff76503bb1bbb) docs: remove no longer used docs - [66e323c](https://github.com/appium/ruby_lib/commit/66e323c08dbc9616366e55ebf3835530549edf37) chore: remove unused docs_block #### v15.0.1 2024-04-26 - [3ab38a7](https://github.com/appium/ruby_lib/commit/3ab38a7339bf077dd85d9b700f08ddfe2ca608e5) Release 15.0.1 - [720dfdd](https://github.com/appium/ruby_lib/commit/720dfdd31f0feacf5926f668ff15e521920e360c) chore: bump thor and remove unused posix - [c869327](https://github.com/appium/ruby_lib/commit/c869327d50d2046a2c45e3a360b8667e006f9f56) chore: Update rubocop requirement from = 1.63.2 to = 1.63.3 (#1026) - [6543765](https://github.com/appium/ruby_lib/commit/65437658a89b234fbc431246266a383a0988009a) chore: Update rubocop requirement from = 1.63.1 to = 1.63.2 (#1025) - [2b428b5](https://github.com/appium/ruby_lib/commit/2b428b5e714e83ee283bce993fd3eba61827a287) chore: Update rubocop requirement from = 1.63.0 to = 1.63.1 (#1024) #### v15.0.0 2024-04-11 - [203a605](https://github.com/appium/ruby_lib/commit/203a6052db42039c89cd000f245f1534379bc86b) Release 15.0.0 - [7ab9f44](https://github.com/appium/ruby_lib/commit/7ab9f442ee9a9d22ad021316171e6824628eeb99) chore: Update rubocop requirement from = 1.62.1 to = 1.63.0 (#1023) - [ad20d82](https://github.com/appium/ruby_lib/commit/ad20d828e8124f37c3ab3055c744c2c76c74f563) ci: add 3.3 - [df9752c](https://github.com/appium/ruby_lib/commit/df9752c5176db395e7a427a77c4755293ff75cee) feat: remove "spec" deps (#1022) - [c5a7216](https://github.com/appium/ruby_lib/commit/c5a7216c005bb819ff7bc3fe313e7400777b9587) test: add empty test code (#1021) - [c450c20](https://github.com/appium/ruby_lib/commit/c450c20bae801e2f9f9ce66a9df2e352a614f73f) feat: bump ruby lib core v8 (#1018) - [9d40e0e](https://github.com/appium/ruby_lib/commit/9d40e0e2c2cbe571fd788c12565b3cb3d92f16a4) chore: Update rubocop requirement from = 1.62.0 to = 1.62.1 (#1020) - [98861af](https://github.com/appium/ruby_lib/commit/98861af3d779ce288937344a63aec7cbefed9db1) chore: Update rubocop requirement from = 1.61.0 to = 1.62.0 (#1017) - [1b385bc](https://github.com/appium/ruby_lib/commit/1b385bc2bab3f45d38a4f58e8c79ddbbe58d5596) chore: Update rubocop requirement from = 1.60.2 to = 1.61.0 (#1016) - [612d944](https://github.com/appium/ruby_lib/commit/612d944fc60b202d3e24c7e052004cef1b69c8d0) chore: Update rubocop requirement from = 1.60.1 to = 1.60.2 (#1013) #### v14.0.0 2024-01-25 - [50cf980](https://github.com/appium/ruby_lib/commit/50cf980b570acd7d2d95ea64d1d1b0225f96c73b) Release 14.0.0 - [978ed76](https://github.com/appium/ruby_lib/commit/978ed769120338d817fd69dadeb3894549021245) bump the major version as deprecation code removal - [ea3cc5d](https://github.com/appium/ruby_lib/commit/ea3cc5d41653f1df4b8bdad1ec36f142c1430e47) feat: remove deprecated export_session (#1015) #### v13.0.2 2024-01-25 - [9c52fd3](https://github.com/appium/ruby_lib/commit/9c52fd3a8f0ef88d7c4e83f210ab22f817a30632) Release 13.0.2 - [d14669e](https://github.com/appium/ruby_lib/commit/d14669ebfe091f06e5c248787c753419cee9ed6f) chore: restrict the ruby core version (#1014) - [202718c](https://github.com/appium/ruby_lib/commit/202718ca86a99a3443510c9992f21752c090136c) chore: Update rubocop requirement from = 1.60.0 to = 1.60.1 (#1011) - [4e93dce](https://github.com/appium/ruby_lib/commit/4e93dce9d7c4d86fb568ca60cfb8d9918f3b20f6) chore: Update rubocop requirement from = 1.59.0 to = 1.60.0 (#1010) - [cb2f421](https://github.com/appium/ruby_lib/commit/cb2f42108c600752b120e06917eea3b0a15f2b6f) chore: Update hashdiff requirement from ~> 1.0.0 to ~> 1.1.0 (#1009) - [7342c05](https://github.com/appium/ruby_lib/commit/7342c055090e49f03a8c5d5229c1d795d0c60fd5) chore: Update rubocop requirement from = 1.58.0 to = 1.59.0 (#1008) - [033eb4f](https://github.com/appium/ruby_lib/commit/033eb4f70cf5a6a5ba015bb86c1f61f2c4ca341e) chore: Update rubocop requirement from = 1.57.2 to = 1.58.0 (#1007) - [d3b9c56](https://github.com/appium/ruby_lib/commit/d3b9c56bfa5dbf9939499bd9d1b10639914a4a46) chore: Update rubocop requirement from = 1.57.1 to = 1.57.2 (#1006) - [fd8e103](https://github.com/appium/ruby_lib/commit/fd8e103a507e7c6a1815cfb0b590c84cedb8caca) chore: Update rubocop requirement from = 1.57.0 to = 1.57.1 (#1005) - [5d3e809](https://github.com/appium/ruby_lib/commit/5d3e809d1e7c05b276b5e19a05822204d4d852fb) chore: Update rubocop requirement from = 1.56.4 to = 1.57.0 (#1004) - [e6383f8](https://github.com/appium/ruby_lib/commit/e6383f84c723e08db670bd2b59f88d07da210eb5) chore: Update rubocop requirement from = 1.56.2 to = 1.56.4 (#1003) - [c37e87f](https://github.com/appium/ruby_lib/commit/c37e87f6b50e71e99bccf2c3601def497412482c) chore: Update rubocop requirement from = 1.56.1 to = 1.56.2 (#1001) - [ee96909](https://github.com/appium/ruby_lib/commit/ee969091251d3fb5ace65ef2d0f0d543880bb4dd) chore: Update rubocop requirement from = 1.56.0 to = 1.56.1 (#1000) - [4282704](https://github.com/appium/ruby_lib/commit/42827044578a215ac8cd024f15e56ccfb075a760) chore: Update rubocop requirement from = 1.55.1 to = 1.56.0 (#999) - [2083158](https://github.com/appium/ruby_lib/commit/20831586a664e39b51e953fc755860b5d1255a9a) chore: Update rubocop requirement from = 1.55.0 to = 1.55.1 (#998) - [7807e5d](https://github.com/appium/ruby_lib/commit/7807e5d2de3803c08a480d2e760b0d7d8957b06d) chore: Update rubocop requirement from = 1.54.2 to = 1.55.0 (#997) - [093449f](https://github.com/appium/ruby_lib/commit/093449fbf31eb8751b9c07affa2d4204312bd887) docs: readme.md - [e156bbd](https://github.com/appium/ruby_lib/commit/e156bbd5ef012db7a2c0472a7a51764a592b25a6) chore: add CODEOWNERS - [00a5b5d](https://github.com/appium/ruby_lib/commit/00a5b5dcef0a3bf53ed52f19ce765ffc9d22990e) chore: Update rubocop requirement from = 1.53.1 to = 1.54.2 (#996) - [d5c1caa](https://github.com/appium/ruby_lib/commit/d5c1caad5f2f91f6ecf66dfe137a54ee6693fb22) chore: Update rubocop requirement from = 1.53.0 to = 1.53.1 (#993) - [6aa7001](https://github.com/appium/ruby_lib/commit/6aa70019fd7d33fdbc35b292a640708f3a98a6e1) chore: Update rubocop requirement from = 1.52.1 to = 1.53.0 (#992) #### v13.0.1 2023-06-19 - [777e15d](https://github.com/appium/ruby_lib/commit/777e15d7c0a727cbe25b1e51a3ba7a68759a12db) Release 13.0.1 - [d6a2afe](https://github.com/appium/ruby_lib/commit/d6a2afede2c39f242a47e995efe2ff047afe35cd) chore: Update appium_lib_core requirement from ~> 6.0 to >= 6, < 8 (#991) #### v13.0.0 2023-06-18 - [a5add59](https://github.com/appium/ruby_lib/commit/a5add59a76fd88883c323566387c03b95a6db265) Release 13.0.0 - [7af0cde](https://github.com/appium/ruby_lib/commit/7af0cdeab1afa8832cf7725fb14705f49b1fa1dd) feat: drop Ruby 2.7 (#990) - [2a3bee4](https://github.com/appium/ruby_lib/commit/2a3bee4ce4ebd82a6e8e27923332ec50c8252de5) chore: Update rubocop requirement from = 1.52.0 to = 1.52.1 (#989) - [669beaa](https://github.com/appium/ruby_lib/commit/669beaa5734d34ea5f6af4ccf345d594ba52225f) chore: Update rubocop requirement from = 1.51.0 to = 1.52.0 (#988) - [b96709e](https://github.com/appium/ruby_lib/commit/b96709e9b0833bfe898b35326564bfa8a819ac2a) chore: Update fakefs requirement from ~> 2.4.0 to ~> 2.5.0 (#987) - [d075903](https://github.com/appium/ruby_lib/commit/d075903ff5586a996a6775a3fbe938765c66c50c) chore: Update rubocop requirement from = 1.50.2 to = 1.51.0 (#986) #### v12.2.2 2023-04-27 - [2f3ac2d](https://github.com/appium/ruby_lib/commit/2f3ac2df0e770e033076429059f5b96dde0565b5) Release 12.2.2 - [aba17f0](https://github.com/appium/ruby_lib/commit/aba17f0ba8d91e070ad37ad6e1cf2dde60da3ef9) fix: tune quit in start_driver to not raise an exception there (#985) #### v12.2.1 2023-04-24 - [8e93297](https://github.com/appium/ruby_lib/commit/8e932971b216be735290757d1885498e8d57347f) Release 12.2.1 - [a47a7ad](https://github.com/appium/ruby_lib/commit/a47a7ad905ce36b94568cdf54b45eeeffd3eaad5) docs: remove travis badge - [a93d286](https://github.com/appium/ruby_lib/commit/a93d286106d706ef5bb6d97680542b2f79483d4f) fix default_wait value (#983) - [712ab14](https://github.com/appium/ruby_lib/commit/712ab14dd6d798962b228da831bebd20f2c73403) chore: Update rubocop requirement from = 1.49.0 to = 1.50.2 (#982) - [363067e](https://github.com/appium/ruby_lib/commit/363067edd60ba9d557c37d4153398000f5447067) chore: Update rubocop requirement from = 1.48.1 to = 1.49.0 (#979) - [779cbc0](https://github.com/appium/ruby_lib/commit/779cbc020f10fb405c3b02a96a1215864a571028) chore: Update rubocop requirement from = 1.47.0 to = 1.48.1 (#978) - [225c510](https://github.com/appium/ruby_lib/commit/225c510042ccc1e32ed716b8fa4f6b617ebd409f) chore: Update rubocop requirement from = 1.46.0 to = 1.47.0 (#976) - [9715260](https://github.com/appium/ruby_lib/commit/9715260e2d752b3967cbfb2f052c4693d883f634) chore: Update rubocop requirement from = 1.45.1 to = 1.46.0 (#975) - [1fd3bf7](https://github.com/appium/ruby_lib/commit/1fd3bf7988d54e3cbf9be4cdd8a2ffef0ffffb6a) core#quit_driver is deprecated use core.driver.quit (#973) - [3850ae2](https://github.com/appium/ruby_lib/commit/3850ae2b3fc2e09389ba04cbf741369aab37f7c1) chore: Update fakefs requirement from ~> 2.3.0 to ~> 2.4.0 (#972) - [a4d1808](https://github.com/appium/ruby_lib/commit/a4d1808c381165559d8efd453337cfe2a0f5262d) chore: Update fakefs requirement from ~> 2.2.0 to ~> 2.3.0 (#971) - [a913380](https://github.com/appium/ruby_lib/commit/a9133804acc497ac72a48644bba3b77afb7a71b7) chore: Update fakefs requirement from ~> 2.0.0 to ~> 2.2.0 (#970) - [129bebb](https://github.com/appium/ruby_lib/commit/129bebb79c9eab5933bf10f76a56540a6995fffc) chore: Update rubocop requirement from = 1.44.1 to = 1.45.1 (#969) - [1781671](https://github.com/appium/ruby_lib/commit/17816716ee3f7bdcae8eeb24a4dc279735929524) chore: Update rubocop requirement from = 1.44.0 to = 1.44.1 (#968) - [852af7d](https://github.com/appium/ruby_lib/commit/852af7d2cbf08408f541bb7850a6bfef7b6270b6) chore: Update rubocop requirement from = 1.43.0 to = 1.44.0 (#967) - [06a3194](https://github.com/appium/ruby_lib/commit/06a3194c3e57006f8ac957b3aca2eeb2bf640d9f) chore: Update rubocop requirement from = 1.42.0 to = 1.43.0 (#966) - [a19f211](https://github.com/appium/ruby_lib/commit/a19f211a7ed0030de0b243db62c4be297cb584cb) chore: Update fakefs requirement from ~> 1.9.0 to ~> 2.0.0 (#965) - [9ea6c91](https://github.com/appium/ruby_lib/commit/9ea6c9126a90a405beb4d1bd86eebc4652db5698) chore: Update rubocop requirement from = 1.41.1 to = 1.42.0 (#964) #### v12.2.0 2022-12-25 - [83c756d](https://github.com/appium/ruby_lib/commit/83c756d67c3f19deff6e9270856e0889f3de8b9b) Release 12.2.0 - [e963c02](https://github.com/appium/ruby_lib/commit/e963c025630cb8eaab6dcdf47b1a9b402db98541) chore: bump the ruby core ver (#963) - [ce80e17](https://github.com/appium/ruby_lib/commit/ce80e17369268be2c8da2a7007a8f5173c144404) chore: remove non-xuitest stuff (#960) - [7011c05](https://github.com/appium/ruby_lib/commit/7011c05ccd14bbdb92652be8ec811d5c04c9dcc7) chore: Update rubocop requirement from = 1.41.0 to = 1.41.1 (#962) - [18dc444](https://github.com/appium/ruby_lib/commit/18dc44429aba30dc675e0be020699790aa0f41ec) chore: Update rubocop requirement from = 1.40.0 to = 1.41.0 (#961) #### v12.1.3 2022-12-13 - [65f8b1c](https://github.com/appium/ruby_lib/commit/65f8b1c4406f358bf4a44ef0d4d7ae429ddc23c4) Release 12.1.3 - [4b95151](https://github.com/appium/ruby_lib/commit/4b95151ade73494304fa9c07aca465d54e779a24) feat: do not use deprecated methods (#959) - [56b9d06](https://github.com/appium/ruby_lib/commit/56b9d06bb3ee94919b48d7b3c216ffe244ba6730) chore: Update rubocop requirement from = 1.39.0 to = 1.40.0 (#958) - [19e0b0c](https://github.com/appium/ruby_lib/commit/19e0b0c51bde24cf1522ed27f74cfad913b46a67) chore: Update fakefs requirement from ~> 1.8.0 to ~> 1.9.0 (#957) - [40786c1](https://github.com/appium/ruby_lib/commit/40786c1aabbe464003a393abf22e7e8dd105816c) chore: Update rubocop requirement from = 1.38.0 to = 1.39.0 (#956) #### v12.1.2 2022-11-13 - [c3330bd](https://github.com/appium/ruby_lib/commit/c3330bd208d4aba2cdc616f5ca4ac23a3ec4790a) Release 12.1.2 - [40ca5c8](https://github.com/appium/ruby_lib/commit/40ca5c8a200638e145f71c27b320d19d1f3f63db) fix: non app in the caps by toml (#955) - [b953b30](https://github.com/appium/ruby_lib/commit/b953b30c854232d11628ef894a8d6d43f8b59883) chore: Update rubocop requirement from = 1.37.1 to = 1.38.0 (#954) - [a62597a](https://github.com/appium/ruby_lib/commit/a62597a5b0c7ff0a593e7fecaec66729b44ef78e) chore: Update rubocop requirement from = 1.37.0 to = 1.37.1 (#953) - [049ac4e](https://github.com/appium/ruby_lib/commit/049ac4ec86399fe5406b6b0ca336ac0e2a8c2735) chore: Update rubocop requirement from = 1.36.0 to = 1.37.0 (#952) #### v12.1.1 2022-10-19 - [83c89c1](https://github.com/appium/ruby_lib/commit/83c89c107ea0e030b7eae2d8ab664c38766df6ed) Release 12.1.1 - [e40222d](https://github.com/appium/ruby_lib/commit/e40222d66f497fe295aea982ef0c042b901f6e3f) fix: use warn (#951) - [a9b7558](https://github.com/appium/ruby_lib/commit/a9b75583e9923ade4f4fd16cb7fad03cc0f7c1be) docs: tweak - [600f867](https://github.com/appium/ruby_lib/commit/600f8670f97d91babfd84e1c6c1ef34d2682b883) docs: updating (#950) - [a81ea4b](https://github.com/appium/ruby_lib/commit/a81ea4b2a74ea71fa62c1756ffea2f85da57d49b) docd: udpate readme - [8f20fe1](https://github.com/appium/ruby_lib/commit/8f20fe12b728195a8d2eb7d39004de4075caeff8) Release 12.1.0 - [b00662a](https://github.com/appium/ruby_lib/commit/b00662a3976aeadc8d5385fd00129fb9dafa967c) chore: specify latest core - [98a3c6b](https://github.com/appium/ruby_lib/commit/98a3c6b9720eeff74f6eefda6e54196477854ed3) feat: update the minimal ruby lib core version (#946) - [45a2194](https://github.com/appium/ruby_lib/commit/45a21942311ed4e5b88df3ad9ddb540693422b5e) docs: update the readme - [c29cf02](https://github.com/appium/ruby_lib/commit/c29cf0284041f449dc594248cadf47bf7ca074ae) chore: Update rubocop requirement from = 1.35.1 to = 1.36.0 (#944) - [26ff210](https://github.com/appium/ruby_lib/commit/26ff21044030eb833c5c167026834f8a522c1a7c) chore: Update rubocop requirement from = 1.35.0 to = 1.35.1 (#941) - [1984bd0](https://github.com/appium/ruby_lib/commit/1984bd09e4fa55a41b9c1cf22ae9c4fffa51b149) chore: Update rubocop requirement from = 1.34.1 to = 1.35.0 (#940) - [71f889b](https://github.com/appium/ruby_lib/commit/71f889b2671696244609d2ce970dc602be28644a) chore: Update rubocop requirement from = 1.34.0 to = 1.34.1 (#939) - [6d4c02d](https://github.com/appium/ruby_lib/commit/6d4c02d0f8d59d5debe60d782260bf1b2e4b80ad) chore: Update rubocop requirement from = 1.33.0 to = 1.34.0 (#938) - [6d10490](https://github.com/appium/ruby_lib/commit/6d104904974798e187fc07ad6f98875c09368ca7) chore: Update rubocop requirement from = 1.32.0 to = 1.33.0 (#937) - [0144c9c](https://github.com/appium/ruby_lib/commit/0144c9c9d7331e5384de0a528eedf82be98affbd) chore: Update rubocop requirement from = 1.31.2 to = 1.32.0 (#936) - [6d08328](https://github.com/appium/ruby_lib/commit/6d083282eb0f04dc70453d5290af2eb6f3d5da90) chore: Update rubocop requirement from = 1.31.1 to = 1.31.2 (#934) - [8554315](https://github.com/appium/ruby_lib/commit/8554315055cb5742cb8251e087a7e6d0cc3b7504) chore: Update rubocop requirement from = 1.31.0 to = 1.31.1 (#933) - [50b76c6](https://github.com/appium/ruby_lib/commit/50b76c6713d5ae1134dbe7f2d5cfae95df9dede6) chore: Update rubocop requirement from = 1.30.1 to = 1.31.0 (#932) - [b55c2a5](https://github.com/appium/ruby_lib/commit/b55c2a58e5ea0ffc215e43dc8e1b28a99c7be372) chore: Update fakefs requirement from ~> 1.7.0 to ~> 1.8.0 (#931) - [7c501bc](https://github.com/appium/ruby_lib/commit/7c501bc47f8a40bf83088a43af2892d46cef561c) chore: Update fakefs requirement from ~> 1.5.0 to ~> 1.7.0 (#930) - [574e3c4](https://github.com/appium/ruby_lib/commit/574e3c4acc9f38419250aa3a046143acc8d55a75) chore: Update rubocop requirement from = 1.30.0 to = 1.30.1 (#929) - [0dacfea](https://github.com/appium/ruby_lib/commit/0dacfea1924f953ae8c6328c97065dcdb6b372d7) chore: Update rubocop requirement from = 1.29.1 to = 1.30.0 (#928) - [cf368c8](https://github.com/appium/ruby_lib/commit/cf368c848a76cf5a86c26f006cd4ff412f1f8a86) chore: Update fakefs requirement from ~> 1.4.0 to ~> 1.5.0 (#927) - [2e9190a](https://github.com/appium/ruby_lib/commit/2e9190aa8905c3d06adcc16a87209f3841e4cdc4) chore: Update rubocop requirement from = 1.29.0 to = 1.29.1 (#926) - [99360fb](https://github.com/appium/ruby_lib/commit/99360fb8b0aab56fc3eb6e903cf89e10bbd8b78b) chore: Update rubocop requirement from = 1.28.2 to = 1.29.0 (#925) - [9bf18ce](https://github.com/appium/ruby_lib/commit/9bf18ce0365f4c677d81d83b3a33ef7125a8e1dd) chore: Update rubocop requirement from = 1.28.1 to = 1.28.2 (#924) - [d7a5983](https://github.com/appium/ruby_lib/commit/d7a598369c0e28f8924e04aaa6d2159662fa710f) chore: Update rubocop requirement from = 1.28.0 to = 1.28.1 (#923) - [e33f440](https://github.com/appium/ruby_lib/commit/e33f4408ccf28564316196b9555b23aaa83d9b5e) chore: Update rubocop requirement from = 1.27.0 to = 1.28.0 (#922) - [e598c26](https://github.com/appium/ruby_lib/commit/e598c2681c565c8d52338c6bb544374df5c3729b) chore: Update rubocop requirement from = 1.26.1 to = 1.27.0 (#921) #### v12.0.1 2022-04-02 - [ae4bddd](https://github.com/appium/ruby_lib/commit/ae4bddd7ba5bf3aafe8fedc44919bb02b4f260be) Release 12.0.1 - [a5d4c4f](https://github.com/appium/ruby_lib/commit/a5d4c4f08cd3fc5d2ca575595f0741b4d22bf7b9) fix: remove the method and define again instead (#920) - [484006b](https://github.com/appium/ruby_lib/commit/484006b903c6bc15b5ce1767cf9c407c978afab9) docs: tweak - [e22140e](https://github.com/appium/ruby_lib/commit/e22140e970ddb5975e16a5d4f46b1d9a29da2c31) chore: Update rubocop requirement from = 1.26.0 to = 1.26.1 (#919) - [a900972](https://github.com/appium/ruby_lib/commit/a9009728f9cee8a432fe6d1b0cd7caf1e77b0106) chore: Update rubocop requirement from = 1.25.1 to = 1.26.0 (#918) - [923ba1c](https://github.com/appium/ruby_lib/commit/923ba1ca8602fd404090efef09174166794ce074) chore: Update rubocop requirement from = 1.25.0 to = 1.25.1 (#916) - [0dc8e19](https://github.com/appium/ruby_lib/commit/0dc8e19a2c481c3d6dea3be4e309f0aafd256656) chore: Update rubocop requirement from = 1.24.1 to = 1.25.0 (#915) - [b02bb65](https://github.com/appium/ruby_lib/commit/b02bb653dfc8ff7c770155b7c4c8d6afaecd8a5c) chore: Update rubocop requirement from = 1.24.0 to = 1.24.1 (#914) - [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) - [eac87a4](https://github.com/appium/ruby_lib/commit/eac87a4cc8bf55bfe6fc8820ff947713042c79a4) chore: Update rubocop requirement from = 1.23.0 to = 1.24.0 (#912) - [ac25f13](https://github.com/appium/ruby_lib/commit/ac25f13f7c36017c13449b5038b2f698806ee1eb) chore: Update rubocop requirement from = 1.22.3 to = 1.23.0 (#911) #### v12.0.0 2021-11-06 - [3060ef3](https://github.com/appium/ruby_lib/commit/3060ef3bf06c19a79731a49985efa75c3337dd27) Release 12.0.0 - [2c76d15](https://github.com/appium/ruby_lib/commit/2c76d15edafb43e8c0124bfd4c1c9e95f61fb725) chore: bump version to 12.0.0 - [19bc90f](https://github.com/appium/ruby_lib/commit/19bc90fef5646f3cde201654ae4fd92da2124b1c) docs: update readme - [3239d7f](https://github.com/appium/ruby_lib/commit/3239d7f9a64529c8afc87c2f99a7984eb3057fd5) docs: update changelog - [bbf56a5](https://github.com/appium/ruby_lib/commit/bbf56a5e502bdb1e2b38245c879eafbc7d9c0ea9) chore: bump core to 5.0.0, bump version to rc5 - [b785de1](https://github.com/appium/ruby_lib/commit/b785de188f15da76e91c2a10cccd95c13de3c331) chore: bump the version - [d14d151](https://github.com/appium/ruby_lib/commit/d14d15167cc462d75acbef8d7d82b0fb728ec3a5) Merge branch 'master' of github.com:appium/ruby_lib - [35bf3ed](https://github.com/appium/ruby_lib/commit/35bf3edcf6dcbfd0b2122aa32bfb85d7209bc52f) chore: bump core version - [e990681](https://github.com/appium/ruby_lib/commit/e990681bad2932e895d3e706e5db2593d727b2b7) chore: Update rubocop requirement from = 1.22.2 to = 1.22.3 (#910) - [9d3f1b6](https://github.com/appium/ruby_lib/commit/9d3f1b62bc32ef1ea210a92a69d444bc830680f8) docs: remove outdated docs - [1049a68](https://github.com/appium/ruby_lib/commit/1049a688cbd11b468002e0fb1c1d1a960a6350c7) chore: bump version to 12.0.0.rc3 - [8448f29](https://github.com/appium/ruby_lib/commit/8448f299ad91cf47f69c961da811310cd13d906b) chore: remove selendroid stuff - [171f3bd](https://github.com/appium/ruby_lib/commit/171f3bd0a9443a7c0c386c8a2c1340f6117c4aa9) chore: update tests with W3C spec for interactions (#909) - [01505ed](https://github.com/appium/ruby_lib/commit/01505ed5bf51ce386f285ae1790b91f48bc38487) chore: bump version - [8a873f2](https://github.com/appium/ruby_lib/commit/8a873f2c0606488b640d0c4c21237ddb5db97516) chore: bump core version to rc6 - [2bf24f2](https://github.com/appium/ruby_lib/commit/2bf24f2fc93141415fee1f43a5434a722c64e576) chore: Update fakefs requirement from ~> 1.3.0 to ~> 1.4.0 (#906) - [7e9f58c](https://github.com/appium/ruby_lib/commit/7e9f58c483f1c600525d9dc1584b7a4712a33b6a) chore: Update rubocop requirement from = 1.22.1 to = 1.22.2 (#907) - [5683456](https://github.com/appium/ruby_lib/commit/5683456f6c6f434d3fa1490a250d23acc3033729) feat: apply core 5.x for selenium v4 (#905) - [c0098b4](https://github.com/appium/ruby_lib/commit/c0098b480786ce0442d3d06bf4d3d161375c760d) chore: Update rubocop requirement from = 1.12.0 to = 1.12.1 (#904) - [2adbb0e](https://github.com/appium/ruby_lib/commit/2adbb0e03e55f57f0c4001d1577d1577dfd63ae2) chore: Update rubocop requirement from = 1.11.0 to = 1.12.0 (#903) - [83769cc](https://github.com/appium/ruby_lib/commit/83769cc9bc8a96cb0526e950a9b7e8d656e84390) chore: Update rubocop requirement from = 1.8.1 to = 1.11.0 (#902) - [6e6b61d](https://github.com/appium/ruby_lib/commit/6e6b61d455773147c76f41df65503fb6d61d6019) chore: Update tomlrb requirement from ~> 1.1 to >= 1.1, < 3.0 (#886) - [0e34f82](https://github.com/appium/ruby_lib/commit/0e34f82310b9906af858ccf5230a7b0f23fd12f9) chore: Create Dependabot config file (#900) - [4783382](https://github.com/appium/ruby_lib/commit/47833829bed009416949ed8ecd60e1a8356e28ce) chore: address 11.2 #### v11.2.0 2021-01-25 - [06f2e54](https://github.com/appium/ruby_lib/commit/06f2e54b4b55df25e624272b5a2cd7b23a000298) Release 11.2.0 - [8489c32](https://github.com/appium/ruby_lib/commit/8489c32dbb9c2b499af82e874aa532f2c9f63d8d) chore: Update rubocop requirement from = 1.8.0 to = 1.8.1 (#897) - [eba6a68](https://github.com/appium/ruby_lib/commit/eba6a68b93f010101b3713fef162c23e6c75b330) chore: Update rubocop requirement from = 1.7.0 to = 1.8.0 (#896) #### v11.1.0 2020-12-29 - [bc3da9b](https://github.com/appium/ruby_lib/commit/bc3da9bc1ee58d5e96811b72f3ed737ed0e9c401) Release 11.1.0 - [3c33cd6](https://github.com/appium/ruby_lib/commit/3c33cd639f8ce55fb81c5ae2116a863407529599) ci: Set up CI with Azure Pipelines (#895) - [ecee089](https://github.com/appium/ruby_lib/commit/ecee08981f935295e6413cd98dea4366cbc7bc69) feat: work with Ruby 3 (#893) - [bb3d715](https://github.com/appium/ruby_lib/commit/bb3d715e39509ac091b8f493cca42eb4fe8fd5bf) feat: work with Ruby 3 (#892) - [eb5cee7](https://github.com/appium/ruby_lib/commit/eb5cee7a926b90bbedd6aa28f013a0b3c5f38510) chore: Update rubocop requirement from = 1.6.1 to = 1.7.0 (#891) - [219181d](https://github.com/appium/ruby_lib/commit/219181d80f3b86999706f90a68996945fdc7b1d0) fix: rubocop (#890) - [334b791](https://github.com/appium/ruby_lib/commit/334b791a3c4420598e3e832023aa1a16af92492f) chore: Update fakefs requirement from ~> 0.13.0 to ~> 1.3.0 (#888) #### v11.0.0 2020-12-19 - [b4313b0](https://github.com/appium/ruby_lib/commit/b4313b09e62dd22bb95c2e0bc6edd296c7ece7b4) Release 11.0.0 - [42f01dd](https://github.com/appium/ruby_lib/commit/42f01dd3513e82f9a7ed25ac9055a65dfaa7d81f) feat: bump ruby version (#887) - [dc228b3](https://github.com/appium/ruby_lib/commit/dc228b33487281d0428dcd20e92263d7132dd53e) ci: move to GitHub Actions (#882) #### v10.6.0 2020-04-03 - [65f690f](https://github.com/appium/ruby_lib/commit/65f690f1fec62a5f8868270287b0099d8b22a2ac) Release 10.6.0 - [f792db3](https://github.com/appium/ruby_lib/commit/f792db3afbfe3f6056e0af60ce9f6be3e2cecadc) feat: remove pager off (#879) - [7ad3189](https://github.com/appium/ruby_lib/commit/7ad318925c0cd2c3e73cc015a1ec929485b8af85) Update hashdiff requirement from ~> 0.3.7 to ~> 1.0.0 (#874) - [457e765](https://github.com/appium/ruby_lib/commit/457e7657175e6c9ba981ca476098469e91e522e1) Update rubocop requirement from ~> 0.61.0 to ~> 0.68.1 (#875) - [9a2b9fa](https://github.com/appium/ruby_lib/commit/9a2b9fa736877141f92d35b9e2ae97657d9955d7) Update rake requirement from ~> 12.0 to ~> 13.0 (#876) - [8748244](https://github.com/appium/ruby_lib/commit/8748244f75ae9344e8b22dd20b2d42fb0bd84d75) fix ruby27 warning (#872) - [f1734ab](https://github.com/appium/ruby_lib/commit/f1734ab0ff2a210463ab6a83120a673e1b6efd4a) ci: add 2.7 (#871) - [b26a8f7](https://github.com/appium/ruby_lib/commit/b26a8f7c00c966ee3f193b4c97255a4751f0041e) fix a yardoc syntax #### v10.5.0 2019-11-09 - [722c3a9](https://github.com/appium/ruby_lib/commit/722c3a9aa387d3537b648a50dc24070e62fcc57a) Release 10.5.0 - [7a2197b](https://github.com/appium/ruby_lib/commit/7a2197b46f6ec15f1adc8626bbff1be74640e98e) feat: Add log event/s (#868) #### v10.4.1 2019-09-11 - [12317e4](https://github.com/appium/ruby_lib/commit/12317e4d74b20d01813526b28e642e3522193fa3) Release 10.4.1 - [58218e1](https://github.com/appium/ruby_lib/commit/58218e18f74df362e874b2a39d9e922b27b6bd5e) fix ios page (#866) - [7f010e7](https://github.com/appium/ruby_lib/commit/7f010e70149847ae5af8dcf08eae889311f78e6d) fix typo in a comment #### v10.4.0 2019-07-19 - [954a3a8](https://github.com/appium/ruby_lib/commit/954a3a8d4d5cd56fa5a4e80d021805759dbf5e10) Release 10.4.0 - [8289c9f](https://github.com/appium/ruby_lib/commit/8289c9f8e19fab754538f229e1a5513e2994dba3) fix warning message in driver detection (#864) - [5e61241](https://github.com/appium/ruby_lib/commit/5e612419ccd4dc5f5bd8b657a972cce4113bf9e7) update core 3.2 (#863) - [1f58984](https://github.com/appium/ruby_lib/commit/1f5898400dd1928bfe42ddd5f842d1f8738f2f76) Update readme.md (#861) #### v10.3.1 2019-04-11 - [ef89749](https://github.com/appium/ruby_lib/commit/ef89749d25c7044fe27fa4b7c1adfd011b60bba1) Release 10.3.1 - [d90f149](https://github.com/appium/ruby_lib/commit/d90f1499f6c7f5c8222f7915d60c7a7218d43949) remove ';' to avoid 'Unclosed paren in expression' (#859) #### v10.3.0 2019-03-31 - [499e824](https://github.com/appium/ruby_lib/commit/499e824668f63958c2fe047b76841612f74d2c1c) Release 10.3.0 - [fa90527](https://github.com/appium/ruby_lib/commit/fa90527b709cbb2e9ea1e86276a2a884d2a9d4c3) bump core to 3.1.x (#857) - [8e7abee](https://github.com/appium/ruby_lib/commit/8e7abeee3b0bc46b8d28b4352bed39819d68cbaf) Bump rubocop 23 (#855) #### v10.2.0 2019-03-01 - [f1b8a2e](https://github.com/appium/ruby_lib/commit/f1b8a2e32fc935508e13431570fd7de4a90b6bd7) Release 10.2.0 - [dbac05e](https://github.com/appium/ruby_lib/commit/dbac05e58dc25c1e682a4183dff4ead7202a857c) Fix find element by image (#854) #### v10.1.0 2019-02-21 - [4b43cf7](https://github.com/appium/ruby_lib/commit/4b43cf7b240a7b4cab7b22198ed4dd1307611545) Release 10.1.0 - [588f83f](https://github.com/appium/ruby_lib/commit/588f83f07360d581a317709a539aea8ecb175617) Case sensitive exact (#853) #### v10.0.0 2019-02-08 - [4e4ec29](https://github.com/appium/ruby_lib/commit/4e4ec298096f13f60db51bda2019c8e12a0d0c25) Release 10.0.0 - [f64e2e4](https://github.com/appium/ruby_lib/commit/f64e2e406e41b596a6e38de9227cc594938f8a06) Fix newline in doc (#850) - [a3b3073](https://github.com/appium/ruby_lib/commit/a3b3073d041270d6bbcb21bf8c795c172a90a59a) bump core (#848) - [41c940c](https://github.com/appium/ruby_lib/commit/41c940c73fd4ec12ac5bd8119a0a22422dc26819) remove wrong comment #### v9.18.0 2019-01-13 - [32f3272](https://github.com/appium/ruby_lib/commit/32f327239055362ef630979d5975d0fac64d94c6) Release 9.18.0 - [e0f3683](https://github.com/appium/ruby_lib/commit/e0f36830edf0c33617efa50907c44b4ddc58702d) Enhance espresso adaptation for text, button, finds wrappers (#844) - [fb49333](https://github.com/appium/ruby_lib/commit/fb49333c46a7b612920d05d2f9ebc51fd7bfdb20) Add ruby 260 (#843) #### v9.17.0 2018-12-15 - [84f71e4](https://github.com/appium/ruby_lib/commit/84f71e47b86a2f7a1de71c13888adce68622a35b) Release 9.17.0 - [13f9551](https://github.com/appium/ruby_lib/commit/13f9551f8273cbf1ef959dfd79dc0c53a2c2e0d0) Can call w3c action (#842) - [908c3f0](https://github.com/appium/ruby_lib/commit/908c3f08cfea7895a2128b606f6b258c60b894dd) tweak android test code (#841) - [af27d01](https://github.com/appium/ruby_lib/commit/af27d011862163653c73aab037d16bcfb3abd28a) remove deprecation or unnecessary code (#839) #### v9.16.1 2018-11-28 - [fa8d4ed](https://github.com/appium/ruby_lib/commit/fa8d4ed2aaa5259a1fa744be955555cf775ead3e) Release 9.16.1 - [5172e19](https://github.com/appium/ruby_lib/commit/5172e19fc55d4649f679b50d0560d146b9e9ac71) fix version comparision, show warning if the appium version is under 1.6.0 (#837) - [152d04a](https://github.com/appium/ruby_lib/commit/152d04aa3c428e610c7e511a05a3563195e7cc81) remove a wrong comment - [65efdfd](https://github.com/appium/ruby_lib/commit/65efdfd121a5a01e2c8c0a7ca26df9c66ab446f0) fix generated docs (#835) - [81f369b](https://github.com/appium/ruby_lib/commit/81f369bca6d393eb273375035602e39bc89f13a6) update a description of ruby_lib_core #### v9.16.0 2018-11-14 - [621a9eb](https://github.com/appium/ruby_lib/commit/621a9ebaf18bcd80eb0e1f5fc17fbb4dddf5293a) Release 9.16.0 - [b634a7d](https://github.com/appium/ruby_lib/commit/b634a7d32123c6ad0ebea59798fe5c99721782bd) Use thor (#832) - [58f10f0](https://github.com/appium/ruby_lib/commit/58f10f01d1b02bc0619b189c7f7920e7b14332ca) add a line for ruby_lib_core - [3bb224c](https://github.com/appium/ruby_lib/commit/3bb224cc7a23f868fdd570ed6113019d6f349984) Do not take care of path of :app for windows (#831) #### v9.15.2 2018-11-07 - [12eb2f3](https://github.com/appium/ruby_lib/commit/12eb2f39fe8d022efe0fb4a666c8661f9270cc7d) Release 9 15 2 (#829) - [bb005f7](https://github.com/appium/ruby_lib/commit/bb005f7c594101a460460a8c771610eabc51da73) add execute_async_script (#828) - [00dcf13](https://github.com/appium/ruby_lib/commit/00dcf13c7757d248a0aa94ccdada3183951d2f54) wrap some of selenium webdriver apis in bridge for Appium::Driver (#827) - [8b42a97](https://github.com/appium/ruby_lib/commit/8b42a9726eae67f52d79820e27ff3a0169d7a0f5) Bump rubocop (#826) - [4f25e39](https://github.com/appium/ruby_lib/commit/4f25e3996f444be8c3031117df15b5da8c373d62) Update ios_xcuitest.md (#825) - [2a66e84](https://github.com/appium/ruby_lib/commit/2a66e843a5bca7442c5f48d2c514a18169b923c3) Bump ios version for test target (#822) - [5fea863](https://github.com/appium/ruby_lib/commit/5fea863f7b2b48522f556d9eecff0fbb3a59e330) add an example of multiple action chains (#819) - [ca1b070](https://github.com/appium/ruby_lib/commit/ca1b070ac05fbcf9bfa9eb17479780ae021fcbd4) update grid environments (#818) #### v9.15.1 2018-08-27 - [14d1835](https://github.com/appium/ruby_lib/commit/14d1835fc2d8385af5b8b4489d6b6bb077e510e4) Release 9 15 1 (#817) - [5f6c18e](https://github.com/appium/ruby_lib/commit/5f6c18ed9774fe027ee748e812ff91ee6d15a130) Add extend core (#816) - [c6e5321](https://github.com/appium/ruby_lib/commit/c6e532186b7552212ba61ab2e351dba247a35312) Tweak gemspec (#814) - [2864eec](https://github.com/appium/ruby_lib/commit/2864eec1d05fb69a461c37e4295f159aebe406ca) add tests and tweak helpers which handle xml (#813) - [e04afe9](https://github.com/appium/ruby_lib/commit/e04afe92dbe6ea38773c234deb97cb4a7f8ffdd2) Revert "Use ::REXML::Document by default in CountElements (#811)" (#812) - [1dcc665](https://github.com/appium/ruby_lib/commit/1dcc6650974a57369cc6b087b577cc1146bdaa1f) Use ::REXML::Document by default in CountElements (#811) #### v9.15.0 2018-08-10 - [b09ea84](https://github.com/appium/ruby_lib/commit/b09ea848cc595d8d3ef6494e0a26770521b9432c) Release 9 15 0 (#810) - [2e05c62](https://github.com/appium/ruby_lib/commit/2e05c62b07d7c8e395e429fe8b5add58cd41d2d2) Fix rubocop for mighty (#809) - [b4da941](https://github.com/appium/ruby_lib/commit/b4da94126b8f7791c510e81d7f080b248bbcdb72) add a pull reqeust template (#808) - [e553b3f](https://github.com/appium/ruby_lib/commit/e553b3fab6e733cb91a42dab93ea5331af79fa76) add a section about parallel tests (#807) - [6c6b73f](https://github.com/appium/ruby_lib/commit/6c6b73f18e76c73e71fde1ddf265913472423bce) update core version (#806) - [a1b2182](https://github.com/appium/ruby_lib/commit/a1b2182ac1f85b0f48ff934221876e9fd3292189) Relax absolute app path (#804) - [30ca236](https://github.com/appium/ruby_lib/commit/30ca236d871e06efc069ff59c5f13753dc109971) add a limitation in readme (#803) #### v9.14.3 2018-07-07 - [355ce1a](https://github.com/appium/ruby_lib/commit/355ce1a1618a06353da5dbc02eeb339031e9ded1) Release 9 14 3 (#799) - [cc35f60](https://github.com/appium/ruby_lib/commit/cc35f60ee1b42204a9a368e1e7679354e4f05ee7) update (#798) - [08edb8c](https://github.com/appium/ruby_lib/commit/08edb8c92aa62d7227a9a49c9d33bcbb82de7841) add tizen (#797) #### v9.14.2 2018-06-25 - [15d656c](https://github.com/appium/ruby_lib/commit/15d656c7de10a52f3da233a78e939733d9ca4f2a) Release 9 14 2 (#796) - [4a8261f](https://github.com/appium/ruby_lib/commit/4a8261fc24274a876d03aa61ea81028d070c3a46) add find element/s by image (#795) - [23bf449](https://github.com/appium/ruby_lib/commit/23bf44916c9e97af4e6cd0b9b64f87078aae05d2) add install certificate (#789) - [3791c86](https://github.com/appium/ruby_lib/commit/3791c86940d52d6eba5aeb29afd4d26698ec9777) Update readme.md (#791) - [b9679e1](https://github.com/appium/ruby_lib/commit/b9679e1295a031933b124530b85b30f9f086d2f3) Add get contexts (#788) #### v9.14.1 2018-05-31 - [cc322d6](https://github.com/appium/ruby_lib/commit/cc322d6a36ad85014b3eed1cdec4481f07b6a95d) Release 9 14 1 (#787) - [b2772d9](https://github.com/appium/ruby_lib/commit/b2772d952117a9e5d760904ddbfaf5828e8d44cf) Fix an initialisation error (#786) #### v9.14.0 2018-05-28 - [d60947d](https://github.com/appium/ruby_lib/commit/d60947df856da65dd31fcdbc34d71719a75d9003) Release 9 14 0 (#783) #### v9.13.0 2018-05-08 - [c8b797e](https://github.com/appium/ruby_lib/commit/c8b797ef404c57a24b00e9c355ec36b3335f4a5f) Release 9 13 0 (#781) #### v9.12.1 2018-05-06 - [8ce022f](https://github.com/appium/ruby_lib/commit/8ce022f0f8eabe668230f9aa63a0228d60704c05) Release 9 12 1 (#780) - [c9b0470](https://github.com/appium/ruby_lib/commit/c9b0470e866c6e70ba689628d4e0924db39f452c) add no hash but numeric case in wait (#779) - [9a8356b](https://github.com/appium/ruby_lib/commit/9a8356b84198c6c9afb4d1dcf9a9c4067424b4c8) Add syslog websocket ios re (#777) #### v9.12.0 2018-04-25 - [7a5a12c](https://github.com/appium/ruby_lib/commit/7a5a12ce78ce0a8154ea55ff7f44ecd10ba5b771) Release 9 12 0 (#775) - [7dcb4fa](https://github.com/appium/ruby_lib/commit/7dcb4fa287e61c813ab8f522e5a4d397a95f5039) remove hot fix actions (#773) #### v9.11.1 2018-04-22 - [778aaf4](https://github.com/appium/ruby_lib/commit/778aaf4dfd5879759fd296f770aef59a6eca685e) Release 9 11 1 (#772) - [c89f526](https://github.com/appium/ruby_lib/commit/c89f526e97be008b4320c89d7a02267dcb23aa1d) fix some tests and fix compatibility for wait (#771) #### v9.11.0 2018-04-19 - [91f4db4](https://github.com/appium/ruby_lib/commit/91f4db40f0b1e29bc77231f3ce850bee193d4968) Release 9 11 0 (#770) - [74437a7](https://github.com/appium/ruby_lib/commit/74437a7d10203ae6125dbcecd11d761b0dad3819) add mobile logs broadcast (#764) - [97c6421](https://github.com/appium/ruby_lib/commit/97c6421a557adb40dc134e0a6d65687e918498f3) remove old docs (#768) - [f58dace](https://github.com/appium/ruby_lib/commit/f58dacea3a003c8c7f4871fd788e9545185cb958) add some comments in examples for drivers (#767) - [0852bc7](https://github.com/appium/ruby_lib/commit/0852bc7c894015312f42ed252d1cfce185c6cf4e) clean docs up (#765) #### v9.10.0 2018-02-14 - [5538a43](https://github.com/appium/ruby_lib/commit/5538a43c96adda5b7400fd50e60f650873fef8b2) Release 9 10 0 (#763) #### v9.9.2 2018-02-12 - [31908a9](https://github.com/appium/ruby_lib/commit/31908a96bf6389f93e6dc3c013bf9d0a9a5b9e12) Release 9 9 2 (#762) - [51eb451](https://github.com/appium/ruby_lib/commit/51eb451348005a7f6b8e0677570811690b7208da) Fix Security Vulnerability (#761) #### v9.9.1 2018-02-02 - [591048d](https://github.com/appium/ruby_lib/commit/591048d98b63f1cde559227e166705147880902e) Release 9 9 1 (#759) - [03f2850](https://github.com/appium/ruby_lib/commit/03f2850f04e1a4fcb33b6f28f9c14e1efb694eff) Fix minitest revert (#758) #### v9.9.0 2018-01-29 - [913c6b5](https://github.com/appium/ruby_lib/commit/913c6b5098ebdd6659d949121b42f4a38d8c34d4) Release 9 9 0 (#756) - [b8d73ca](https://github.com/appium/ruby_lib/commit/b8d73cafcc429e04f06b891d688513a9622c730a) fix test and add the latest grid (#754) #### v9.8.5 2018-01-26 - [228c5dd](https://github.com/appium/ruby_lib/commit/228c5dd39189b61e4b541852d740fb5d67c8dfbd) Release 9 8 5 (#753) - [4dc8882](https://github.com/appium/ruby_lib/commit/4dc888211c605ad1d3fc7b38cd8427109698c0cd) Update CHANGELOG.md (#752) - [d185307](https://github.com/appium/ruby_lib/commit/d185307774bf2a9bc8a3d4e2ef871b0c00e1d73c) fix Minitest::VERSION error (#751) #### v9.8.4 2018-01-25 - [7b72377](https://github.com/appium/ruby_lib/commit/7b72377d4541c9e7d313631fc543ca93037b892c) Release 9 8 4 (#749) - [eeea236](https://github.com/appium/ruby_lib/commit/eeea2362bb4660f53cf274c155c57169de225e6a) fix: add condition flow for minitest (#748) #### v9.8.3 2018-01-14 - [5de0bec](https://github.com/appium/ruby_lib/commit/5de0bec7bed7096a92531e866f75f95ec29941bf) Release 9 8 3 (#746) - [d45ab00](https://github.com/appium/ruby_lib/commit/d45ab00320e4ceac60d01e4dadf5a171ecee9c14) Bump core to 124 (#743) - [275b0a3](https://github.com/appium/ruby_lib/commit/275b0a3ffe9d189e9876dbfcaa748302d6951755) add ruby 2.5 for travis (#742) #### v9.8.2 2017-12-27 - [500a7a3](https://github.com/appium/ruby_lib/commit/500a7a39e9db4642332ff5e1816d342cf5b4d4d5) Release 9 8 2 (#741) - [d465462](https://github.com/appium/ruby_lib/commit/d465462d1ba315a201ab11a01f5272046353fa27) update core (#740) - [987c4e3](https://github.com/appium/ruby_lib/commit/987c4e37372ca5c5d42a58ead6423b3e941e5ad7) add handling multiple apps (#738) - [1b8f8e3](https://github.com/appium/ruby_lib/commit/1b8f8e362359a1486508f23bc7f6b9cfafa103c5) Update and add description for actions (#737) - [c691c36](https://github.com/appium/ruby_lib/commit/c691c360e6052cf6adf369bc4c222478b18ab716) Add run shell sortcut for android (#732) #### v9.8.1 2017-12-17 - [1081ae0](https://github.com/appium/ruby_lib/commit/1081ae01e7cf5c4682cadcf0219b07912cc3734f) Release 9 8 1 (#731) - [8212de4](https://github.com/appium/ruby_lib/commit/8212de4037f8c0bcd0c9a5d828dec6db32ace697) update ruby_core to fix creating session for the W3C createSession for Appium (#730) - [e89b08f](https://github.com/appium/ruby_lib/commit/e89b08f931b378f5b56a2dbdd1b78e8ed382db9f) docs: fix the xcuitest link (#727) - [e12787d](https://github.com/appium/ruby_lib/commit/e12787dc1ebd35a9760e9e59e094bc30b2dfe627) add alias (#725) - [047ed32](https://github.com/appium/ruby_lib/commit/047ed3296ce5a33a4ea9814348dc4b8af2fbebcc) Release 9 8 0 (#724) - [5bfb413](https://github.com/appium/ruby_lib/commit/5bfb4130869ca7979e5216efac452c206edf3c06) docs: update ruby lib core (#722) - [6b5a449](https://github.com/appium/ruby_lib/commit/6b5a4493186083a09348ec060842a7dce15bfc5a) docs: update readme and insert URL to the core library (#721) - [3bab5b2](https://github.com/appium/ruby_lib/commit/3bab5b2bf8c82af3c81f32352de99cdba30b3c5a) doc: update comments (#720) - [9dfa0b9](https://github.com/appium/ruby_lib/commit/9dfa0b9c0c3df6f7ec88d578e304ad1fd3704742) refactor: replace core directory to core library (#718) - [04a6f45](https://github.com/appium/ruby_lib/commit/04a6f45bd6bbbce463919207a37bccdb5a39bdfc) docs: update readme (#719) #### v9.7.5 2017-11-04 - [1e1bb7e](https://github.com/appium/ruby_lib/commit/1e1bb7e3f1f500fa0dffe361b875b6b16941e290) Release 9 7 5 (#717) - [6a6d07e](https://github.com/appium/ruby_lib/commit/6a6d07e80686a171f76ea4fa013996e7f81f6fb9) fix: take care capybara case (#716) #### v9.7.4 2017-10-28 - [8522f49](https://github.com/appium/ruby_lib/commit/8522f496eff2a72648a563af8ce06cb8c7270256) Release 9 7 4 (#715) - [ad6ca97](https://github.com/appium/ruby_lib/commit/ad6ca9709351b99f547b789846be3faf62f6558f) fix: Define source in common section (#714) - [bb80136](https://github.com/appium/ruby_lib/commit/bb80136adf909f49582ff69f2c9276669b4edf78) remove todo (#712) - [b7a6e1d](https://github.com/appium/ruby_lib/commit/b7a6e1d3e2ed0a04de571c857f6c469ac6f24153) refactor: Define multi touch base class (#711) - [14ff169](https://github.com/appium/ruby_lib/commit/14ff169cf91b36750d1e8cb498723884dcdc66b8) feature: add unlock (#710) #### v9.7.3 2017-10-21 - [e570a64](https://github.com/appium/ruby_lib/commit/e570a640106c57521335f837082cf00abf0d8c10) update changelog (#709) - [f598950](https://github.com/appium/ruby_lib/commit/f5989500dabcd21cd6daaacab828942de998497a) Release 9 7 3 (#708) - [67385e9](https://github.com/appium/ruby_lib/commit/67385e9c203c4bbd062c7bf3397fca7bbb8d636b) refactor: Separate touch actions (#707) - [d1dd4fb](https://github.com/appium/ruby_lib/commit/d1dd4fbea8958e0b317c59fd2a5aaa0d027078e9) refactor: set uiautomator2 by default for android (#706) - [8c92ace](https://github.com/appium/ruby_lib/commit/8c92ace7c3c27ee31714c8f3e7d2ebeb48bc07ec) feature: Add espresso bridge (#705) - [cc4f9e7](https://github.com/appium/ruby_lib/commit/cc4f9e7f67ab66ca0f20849b3b249b99b0671783) feature: Add espresso (#704) - [6088233](https://github.com/appium/ruby_lib/commit/60882332ca2a08cfcd7b6f5e6b37df98a68e396a) docs: clean up (#703) - [5cf149c](https://github.com/appium/ruby_lib/commit/5cf149c1304e5abc2fccd5477f22f6fd70f1cb85) docs: add examples and tag_name (#702) - [dd4ace1](https://github.com/appium/ruby_lib/commit/dd4ace10ee650e8b1e2c8bb50a4a29288a350949) add an example for the predicate (#701) - [3ea887d](https://github.com/appium/ruby_lib/commit/3ea887d17b6c0b7235f21e3424ada65fe662df22) feature: add get source for xcuitest (#699) - [9af174f](https://github.com/appium/ruby_lib/commit/9af174fd343481f2b38cd96344a7c24c071e5695) docs: update docs for search context (#700) - [798c3aa](https://github.com/appium/ruby_lib/commit/798c3aae8f5ec42f0286b17624e2d667e362b24c) feature: introduce process model (#698) - [3c6b146](https://github.com/appium/ruby_lib/commit/3c6b146ef21daefa2b86e24581483ee21a264de8) docs: separate parallel tests (#695) - [c73ed12](https://github.com/appium/ruby_lib/commit/c73ed12973efb4c4fea031810e2ca6678f363191) refactor: make export session path manageable (#694) #### v9.7.2 2017-10-07 - [f949287](https://github.com/appium/ruby_lib/commit/f94928755a29917cf6e1a04d702bff5e4823eedc) docs: update changelog (#693) - [1f20df4](https://github.com/appium/ruby_lib/commit/1f20df4ea663c881d10d173c2df178169f257c95) Release 9 7 2 (#692) - [51cba8e](https://github.com/appium/ruby_lib/commit/51cba8eca4346af945322898a5c61b91f60e4026) doc: add error message (#691) - [b9bb275](https://github.com/appium/ruby_lib/commit/b9bb2751313ea478ee775d979543f05dc44f9e21) feature: add flatten_hash_keys (#688) - [3bdc1f9](https://github.com/appium/ruby_lib/commit/3bdc1f9cf6ad5eb2279dfd6cb43e35fc469720de) fix: path for uiautomation (#690) - [3102784](https://github.com/appium/ruby_lib/commit/31027845774373e22b907242944f391ddf755581) fix: export session (#689) - [212f70e](https://github.com/appium/ruby_lib/commit/212f70e4f982d047e9f409b32fc5f4fc779ceb10) docs: Add documentation (#685) - [38670ef](https://github.com/appium/ruby_lib/commit/38670efc19b2350191cc440c1fc911fd20007694) docs: Add documentation (#683) #### v9.7.1 2017-10-01 - [ebde85f](https://github.com/appium/ruby_lib/commit/ebde85fac616ac09e19a5f8215195e536d88344d) Release 9 7 1 (#682) - [db29b66](https://github.com/appium/ruby_lib/commit/db29b664172935f7814266c7357e099969404fe3) fix: Fix appium version error (#681) #### v9.7.0 2017-10-01 - [bf12459](https://github.com/appium/ruby_lib/commit/bf124597977514e4d338efaaea5a29bdcbef5578) Release 9 7 0 (#679) - [a6240cb](https://github.com/appium/ruby_lib/commit/a6240cb3144679865b9ca455a3906586268c20db) refactor: Move window size method and touch related actions (#678) - [36ef57b](https://github.com/appium/ruby_lib/commit/36ef57b9b11c8efc0a6b458cf5c1a11c75b7ef0e) docs: update documentation and comments (#677) - [e3f5b0d](https://github.com/appium/ruby_lib/commit/e3f5b0d91b35d5b2b3b11e63911e2bf48ca11f08) refactor: define bridge in core (#676) - [eb7680f](https://github.com/appium/ruby_lib/commit/eb7680f6db1e821901045beacba0a8b80de722fb) refactor: collect no agrs in core/command (#675) - [f174e75](https://github.com/appium/ruby_lib/commit/f174e75e81912ddd5118e066349774caf54b4a74) remove some todos which isn't need more (#673) - [8471880](https://github.com/appium/ruby_lib/commit/84718805fb4c6246692564295294073b90ada700) refactor: separate core android ios more (#670) - [2e09e83](https://github.com/appium/ruby_lib/commit/2e09e839cce26571fb5857097d3c7f3391bfe3ff) refactor: move some drivers in core (#669) - [35b0ded](https://github.com/appium/ruby_lib/commit/35b0dedcfc08e66e6e7a9414db645e129bf5d373) refactor: replace extend for to bridge for in driver (#668) - [c1b6923](https://github.com/appium/ruby_lib/commit/c1b69232d556338dbcde1652af78534ce6b750c9) doc: add routes references (#667) - [d44f00a](https://github.com/appium/ruby_lib/commit/d44f00a6cb8f52770da4ae7b7d69b8eaf3ae1581) refactor: Reduce patch_webdriver_element and some DEPRECATIONs (#663) - [2f24cb2](https://github.com/appium/ruby_lib/commit/2f24cb2ba17becbbe0e5e96bd2e4eb672f026024) feature: update toggle touch id enrollment (#664) - [895874d](https://github.com/appium/ruby_lib/commit/895874d51f5491db6a26669ae8e6f78c243c6eb3) refactor: add some comments and remote_status (#662) - [e813dfe](https://github.com/appium/ruby_lib/commit/e813dfe5689c450945df41d8c1973d9d58b8b0ff) refactor: put warn if no device matched (#658) - [d95b02e](https://github.com/appium/ruby_lib/commit/d95b02e6fa6a78525af120e0096beb3559dc6f72) refactor: re-struct directories (#655) - [070be93](https://github.com/appium/ruby_lib/commit/070be935f52184f34462cd5b48ca3bf842c45ea2) docs: update the way to call Appium::Driver.new (#656) - [f600fe6](https://github.com/appium/ruby_lib/commit/f600fe6fbc55281c58b2593d0aa55ae93a32a913) refactor: separate some methods and modules (#651) #### v9.6.1 2017-08-27 - [a542287](https://github.com/appium/ruby_lib/commit/a5422874b4ab60430ab9d58289aac001ecd90ecf) Release 9 6 1 (#650) - [cb9450d](https://github.com/appium/ruby_lib/commit/cb9450d207fb2e23b4dfef4318f47ea3d04c7689) refactor: divide dependencies (#649) - [0673ad7](https://github.com/appium/ruby_lib/commit/0673ad71a0c13e72c96fa7928ce1077c3684d4c2) feature: add commands for get_pasteboard and set_pasteboard (#648) - [420c855](https://github.com/appium/ruby_lib/commit/420c855efb27e2dd84fce8b0dbeb0e86d41f72ee) use 1.8.0 to reduce constant ::Fixnum error (#647) - [f801cf2](https://github.com/appium/ruby_lib/commit/f801cf20127205c0c6daae91961276e17a402675) test: add a test for tap (#646) - [eafaa3d](https://github.com/appium/ruby_lib/commit/eafaa3d73124c46fba372730290dde9e2bac812d) doc: Update CHANGELOG.md (#645) #### v9.6.0 2017-08-20 - [e1a2cd4](https://github.com/appium/ruby_lib/commit/e1a2cd493a370655b390a1d3803a85fbdb5f7f9d) Release 9 6 0 (#643) - [6c6e916](https://github.com/appium/ruby_lib/commit/6c6e9165998a457188b1e53476c9bdbb18fa2ef7) refactor: separate uiautomator2 (#642) - [2b1a5ee](https://github.com/appium/ruby_lib/commit/2b1a5eef44be48df5e14dc42000b4a776a2bae5b) Append documentations (#640) - [6ee404d](https://github.com/appium/ruby_lib/commit/6ee404ddbe932b97d50904a2f273b7404485d79e) refactor: Separate xcuitest more (#639) - [8a7c386](https://github.com/appium/ruby_lib/commit/8a7c386a51e9f83826e1d5d799cc509cd0c7e3ae) feature: test code for multiple iOS simulators (#637) - [b7daaac](https://github.com/appium/ruby_lib/commit/b7daaac9b2262c80ee679263a809bd98371b312b) fix: Fix Android scroll_to and scroll_to_exact (#638) - [65b2c7a](https://github.com/appium/ruby_lib/commit/65b2c7a9edb65e50c61c5e64408e9d7ee36465cf) refactor: remove unused definition and rename arguments for initilizer (#635) - [35d3b11](https://github.com/appium/ruby_lib/commit/35d3b11dafac3363902fc0352a62d957fd90a947) Alias `quit_driver` to `driver_quit`. (#634) - [214cf72](https://github.com/appium/ruby_lib/commit/214cf72bd8aefffb974d5757d218a668e14a87c7) fix: Fix android tests and add broken ime methods (#633) - [aaf307d](https://github.com/appium/ruby_lib/commit/aaf307d9bacc30d5c9edb0507d1541ef626d3308) refactor: loading xcuitest related methods only for XCUITest case (#631) - [20bc86a](https://github.com/appium/ruby_lib/commit/20bc86a5195ef0f6d51ccba68019c1228cd2a0f1) add extending bridge commands for W3C (#632) - [6288409](https://github.com/appium/ruby_lib/commit/62884095bd59b420c1eb0d9295e9d3f31ca16195) refactor: set global driver as arguments (#629) #### v9.5.0 2017-08-05 - [19177f5](https://github.com/appium/ruby_lib/commit/19177f5348300a0e2e1e0510b99efac2f3067201) Release 9 5 0 (#628) - [4219f1d](https://github.com/appium/ruby_lib/commit/4219f1d3f639a421bc4fc6a772c242d782357ae1) feature: support selenium-webdriver3.4.1+ (#627) #### v9.4.10 2017-07-30 - [6eae1b6](https://github.com/appium/ruby_lib/commit/6eae1b6412ba8dc6c967a44dd9a987944c8e6444) Release 9 4 10 (#626) - [3df1b2d](https://github.com/appium/ruby_lib/commit/3df1b2d212f1f0ea9975b80009894e4fa138a414) refactor: search contexts and its structure (#625) - [673bdef](https://github.com/appium/ruby_lib/commit/673bdeffba6946e932096e0bc44d5e8faaf3ec07) refactor: reduce complexity in android helper (#624) - [d5c9118](https://github.com/appium/ruby_lib/commit/d5c9118ca06f2e3daf3ea41ebe9aaf5769e7493e) Create ISSUE_TEMPLATE.md (#623) - [355207c](https://github.com/appium/ruby_lib/commit/355207cbb234a1f6fb98da1d5e328f371b35cbd8) doc: append a documentation for android coverage (#622) - [47a5ba9](https://github.com/appium/ruby_lib/commit/47a5ba98ed2ce7387382c6fbc38721a72331a8d1) refactor: use element.rect for Selenium Webdriver 3.4.0+ (#621) - [7cfa539](https://github.com/appium/ruby_lib/commit/7cfa539fe4359a40151d006c0a301496024a1c3f) chore: ignoring DS Store (#620) - [d834c97](https://github.com/appium/ruby_lib/commit/d834c97780e7e95d1488c57a6fae7e751db5fe6f) feature: add react native app (#619) - [947106f](https://github.com/appium/ruby_lib/commit/947106fdc5a8d2653b65cfa473a4eb1111835085) feature: add commit message format to handle release note smarter (#616) - [d126ba1](https://github.com/appium/ruby_lib/commit/d126ba14ba0533f3a54cb51a849443adbcf84e91) add progname (#615) - [9c4d555](https://github.com/appium/ruby_lib/commit/9c4d555c97ad99bbd6f0c8e359713fac959f8717) remove rails/duplicable and related methods (#614) #### v9.4.9 2017-07-01 - [cfe84fc](https://github.com/appium/ruby_lib/commit/cfe84fc009c418eebe95babf8160f36209f9fecf) Release 9 4 9 (#613) - [0e88589](https://github.com/appium/ruby_lib/commit/0e885890e3c9d7f5067869a9893009f0a32f7af0) fix handling element for xcuitest guestures (#611) #### v9.4.8 2017-06-24 - [209fb3f](https://github.com/appium/ruby_lib/commit/209fb3fce4f2e567c6d6ba2395eec9b98669d02d) Release 9 4 8 (#610) - [40c92eb](https://github.com/appium/ruby_lib/commit/40c92eb1a7e01663d2b9b47314d9e7a9fa0e6586) Add visibility for ios (#609) - [20307a0](https://github.com/appium/ruby_lib/commit/20307a06269aef7123c865091062b97cdbbe8430) mark deprecated for client side xpath strategy (#608) - [5d40446](https://github.com/appium/ruby_lib/commit/5d40446a913432113931d9430ff36c8179cc6cbb) Return a result of yield (#606) - [cc913ed](https://github.com/appium/ruby_lib/commit/cc913edb4bc24c18a58c2c5490dfb7b5a705d303) add getting current package name (#605) - [fa33239](https://github.com/appium/ruby_lib/commit/fa332395c2f4fae70bf672fb12f002a3194cdc2c) inherit selenium's wait (#603) #### v9.4.7 2017-06-11 - [ef9efbd](https://github.com/appium/ruby_lib/commit/ef9efbd6d3fadfaebaa4245bed40d28aec33be32) Release 9 4 7 (#601) - [29f031a](https://github.com/appium/ruby_lib/commit/29f031a0b8d180289cfd8a9de4216300916cd5cc) Ignore server version check for grid (#600) - [1b7a4b4](https://github.com/appium/ruby_lib/commit/1b7a4b45074761141d25b1461d0c23672889905d) Update CHANGELOG.md (#597) #### v9.4.6 2017-05-25 - [a44ea77](https://github.com/appium/ruby_lib/commit/a44ea770287407ba9b488e25e259884676c89709) Release 9 4 6 (#593) - [9f9c688](https://github.com/appium/ruby_lib/commit/9f9c688d1a9d0b2213dc41a256a0085a603f128e) exclude test directories and grids (#592) #### v9.4.5 2017-05-25 - [8e7ea79](https://github.com/appium/ruby_lib/commit/8e7ea79ca476bdc172015aea3ed2b4dc3b571d00) Release 9 4 5 (#590) - [4001282](https://github.com/appium/ruby_lib/commit/40012821fd3a3b5f7f484de951bec9fbb00f225c) add grid 2.x (#589) - [fa00890](https://github.com/appium/ruby_lib/commit/fa008908ce95d1d8cd76bd9bb1ea927b36a64f9a) update some grid parameters (#588) - [44e12cb](https://github.com/appium/ruby_lib/commit/44e12cb2f0aec3a9f9954819c68646ed83efb297) add grid settings (#587) - [4d98683](https://github.com/appium/ruby_lib/commit/4d986830facd0e4ef1978e247a3c8ffd0a02427b) skip loading Pry.config.pager = false if users have .pryrc (#585) - [517f30d](https://github.com/appium/ruby_lib/commit/517f30d6cdbcbf683311612c705ac876b1e3521a) fix some ambiguous gesture (#584) - [b69f0e0](https://github.com/appium/ruby_lib/commit/b69f0e0ce061ebeb6462b0118411af85b388addd) replace attr_accessor to attr_reader (#583) - [5eff035](https://github.com/appium/ruby_lib/commit/5eff0353ee32a40e56dea8b36a9b3bb86269579e) add touch and hold (#581) - [e736359](https://github.com/appium/ruby_lib/commit/e736359bc9b8b3a369dcbcc727cb858d2f98e94f) add alert test case (#579) #### v9.4.4 2017-05-13 - [230bac6](https://github.com/appium/ruby_lib/commit/230bac6fbcf26645111f76caab64dbf46de84897) Release 9 4 4 (#577) - [1facf0f](https://github.com/appium/ruby_lib/commit/1facf0f70d9607ba7d7e062d87ee7a900dbcd90a) add mobile alert (#575) - [a2b0675](https://github.com/appium/ruby_lib/commit/a2b067520de4237bd2cd71fd2a22f002cc3a8814) add travis example for ios (#573) - [2ff78b1](https://github.com/appium/ruby_lib/commit/2ff78b190f53011c9f0b26777cb1caf64410eaf8) clean hide_keybaord for ios (#572) - [27e10f8](https://github.com/appium/ruby_lib/commit/27e10f8ba310ce933171b169607172e593344ad7) revert _fix_android_native_source and instance counting (#571) - [4a70d78](https://github.com/appium/ruby_lib/commit/4a70d78d1fcf008654d54d47660f341321a3922e) update latest apk for android tests (#570) - [bd7d67b](https://github.com/appium/ruby_lib/commit/bd7d67b2dd12590937cf059e198d64bde6f9141d) add special thanks (#567) #### v9.4.3 2017-05-03 - [c413bd7](https://github.com/appium/ruby_lib/commit/c413bd77d0fec58e1c2cce6821694bcf659b9e1b) Release 9 4 3 (#566) - [8e600af](https://github.com/appium/ruby_lib/commit/8e600af469f0e00f1fb6cce331c72b13d11598c8) fix tests for uiautomator2 (#565) - [ab8ecf8](https://github.com/appium/ruby_lib/commit/ab8ecf860088f690777e7c8086c31753463577c8) Update android_uiautomator.md (#564) - [4f035d3](https://github.com/appium/ruby_lib/commit/4f035d39a0b3a3c39a9ef6a5cd0d2cb19d39f7d4) Use uiautomator for uiautomator2 (#561) - [71d8eb6](https://github.com/appium/ruby_lib/commit/71d8eb676bf5ac6d83c5da112d068865d76ebab4) Add link to issue in generating release notes (#562) - [915e75d](https://github.com/appium/ruby_lib/commit/915e75d08e89b4248ca104124f7430463c13ab22) don't use selenium-webdriver 3.5+ (#559) - [7e9c8ef](https://github.com/appium/ruby_lib/commit/7e9c8ef7fbed4e076fa6aec49f20d786fa6cbdf6) update workaround (#557) - [801a5a0](https://github.com/appium/ruby_lib/commit/801a5a07e5c1c062f5d108a844721c7a569765a3) add workaround (#556) #### v9.4.2 2017-04-21 - [0cd41ef](https://github.com/appium/ruby_lib/commit/0cd41ef58b6abf8444fcb95db59aebb2c6c2a890) Release 9 4 2 (#554) - [d01ebd2](https://github.com/appium/ruby_lib/commit/d01ebd28d350eab752dcc10f6f9675610cbb596c) fix drag_from_to_for_duration (#553) - [4f5a474](https://github.com/appium/ruby_lib/commit/4f5a4743b0acebbdefe6091a49cd86e1e3aa7eeb) add offset (#551) #### v9.4.1 2017-04-19 - [491a142](https://github.com/appium/ruby_lib/commit/491a142942cc0eb8addfb15e2bbd805d260cebc0) Release 9 4 1 (#550) - [d721297](https://github.com/appium/ruby_lib/commit/d721297a634cebc0d22f26a132345126036c71d6) separate find_element/s for uiautomator and xpath (#547) #### v9.4.0 2017-04-17 - [9492690](https://github.com/appium/ruby_lib/commit/9492690f80efaab79ce165e16dd335fca9717c4a) Release 9 4 0 (#545) - [2ea94c3](https://github.com/appium/ruby_lib/commit/2ea94c3933f1ecd1362c33f306348236facefc37) add mobile gesture (#542) - [1c7dd0f](https://github.com/appium/ruby_lib/commit/1c7dd0ff844265e76b3f2e15a0e6b3651005518f) use xpath instead of uiselectors (#544) - [5841a39](https://github.com/appium/ruby_lib/commit/5841a39d60b0986f1a1dd786b910bfbd6223d124) add mobile gesture for XCUITest (#537) #### v9.3.8 2017-04-13 - [7a7cf44](https://github.com/appium/ruby_lib/commit/7a7cf44c3cb11a90142285b8e8d731dc452b89eb) Release 9 3 8 (#540) - [5e67b88](https://github.com/appium/ruby_lib/commit/5e67b8813950148661bc4491811a696edeffc63c) allow using TestObject server (#538) - [9fdf89f](https://github.com/appium/ruby_lib/commit/9fdf89f9c3993730aabf1b8e25f03a773e565d98) add link to mobile gesture for XCUITets (#536) #### v9.3.7 2017-04-09 - [8daf6f7](https://github.com/appium/ruby_lib/commit/8daf6f773c9b8acd7a89e2a9225fd834de5b4e2e) Release 9 3 7 (#535) - [893c714](https://github.com/appium/ruby_lib/commit/893c714f4b60985753950f74e9e4b3bfb5f066eb) Remove appium suffix from find element (#532) - [61ee15c](https://github.com/appium/ruby_lib/commit/61ee15c58ec536db1c32f8e278f8214148c96552) Update docs for find_element/s (#531) - [17d17e6](https://github.com/appium/ruby_lib/commit/17d17e65a52cc22d093f913084673cb3a33b450c) fix markup (#526) - [9de862c](https://github.com/appium/ruby_lib/commit/9de862ca6440e8a2e864b7b342725ac7699c096b) fix the android doc markup (#525) #### v9.3.6 2017-03-31 - [0f1e3aa](https://github.com/appium/ruby_lib/commit/0f1e3aa48ce2d561af0a5897ab62017306009d8b) Release 9 3 6 (#523) - [4ae0815](https://github.com/appium/ruby_lib/commit/4ae081549cf1aad89c6d304fc8a8b9499db96160) Add toggle touch id enrollment (#521) #### v9.3.5 2017-03-26 - [c652bb3](https://github.com/appium/ruby_lib/commit/c652bb3332016a3c8ba7502e31477a330ab1c1ab) Release 9 3 5 (#520) - [c8ae26d](https://github.com/appium/ruby_lib/commit/c8ae26d6c9c400c5f40c3d1b620a3a5ba09c5932) Add some android commands (#517) - [e0db50e](https://github.com/appium/ruby_lib/commit/e0db50e5635dc359620eec9f79609f55af6ba529) Add class chain (#515) - [43ea919](https://github.com/appium/ruby_lib/commit/43ea919e4830477751f98aa6cf2475a54bcecb8e) [WIP]add scrollable index param into scroll_uiselector (#507) - [80f8071](https://github.com/appium/ruby_lib/commit/80f80715dcee6de968700ece40894222af41579a) add clearing actions after calling perform (#512) #### v9.3.4 2017-03-16 - [2b01065](https://github.com/appium/ruby_lib/commit/2b01065d0b2c2287ed9568cb23de5e459082ef62) Release 9 3 4 (#509) - [0abf62f](https://github.com/appium/ruby_lib/commit/0abf62f0fa99d1ce0841a98e86a6ca334a143f0e) add doc for uiautomator (#508) - [0199159](https://github.com/appium/ruby_lib/commit/0199159b6f0193884ebcffbfa460b3403859e537) Search with predicate (#504) - [dbd8762](https://github.com/appium/ruby_lib/commit/dbd87620b771e7448e9826181b0ae595701ccaa2) Update deactive app for xcuitest (#502) - [e06b25e](https://github.com/appium/ruby_lib/commit/e06b25ed1df5ed1a67fcf1a59767cc42ddcdb0d0) add a test for predicate (#499) - [447f13c](https://github.com/appium/ruby_lib/commit/447f13cd799652d203bed4fc557b3c251ef2aa2c) Use awesome print 1.7 (#498) - [a68cc5f](https://github.com/appium/ruby_lib/commit/a68cc5fc38b64d1d41945024a808df9af90828d7) remove workaround for rainbow (#497) #### v9.3.3 2017-02-18 - [422a468](https://github.com/appium/ruby_lib/commit/422a4683f10fc99d3731985d532b71e1fe80b4e6) Release 9 3 3 (#494) - [c09cf1e](https://github.com/appium/ruby_lib/commit/c09cf1efb33b276d6faf179b1344435df5dc7d16) add tags_include and tags_exact to find value (#490) #### v9.3.2 2017-02-11 - [39fd66f](https://github.com/appium/ruby_lib/commit/39fd66f354b6fdd6bba7ae6f5e28f86dc301cdf9) Release 9 3 2 (#487) - [7edcd09](https://github.com/appium/ruby_lib/commit/7edcd098be56c0ea72c4d33f91600009df1c1b88) Update changelog and add tests (#486) - [5731059](https://github.com/appium/ruby_lib/commit/5731059766542b5a7615fff20644db42177586e4) allow SAUCE_ENDPOINT env var to override sauce server url/path (#485) #### v9.3.1 2017-02-05 - [fa555d1](https://github.com/appium/ruby_lib/commit/fa555d10e7a5c48e4976fbbf2e9c061a5948d6bd) Release 9 3 1 (#484) - [c3bc3be](https://github.com/appium/ruby_lib/commit/c3bc3bed375c76e5a7c5fd76bb1225adad54656c) add changelog (#483) - [6849567](https://github.com/appium/ruby_lib/commit/68495675f35856bbf4179176f23a3c05f4cb1592) add getting performance command (#480) - [0b52c16](https://github.com/appium/ruby_lib/commit/0b52c16b6bf0591b500b1f6e1ebc04c0a7032cc6) Fix missed var rename (#481) - [54a8979](https://github.com/appium/ruby_lib/commit/54a897908c066905fd99b5eee7d539a757e987ac) add android tests for capabilities (#477) - [5ba85ec](https://github.com/appium/ruby_lib/commit/5ba85ec455378505dd953002ae5aca8bbd980a1f) add documents for toml (#478) - [bab7df7](https://github.com/appium/ruby_lib/commit/bab7df7f097fef9e848f33a60d70d0e7e018c25c) Clarify disabling Sauce Labs. (#471) - [cf0bda0](https://github.com/appium/ruby_lib/commit/cf0bda06c392274949843888272a762b9ed01a47) remove outdated methods (#475) #### v9.3.0 2017-01-22 - [a1c2872](https://github.com/appium/ruby_lib/commit/a1c287296c9eace08ef19449998fba7229b65697) Release 9 3 0 (#474) - [23d937a](https://github.com/appium/ruby_lib/commit/23d937a60da55c2d95ccbbda07ad23bda1b53a7b) update changelogs for v9.3.0 (#472) - [34803ef](https://github.com/appium/ruby_lib/commit/34803ef6b7b94df9ef4e147ba8fec5c1d2cfaada) arrange docs (#470) - [c1106aa](https://github.com/appium/ruby_lib/commit/c1106aaa6f48a4ed22dc1a7e55c9c4119cdef15c) fix returning only visible elements (#465) - [0104a87](https://github.com/appium/ruby_lib/commit/0104a87fad933598bb2b8ac1174319857494ba21) add capability to be able to set default timeout/interval for wait/wait_true (#468) - [1372e64](https://github.com/appium/ruby_lib/commit/1372e6453536eb64829825b5bf405ad0f11a9a46) fix typo (#467) - [a5ddd4a](https://github.com/appium/ruby_lib/commit/a5ddd4aa1d5f009b9024ee5aa5434805ba73895c) fix swipe, pinch, zoom (#466) - [a1c2e9e](https://github.com/appium/ruby_lib/commit/a1c2e9e815e9f85c929da857e26f419629d760df) fix appium server's version check (#464) #### v9.2.0 2017-01-09 - [958ae3e](https://github.com/appium/ruby_lib/commit/958ae3e2fc84b78191baf22e967c8a2fb7eded22) Release 9 2 0 (#460) - [292acdf](https://github.com/appium/ruby_lib/commit/292acdf323e7725ef6cc09f2c56d94a8f54ec801) update changelog for 9.2.0 (#458) - [1457728](https://github.com/appium/ruby_lib/commit/1457728872214746d9792d916a262a5f996e78ef) Remove last waits (#456) - [b10cf83](https://github.com/appium/ruby_lib/commit/b10cf837edafea96e2b2d13e7adf6a87dd448723) add examples for predicate (#455) - [d050100](https://github.com/appium/ruby_lib/commit/d050100c0f461c639c417f64ec12d569c412bfb6) Add some documents (#454) - [6ee434f](https://github.com/appium/ruby_lib/commit/6ee434f9dbabb7bdb775692382972731c39a71c9) set auomation name from server if client side is nil (#451) - [6abb146](https://github.com/appium/ruby_lib/commit/6abb14627fc454684ad4766d9dd95dfd4b52d564) add link to locatorStrategies (#449) - [74dc747](https://github.com/appium/ruby_lib/commit/74dc747f56fe78f2bd883c1070d2ea25af0fa382) add changelog (#448) - [4e8a449](https://github.com/appium/ruby_lib/commit/4e8a449bf2ff5a3e6f778389b336ecd1a712c25f) arrange a bit (#446) - [4efeefa](https://github.com/appium/ruby_lib/commit/4efeefa7e3cb751dcc11280e26169e4ba57b3065) Release 9 1 3 (#445) - [ba2fbdc](https://github.com/appium/ruby_lib/commit/ba2fbdcb206609259134fc09eac7940c21cc2c13) Release 9.1.3 #### v9.1.3 2017-01-04 - [ba2fbdc](https://github.com/appium/ruby_lib/commit/ba2fbdcb206609259134fc09eac7940c21cc2c13) Release 9.1.3 - [f0c15c5](https://github.com/appium/ruby_lib/commit/f0c15c5b0211b40a8412583c5180a19dc4b56047) update documentations in xcuitest (#444) - [67114d1](https://github.com/appium/ruby_lib/commit/67114d1c16f4289c9aa4e7bb02fcc05a08cc3575) Improve performance for button/s and text/s (#442) - [2d1f30e](https://github.com/appium/ruby_lib/commit/2d1f30e9b4d89dc51bb546d535c0bd3f14687394) simplify a bit and move tests to suitable file (#441) - [1efed4c](https://github.com/appium/ruby_lib/commit/1efed4cbf45b889ca9e64f91346e786a89ba3c42) add documentation for alternative long_press method (#440) - [71e629f](https://github.com/appium/ruby_lib/commit/71e629f34065b6a6e39e9bc18bcf4eb0576be0cb) update small changes (#439) - [cec023c](https://github.com/appium/ruby_lib/commit/cec023cc9388afe5283c7637622f369a9b891b1e) Use open timeout and read timeout and require selenium-webdriver3.0.4+ (#437) - [ffa78a6](https://github.com/appium/ruby_lib/commit/ffa78a64b1dd68fa24c80779eff0a9c2ab685c19) Release 9 1 2 (#434) - [22401b0](https://github.com/appium/ruby_lib/commit/22401b065f2317e82d37b5188ad9c18c701b0a41) Release 9.1.2 #### v9.1.2 2016-12-25 - [22401b0](https://github.com/appium/ruby_lib/commit/22401b065f2317e82d37b5188ad9c18c701b0a41) Release 9.1.2 - [ab3ba8e](https://github.com/appium/ruby_lib/commit/ab3ba8e0fd9e6867b63c5cd0a3f929aca8fc236b) Fix set immediate value (#432) - [75acc43](https://github.com/appium/ruby_lib/commit/75acc4313fffca87c3c9c54214175a9981c0d540) disable lint unified integer (#431) - [baf5f3c](https://github.com/appium/ruby_lib/commit/baf5f3c7bc3cf51b5f38878f40d88563546dfc10) update tests for finds_exact (#429) - [42df79b](https://github.com/appium/ruby_lib/commit/42df79b4cd0b5a36f52628f0acdeb688c5170c0c) fix identicalConditionalBranches (#428) - [2a91a6d](https://github.com/appium/ruby_lib/commit/2a91a6dcd50097101e212b1ed9fc64a470dd95da) add appium_client_version (#421) - [7c39087](https://github.com/appium/ruby_lib/commit/7c39087676071a4cf27d97fc309e13e968dfb21c) fix rubocop associated with block call (#422) - [1979cd8](https://github.com/appium/ruby_lib/commit/1979cd824947d1182fb99ff0f00dbfff165c0aab) Release 9 1 1 (#427) - [c016ba3](https://github.com/appium/ruby_lib/commit/c016ba3f9d265ca8b851ec8ed85670ee50b4215b) Release 9.1.1 #### v9.1.1 2016-12-19 - [c016ba3](https://github.com/appium/ruby_lib/commit/c016ba3f9d265ca8b851ec8ed85670ee50b4215b) Release 9.1.1 - [125f144](https://github.com/appium/ruby_lib/commit/125f144481f0b01ab7014ca83968924e7bf827ba) bugfix for finding an array of exact elements in ios (#424) - [586205a](https://github.com/appium/ruby_lib/commit/586205ab9d6ce0c286a6036616a7755b74f6a1ba) Release 9 1 0 (#419) - [ba9ec64](https://github.com/appium/ruby_lib/commit/ba9ec64031f242b3065674b1e4f8b236b391f9fa) Release 9.1.0 #### v9.1.0 2016-12-18 - [ba9ec64](https://github.com/appium/ruby_lib/commit/ba9ec64031f242b3065674b1e4f8b236b391f9fa) Release 9.1.0 - [5e2ed6a](https://github.com/appium/ruby_lib/commit/5e2ed6a984837ff30efa39ebd36e2ee5fc607c89) update readme and template (#418) - [e4b4426](https://github.com/appium/ruby_lib/commit/e4b4426a1322a3a552bad93c4d8a54c9592bebc6) Fix rubocop (#417) - [da4ed34](https://github.com/appium/ruby_lib/commit/da4ed34296ebffff8ed6d6b970ca5ca5a47ca72f) Require ruby 22 (#416) - [858863a](https://github.com/appium/ruby_lib/commit/858863ad88e0d4e32acb109c6bd087a040817fd2) Support over selenium-webdriver3.0.2 (#413) - [fbcaa62](https://github.com/appium/ruby_lib/commit/fbcaa62219eca64ebe8892f02d91b0103ee53909) update selenium-webdriver 3.0 and add patches to work with Appium (#383) - [19fb322](https://github.com/appium/ruby_lib/commit/19fb322fe0d9fc184fc708d111764e8b38c3c188) update some tips for finding elements (#412) - [e485121](https://github.com/appium/ruby_lib/commit/e4851210a2d0202bea3a62aea7f7c33798476466) Release 9 0 0 (#411) - [54ff9c4](https://github.com/appium/ruby_lib/commit/54ff9c45df80ce901b718347e79e761f93a4316b) Release 9.0.0 #### v9.0.0 2016-12-09 - [54ff9c4](https://github.com/appium/ruby_lib/commit/54ff9c45df80ce901b718347e79e761f93a4316b) Release 9.0.0 - [930d4c7](https://github.com/appium/ruby_lib/commit/930d4c701865cfab603c5030bd92d6049bb8b5ad) add documentations (#410) - [e765d1f](https://github.com/appium/ruby_lib/commit/e765d1f437a842c942e3efde0a33e15327571ced) Fix tests for xcuitest strategy (#408) - [cfabca1](https://github.com/appium/ruby_lib/commit/cfabca11933247e7fba6946d3128cf58035bd820) Feature/xcuitest (#388) - [75dd133](https://github.com/appium/ruby_lib/commit/75dd133d3279233312926aff66ec026a7c2e8766) Release 8 2 1 (#407) - [ad91ee4](https://github.com/appium/ruby_lib/commit/ad91ee47a96bf7a19b6f784dc760ac70b8788e5a) Release 8.2.1 #### v8.2.1 2016-11-29 - [ad91ee4](https://github.com/appium/ruby_lib/commit/ad91ee47a96bf7a19b6f784dc760ac70b8788e5a) Release 8.2.1 - [62488a5](https://github.com/appium/ruby_lib/commit/62488a551ee2545096a2f4256a41c39a82d506fc) bugfix_swipe_with_deltas (#405) - [fdeec0d](https://github.com/appium/ruby_lib/commit/fdeec0de9ac198d77d361c1fb18fc64679d98ac2) Add docs (#404) - [63ce8fa](https://github.com/appium/ruby_lib/commit/63ce8fa4eafffe0607b4fc11d86fbdab01a8f7bb) Release 8.2.0 (#403) - [4535ec9](https://github.com/appium/ruby_lib/commit/4535ec91f435255ae31b4c4fea9d96e5405d79f5) Release 8.2.0 - [afcc91e](https://github.com/appium/ruby_lib/commit/afcc91eabea63ec93f70f22b1095f7ce7022af76) Release 8.1.0 #### v8.2.0 2016-11-26 - [4535ec9](https://github.com/appium/ruby_lib/commit/4535ec91f435255ae31b4c4fea9d96e5405d79f5) Release 8.2.0 - [afcc91e](https://github.com/appium/ruby_lib/commit/afcc91eabea63ec93f70f22b1095f7ce7022af76) Release 8.1.0 - [8a08021](https://github.com/appium/ruby_lib/commit/8a080213dbe4843f50b6acfbe80628209bfd143d) add endpoint for handling IME in remote bridge (#400) - [222cd47](https://github.com/appium/ruby_lib/commit/222cd47f69ba24b82a122734b0a136e5d6aed330) Allow to name toml files differently than appium.txt, fixes #280 (#397) - [d3a9235](https://github.com/appium/ruby_lib/commit/d3a9235767d6ba770246afac0e62ac58da0eb4b0) update release note and documentation (#396) - [b5ac170](https://github.com/appium/ruby_lib/commit/b5ac170f1269e273a01a51429c5e45d2f3e989b1) Release 810 (#394) - [95d3a65](https://github.com/appium/ruby_lib/commit/95d3a6535472559590c4d043e887d15acc445a1a) Release 8.1.0 - [4b5d817](https://github.com/appium/ruby_lib/commit/4b5d81752565f02645e301555e4be78b0235daf5) Release 8.1.0 #### v8.1.0 2016-11-18 - [95d3a65](https://github.com/appium/ruby_lib/commit/95d3a6535472559590c4d043e887d15acc445a1a) Release 8.1.0 - [4b5d817](https://github.com/appium/ruby_lib/commit/4b5d81752565f02645e301555e4be78b0235daf5) Release 8.1.0 - [6c38ca5](https://github.com/appium/ruby_lib/commit/6c38ca5276342ade6168eb9080424a03608a1b3e) replace end_ to delta_ because end_ is deprecated in #380 (#392) - [09654ab](https://github.com/appium/ruby_lib/commit/09654ab9dbc69a31eff7e7bd426db985da09e3b8) Add EventListener to Driver (#389) - [2d8fc5f](https://github.com/appium/ruby_lib/commit/2d8fc5ff7acce9417847e66772b59fc691c1dbaa) Added touch id endpoint (#384) - [11b80e3](https://github.com/appium/ruby_lib/commit/11b80e398e98fbc71e580f659764ba54f87da4f3) Added double_tap and two_finger_tap to Appium::TouchAction (#377) - [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) - [6705226](https://github.com/appium/ruby_lib/commit/67052266b601270d2432c18b47739c9681af5563) Use secure sauce endpoint (https://ondemand.saucelabs.com:443) (#378) - [acdcff0](https://github.com/appium/ruby_lib/commit/acdcff06ae10f1ff4461ed94486346b4514a6e3a) Merge pull request #376 from sergey-plevako-badoo/add_double_tap_and_two_finger_tap - [eea3a6f](https://github.com/appium/ruby_lib/commit/eea3a6feaccd317b8a8ac4e2f83cc867613cdd02) Added double_tap and two_finger_tap to Appium::TouchAction - [ac03116](https://github.com/appium/ruby_lib/commit/ac03116756a72fbd624fa32ea886123b955d7089) Include url in raised connection error (#374) - [924c28b](https://github.com/appium/ruby_lib/commit/924c28bfa675b23b2519565dbcb0ee3531f05cd9) Fix docs of find elements (#372) - [8b71cdc](https://github.com/appium/ruby_lib/commit/8b71cdc81be8f50f5f97f0131aee5f3dc67c3eb7) Add default value for duration in swipe (#368) - [f58c8aa](https://github.com/appium/ruby_lib/commit/f58c8aa5a9eb349a7224c5c460c5a866444ff5dd) Merge pull request #363 from SrinivasanTarget/master - [f8cff26](https://github.com/appium/ruby_lib/commit/f8cff2659992962b6ab5bf49fa075b02d2d110ef) updated webdriver dependency #### v8.0.2 2016-01-29 - [d67cbba](https://github.com/appium/ruby_lib/commit/d67cbbac43f511515f6e6f53197cfae2bb7671e0) Release 8.0.2 - [ec6815d](https://github.com/appium/ruby_lib/commit/ec6815dcc56ec0e1b56e2ae9eab5786e93d20eec) Update iOS platform version - [92be077](https://github.com/appium/ruby_lib/commit/92be077e9eee04f411ac6d93c66004c51fddcbf1) Merge pull request #361 from SrinivasanTarget/master - [02a3f5f](https://github.com/appium/ruby_lib/commit/02a3f5f049059401a594db5c4d01202f7112f258) Add device_time - [aeb8f9a](https://github.com/appium/ruby_lib/commit/aeb8f9aff7f7288b9f932182a19f8a99c4ffe2fd) Update selenium-webdriver dependency to 2.49 #### v8.0.1 2016-01-10 - [ed91786](https://github.com/appium/ruby_lib/commit/ed917866929f0f7b0ff7ef0aedb5a9b35fdcc95b) Release 8.0.1 - [373f110](https://github.com/appium/ruby_lib/commit/373f11073ba9e8505be18e1826a02cc7d4b62478) Update contributing.md - [be4dca6](https://github.com/appium/ruby_lib/commit/be4dca6e8918e368864c383d34a0974c4a0f2a59) Merge pull request #358 from bayandin/change-toml-parser - [9a386c4](https://github.com/appium/ruby_lib/commit/9a386c4cb305a9e7440f8c699317087c36f1db33) Replace toml with tomlrb - [2ce8376](https://github.com/appium/ruby_lib/commit/2ce83763f7f81caf972b394fa5da7b8cf3065ca7) Merge pull request #357 from bayandin/selenium-compatibility - [28f6efb](https://github.com/appium/ruby_lib/commit/28f6efbacfa4954ab487bafd801cb0a68dee8d5d) Do not check platformName in passed caps #### v8.0.0 2015-10-08 - [e71fd1e](https://github.com/appium/ruby_lib/commit/e71fd1e1a220d9453a954ece00e07875a6b5f7ef) Release 8.0.0 - [c89464f](https://github.com/appium/ruby_lib/commit/c89464f22314d7521292f2b3e9367e53f1c5f00e) Update selenium-webdriver dependency to 2.48 - [d9fbf8b](https://github.com/appium/ruby_lib/commit/d9fbf8b71c895328c7c0f5ca1de9d4d76490a235) Merge pull request #354 from titusfortner/command_fix - [829c76b](https://github.com/appium/ruby_lib/commit/829c76b8f2e2b535dc230106a5e403663d301145) fix COMMANDS location - [ad8bf40](https://github.com/appium/ruby_lib/commit/ad8bf400711005f32440618b370ee2551f172a7d) Update badges - [252e838](https://github.com/appium/ruby_lib/commit/252e83806318df7df28e9060d3f8e1e56dc732ba) Disable Travis email spam #### v7.0.0 2015-05-08 - [af83896](https://github.com/appium/ruby_lib/commit/af838966d0724793d3dbfa35798ca6dd9f8a3143) Release 7.0.0 - [7bb780d](https://github.com/appium/ruby_lib/commit/7bb780d2f3d4bbbc2dcade6cd0aa9fdf5cd7b3d9) Fix make_docs script - [b8cc4dd](https://github.com/appium/ruby_lib/commit/b8cc4dd425c6b1605d0a67ded8b51dac0ac0373d) Add note about implicit wait change - [2599a46](https://github.com/appium/ruby_lib/commit/2599a465896add2cf11634d26bf81bba4a99f39c) Fix set_location Android test on emulator - [8162e27](https://github.com/appium/ruby_lib/commit/8162e274732172229df48834c188fbf7d3819430) Work around empty app strings - [1657f8c](https://github.com/appium/ruby_lib/commit/1657f8c58c8c8505c3e7f07657fddc6c0b8f154e) Merge pull request #333 from hipyard/geolocation_pr - [dbb32b2](https://github.com/appium/ruby_lib/commit/dbb32b25e11576411ae4f62735b4f38e71e074d4) add set_location method for setting geolocation - [e441d6d](https://github.com/appium/ruby_lib/commit/e441d6d7d2219194cda58f194c07553e81c4d4d8) Merge pull request #334 from hipyard/settable_logger - [ed56450](https://github.com/appium/ruby_lib/commit/ed56450de85926f9bf991f4c50dca81fadad3376) logger setter method - [8634cad](https://github.com/appium/ruby_lib/commit/8634cad862f98fcd74e2262261dc86c21f3b5595) Merge pull request #336 from JaniJegoroff/fix-tests - [4afcf6f](https://github.com/appium/ruby_lib/commit/4afcf6fac61a973f41e165cf2bb8e48aab5d9ac4) Fix for "undefined local variable or method" errors - [9ea0754](https://github.com/appium/ruby_lib/commit/9ea07543fd760b3da09ae2673618caff0a383ae2) Merge pull request #330 from JaniJegoroff/add-locked-method - [73a7dc0](https://github.com/appium/ruby_lib/commit/73a7dc0b45098e4b26e5fef62207a87e4d6e61a1) Add device_locked? method - [1348a8c](https://github.com/appium/ruby_lib/commit/1348a8c015b36d7346542443229b3dfe338a3e48) Update .rubocop.yml - [de37577](https://github.com/appium/ruby_lib/commit/de37577fec4eac123c8b07873acd6d0a81de1cc4) Update dependencies - [b19d0e0](https://github.com/appium/ruby_lib/commit/b19d0e03940d80314cb61c3c86f28c6f54e9da57) Improve promote method documentation - [1b88060](https://github.com/appium/ruby_lib/commit/1b88060dc0a439e02323f52d6d695b1587aeba17) Merge pull request #329 from appium/rubocop - [e9d1986](https://github.com/appium/ruby_lib/commit/e9d1986a1e46319bfb42fa30de8c4778f6dbc3fb) Fix remaining rubocop issues - [7feace9](https://github.com/appium/ruby_lib/commit/7feace96c7030455a45c7527d3b5c4f184c3abab) Merge pull request #327 from JaniJegoroff/stable-android-tests - [502c9d5](https://github.com/appium/ruby_lib/commit/502c9d56e1f1fcfcce1f6016b1484499ec5f2522) Fix for Android tests - [b73c782](https://github.com/appium/ruby_lib/commit/b73c78237c4b331b9e4602bd92da7a2de45afc15) Fix rubocop Rakefile issues - [93cb8a5](https://github.com/appium/ruby_lib/commit/93cb8a59aa7f4fb0b398aa67cd5b93b6e34534b2) Run rubocop on more files - [cd8638b](https://github.com/appium/ruby_lib/commit/cd8638b8dc5a3a313dbbad4c42ed9291789139a8) Merge pull request #325 from JaniJegoroff/rubocop-android-tests - [bd54f96](https://github.com/appium/ruby_lib/commit/bd54f9690e57695f85da8378a1f45fc7a314681b) Rubocop - Style/UnlessElse - [3c520a9](https://github.com/appium/ruby_lib/commit/3c520a90e8639bdb265f3849ff5d84ad751f5d78) Rubocop - Metrics/LineLength - [e80398f](https://github.com/appium/ruby_lib/commit/e80398f149d8f3767512831b91af598e98ec4d59) Rubocop - Lint/RescueException - [b41a3da](https://github.com/appium/ruby_lib/commit/b41a3dabbf662eaa3d6498245d2f305d7e0d96a9) Rubocop - Style/Semicolon - [af3ea2e](https://github.com/appium/ruby_lib/commit/af3ea2ee0f8aba75262966025965ef5cc6af0f86) Rubocop - Style/PredicateName - [7907af6](https://github.com/appium/ruby_lib/commit/7907af6f67add544ca122eb696ec5647b6a8652b) Rubocop - Style/BlockComments - [95d34b7](https://github.com/appium/ruby_lib/commit/95d34b71e268d67c7561e96d8a9206f6d9895b0b) Rubocop - Style/SignalException - [cd6728f](https://github.com/appium/ruby_lib/commit/cd6728f4836aea74bed25b1d4571d73319cd280d) Rubocop - Style/SymbolProc - [e383ac6](https://github.com/appium/ruby_lib/commit/e383ac618411c5055839bbd3a908e050e4039fdc) Rubocop - Style/PercentLiteralDelimiters - [211bd82](https://github.com/appium/ruby_lib/commit/211bd821deb40a20034c1c20bcc1572a8ba47aef) Rubocop - Style/LeadingCommentSpace - [d141499](https://github.com/appium/ruby_lib/commit/d14149962c3ec7788beda980fa849dc5ca4683e8) Rubocop - Style/CommentIndentation - [45dbc04](https://github.com/appium/ruby_lib/commit/45dbc0414df6c59879760d92b14ac3aa999b3d6f) Rubocop - Style/CommentAnnotation - [db0961f](https://github.com/appium/ruby_lib/commit/db0961f03351bb04cdc6f43421bd1099b1e9bbfa) Rubocop - Style/DeprecatedHashMethods - [d710d6e](https://github.com/appium/ruby_lib/commit/d710d6e68c19abaf1f30ea7c645f83c3efc80af0) Rubocop - Style/EmptyLinesAroundBlockBody - [e8875c1](https://github.com/appium/ruby_lib/commit/e8875c176710d49b1aa65db074cf4cc5f602df09) Rubocop - Style/SpaceInsideParens - [b489f48](https://github.com/appium/ruby_lib/commit/b489f48adc96c4241ec53dfe73b94161d1d8dbd1) Rubocop - Lint/AmbiguousRegexpLiteral - [807f258](https://github.com/appium/ruby_lib/commit/807f258766be2a892f7e1ddb8fb9eb89dd36c680) Rubocop - Style/TrailingComma - [432144f](https://github.com/appium/ruby_lib/commit/432144fbc54ff91985b54c9100b2b45f238a0b90) Rubocop - Style/MethodDefParentheses - [510a2a6](https://github.com/appium/ruby_lib/commit/510a2a6ebc8ad3bfd6e8ad3c2720b8ac2ea76885) Rubocop - Lint/DeprecatedClassMethods - [47f1790](https://github.com/appium/ruby_lib/commit/47f179040dfaab80e043eaf11e5d2582b91c06c6) Rubocop - Style/BracesAroundHashParameters - [1b946fb](https://github.com/appium/ruby_lib/commit/1b946fbc2de48d73623c0f20340d74e2b2ecec9b) Rubocop - Style/HashSyntax - [86163f7](https://github.com/appium/ruby_lib/commit/86163f7ec0a247dd73885de14011821b6ebb2100) Rubocop - Style/TrailingBlankLines - [a7aef30](https://github.com/appium/ruby_lib/commit/a7aef30492334e57aa9e1e421062840765b852b3) Rubocop rake task - [1be017b](https://github.com/appium/ruby_lib/commit/1be017b14e1fedef9511a0341839b45d1d754c36) Merge pull request #324 from appium/rubocop - [fb534a0](https://github.com/appium/ruby_lib/commit/fb534a0078a0ce2097990591455f35d3d843da9b) Fix more rubocop issues - [893165d](https://github.com/appium/ruby_lib/commit/893165dc1a869a2d240c054e13d26438728efb98) Merge pull request #323 from JaniJegoroff/rubocop-ios-tests - [b1d9d5f](https://github.com/appium/ruby_lib/commit/b1d9d5fbdc54cb19a4b334d8820dfa7122118a9d) Rubocop - Metrics/LineLength - [39d8b4e](https://github.com/appium/ruby_lib/commit/39d8b4e8354cf8afbd96d8721582cdcab4b49b48) Rubocop - Lint/RescueException - [1460120](https://github.com/appium/ruby_lib/commit/1460120819e09c5879882661de49e7042d0892a4) Rubocop - Lint/HandleExceptions - [7f04d50](https://github.com/appium/ruby_lib/commit/7f04d50f7bea7a042115653d3f45d84d181b302c) Rubocop - Style/Semicolon - [1615e6d](https://github.com/appium/ruby_lib/commit/1615e6df1bd0dd5e721a5226cffb781d5a7c08bf) Rubocop -Lint/ShadowingOuterLocalVariable - [15e7c62](https://github.com/appium/ruby_lib/commit/15e7c62e068fdff2b935c53ad731351655027ce0) Rubocop - Style/SignalException - [0ecda98](https://github.com/appium/ruby_lib/commit/0ecda987aa73799dd45c423b5a1b7d28f595ca17) Rubocop - Style/BlockComments - [6dc9ee1](https://github.com/appium/ruby_lib/commit/6dc9ee16ab4d71f69da30f2e277dec787ebea8fd) Rubocop - Style/BlockComments - [a9d9573](https://github.com/appium/ruby_lib/commit/a9d9573a0b79490d357cd44ae8ac51f77bbfb83e) Rubocop - Style/SpaceAroundEqualsInParameterDefault - [66f4e14](https://github.com/appium/ruby_lib/commit/66f4e146a945db5a992c14805542ce3a4eb39ba0) Rubocop - Style/LeadingCommentSpace - [6c8efda](https://github.com/appium/ruby_lib/commit/6c8efdaca119c2b16728aac34ec97ed5516a689a) Rubocop - Style/PredicateName - [aef6dc9](https://github.com/appium/ruby_lib/commit/aef6dc9bfff3a7f17180ef5f3cd71013b8e3b256) Rubocop - Style/EmptyLinesAroundBlockBody - [c964236](https://github.com/appium/ruby_lib/commit/c9642368577156ac339755df0677432c8b21e11e) Rubocop - Style/CommentIndentation - [d9478af](https://github.com/appium/ruby_lib/commit/d9478afd066cd9add9993306ab6936cd450478b5) Rubocop - Style/SpaceAroundOperators - [22a329e](https://github.com/appium/ruby_lib/commit/22a329e4412be870fae9ddfef23974382038f05b) Rubocop - Style/BarePercentLiterals - [9b855c9](https://github.com/appium/ruby_lib/commit/9b855c904d578f7dcc317bee3d5db2f0d5108843) Rubocop - Style/SymbolProc - [4720e82](https://github.com/appium/ruby_lib/commit/4720e829b878ca048fa363073ba1f1fbe6afe1ec) Rubocop - Lint/AmbiguousRegexpLiteral - [7477497](https://github.com/appium/ruby_lib/commit/747749775a814bfc231037c1f41860e0df8a3b52) Rubocop - Style/StringLiterals - [40c060b](https://github.com/appium/ruby_lib/commit/40c060b64b64115a6780832955c84781db0381d4) Rubocop - Style/SpaceAfterNot - [2793129](https://github.com/appium/ruby_lib/commit/2793129df74057592069593db1eee80a4c5d673d) Rubocop - Style/CommentAnnotation - [e7750e9](https://github.com/appium/ruby_lib/commit/e7750e9897febdbd27192548af7b156925b9273d) Rubocop - Style/RedundantSelf - [403badd](https://github.com/appium/ruby_lib/commit/403badd2aaba11bd833210083a809fdd46da7e4e) Rubocop - Style/MethodDefParentheses - [a62ed2a](https://github.com/appium/ruby_lib/commit/a62ed2abf937da9875f7f16e8ffa0f390a5a33d7) Fix Rubocop rake task pattern - [1aaa1db](https://github.com/appium/ruby_lib/commit/1aaa1db2020a9dc37e3caa858c9290a814daf9e4) Rubocop rake task - [d2e1857](https://github.com/appium/ruby_lib/commit/d2e185708e41807e11bc1e607b9baada8e711823) Rubocop - Style/TrailingWhitespace - [602cb2a](https://github.com/appium/ruby_lib/commit/602cb2a18dfca30f4d0b6aeed84a5786175c1929) Rubocop - Style/TrailingBlankLines - [19507f5](https://github.com/appium/ruby_lib/commit/19507f584515484eba7b98acfada55bcf9d81e0e) Merge pull request #322 from JaniJegoroff/fix-ios-tests - [f0f4f84](https://github.com/appium/ruby_lib/commit/f0f4f847a244ed06b5bf53b5c9b02a3562b1cce2) Fixed iOS tests and updated documentation - [305ce9c](https://github.com/appium/ruby_lib/commit/305ce9c956be4879b3bb70f56a4df71fb4380c62) Add .rubocop.yml - [4b0383c](https://github.com/appium/ruby_lib/commit/4b0383c86c0fcfa98ab759b3f9d1b386ac33bb6b) Add travis. Update migration doc - [3dc3d0c](https://github.com/appium/ruby_lib/commit/3dc3d0cec10cd256dc4adb89e6c53b85107678ef) Merge pull request #320 from JaniJegoroff/rubocop-warning-fixes - [e539d7c](https://github.com/appium/ruby_lib/commit/e539d7c7596af1c56587a5056fef74d936ddc0ce) Renamed method installed? to app_installed? - [4ba5ed9](https://github.com/appium/ruby_lib/commit/4ba5ed90f19c5d9cf71b461142bc1a5890d20574) Link to new Ruby docs - [47276b5](https://github.com/appium/ruby_lib/commit/47276b5c11f47e0940d4407031f8bd7918c43094) Rubocop - Lint/UselessAssignment - [7ec6396](https://github.com/appium/ruby_lib/commit/7ec6396a166793c467fc7b1539d34f7ac6b55105) Rubocop - Style/ClassAndModuleChildren - [25cd420](https://github.com/appium/ruby_lib/commit/25cd420a602744ed30ff0fb99aef9c2821d46d8b) Rubocop - Style/PredicateName - [52d4910](https://github.com/appium/ruby_lib/commit/52d4910133c828de8d807de30e88104d772ab28c) Rubocop - Style/MethodName - [9df1000](https://github.com/appium/ruby_lib/commit/9df1000719f99aff44f1ac9623190531bf76b6c7) Rubocop - Style/CommentAnnotation - [156d595](https://github.com/appium/ruby_lib/commit/156d59563c663d937a3405098bb6204854d91592) Rubocop - Style/BlockComments - [dbda46d](https://github.com/appium/ruby_lib/commit/dbda46dcf7072fa5e8ad6304920f246245377f13) Rubocop - Style/LineEndConcatenation - [8c34235](https://github.com/appium/ruby_lib/commit/8c342350ad939875893e8efda347de7e0b4fd03b) Rubocop - Metrics/BlockNesting - [97e54a6](https://github.com/appium/ruby_lib/commit/97e54a6b73669ffe52d23665b8492d49b54e03fa) Rubocop - Style/VariableName - [5222346](https://github.com/appium/ruby_lib/commit/52223461b25e61de5fb3f3e73fbf8a3aef356188) Rubocop - Style/AlignParameters - [22f849e](https://github.com/appium/ruby_lib/commit/22f849e6318c9843ea9f03c3cb68b9e60b29c323) Rubocop - Metrics/MethodLength (custom method length) - [58aae60](https://github.com/appium/ruby_lib/commit/58aae603561270163a792354da9113fb59242f67) Rubocop - Style/ConstantName (cop disabled) - [2bc8006](https://github.com/appium/ruby_lib/commit/2bc8006d2e21ba9088f3e6ed14be9c57af905565) Rubocop - Style/IfUnlessModifier - [3434ec7](https://github.com/appium/ruby_lib/commit/3434ec76648eb354e6ea77c382f800ea7c64d098) Rubocop - Style/AlignHash - [548f632](https://github.com/appium/ruby_lib/commit/548f632ce73b7ded082982301369248004af4a55) Rubocop - Style/MultilineOperationIndentation - [610c172](https://github.com/appium/ruby_lib/commit/610c172530d141a98c28880f9cc0973be6123183) Rubocop - Lint/AmbiguousRegexpLiteral - [c68702d](https://github.com/appium/ruby_lib/commit/c68702d78459b94a656db7644eb03aae5616d26c) Rubocop - Style/SignalException - [318372e](https://github.com/appium/ruby_lib/commit/318372e7a90d34f2ce00816b9f824d41adebb36c) Rubocop - Style/NilComparison - [7994d0f](https://github.com/appium/ruby_lib/commit/7994d0fe82d1353d4f91bddea3cbbb583d0ef5d6) Rubocop - Style/PercentLiteralDelimiters - [4a6902d](https://github.com/appium/ruby_lib/commit/4a6902dbbfe74eb83d290643138aab803c4abf5f) Rubocop - Style/GuardClause - [07ebfbf](https://github.com/appium/ruby_lib/commit/07ebfbfac19aba459b5711ace9fe87cfe877c2db) Rubocop - Style/SingleSpaceBeforeFirstArg - [ded2c9a](https://github.com/appium/ruby_lib/commit/ded2c9a400549942178146addcc3eb86251f768b) Rubocop - Style/CaseEquality - [cd7c67e](https://github.com/appium/ruby_lib/commit/cd7c67e56293297c49becaff1eb213e782ab5819) Rubocop - Style/MultilineTernaryOperator - [afddea3](https://github.com/appium/ruby_lib/commit/afddea3188c4ce877e6babdf32833e0485b5864b) Rubocop - Style/CaseIndentation - [a843671](https://github.com/appium/ruby_lib/commit/a8436714e000887cbf2b22a77369686df32e937a) Rubocop - Style/EmptyLinesAroundClassBody - [829b17d](https://github.com/appium/ruby_lib/commit/829b17dd7625c3ece5b79ae8c8c053fa6c70d337) Rubocop - Lint/ShadowingOuterLocalVariable - [f5fd8cf](https://github.com/appium/ruby_lib/commit/f5fd8cf487194a53c9c72d738c1c69e669b97cfb) Rubocop - Style/RedundantSelf - [4444168](https://github.com/appium/ruby_lib/commit/444416801d5bf7176c83e4bddd60969b375a4ec5) Rubocop - Style/LeadingCommentSpace - [b18ae54](https://github.com/appium/ruby_lib/commit/b18ae540e02f3de50851fbf5128d53a31328fbb5) Rubocop - Lint/UnusedMethodArgument - [4e24752](https://github.com/appium/ruby_lib/commit/4e2475266401ae72f7506ed5e14cf340d19e4898) Rubocop - Style/FirstParameterIndentation - [5841e9d](https://github.com/appium/ruby_lib/commit/5841e9d6c6879f2aa3a0b13791e6a93086f8a96f) Rubocop - Style/DeprecatedHashMethods - [0264c37](https://github.com/appium/ruby_lib/commit/0264c376d9f81ce1037a106314594e23438ca723) Rubocop - Lint/DeprecatedClassMethods - [1923f64](https://github.com/appium/ruby_lib/commit/1923f6484b7920199604647b682ba935213bb813) Rubocop - Metrics/LineLength - [0ab729a](https://github.com/appium/ruby_lib/commit/0ab729a16b6678ac993dafd93d05d8cf6ceb0703) Custom config file for Rubocop - [6f18e6f](https://github.com/appium/ruby_lib/commit/6f18e6f24519bc77581da2fcd1a9d048b2850e15) Rubocop - Style/ColonMethodCall - [7ba83e5](https://github.com/appium/ruby_lib/commit/7ba83e575ae255f561e919a5a850cab96a14b3bc) Rubocop - Style/IndentationWidth - [20ebd0b](https://github.com/appium/ruby_lib/commit/20ebd0bc014e7f9e5ee3066b20562d602bf87751) Rubocop - Style/BracesAroundHashParameters - [9b08ab7](https://github.com/appium/ruby_lib/commit/9b08ab7f43ca6b0bbfea42afcec61146348bcd19) Rubocop - Style/HashSyntax - [7f28fb2](https://github.com/appium/ruby_lib/commit/7f28fb250abf7b6ea0279c9b19432f13ecfee90c) Rubocop - Style/MultilineOperationIndentation - [978b648](https://github.com/appium/ruby_lib/commit/978b6485b6b959f0cd2b481d67d2972914e84abf) Rubocop - Style/CommentAnnotation - [e939a7c](https://github.com/appium/ruby_lib/commit/e939a7cd8d720aaabc8c5a8f1e9bdfc82db1bdd2) Rubocop - Style/CommentIndentation - [40b6e10](https://github.com/appium/ruby_lib/commit/40b6e10b1aacad0747c1ff26795c27064f77538a) Rubocop - Style/EmptyLinesAroundModuleBody - [49ba5a9](https://github.com/appium/ruby_lib/commit/49ba5a9c9a7d5178f8f65b10a6f78670c4e9bada) Rubocop - Style/ClassCheck - [5b40de9](https://github.com/appium/ruby_lib/commit/5b40de93f3b533304802e1dbf90ea9448a5f5ffa) Rubocop - Style/SelfAssignment - [3e20158](https://github.com/appium/ruby_lib/commit/3e20158258d0ca85bb947cba81e4b1c70f6c44b9) Rubocop - Style/EmptyLines - [91de46e](https://github.com/appium/ruby_lib/commit/91de46e1fde964a64ff580a629e5d87481603cb7) Revert "Rubocop - Style/RegexpLiteral" - [d79ad18](https://github.com/appium/ruby_lib/commit/d79ad184c27a88766b38b27f5dd0ad0d361af592) Rubocop - Style/RegexpLiteral - [9a38dfb](https://github.com/appium/ruby_lib/commit/9a38dfb2255e47c732cc5ae72a76d366f96be198) Rubocop - Lint/AmbiguousOperator - [ab06fa4](https://github.com/appium/ruby_lib/commit/ab06fa4f47c8fde0108cafa3de15fb8eb5176170) Rubocop - Lint/UnusedBlockArgument - [4ce71f8](https://github.com/appium/ruby_lib/commit/4ce71f82b554c193bd741c100c9fdd15f193773c) Rubocop - Style/SymbolProc - [8389f70](https://github.com/appium/ruby_lib/commit/8389f70a91dc9ae540b94b89ed67f65dce9fefc5) Rubocop - Style/BarePercentLiterals - [b818def](https://github.com/appium/ruby_lib/commit/b818defb371a4fe69b30254255556422ecc8e9c0) Rubocop - Style/MethodDefParentheses - [f2ed949](https://github.com/appium/ruby_lib/commit/f2ed949ae8fa94ca54241a37856c5805afc8e983) Rubocop - Style/SpaceAroundOperators - [4fe1f3c](https://github.com/appium/ruby_lib/commit/4fe1f3c6f852d17c4463bddff87005947cd3e5da) Rubocop - Style/AccessModifierIndentation - [76a8888](https://github.com/appium/ruby_lib/commit/76a8888350af9f2e94777d48dd56440fc74ef5d7) Rubocop - Style/RedundantReturn - [96c65d7](https://github.com/appium/ruby_lib/commit/96c65d7ecb12d426bb8b004abe27d487cf7144ba) Rubocop - Style/TrailingComma - [da9c079](https://github.com/appium/ruby_lib/commit/da9c079b81d9078d6f1d9381231f4b2ca27df4db) Rubocop - Style/SpaceInsideBlockBraces - [3fc783e](https://github.com/appium/ruby_lib/commit/3fc783e98800c1bad9bda20ce956e9e1729e6caf) Rubocop - Style/TrailingWhitespace - [55b3c90](https://github.com/appium/ruby_lib/commit/55b3c9022dcf21141b6efd4d0f6afc440910c288) Rubocop - Style/SpaceAroundEqualsInParameterDefault - [677d7e2](https://github.com/appium/ruby_lib/commit/677d7e21eff15d72c02386c97b4cc454442d0f51) Rubocop - Style/TrailingBlankLines - [0084c57](https://github.com/appium/ruby_lib/commit/0084c57cdbde899edd4d79dfbead2a6b107eaf86) Rubocop rake task - [0059d23](https://github.com/appium/ruby_lib/commit/0059d2337f8d8f2948028c73ecd8a1c681c6636c) Set default wait to 0 - [b5bb400](https://github.com/appium/ruby_lib/commit/b5bb4003d78988ec33546cf02d274c86bfa83dbb) Validate resourceId before searching - [c41ee41](https://github.com/appium/ruby_lib/commit/c41ee416214571e304465d135ff18be8c5bcf86b) Add issuestats badges - [2bb8694](https://github.com/appium/ruby_lib/commit/2bb869486e31145124c64cfd555bac9f57e576b7) Raise command error on nil mainWindow for iOS - [f2122de](https://github.com/appium/ruby_lib/commit/f2122de35a9bed7756207d679f9a83c68dcc4642) Don't crash when mainWindow is UIAElementNil #### v6.0.0 2015-01-26 - [ea11190](https://github.com/appium/ruby_lib/commit/ea11190b9ab36e34226d988f85fe612af6f769de) Release 6.0.0 - [d15371d](https://github.com/appium/ruby_lib/commit/d15371deb2bbb0e6a441c7b38cabdc83b3e36256) Update readme.md - [4f99dd3](https://github.com/appium/ruby_lib/commit/4f99dd31ad0a1976214858195b5911e79a42c3a1) Merge pull request #302 from whoward/use-logger - [1673a69](https://github.com/appium/ruby_lib/commit/1673a694121d2ae24ffd1530eb71b7015d44dc52) Use the logger object for outputting debug information - [4573473](https://github.com/appium/ruby_lib/commit/457347379f26804af143269e896f45869e2860e1) Create index_paths.md #### v5.0.1 2014-12-30 - [9b15701](https://github.com/appium/ruby_lib/commit/9b157011965442e6f021dcfeef588450277f1c6a) Release 5.0.1 - [d2e12d8](https://github.com/appium/ruby_lib/commit/d2e12d8275f01f1652430d7908dd118bbfeec706) Merge pull request #298 from sbonebrake/upgrade_awesome_print - [4478662](https://github.com/appium/ruby_lib/commit/44786624397303e9785ce9322b7c6e625e70694e) Upgrade awesome_print and remove the ostruct patch. This fixes issue #297. - [fbf9a6e](https://github.com/appium/ruby_lib/commit/fbf9a6ed170f65d91f53617f0509c5b222bf3859) Update migration.md - [d5172bd](https://github.com/appium/ruby_lib/commit/d5172bd773f8d36e66e9b573c74e99d762d1c28d) Update migration.md #### v5.0.0 2014-12-23 - [7c3bc19](https://github.com/appium/ruby_lib/commit/7c3bc19905d0f008192a59dc7f5a938e3701ec8f) Release 5.0.0 - [0585d78](https://github.com/appium/ruby_lib/commit/0585d78042ec6e32e00dc349c70fb56179db6b1d) Fix page command on Android - [1f2d10a](https://github.com/appium/ruby_lib/commit/1f2d10afa37b9ca863f94eac9558467b3c2539f4) Test touchactions in new file - [6a638c4](https://github.com/appium/ruby_lib/commit/6a638c4a752f135830cb57f58ec5e373b8461944) Fix webview page inspection - [ddd94b4](https://github.com/appium/ruby_lib/commit/ddd94b498601bfd961dc449f00e584ed6bf753d8) Remove method_missing - [ad10640](https://github.com/appium/ruby_lib/commit/ad10640c58ba1435b32a4d3a8268f66ae4c4b74e) Fix set_immediate_value & update debugging - [7c9e8d0](https://github.com/appium/ruby_lib/commit/7c9e8d0ee33a2d067d4e8c5cb19abf456306851a) Don't try and hide the keyboard after .type - [544e34a](https://github.com/appium/ruby_lib/commit/544e34a7cb8c749947e0f1ac4f2cf02a561a32c3) Fix #291 always set implicit wait to default wait - [d6dacd0](https://github.com/appium/ruby_lib/commit/d6dacd03624d8fce68cfbe7419bc0046072955b8) Clean up button test on iOS - [2967a52](https://github.com/appium/ruby_lib/commit/2967a5212cdabbf972d7000ddc275eab7f0293ef) Update contributing.md - [ad35078](https://github.com/appium/ruby_lib/commit/ad35078239f62483345505da2289aa2820a19333) Update contributing.md - [3943039](https://github.com/appium/ruby_lib/commit/394303988c41631b1715dd4731eedbc92de2a568) Create contributing.md - [20c0c4d](https://github.com/appium/ruby_lib/commit/20c0c4d66ef6f2bab9e7ddaae64e778d510c20bb) Merge pull request #289 from sofaking/master - [0e223ac](https://github.com/appium/ruby_lib/commit/0e223ac4097e8e6f43c2a33177355ddf852562c5) iOS text elements tests are green - [16b33af](https://github.com/appium/ruby_lib/commit/16b33af71bd9aec70f01635f775b9cc82c52ae4d) iOS button elements tests are green - [524d412](https://github.com/appium/ruby_lib/commit/524d412ca2576f2b5d0f284fcb9414960b62b97b) Get back to catalog after web view test - [06c3a75](https://github.com/appium/ruby_lib/commit/06c3a75d9350f603b2c06c73341b55020f5217fb) iOS driver tests are green - [c2e80f0](https://github.com/appium/ruby_lib/commit/c2e80f0351ffb2f71a7702d1d9e6d75b734f53ef) iOS web context test is green - [718e6f5](https://github.com/appium/ruby_lib/commit/718e6f541e594c820ab98b13ecc30ac0ae101774) Generic element tests for iOS are green now - [0651054](https://github.com/appium/ruby_lib/commit/065105471867a87ea364064191defb43107f79d3) ios helper tests are green now - [1356454](https://github.com/appium/ruby_lib/commit/1356454390a001c85e885ae00510167362ca89db) Compatibility with Rubies older than 2.1.0 - [99c0b12](https://github.com/appium/ruby_lib/commit/99c0b128da5c6c4e7df2fb1313b7e84f1d6075c9) Add bootcamp guide & example links - [8d2daeb](https://github.com/appium/ruby_lib/commit/8d2daeb9544f6743856552c6828e71bbdecf130f) Fix iOS 8.1 driver test - [c52b099](https://github.com/appium/ruby_lib/commit/c52b09959ffa60784c1b91bf8d7eb9c1a4456725) Update button test - [a069f28](https://github.com/appium/ruby_lib/commit/a069f28854b722e56a34b4796d43c9aed3e833e6) Fix iOS 8.1 test device/device - [4643510](https://github.com/appium/ruby_lib/commit/4643510b8f0ac474340f65ab017b318fd06563a3) Update iOS 8.1 test ios/element/button ✓ - [44c930a](https://github.com/appium/ruby_lib/commit/44c930acce8ee9ef55f9de418922aefc0de39933) Merge pull request #285 from sbonebrake/touch_action_sauce_fix - [bbb4cc2](https://github.com/appium/ruby_lib/commit/bbb4cc2c65174d340a38d08f8e48ef55fef8d2ae) Fix for issue #283 'Ruby bindings TouchAction broken on Sauce Labs' - [3cfe864](https://github.com/appium/ruby_lib/commit/3cfe8648827ed6f78fb4d3bb9610f15aebbb38ed) Update tests for new api.apk - [f1e353a](https://github.com/appium/ruby_lib/commit/f1e353a5720a8dd202be7edd1f6f11235c8aad4a) Skip launch_app test - [8000cfa](https://github.com/appium/ruby_lib/commit/8000cfaa5268d70288d0e3f4ae7e2c8386b5076b) Add _app suffix to install/remove/launch - [bc81782](https://github.com/appium/ruby_lib/commit/bc8178235ed2dd97491d1ab528c68c01cd17a0bc) Fix android common/device test - [252df47](https://github.com/appium/ruby_lib/commit/252df470e9f6fb13f855f0ff2c7320b71499dbfd) Reimplement ele_index / tag to avoid xpath - [c5cf51d](https://github.com/appium/ruby_lib/commit/c5cf51d489e2e1d75e5b649f1c7767ec475d268a) Rewrite iOS helpers - [eb22269](https://github.com/appium/ruby_lib/commit/eb22269712354e5ad9e8af1db30954136930c425) Fix iOS textfield tests - [cfad029](https://github.com/appium/ruby_lib/commit/cfad029ea595f12e0328e7600c7d8c5e2abcd431) Rewrite iOS textfield helpers - [98a561b](https://github.com/appium/ruby_lib/commit/98a561beae09017eaa8be4b1d7cdaf5e3d6e1575) Add _elementOrElementsByType for iOS - [0b9aa53](https://github.com/appium/ruby_lib/commit/0b9aa5399ea7e4bd981ec7b65513f15423c07a6a) Regenerate docs - [b7def85](https://github.com/appium/ruby_lib/commit/b7def85c2bd734049121f7f3ca184d0b26e477fe) Fix accessor docs - [b38c783](https://github.com/appium/ruby_lib/commit/b38c7830250067c25834796e4a513fda7e6f3588) Update predicate methods. Fix version ref - [8d3bbc5](https://github.com/appium/ruby_lib/commit/8d3bbc53fb75e7f5fe60ffe7219f8fcb18095262) Restore xpath based textfield helper for iOS - [de61d18](https://github.com/appium/ruby_lib/commit/de61d18c1a0952cf72a34143672f5f46f962b3d2) Fix ios/element/text test - [d90446d](https://github.com/appium/ruby_lib/commit/d90446db37ffdc8db31bdacecc0a4083d91dd6ae) Fix common/helper iOS test - [5042465](https://github.com/appium/ruby_lib/commit/50424651ce90bd9d311cac2c6648dd3908a95a85) Update device attr docs - [e1f041f](https://github.com/appium/ruby_lib/commit/e1f041f96bc9acee6b218db646be078d68a21495) Device Modes - [dfdacdf](https://github.com/appium/ruby_lib/commit/dfdacdfbd3a1a932dcf98ac46a4f0ff8d38356b3) Update docs.md - [a0a74a9](https://github.com/appium/ruby_lib/commit/a0a74a95c2dd842202380946befe496b324a50b8) Add example of automating preinstalled Android app - [4569b0e](https://github.com/appium/ruby_lib/commit/4569b0e80ebafac295f39e42d93204d440320eff) Merge pull request #267 from 0x1mason/2969 - [cfe9f29](https://github.com/appium/ruby_lib/commit/cfe9f2982d1dff85591ff7375dd92bf54bbd1e75) Added start_activity function and tests - [af6d44c](https://github.com/appium/ruby_lib/commit/af6d44c6ccd3f32a9553be3c290000421edae92d) Add User-Agent - [29dfcbe](https://github.com/appium/ruby_lib/commit/29dfcbe45f9f70602fa29213a032114d3a751150) Merge pull request #266 from Jonahss/master - [ca42554](https://github.com/appium/ruby_lib/commit/ca425545770af7530c6820be59f211a0d0f50009) added get_settings and update_settings methods - [7cd7431](https://github.com/appium/ruby_lib/commit/7cd74310638df62683f804f6e961cb34832ca728) Merge pull request #252 from jskswamy/master - [3ab6f01](https://github.com/appium/ruby_lib/commit/3ab6f01676e03d263be4bdb9193eef125204cc0d) Update nokogiri - [afcbd6b](https://github.com/appium/ruby_lib/commit/afcbd6b6ed868c189b383235a5a81762b0258a08) Update gemspec - [5f0c1c5](https://github.com/appium/ruby_lib/commit/5f0c1c569b2eb6014982cd9c1c246215dc3375ab) Fix textfield index - [d4517b8](https://github.com/appium/ruby_lib/commit/d4517b878763523068f99b89b38a1ea3b0a98c4b) Update comment - [b71c9d4](https://github.com/appium/ruby_lib/commit/b71c9d4dfe5d00e368b7fe56a88a6accfeb7485e) Fix get_source - [c352e68](https://github.com/appium/ruby_lib/commit/c352e6855e9d503199d86640d232dce7bda1734b) Fix uiautomator's invalid xml #243 - [c2b5dcb](https://github.com/appium/ruby_lib/commit/c2b5dcbf733575ffa846432b21fa97575415aab3) Use predicates for ios/element/textfield #### v4.1.0 2014-07-21 - [a13158f](https://github.com/appium/ruby_lib/commit/a13158fb926212d84f26120c3bc5355c8cd34baf) Release 4.1.0 - [be1c710](https://github.com/appium/ruby_lib/commit/be1c710134ee9a001b8e71c0ce5cbb5786bebf1e) Update android specs - [4edd949](https://github.com/appium/ruby_lib/commit/4edd94989519ec14acf9c694d9ed3ae6a5939b10) Update self.promote_singleton_appium_methods - [82a236a](https://github.com/appium/ruby_lib/commit/82a236a84742f1eb6d55acab00d8f222d721bd9a) Update docs.md - [a724d5d](https://github.com/appium/ruby_lib/commit/a724d5d3711cdfa3ea420663949c06017189bf02) Fix #224 - [d05bfe8](https://github.com/appium/ruby_lib/commit/d05bfe85d6c356a8ea6a0f151aaf21dfef979736) Fix docs - [c04d6f0](https://github.com/appium/ruby_lib/commit/c04d6f048ee4e24c66bef662e31a0d957360e7a7) Fix wait / wait_true by using selenium wait method - [da19c8c](https://github.com/appium/ruby_lib/commit/da19c8cca5753f06576b82bbbb6e77e7e36bcb9c) Add iOS 7 note to swipe - [4f4d800](https://github.com/appium/ruby_lib/commit/4f4d80094eac5a4fbc2c11b8050155b2f767839c) Add client side xpath support #### v4.0.0 2014-07-05 - [8cc004a](https://github.com/appium/ruby_lib/commit/8cc004ad04ec087a8a11c06ca0749a5e2c6586a7) Release 4.0.0 - [e8c52c6](https://github.com/appium/ruby_lib/commit/e8c52c67226c94689c715a87ec7cee49c20c0821) Add note to android install test - [e5b3939](https://github.com/appium/ruby_lib/commit/e5b3939068f3fcd65ecd04f3f6fdd8652a159c43) Update install test on Android - [e02498c](https://github.com/appium/ruby_lib/commit/e02498c59272a173aed2eca662ef0c38539b6b24) Fix #152 - [b9db60f](https://github.com/appium/ruby_lib/commit/b9db60fc686c190561d352689dbdd410f1a42123) Reset parser before/after parsing - [9c4672b](https://github.com/appium/ruby_lib/commit/9c4672ba9e5912d7a7aee0b80c78144295c0d5a0) Add instance numbers to page output on Android - [de5732d](https://github.com/appium/ruby_lib/commit/de5732d598ce9639dd18f4764971000f536833ab) Fix #224 - [a206270](https://github.com/appium/ruby_lib/commit/a2062703fbcc2ebe0a80731034aee5d8bfb86108) Fix android device test - [9838d6a](https://github.com/appium/ruby_lib/commit/9838d6a5d910632a96df906c8d15a6084be97ea2) Move context tests to web_context.rb - [d6faefa](https://github.com/appium/ruby_lib/commit/d6faefaa2f18162076a0966b44b2b491f36a7504) Fix common/patch test - [414c4de](https://github.com/appium/ruby_lib/commit/414c4dea9de1404badf301c52142c75ba1125022) Update common/device test for Android L - [ccfb38d](https://github.com/appium/ruby_lib/commit/ccfb38d812d09cfbefcb77a404e9b3bbcbb6a237) Update android/helper for Android L - [24b75d7](https://github.com/appium/ruby_lib/commit/24b75d70f52cf5e2fe090086ed2ee5280cb572bd) Update alert tests for Android L - [8e9c7da](https://github.com/appium/ruby_lib/commit/8e9c7da4bf9ce44ab990da3ea9af9770aeac5c81) Fix #227 - [596f6e0](https://github.com/appium/ruby_lib/commit/596f6e0e0cd6fe6e2b7f878517db46aedb45b716) Fix #223 - [bcd9934](https://github.com/appium/ruby_lib/commit/bcd99340038fa30a3180e673757282b8e40b828f) Add predicate textfield test for iOS - [27732f4](https://github.com/appium/ruby_lib/commit/27732f4c6ebfbb0400419d90ca91528e0861bd68) Merge pull request #225 from appium/remove_complex_find - [3424d64](https://github.com/appium/ruby_lib/commit/3424d64bed8f641a67316c8a52e35f0b9ae7b75d) Remove complex_find. Update tests - [e2c82cc](https://github.com/appium/ruby_lib/commit/e2c82cc95d1443a31f73871fce96ae8aa4e99b6f) Add hide_keyboard for Android. Use custom for iOS - [27a25ba](https://github.com/appium/ruby_lib/commit/27a25baf936271203d13123386a2544b040d9a38) Update hide_keyboard for iOS - [e952bb0](https://github.com/appium/ruby_lib/commit/e952bb0d1287ebdd42254258e749136ed662b5f9) Test pull_folder on iOS & Android - [515e288](https://github.com/appium/ruby_lib/commit/515e28853607c729e6c58252dbe5e90e23b49e1d) available_contexts returns [] instead of nil on error - [86b378e](https://github.com/appium/ruby_lib/commit/86b378e7cf6cea86e2f88a342ab7b19f0cb455a8) Add pull_folder support - [0b3e0cf](https://github.com/appium/ruby_lib/commit/0b3e0cf2e4c5c8d674385e8a573a70d7c1ce3068) Add open_notifications. Fix #210 - [05125b4](https://github.com/appium/ruby_lib/commit/05125b41dd4957c841fcb51566e07905b04bbd0c) Update migration.md - [235e1c0](https://github.com/appium/ruby_lib/commit/235e1c0dc9a93efb6defff27cfebf527784a3ba7) Replace keyevent with press_keycode. Add long_press_keycode - [64d9db1](https://github.com/appium/ruby_lib/commit/64d9db11152e46845b2a055bba97cc6d45edf413) Use one run.rb for all platforms - [335100e](https://github.com/appium/ruby_lib/commit/335100e8027a01bd46842111752d83f6fe3fe9de) Move iOS helpers to common.rb - [ab915cf](https://github.com/appium/ruby_lib/commit/ab915cfa92981afd628569cf7e85517c6e4aec97) Update driver opts - [b495c5e](https://github.com/appium/ruby_lib/commit/b495c5e0bf591c98c733d4636e3c31848857f8c2) Merge pull request #211 from kieferrm/patch-1 - [543f8f3](https://github.com/appium/ruby_lib/commit/543f8f38763bec0d468dcadb3c4a6facf734e569) change require to lower case - [c54eaa1](https://github.com/appium/ruby_lib/commit/c54eaa1d78ed70bdf89405fac30d4129d9734a92) Remove global - [ee5a076](https://github.com/appium/ruby_lib/commit/ee5a07624314095148c6203bfe56454efc268891) Update docs.md - [a581424](https://github.com/appium/ruby_lib/commit/a5814249c8123c0309599847c0d0a9145c9ef819) Clean up cucumber doc #### v3.0.3 2014-06-02 - [3ed875c](https://github.com/appium/ruby_lib/commit/3ed875cc01ba7f670e9b1b8ccfd7b7adb0af82c1) Release 3.0.3 - [fab8ebe](https://github.com/appium/ruby_lib/commit/fab8ebe7245e28ad7628c91ba7766418a97521d0) Encode string to UTF-8 on iOS #208 #### v3.0.2 2014-06-01 - [08fe528](https://github.com/appium/ruby_lib/commit/08fe528887c33d64a3b06a5160859888cb92a9dd) Release 3.0.2 - [a051b35](https://github.com/appium/ruby_lib/commit/a051b355b488db6d303e800451668a1d8cb7d3d0) Fix find by ids on Android - [84e3983](https://github.com/appium/ruby_lib/commit/84e39831d7d0c825c5c7ed44a512fb891e6efef3) Allow setting sauce_username/sauce_access_key to false #### v3.0.1 2014-06-01 - [370b79c](https://github.com/appium/ruby_lib/commit/370b79c4b9f18fa615c145685256f543ee18debd) Release 3.0.1 - [48cb878](https://github.com/appium/ruby_lib/commit/48cb87835076d6faa51f525c86ef0ed478eb0542) Default to UTF_8 encoding - [5b30ed5](https://github.com/appium/ruby_lib/commit/5b30ed563b98a9084e6cb89921efec1944e999af) Fix current_app #### v3.0.0 2014-05-30 - [77d64af](https://github.com/appium/ruby_lib/commit/77d64af57b0e6a828c5d61008c444518e6597e4b) Release 3.0.0 - [86f1655](https://github.com/appium/ruby_lib/commit/86f1655d51ee74ec32e720ff285c30175283d4fd) Rename mobile find to complex_find - [109139b](https://github.com/appium/ruby_lib/commit/109139bd6ff664e020609a5828ab755c9f6dbf2e) Merge pull request #207 from appium/no_xpath - [682797d](https://github.com/appium/ruby_lib/commit/682797d252a040ffcc225a43491842c3e0d6e2ad) Use uiselector instead of xpath - [0c51bca](https://github.com/appium/ruby_lib/commit/0c51bcab548826d125b9f90418079fc8af72071a) Update complex find constants #### v2.1.0 2014-05-21 - [f0db091](https://github.com/appium/ruby_lib/commit/f0db0910ea077e04329d3e0cafb434f829760abb) Release 2.1.0 - [189b99a](https://github.com/appium/ruby_lib/commit/189b99ab91625cc37414fe9aeb681949d4fd85be) Use io.appium.android.apis - [5b1e3d8](https://github.com/appium/ruby_lib/commit/5b1e3d8b014137cdd8f5a4f8af5d7019983aab9a) Fix current_app on Android - [aa6e93a](https://github.com/appium/ruby_lib/commit/aa6e93a0bb88ef31c596c5ac7352b159bc0ea53b) Fix wait - [c590996](https://github.com/appium/ruby_lib/commit/c5909961be059d715200ba58943e1b56e2dd8843) Move posix-spawn to dev dependency - [7a55892](https://github.com/appium/ruby_lib/commit/7a5589244db8f783f9a51b74809ff8fcb4354855) Fix typo - [2a1c009](https://github.com/appium/ruby_lib/commit/2a1c0096db8a4e53ae09a8c556b51b513eacfa74) Merge pull request #197 from xrd/patch-1 - [9de20b7](https://github.com/appium/ruby_lib/commit/9de20b78f5dce29be874e727a027fd976703a0c1) Fix typo - [b306378](https://github.com/appium/ruby_lib/commit/b306378a9d54223e2b446a004a2c5a63574a9143) Merge pull request #196 from DylanLacey/master - [01dd97c](https://github.com/appium/ruby_lib/commit/01dd97ca63b6f8ff7ac65f170b8041241cad1271) Make wait and wait_true use the interval before it reexecutes - [9a138bb](https://github.com/appium/ruby_lib/commit/9a138bb6e2d1b0d836d3940f5e4b7e84d1fc0e3c) Merge pull request #195 from DylanLacey/master - [d85e292](https://github.com/appium/ruby_lib/commit/d85e292df723bcc9ff7227f8573581d44ef73c26) Don't continue to wait for crashed Appium server - [107a90c](https://github.com/appium/ruby_lib/commit/107a90c9137ef4ee7f8b7598c25adddedbdb34d4) Use __FILE__ instead of __dir__ - [12d62bc](https://github.com/appium/ruby_lib/commit/12d62bcec3d8897089bd3045f564c0de271375bd) Merge pull request #194 from DylanLacey/master - [bcc7865](https://github.com/appium/ruby_lib/commit/bcc7865db8f65f5439cd60a983d1c45b80b97eb8) Quit driver before creating a new one. Always. - [a52f215](https://github.com/appium/ruby_lib/commit/a52f215fb2246b35e17636ed9114fc977ad97511) Fix android test - [f43309c](https://github.com/appium/ruby_lib/commit/f43309ca716f5b140ef9370f4ebd4b45a500eb92) Fix #192 - [4a97ba1](https://github.com/appium/ruby_lib/commit/4a97ba12684c7e49e8251305c47b8a3443a9ef98) Set sauce to empty so tests run local #191 - [56d8a04](https://github.com/appium/ruby_lib/commit/56d8a04d8aa7e70f8e90a5e3cde79276bfb6158f) Fix #191 - [ea0fe8e](https://github.com/appium/ruby_lib/commit/ea0fe8e2a9570e984a41fa424a908398694660de) Set empty sauce ENV to nil - [190f023](https://github.com/appium/ruby_lib/commit/190f0237fc94816e71e4327cbf8135913021688b) Update migration.md - [28aa754](https://github.com/appium/ruby_lib/commit/28aa7546b321950d704ba091a91c424a3cc4ac04) Update migration.md - [d9447a9](https://github.com/appium/ruby_lib/commit/d9447a97433b88afbc35c66264b1c67e175aef41) Merge pull request #190 from DylanLacey/xpath - [ac9f5eb](https://github.com/appium/ruby_lib/commit/ac9f5ebecf3a0e603cafc8ad4befda86050fc6d1) Parse HTML as HTML, not XML. - [a84163b](https://github.com/appium/ruby_lib/commit/a84163b113fb232068c9aa02bff61db8c11d374e) Output debug status only when enabled #### v2.0.0 2014-05-14 - [2d7ab8b](https://github.com/appium/ruby_lib/commit/2d7ab8b6cc442f39f6171f8a27bc4923e4d4e2a4) Release 2.0.0 - [84af3e9](https://github.com/appium/ruby_lib/commit/84af3e91dbdfb3781dc64dcf40a55f70ec023734) Merge pull request #189 from appium/update_api - [208ce67](https://github.com/appium/ruby_lib/commit/208ce67ddb34651460ad6a83cfef4eb0c3c97081) Add migration doc - [52b2c3a](https://github.com/appium/ruby_lib/commit/52b2c3a44b9b2af3cfb22579b3a51ca3713f0bd5) Enable page 'static' - [19a2cf8](https://github.com/appium/ruby_lib/commit/19a2cf8025bee2c93ed32168a586accc1c01c25f) Update tests - [5e10809](https://github.com/appium/ruby_lib/commit/5e10809c6bb87da7251d5c32ac5eb547cd97edd1) Format all .rb files - [3f41705](https://github.com/appium/ruby_lib/commit/3f41705636c7be9f994972e5a999bf10430dcf18) Rename s_text to text. Remove e_* methods - [7909daa](https://github.com/appium/ruby_lib/commit/7909daa46c4e8cdbcde9d223b008069335402ed0) Rename press_for_duration to long_press - [d63a58f](https://github.com/appium/ruby_lib/commit/d63a58ffafe12a6bf7e7897480c1eb3c4275076b) Update app_strings to take optional language arg - [71ab5db](https://github.com/appium/ruby_lib/commit/71ab5db00b832a049f9ed5dc544bd2a49afc42c1) Pass element reference, not element, when calling tap - [30b646f](https://github.com/appium/ruby_lib/commit/30b646fefe54830aea4a4e41dbf21471566ab489) Merge pull request #184 from DylanLacey/master - [6afc071](https://github.com/appium/ruby_lib/commit/6afc071921d263db13ead17cf7747e321b4a9487) Change current_context= to set_context. - [8f280ec](https://github.com/appium/ruby_lib/commit/8f280ec52e3bcfe7e917d910271fdfeb8a48562c) Fix page on iOS - [7088169](https://github.com/appium/ruby_lib/commit/7088169dc643b06a785247cfbcbde9c00daf2298) Update android/helper.rb - [537a8c3](https://github.com/appium/ruby_lib/commit/537a8c342d4977ab5e66765e05f69863a48a0fd6) Update Android common/device - [72ff02a](https://github.com/appium/ruby_lib/commit/72ff02a41673b113ecabeaa503e2f1702005d108) Restore strings.xml support on Android - [0dc4965](https://github.com/appium/ruby_lib/commit/0dc4965867cf089d87864401279176d5196a0caa) Update readme.md - [a5c2a1f](https://github.com/appium/ruby_lib/commit/a5c2a1f34b3c42f499dd9a78e90f02b135dd79b7) Update docs - [ca767f4](https://github.com/appium/ruby_lib/commit/ca767f425d3bd0ab763af09eb9065b7e2853ff0b) Improve page/page_class - [034a309](https://github.com/appium/ruby_lib/commit/034a309357ed5450cd977af5082669af2905cb47) Purge byte order marks - [3988ee3](https://github.com/appium/ruby_lib/commit/3988ee341972d2a42b00005ae7d2c694a572088a) Update readme.md - [f1e91a4](https://github.com/appium/ruby_lib/commit/f1e91a4d6cce813080dece73c5f80d06415b645a) Update readme.md #### v1.0.0 2014-04-29 - [5a3ecbb](https://github.com/appium/ruby_lib/commit/5a3ecbb4147693ce3c2c6b693e64074022d03511) Release 1.0.0 - [4b6989a](https://github.com/appium/ruby_lib/commit/4b6989a51c25b3b01398fe6bee2da908ab61a7e2) Merge pull request #172 from DylanLacey/flight - [0824188](https://github.com/appium/ruby_lib/commit/0824188043f76f5243de4d3753ef9e036fcb5ba6) Airline mode. - [7935fc0](https://github.com/appium/ruby_lib/commit/7935fc02afb7720306c7a273d205a2db9bdfb417) Prepare for release - [583a0a6](https://github.com/appium/ruby_lib/commit/583a0a6b7b67cdce4e533f06d98968021c0ed5d9) Update version helper - [982b102](https://github.com/appium/ruby_lib/commit/982b1021ed5e202ae2249791aa9ab091e7cb1b24) Update docs - [74f9e5e](https://github.com/appium/ruby_lib/commit/74f9e5ec97059f036c5c935bc9dcb5fb0000d813) Improve docs - [b5414b7](https://github.com/appium/ruby_lib/commit/b5414b7885804ccabddb53315a12c3b525924654) Update documentation for appium 1.0 - [de25322](https://github.com/appium/ruby_lib/commit/de25322395c233e69c70cc2c9417913e8f393dbd) Fix ios test - [3943f19](https://github.com/appium/ruby_lib/commit/3943f194cd82bcc6880c13fd712041e111440aa5) Do not sort files - [e7bd82a](https://github.com/appium/ruby_lib/commit/e7bd82a133edcf27fa5c8d5cf850d1783ef4cd4c) Fix load_appium_txt - [fe792a5](https://github.com/appium/ruby_lib/commit/fe792a573ffb4ce5cfb3bd4f67cb0506a61dbf21) Fix comment - [bb9f44a](https://github.com/appium/ruby_lib/commit/bb9f44af04add6f4c1007f3641417f6366ae0b3e) Fix error message about missing platformName - [45e56b9](https://github.com/appium/ruby_lib/commit/45e56b9326d2ab9fad29d04626e34fdaf58f9659) Fix flaky android tests by using wait - [723b304](https://github.com/appium/ruby_lib/commit/723b30414719a2e728cfd32b0a43d09daa21c69b) Rename closeApp to close_app - [ec2f6ea](https://github.com/appium/ruby_lib/commit/ec2f6eab1f8f8ab40ef41a82d0c6de1a11705bf0) Improve android/patch test - [e3a7ad5](https://github.com/appium/ruby_lib/commit/e3a7ad5b4cb65a351bf2f61587fe35c0af465042) Merge pull request #169 from bootstraponline/master - [bbcd38b](https://github.com/appium/ruby_lib/commit/bbcd38b184ec047adc73188a1ec86e8cfb09de61) Fix complex find - [684aa0d](https://github.com/appium/ruby_lib/commit/684aa0df432e2c618637c873ca62f5a31626beb2) Merge pull request #168 from DylanLacey/master - [7475d38](https://github.com/appium/ruby_lib/commit/7475d38f069425e69bc81e9c7157734abfb780da) Remove unused error method - [6875a48](https://github.com/appium/ruby_lib/commit/6875a48705114d3d651f509d1e2f4f484e9650f3) Use new complex_find method. - [86371c3](https://github.com/appium/ruby_lib/commit/86371c3c74fd50666aee96bd575adefe3d4618e8) Fix common/helper - [e765488](https://github.com/appium/ruby_lib/commit/e765488f3dc3698092b8751ad400ba67bdcae220) Update Android common/device - [79de9b5](https://github.com/appium/ruby_lib/commit/79de9b59a604f7fc6c74fefb6743c5ede52b6193) Fix android common/helper - [7ac67e3](https://github.com/appium/ruby_lib/commit/7ac67e33655898446b75d4c7ca17bd26bf21fa35) Fix android/helper - [4754137](https://github.com/appium/ruby_lib/commit/47541378b4fdcf2daf36109be59b9e591d5f5666) Fix id resolution. Fix patch and helper - [38af1aa](https://github.com/appium/ruby_lib/commit/38af1aafb8525186f3ae10ee888ae52945753f6e) Fix android alert, text and textfield - [1f82df4](https://github.com/appium/ruby_lib/commit/1f82df4543e2de54564bd89e2ed8275612beb770) Fix page commnand on Android - [b3cd998](https://github.com/appium/ruby_lib/commit/b3cd9987f391447dc7bf86f97cc99b75f166b969) Fix android/element/button - [6e215ff](https://github.com/appium/ruby_lib/commit/6e215ff60752fbdc43b23829676215d10d0004d1) Reorder iOS text methods - [ead35f9](https://github.com/appium/ruby_lib/commit/ead35f99908ea5e9eac298308979a46dc0028751) Refactor iOS textfield xpath - [b26d77d](https://github.com/appium/ruby_lib/commit/b26d77d70967c14aef227dc651252f3ff675850e) Move iOS specific helpers out of common - [a97c1cd](https://github.com/appium/ruby_lib/commit/a97c1cdfa4b545283e463f5e792f7c413654043f) Merge pull request #163 from DylanLacey/master - [537099d](https://github.com/appium/ruby_lib/commit/537099d3afd5e950ef0a1042890c3134ee125578) Update tests to meet new code requirements. - [c7c6d10](https://github.com/appium/ruby_lib/commit/c7c6d10152dd61b856c1dfe828aa70dc4e4e48c3) Ensure elements on iOS are visible - [e0cb0c9](https://github.com/appium/ruby_lib/commit/e0cb0c911f831c4f8288d9c467b5546128c4e467) Update Rakefile - [6a174e2](https://github.com/appium/ruby_lib/commit/6a174e2a05fd6612f2592e0734122d60c2101d86) Modern ruby defaults to utf-8 - [5540ffc](https://github.com/appium/ruby_lib/commit/5540ffc0f93abc85cefd7e397e39c8022071e171) Update ios_tests - [ecc7d02](https://github.com/appium/ruby_lib/commit/ecc7d0262e902f0e46e49f6395a00aa88558978c) Update iOS support - [8845a1e](https://github.com/appium/ruby_lib/commit/8845a1ed82d06ad3164dadc6fcc57c23482f5ca9) Rewrite iOS support for appium 1.0 - [b0e0bfd](https://github.com/appium/ruby_lib/commit/b0e0bfd43edd011f2f628d588de7bef7829e0db6) Update textfield and flaky.txt - [7c40873](https://github.com/appium/ruby_lib/commit/7c40873ed4521c004b5033378fd87b44714264af) Fix ios[ios/element/textfield] - [ee0ccd2](https://github.com/appium/ruby_lib/commit/ee0ccd2f443c4f2ce80b1ea80f17b2d11d870a08) Fix ios[ios/element/alert] - [f439730](https://github.com/appium/ruby_lib/commit/f4397302cc9ffc42759fe946e0da643df2c89100) Fix ios[common/helper] - [3582d34](https://github.com/appium/ruby_lib/commit/3582d3495976bb724b39febf92d850dd5fd08508) Fix iOS common/element/button - [67f719e](https://github.com/appium/ruby_lib/commit/67f719eca1812f143e8b2445ceac154c87ec13c5) Add flaky.txt - [7847df2](https://github.com/appium/ruby_lib/commit/7847df21888ce5e089e81be24d035d4f8d1d7b92) Merge pull request #159 from DylanLacey/master - [4c816e2](https://github.com/appium/ruby_lib/commit/4c816e252a2e018e3db9730ea56a7a23eb7adbdd) Fix wait - [b58f283](https://github.com/appium/ruby_lib/commit/b58f283503af8ed3a16e054dd589b1662be533cb) Update one_test runner - [52b2a5c](https://github.com/appium/ruby_lib/commit/52b2a5cff30cae5c27e878071fd9a2c4ce16c48f) Enable running with flake - [9861a88](https://github.com/appium/ruby_lib/commit/9861a885b9bbdc45eaddf00589f854ec2355b24e) Update tag references - [326aeb5](https://github.com/appium/ruby_lib/commit/326aeb50375300662167f0f9f23211efa59fb052) Don't call mobile methods - [09329d1](https://github.com/appium/ruby_lib/commit/09329d1d0fb583733b7530d6fc1161611e2b16d3) Name before_first/after_last for better error messages - [5302418](https://github.com/appium/ruby_lib/commit/5302418d5180d02c87139662b7b97d53042faf24) Fix ios/element/generic - [9bf869f](https://github.com/appium/ruby_lib/commit/9bf869f889e80754132741bce4776d1e2bf0bf14) ios/element/text is passing - [2e10eb3](https://github.com/appium/ruby_lib/commit/2e10eb3407408c2979384c73a31c4ddbe8fc2dd3) Start updating for new XPath - [62c977a](https://github.com/appium/ruby_lib/commit/62c977a158ebb85bac2603be1321723d5c785931) Add note about source_window + appium 1.0 - [2bb509f](https://github.com/appium/ruby_lib/commit/2bb509ff60733c950c4edba1754bddbfa1855003) Replace mobile methods for appium 1.0 - [2c8142b](https://github.com/appium/ruby_lib/commit/2c8142b0026c0222d635c936448564002ca5eadb) Fix page_class to work with Appium 1.0 - [265b658](https://github.com/appium/ruby_lib/commit/265b65833ed3971a1bf41b647edf0613786258bd) Use nokogiri to parse XML - [8c96eae](https://github.com/appium/ruby_lib/commit/8c96eaeab594d940ce30ede29f6253e1e5fd7370) Merge pull request #157 from appium/update_spec - [5c9e840](https://github.com/appium/ruby_lib/commit/5c9e840b7edafd083f3d5f3003086550baf3c242) Update tests to work with new spec gem - [0331fe0](https://github.com/appium/ruby_lib/commit/0331fe0f4c897b4cd41b67eecd6357416925d629) Merge pull request #155 from DylanLacey/keyevent - [3a9bebd](https://github.com/appium/ruby_lib/commit/3a9bebd48cc8ecc8a1d8e9c50d1db433e66bae1f) Add keyevent method - [758afbf](https://github.com/appium/ruby_lib/commit/758afbfee3beaf435ecc8c0f47584deb91b3ae2f) Merge pull request #154 from DylanLacey/master - [294ba49](https://github.com/appium/ruby_lib/commit/294ba49f4f98cce498f2b8217e639ab0c33c5036) Extend Appium::Device methods before promoting Appium methods. - [d432e36](https://github.com/appium/ruby_lib/commit/d432e365219914091f7a1bf532a758cfd2647aed) Merge pull request #149 from DylanLacey/chainz - [965ec7b](https://github.com/appium/ruby_lib/commit/965ec7bab13e8a92a4f5065ff1c4142ba58043d2) Add multi-touch actions, touch actions. - [d8cbacd](https://github.com/appium/ruby_lib/commit/d8cbacd938e41ce0ccc817f354ab6580f4742636) textfield_named to use chained find_element - [e76e6dd](https://github.com/appium/ruby_lib/commit/e76e6dd5f2046a73a2458a3bc03aa546c810ed20) Merge pull request #151 from DylanLacey/docs - [ecbbb18](https://github.com/appium/ruby_lib/commit/ecbbb18fa09b861a733f7b0071d2164e712697c2) Merge pull request #150 from DylanLacey/files - [7ef61e1](https://github.com/appium/ruby_lib/commit/7ef61e1cd1733217479646060c5131ef3235b852) Update doc - [6c97d17](https://github.com/appium/ruby_lib/commit/6c97d17ac177656c96a00ee29d64293e63a84c22) Add file methods - [aea8c5d](https://github.com/appium/ruby_lib/commit/aea8c5dd688778ba3cf076390a89455f5bec36cf) Update doc - [854d2c6](https://github.com/appium/ruby_lib/commit/854d2c689f9ea43701b4ae18fa83b121bf227f85) Fix invalid warnings Fix #147 - [0408cc0](https://github.com/appium/ruby_lib/commit/0408cc0c7a99d3347cf6b762f28b1c4fa9339e2b) Fix driver docs - [e72c170](https://github.com/appium/ruby_lib/commit/e72c17094ff249f822346be9a62c135156d7758d) Remove Selendroid specific code - [4e9f3d6](https://github.com/appium/ruby_lib/commit/4e9f3d6f95fbd97c4db118e22de2741a49993d21) Validate platformName Fix #146 - [38fc42e](https://github.com/appium/ruby_lib/commit/38fc42e599b02dcc17d007812cf9defbd21a6573) Clarify wait_true doc Fix #127 - [285a97b](https://github.com/appium/ruby_lib/commit/285a97b0e15eb42034a91a2b59d8ba9bd8b0abe9) Fix ignore, wait, wait_true - [1b160b4](https://github.com/appium/ruby_lib/commit/1b160b46ecab5fccd45191f5af5f18eaf86a3188) Fix typing on iOS - [44eb53b](https://github.com/appium/ruby_lib/commit/44eb53b61c994dd16fd8636dd4bf43b70c98226e) Add comments to end - [a4d2c55](https://github.com/appium/ruby_lib/commit/a4d2c553a46b0cd64ecbc67193023e9802db2c0d) Add OpenStruct support to Awesome Print - [12b35a6](https://github.com/appium/ruby_lib/commit/12b35a612fcf7bb05173ef3e3ece66a0ecab4a0f) All tests passing - [01f4ecf](https://github.com/appium/ruby_lib/commit/01f4ecfdf5b5446c6eced06ca86cc85ff42edecd) Fix 'undefined' is not a function - [af76d4d](https://github.com/appium/ruby_lib/commit/af76d4daba1cc785325e62f4a1392895da7c7731) Fix broken ends - [9a214aa](https://github.com/appium/ruby_lib/commit/9a214aa7fb59042606956be1686c6c5a459a192c) Don't use add_to_path - [67a997c](https://github.com/appium/ruby_lib/commit/67a997c8396b4c8681f63be5d37f8055d39d220e) Clean up module syntax - [8be5b7c](https://github.com/appium/ruby_lib/commit/8be5b7c5b3dbdc1682a48b9ca85f2389c2a19502) Merge pull request #142 from appium/wip - [fb61522](https://github.com/appium/ruby_lib/commit/fb615225eae819eef70153a76e954ffa2991845e) Rename test folders - [8f2049f](https://github.com/appium/ruby_lib/commit/8f2049ff18e3dc20b7cd7a30cd15b0fcb1676341) Update capabilities and appium.txt - [62dc430](https://github.com/appium/ruby_lib/commit/62dc43030d047c3baaec28f524430893ac427ff9) Merge pull request #139 from DylanLacey/complex_find - [bc20a71](https://github.com/appium/ruby_lib/commit/bc20a7181b5159bbb8cd304e182a49765fec5b9d) Add complex find - [38a9429](https://github.com/appium/ruby_lib/commit/38a942973adc8768d7e5e1b270bad8d68323e33b) Merge pull request #140 from DylanLacey/hide - [f6d5987](https://github.com/appium/ruby_lib/commit/f6d598704f096dccfc0feedf28850d7059cd79f8) Add keyboard hidin' - [c0076e9](https://github.com/appium/ruby_lib/commit/c0076e92cdbeb3ce90fab536480a746c6acf933b) Merge pull request #138 from DylanLacey/noarg_methods - [23f24c9](https://github.com/appium/ruby_lib/commit/23f24c9193318c2cfb3432d01459aaf3b8121ab6) add current_activity, background_app, app_installed - [eb12171](https://github.com/appium/ruby_lib/commit/eb121710af6c7a3d128754a359640c36b7e73501) Merge pull request #135 from DylanLacey/contexts - [b8f3a91](https://github.com/appium/ruby_lib/commit/b8f3a919d11fc347b84ce4c1a38aab2705461553) Add context switching - [c13b877](https://github.com/appium/ruby_lib/commit/c13b877c75bd67390755720cc15842411a2d7218) Merge pull request #137 from DylanLacey/accessibility_id - [5c9d18f](https://github.com/appium/ruby_lib/commit/5c9d18f286c31f8ddbc6ad5cdd0b34a1041e775f) Add accessiblity_id finder - [5d1722f](https://github.com/appium/ruby_lib/commit/5d1722f965db7cac26eb7c14b3080f22ba5e1664) Merge pull request #136 from DylanLacey/uiauto_finders - [fdd14da](https://github.com/appium/ruby_lib/commit/fdd14daf4811aac740bdd7e1662f2d61aa43c359) Add uiautomat[ion|or] locators - [ef42569](https://github.com/appium/ruby_lib/commit/ef42569d2d0bc4bb741ed0132ba78371bb84b5f4) Merge pull request #133 from DylanLacey/master - [a6fbb15](https://github.com/appium/ruby_lib/commit/a6fbb15b1909df4d69c059a754fc7973123b17a3) Log warning when methods are added to Selenium - [6590e9f](https://github.com/appium/ruby_lib/commit/6590e9f5f30b7fa07c16390c965077a780116d44) All tests passing on master branch of appium - [cd5a25d](https://github.com/appium/ruby_lib/commit/cd5a25d395ec0d7f7361ce0a18a14aa4dc81f486) Update android tests - [7fc8c55](https://github.com/appium/ruby_lib/commit/7fc8c55b9c0866b14ce23f0c72fc5580d0935125) Update android tests - [6e32210](https://github.com/appium/ruby_lib/commit/6e3221015a028b184d0888d8d0281adc88c91d05) Add ruby_lib_ios and ruby_lib_android tests to ruby_lib - [b9b449a](https://github.com/appium/ruby_lib/commit/b9b449a1502db280728cf8b5d20ec36f7ae59a1d) Merge pull request #129 from DylanLacey/master - [f87a379](https://github.com/appium/ruby_lib/commit/f87a37906fe8cd66c549c351c8808d79586a1f79) Added calls to explicit endpoints for :install, :remove, :close, :launch, :lock, :shake. - [2ea9aa5](https://github.com/appium/ruby_lib/commit/2ea9aa598d38e2163a01a90ceee4473372999d67) Upgrade to SVG badges - [003bbe6](https://github.com/appium/ruby_lib/commit/003bbe6a92c2538c51dbea56f69fb525eec22db6) Status is in the official bindings - [d0b6198](https://github.com/appium/ruby_lib/commit/d0b619833457c974b500b00242ceb2fc7598f5d0) Document how to activate fast reset #### v0.24.1 2014-03-26 - [a07da28](https://github.com/appium/ruby_lib/commit/a07da28de1e7133c77070859c2c35d7bd2635684) Release 0.24.1 - [4718b0b](https://github.com/appium/ruby_lib/commit/4718b0b126748b14237ead15fd09812449512b12) Client should never send fastReset or skipUninstall #### v0.24.0 2014-03-25 - [937f782](https://github.com/appium/ruby_lib/commit/937f7822bd5e248e2bdbc43a4602611d18df5d78) Release 0.24.0 - [6e3fd72](https://github.com/appium/ruby_lib/commit/6e3fd720d90eda14f284c04ae4b8edb62ca7c010) fast_clear is no more #### v0.23.0 2014-03-21 - [b6cda97](https://github.com/appium/ruby_lib/commit/b6cda9756f530d712f431df272cf5abdcd678131) Release 0.23.0 - [8ce3009](https://github.com/appium/ruby_lib/commit/8ce3009ab6c8e957a7cee817df4a658b1ae3a834) Fix caps for new appium - [a6e7df2](https://github.com/appium/ruby_lib/commit/a6e7df258daf905c5dbaa6143aca9f5040e1308e) Remove device whitelist from appium.txt #### v0.22.1 2014-03-20 - [82c40cd](https://github.com/appium/ruby_lib/commit/82c40cdd97eb7278d77b2b668cae554e55f1836d) Release 0.22.1 - [c436daa](https://github.com/appium/ruby_lib/commit/c436daa916dfb7b3a824f498c98f4718d3aacca1) Disable device white list - [4cca152](https://github.com/appium/ruby_lib/commit/4cca152aa2519f5b3ae1292886c286f87d9fbbe8) Fix release rake task #### v0.22.0 2014-03-19 - [4d88ecd](https://github.com/appium/ruby_lib/commit/4d88ecd87be7a2319dd0b7e437e230300269175f) Release 0.22.0 - [347e81e](https://github.com/appium/ruby_lib/commit/347e81e2c3fae3b1b26bd707356c663a158198d4) Support all appium caps #### v0.21.0 2014-03-13 - [db2df39](https://github.com/appium/ruby_lib/commit/db2df39eb6fc09e516e22334dd990699755c0509) Release 0.21.0 - [bf74d7a](https://github.com/appium/ruby_lib/commit/bf74d7a70c0f7cab8e4cb115d53d86c3720e2df3) Remove webview. Update gemspec #### v0.20.0 2014-03-13 - [e79923f](https://github.com/appium/ruby_lib/commit/e79923f731c0f7ba85f280b512f5d82d365fd619) Release 0.20.0 - [9a6c6ea](https://github.com/appium/ruby_lib/commit/9a6c6eaf798938f8a483466e718e53483e3c0f02) Add bundle update to release rake task - [093ba77](https://github.com/appium/ruby_lib/commit/093ba7712275b009d66146bcd9429ed9bf2f8d7f) Update readme.md - [8dbe853](https://github.com/appium/ruby_lib/commit/8dbe853909a3a2691d3cc510d9751cfe8179dc76) Fix mainApp - [347ae13](https://github.com/appium/ruby_lib/commit/347ae13cc78101875bb223fdfee97898f50a791b) Update readme.md - [ba4d51c](https://github.com/appium/ruby_lib/commit/ba4d51c44329db8a849f59bfeedfa1eb99538d3a) Update location_rel to use center point #### v0.19.1 2014-02-25 - [efa2e3f](https://github.com/appium/ruby_lib/commit/efa2e3feb74319a19d1fe3ef49d5a7fe3a2eb59a) Release 0.19.1 - [1aee2fc](https://github.com/appium/ruby_lib/commit/1aee2fcc5773cc92b1f83a80188f6cac50d2e206) Add android coverage cap - [ccb213f](https://github.com/appium/ruby_lib/commit/ccb213f3866672f2be7ea526e6deb1656d497e6e) Update path logic - [9772383](https://github.com/appium/ruby_lib/commit/97723833f1d888fa809d704801d98bdff8a3e2a4) Fix load_appium_txt relative path #### v0.19.0 2014-02-20 - [6fd332b](https://github.com/appium/ruby_lib/commit/6fd332b1715d7b8f4b3b3c99e7ca58e5d4d01b52) Release 0.19.0 - [69f2058](https://github.com/appium/ruby_lib/commit/69f2058c3dffb60bb5040f920481da5fed571a6a) Merge pull request #119 from misttar/feature/appium_ruby_console_on_windows - [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; - [f529113](https://github.com/appium/ruby_lib/commit/f529113c3f54c351d668da9695b8a5a7e2377169) Merge pull request #118 from justingrammens/master - [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. - [d55a2f5](https://github.com/appium/ruby_lib/commit/d55a2f5beefb0b6e3068470769da64c8c47551ec) Fix webview - [da987f6](https://github.com/appium/ruby_lib/commit/da987f6b11b191ace34ea63764eb121c8ddae42e) Merge pull request #114 from misttar/app_path_on_windows - [488236e](https://github.com/appium/ruby_lib/commit/488236e8856e984f7d9285f33d7660d33fbd835d) Adding a small patch to fix loading the app with absolute windows paths; - [6e789d5](https://github.com/appium/ruby_lib/commit/6e789d54341979c412c9a6f3b956cf9b777c87ad) Fix tag_name - [af4517f](https://github.com/appium/ruby_lib/commit/af4517fa10a060e92c12bd49a93289ece709c0ac) Update MiniTest Expectations link - [8810bbe](https://github.com/appium/ruby_lib/commit/8810bbe640546f962325358d9ab763a0dc038057) Update name doc for iOS - [f08854a](https://github.com/appium/ruby_lib/commit/f08854a3cb498c12a00bdca8d0a3f9ffedf06bad) Escape single quotes for iOS JS selectors #### v0.18.2 2014-01-28 - [f7a2e26](https://github.com/appium/ruby_lib/commit/f7a2e26b623404b83b2bbd9065aa7b57ab0fd62d) Release 0.18.2 - [b123321](https://github.com/appium/ruby_lib/commit/b12332186befb84b7ef6107a27db035ca2b65400) Check ENV['DEVICE'] when :device isn't set. #### v0.18.1 2014-01-28 - [d98aafc](https://github.com/appium/ruby_lib/commit/d98aafc1571c49d97f104ce5d275cf758f27e421) Release 0.18.1 - [14bcd8f](https://github.com/appium/ruby_lib/commit/14bcd8fd50e6fc4f74c81d900c0c05a302d080b9) Fix device cap #### v0.18.0 2014-01-27 - [e0ea2f2](https://github.com/appium/ruby_lib/commit/e0ea2f2d77875b9ffc88d8649b3652c39a1ab51a) Release 0.18.0 - [c94bf57](https://github.com/appium/ruby_lib/commit/c94bf57dadf2049a3aace8ed35d978c1d4545be2) Update capabilities for Sauce - [2859c83](https://github.com/appium/ruby_lib/commit/2859c831916ef1541fe2a283c9afc6af55e43a25) Update session id example #### v0.17.0 2014-01-22 - [8571197](https://github.com/appium/ruby_lib/commit/8571197b04ea923db6e375bae808bf84dea52c98) Release 0.17.0 - [1134b87](https://github.com/appium/ruby_lib/commit/1134b878791c0abb23d11250ad185c34708d54be) Fix fast clear. Fix #110 - [f0bc0b5](https://github.com/appium/ruby_lib/commit/f0bc0b5229dc21f736ab17c533e1d073c3b44a3c) Update api_19_webview.md - [94657b4](https://github.com/appium/ruby_lib/commit/94657b45394bcd823955270529aee79b305383f3) Update api_19_webview.md - [3b93375](https://github.com/appium/ruby_lib/commit/3b933752f560af6cf7cf976e8f2511222d255068) Create api_19_webview.md - [9b838f4](https://github.com/appium/ruby_lib/commit/9b838f4dc280126e4468a177fa4dd83eb2417512) First attempt at webview automation for Android API 19 #### v0.16.0 2014-01-09 - [b9264f6](https://github.com/appium/ruby_lib/commit/b9264f66b9dd04eb5221c3a4c4ea17c4eb9ef8aa) Release 0.16.0 - [18466ea](https://github.com/appium/ruby_lib/commit/18466eae986647b27e3dbb041c591ce2dbc972a2) Hide invisible elements in iOS page output #### v0.15.2 2013-12-23 - [35b84fd](https://github.com/appium/ruby_lib/commit/35b84fd4a0dcf37fe136451c9bcfa936e1017023) Release 0.15.2 - [23504ea](https://github.com/appium/ruby_lib/commit/23504ea17c483650342832a204acac542a77b48b) Update selenium-webdriver for driver.manage.logs support #### v0.15.1 2013-12-13 - [8340d99](https://github.com/appium/ruby_lib/commit/8340d993185ec22f02ca4ce3a3d24e65f367f3e3) Release 0.15.1 - [ee39131](https://github.com/appium/ruby_lib/commit/ee391317b38f9dc7a0c13d148746401545a1f21e) Default to OS X 10.9 & iOS 7 on Sauce - [9627036](https://github.com/appium/ruby_lib/commit/962703617a3050dddb0be9f6ec757ca4b5070ff0) Fix promote_singleton_appium_methods - [81ce5d0](https://github.com/appium/ruby_lib/commit/81ce5d063b927d785cad3111b1ec7c50def6bfca) Fix docs - [fe60570](https://github.com/appium/ruby_lib/commit/fe6057045fd4d9ee1eb77ec57108755b4d445592) Error if we're generating an empty file - [0162656](https://github.com/appium/ruby_lib/commit/0162656e90e7db9f33c84fe1273ec96d8efc745f) Prevent duplicate tags #### v0.15.0 2013-11-25 - [c27ac6f](https://github.com/appium/ruby_lib/commit/c27ac6fc37cb0c1b52aa2b15af480d17745adcf8) Release 0.15.0 - [77a7736](https://github.com/appium/ruby_lib/commit/77a7736c3589db6ba2f029b97beae3e0d383cee9) wait and wait_true no longer use default_wait - [18a4b94](https://github.com/appium/ruby_lib/commit/18a4b9472be56b533d01c9b2758d365b3c3129fe) Fix exists - [dd885bf](https://github.com/appium/ruby_lib/commit/dd885bffc04e6306b6b70162e58e7149280bee0b) timeout(0) waits forever so default to 1 as the min wait #### v0.14.0 2013-11-22 - [e7ed56b](https://github.com/appium/ruby_lib/commit/e7ed56b6304d7c9f6a24384915def1a3bc732c4e) Release 0.14.0 - [eea5ef1](https://github.com/appium/ruby_lib/commit/eea5ef19bd7d52aac24e55e76544980b8c144a84) set_wait remembers the second to last wait - [7ef3406](https://github.com/appium/ruby_lib/commit/7ef34065982f4832584b12174fd491d5e1919c9b) Release 0.13.0 - [e1632bc](https://github.com/appium/ruby_lib/commit/e1632bc88116996a5ed3983a0a9f3ec864d229d9) Release 0.13.0 - [87c5e12](https://github.com/appium/ruby_lib/commit/87c5e120c51e3344241ca48ccb4ba4990dc76cbd) Release 0.13.0 - [647cb94](https://github.com/appium/ruby_lib/commit/647cb942f344c635e067f2ae563f4fae12685148) Release 0.13.0 #### v0.13.0 2013-11-22 - [e1632bc](https://github.com/appium/ruby_lib/commit/e1632bc88116996a5ed3983a0a9f3ec864d229d9) Release 0.13.0 - [87c5e12](https://github.com/appium/ruby_lib/commit/87c5e120c51e3344241ca48ccb4ba4990dc76cbd) Release 0.13.0 - [647cb94](https://github.com/appium/ruby_lib/commit/647cb942f344c635e067f2ae563f4fae12685148) Release 0.13.0 - [a235a2c](https://github.com/appium/ruby_lib/commit/a235a2c70d2c7dc1934c9fb403fb95cc3ae56e04) Update name_exact - [f1d2701](https://github.com/appium/ruby_lib/commit/f1d270120ae248beb6746a0149ebcbe4e34ebcca) names on Android will return the text values when no arg is passed - [7ac38c9](https://github.com/appium/ruby_lib/commit/7ac38c97b99178f6ae0bf8f7b5474a0cd3379e87) Fix return value of name_exact - [e6da4aa](https://github.com/appium/ruby_lib/commit/e6da4aa4937bfdc6f094f7895ecf172f8b96f32a) Add textfield_named for iOS - [789fc52](https://github.com/appium/ruby_lib/commit/789fc5276ad000dafd5a400f3d9aa8cfcd37e17d) Add ios_version method - [5447f4c](https://github.com/appium/ruby_lib/commit/5447f4cf3645459ddb4335b4a242b7639fc860f8) Rename password to ios_password - [a5b85de](https://github.com/appium/ruby_lib/commit/a5b85de11e413e301f94d41689658b01342bb1c8) Add scroll_to_exact for Android & more - [cc7e778](https://github.com/appium/ruby_lib/commit/cc7e778fd1532e5e15ea9933a300189ce8dc9e8a) Default to fastClear: false - [f54f145](https://github.com/appium/ruby_lib/commit/f54f14551e04517c71d9177fc0bd72797cd77781) Add link to minitest expectations #### v0.12.0 2013-11-07 - [c92bd37](https://github.com/appium/ruby_lib/commit/c92bd3710be09731aa8ba4547a3e19af9eeaceab) Release 0.12.0 - [f1b7633](https://github.com/appium/ruby_lib/commit/f1b7633e5dcfcd6d0d21f003ce0d98de1d093a13) Add s_texts_names. Fix alert_dismiss_text and alert_accept_text for iOS 7 - [6f2d698](https://github.com/appium/ruby_lib/commit/6f2d6981b1f12443c4079dba455b16d1f331f903) Fix page on iOS 7 - [70dbac3](https://github.com/appium/ruby_lib/commit/70dbac321688dfbec1d5f0a8efe6a7282678b88b) set_wait and no_wait now update @default_wait - [1f31754](https://github.com/appium/ruby_lib/commit/1f31754386dfd282e1143e3386ba18b1c656bb9d) Restore readme - [1e7a4c3](https://github.com/appium/ruby_lib/commit/1e7a4c36d1ea0df0ed87a2decbf8793406673774) Update Android page to always output resource-ids #### v0.11.1 2013-09-24 - [0551d9a](https://github.com/appium/ruby_lib/commit/0551d9a4de2cb3d62efe63a87b01c15526202336) Release 0.11.1 - [283040e](https://github.com/appium/ruby_lib/commit/283040e7227b7838124e835578d549fadc101cdc) Fix s_texts method overloading #### v0.11.0 2013-09-24 - [948074c](https://github.com/appium/ruby_lib/commit/948074c44917029fb27b08ed582c90d7f73a7cde) Release 0.11.0 - [a0dfe2c](https://github.com/appium/ruby_lib/commit/a0dfe2c5a99f9354b1c0f4fa766619505d4c85ae) Add s_texts, s_texts_exact - [5b3bb88](https://github.com/appium/ruby_lib/commit/5b3bb886951b8efe9845d423a4da310742a52bcb) wait and wait_true now respect default_wait - [5c3083b](https://github.com/appium/ruby_lib/commit/5c3083b819dc3dca66ee07fcb6e7aeadcfbc1d2c) Update Android tag maps - [c2b7098](https://github.com/appium/ruby_lib/commit/c2b70980ba80cefe82f776ac7c0e567a7dc93884) Sort page_class on Android #### v0.10.0 2013-09-20 - [6ab8180](https://github.com/appium/ruby_lib/commit/6ab8180ca332239793c0abc5ee3a31b0b081b6c4) Release 0.10.0 - [afb0b09](https://github.com/appium/ruby_lib/commit/afb0b09b54682fd497857a41affcdca531eb6911) Add promote_singleton_appium_methods(main_module) - [631c584](https://github.com/appium/ruby_lib/commit/631c5846373031a16cacb18bc0259663bd64b7b7) .location_rel now returns a fraction - [bf45140](https://github.com/appium/ruby_lib/commit/bf451407454853873305e25f7026e97a4119694d) page on iOS now takes window number - [cb38755](https://github.com/appium/ruby_lib/commit/cb38755ec824e139b40cf291eb0d3421cca3dfad) Fix Android fast duration - [c81bba8](https://github.com/appium/ruby_lib/commit/c81bba81bdba9a184b2fcc50fa1aabfdafd19e96) Sauce doesn't use dashes in the session id - [613c33e](https://github.com/appium/ruby_lib/commit/613c33ee22b389a3c42d96cb618a9858a6bc2e88) Add note about xpath index #### v0.9.1 2013-09-19 - [cd9fc63](https://github.com/appium/ruby_lib/commit/cd9fc636c5fc1071ad95ea08a7ab5c077737e6a7) Release 0.9.1 - [c5c2b83](https://github.com/appium/ruby_lib/commit/c5c2b832c5f535eacb657b4cfc5cb5d89e0ad8ee) XPath index starts at 1 for textfield - [511f76e](https://github.com/appium/ruby_lib/commit/511f76ea711516e5b2a95918343b8e903d17dc1a) Fix server_version path debug output #### v0.9.0 2013-09-19 - [28f2161](https://github.com/appium/ruby_lib/commit/28f21615a435364246725e8f9adac62c0257dffa) Release 0.9.0 - [25837ae](https://github.com/appium/ruby_lib/commit/25837aeccf47623c1e4055d51238ac7e443a2d4f) iOS textfields use xpath now #### v0.8.0 2013-09-19 - [205e04a](https://github.com/appium/ruby_lib/commit/205e04a562e6606b583449cc285e5f4cc5ce9387) Release 0.8.0 - [67f6361](https://github.com/appium/ruby_lib/commit/67f63614238507deac5e3d336f3217f7edc2cd62) Fix textfield methods on iOS #### v0.7.1 2013-09-09 - [1e0f36e](https://github.com/appium/ruby_lib/commit/1e0f36e22833246873b6ecb8cc4d2bf3544de2c8) Release 0.7.1 - [b611ac6](https://github.com/appium/ruby_lib/commit/b611ac6c361b7044d07d2501ae032784aa891c66) Fix typing on disabled textfield - [d887050](https://github.com/appium/ruby_lib/commit/d887050006dd4e18e8b558b542eb0a090fecf985) xml_keys, xml_values, resolve_id work on iOS - [e148f2a](https://github.com/appium/ruby_lib/commit/e148f2ad746795b7dcf3960ed8f837fad2b78f24) Allow custom URL. Fix #84 - [8d6ae78](https://github.com/appium/ruby_lib/commit/8d6ae788006fd9430cc34fc0dc3e390876758a1a) Use our docs not rubydoc.info #### v0.7.0 2013-09-05 - [c8f3041](https://github.com/appium/ruby_lib/commit/c8f3041049c2feb9ac85f67e85523118a6ce5a84) Release 0.7.0 - [f98534d](https://github.com/appium/ruby_lib/commit/f98534dc92aa04a0afe05b6ed0e60c4be1d9394c) iOS page supports ids and defaults to 1st window - [ab6cb4f](https://github.com/appium/ruby_lib/commit/ab6cb4f66cb496a9c557b4c6246b8ecd7a3e06ed) strings.xml is now client side. compressed xml support - [e976552](https://github.com/appium/ruby_lib/commit/e9765527a8858d4d72e9372afdccbf0a2297f5c5) Add Android API 18 resource id to page output - [ddc5e36](https://github.com/appium/ruby_lib/commit/ddc5e3651e4920dab9198e33b77fcf570c7e5f8b) browserName is never used - [c5211e5](https://github.com/appium/ruby_lib/commit/c5211e52c51170653d85b9f2a249e4a346c17f7a) Print all matching ids in page - [8d19157](https://github.com/appium/ruby_lib/commit/8d1915732718864102cdfefcf4db0adb71377a74) Include strings.xml ids in page output on Android - [b615628](https://github.com/appium/ruby_lib/commit/b61562808624e1324be0934237dbef26a608aebf) Update readme.md - [adc4eba](https://github.com/appium/ruby_lib/commit/adc4ebaaade7778b975c166e1ab16f5c40cc2517) Add id example - [42d2a86](https://github.com/appium/ruby_lib/commit/42d2a860f8989a0d8df08815be1a5be4bd895ef6) Add more code examples - [fa45efd](https://github.com/appium/ruby_lib/commit/fa45efda445b7541f49f510ec08be9e99584ff72) Update docs.md #### v0.6.7 2013-08-23 - [a1f5942](https://github.com/appium/ruby_lib/commit/a1f5942e907339f1c3968c5af03feb5bde6b1b7c) Release 0.6.7 - [4a08dd6](https://github.com/appium/ruby_lib/commit/4a08dd63add2fd11e7cbb7aadaa086f6fb014ed2) Enable bundleid in app device cap - [caff218](https://github.com/appium/ruby_lib/commit/caff2187c378e619ee5b4e0524734df372354b69) Improve docs - [b579ca7](https://github.com/appium/ruby_lib/commit/b579ca7fd83c6673be1f04d745b9d6cbdaeb6504) Add iOS Jenkins Xcode note - [4fbf0fb](https://github.com/appium/ruby_lib/commit/4fbf0fbdea07120ebf4d270bfee2cf251ba312fb) Add landscape and portrait rotate examples - [c6d4353](https://github.com/appium/ruby_lib/commit/c6d43537c759342b1ceed72cf8a81573c5070c65) Allow setting device cap #### v0.6.6 2013-08-19 - [5b84a0b](https://github.com/appium/ruby_lib/commit/5b84a0bd9d9273c704414bdb9a9857b503439b90) Release 0.6.6 - [6f3b002](https://github.com/appium/ruby_lib/commit/6f3b0027757d8fbf62bc26d8a3497caab025c8c8) Add export session option. - [b05c07e](https://github.com/appium/ruby_lib/commit/b05c07e5ddcb6ba7dc79d20a38f1dae8567c52c6) Fix screenshot return value #### v0.6.5 2013-08-13 - [8b7b4d6](https://github.com/appium/ruby_lib/commit/8b7b4d6d7836bfede93b6da99bdcac836d218481) Release 0.6.5 - [8dadb52](https://github.com/appium/ruby_lib/commit/8dadb52e0bc0372cef575d5f1c82acdc9bec4c20) Add directory support to appium.txt require #### v0.6.4 2013-08-09 - [94a9bbc](https://github.com/appium/ruby_lib/commit/94a9bbc595f42008d7fdb7ba6814efd38955294b) Release 0.6.4 - [3b24fcd](https://github.com/appium/ruby_lib/commit/3b24fcd4c23941502eec22d99a3e3db7094b9401) Add optional $driver.global_webdriver_http_sleep - [dae3508](https://github.com/appium/ruby_lib/commit/dae3508b566de1a3eaae64483cd79d9502a71859) Add longClick example #### v0.6.3 2013-08-07 - [ccf8e37](https://github.com/appium/ruby_lib/commit/ccf8e375283bd9038fcf6c1db576f7539065e6d0) Release 0.6.3 - [d55c6fa](https://github.com/appium/ruby_lib/commit/d55c6faddcbfd42b1f500e617e38eaa18ddc6532) Fix device and rake uninstall - [8c704ee](https://github.com/appium/ruby_lib/commit/8c704eece569c37bcc491e8edf88b34e1310ee96) Support OpenStruct in Awesome Print - [898fe27](https://github.com/appium/ruby_lib/commit/898fe27a86056b5ec6931555ad778c04c3a3a342) Device is not case sensitive #### v0.6.2 2013-08-07 - [509e7b8](https://github.com/appium/ruby_lib/commit/509e7b81f02c6b0c4cdcb07aca034c9dad260ff4) Release 0.6.2 - [69a698b](https://github.com/appium/ruby_lib/commit/69a698b0ba7b3aa7bbe8846711eac8da0108552e) Add px_to_window_rel - [218185f](https://github.com/appium/ruby_lib/commit/218185fea68277537ed47dbc9312c874e26489b9) Add promote example - [b57772c](https://github.com/appium/ruby_lib/commit/b57772c48c409d981518d9aee7ab1b7accd3465a) Fix comments #### v0.6.1 2013-08-05 - [44b4b29](https://github.com/appium/ruby_lib/commit/44b4b29596b59b1d8a7a7ab7485f176a84143ac3) Release 0.6.1 - [a58228f](https://github.com/appium/ruby_lib/commit/a58228f728576be4bbe8325788ed28571b810bb4) Refactor promotion into a method #### v0.6.0 2013-08-05 - [09aa23d](https://github.com/appium/ruby_lib/commit/09aa23d8c1b769b054c7d0e24ec86cf55d6bc027) Release 0.6.0 - [cbaf19d](https://github.com/appium/ruby_lib/commit/cbaf19d9d607b00dde89aca3829f17808780c2f3) Add keyboard send_keys documentation - [25333d6](https://github.com/appium/ruby_lib/commit/25333d6d2871ba5009dcf4050185dbdf1d324ce9) Fix for Minitest 5 - [1e047b0](https://github.com/appium/ruby_lib/commit/1e047b092740703083ed9e452f9e77d6086f8372) Minitest 5 only - [7ef93e9](https://github.com/appium/ruby_lib/commit/7ef93e99fbc373a6d4f2a75f1abc81a12a9688fa) Update usage example - [47f53f9](https://github.com/appium/ruby_lib/commit/47f53f9706d3aa302a431c2b91592ee8c72ba399) Device is now required - [62d5f2a](https://github.com/appium/ruby_lib/commit/62d5f2a258e927ee56e042466503c023c9138f6c) Patch only MiniTest - [6ce29df](https://github.com/appium/ruby_lib/commit/6ce29df7b9d7b144a750579faab9629741f64593) Fix release notes #### v0.5.16 2013-07-26 - [bd71fb4](https://github.com/appium/ruby_lib/commit/bd71fb4e430608d32923c583c8d4d592f11a96fc) Release 0.5.16 - [7b83b85](https://github.com/appium/ruby_lib/commit/7b83b85c41caf25376414d978ff63d49ab22f057) Only return files that exist - [1f0428d](https://github.com/appium/ruby_lib/commit/1f0428dca4e843a82de2d46be3c724e2dc7930c7) Fix keyboard race condition - [c99ed34](https://github.com/appium/ruby_lib/commit/c99ed341c779fb3eff4ab92a95a4a773a1ce212f) Update docs.md - [7103921](https://github.com/appium/ruby_lib/commit/71039210e1e0b7481df59210ce4addebcae7ba08) Fix link - [f76ea9b](https://github.com/appium/ruby_lib/commit/f76ea9b42a728aae247f88f732879cda94101624) Add require support to appium.txt - [12b8e59](https://github.com/appium/ruby_lib/commit/12b8e5938cb616015cb86d62e41ee9d29cace097) Update docs.md - [7d6a8f2](https://github.com/appium/ruby_lib/commit/7d6a8f2fa728e616e7fd459cdeef0d5cce9064b4) Add current_app to docs - [16ea945](https://github.com/appium/ruby_lib/commit/16ea9454941d84bb02ba4950aeea8df6d70cab26) Fix hide keyboard on iOS - [ad9263c](https://github.com/appium/ruby_lib/commit/ad9263cbabb4e1c56bbe9fafe85b048f2a285c11) Add Sauce wait req - [98ee244](https://github.com/appium/ruby_lib/commit/98ee244d460f6251c5c6cff8cc79ca8610cc6165) Add .clear example for textfield - [d373071](https://github.com/appium/ruby_lib/commit/d3730717faba192cc66f5346c2847ecf6cb60e16) Fix activity name example in readme - [50023f3](https://github.com/appium/ruby_lib/commit/50023f3a8201b0875025e5a94ec841fb23c35714) Fix Android version - [c4d281a](https://github.com/appium/ruby_lib/commit/c4d281a62d7923f9e6a65fbc870cb1dc6a959849) Add Android set version code - [5675f4a](https://github.com/appium/ruby_lib/commit/5675f4a03f8b20939e8cc1b5b13df795072d6553) Update readme.md #### v0.5.15 2013-07-03 - [734fe68](https://github.com/appium/ruby_lib/commit/734fe6887f36aa1ad59ef7ce992ba2e2f4c8c7d3) Release 0.5.15 - [0e203d7](https://github.com/appium/ruby_lib/commit/0e203d76610abd519ba9d2fe9c14b50c94df5bbd) Fix driver methods overriding object methods - [efc4602](https://github.com/appium/ruby_lib/commit/efc460278af5b6f2a24c290f704781be4e9b2d4b) Fix open struct #### v0.5.14 2013-07-03 - [521f79b](https://github.com/appium/ruby_lib/commit/521f79b11497c0c963b7059347e02d81a08f665a) Release 0.5.14 - [7831c7d](https://github.com/appium/ruby_lib/commit/7831c7d21bc6ae3c39d91c6903cb5e96ec066f16) Update current_app - [3009abc](https://github.com/appium/ruby_lib/commit/3009abc44624f58c2201ad881b918e79252c2a83) Add iOS version commands - [d224b6b](https://github.com/appium/ruby_lib/commit/d224b6b982d6ca7bc741ec9f92d597203081d4c6) Update readme.md - [89a43da](https://github.com/appium/ruby_lib/commit/89a43da27d3629d5a4f3dc521fefb6e00a97ad2e) Update docs.md - [85469de](https://github.com/appium/ruby_lib/commit/85469de2cb574722719e77809498319d948add15) Update readme.md - [95c5c3c](https://github.com/appium/ruby_lib/commit/95c5c3cccf7b038293c9b8bd8bb168edc5bdd6a2) Current app is only for Android - [460699c](https://github.com/appium/ruby_lib/commit/460699cce767339bf73efd8b5791464130681cb8) Update current_app #### v0.5.13 2013-06-19 - [146e19a](https://github.com/appium/ruby_lib/commit/146e19a1b322d1bb625c6bb3ce1b80e67a7e80fa) Release 0.5.13 - [2eb4bb0](https://github.com/appium/ruby_lib/commit/2eb4bb0c696f41c839227dd99256d77d52bf995f) Check method exists before calling - [8d48ca2](https://github.com/appium/ruby_lib/commit/8d48ca2c4463b54d5d68332b58e3ed8eff01edf0) Current app is in the lib now - [683ae29](https://github.com/appium/ruby_lib/commit/683ae2975fde08d069fefb731a342c7ddd9ebb92) Add current_app #### v0.5.12 2013-06-18 - [89b0902](https://github.com/appium/ruby_lib/commit/89b0902ed94ed43d8a9f0e364463da77015dcfb7) Release 0.5.12 - [7c4e8d1](https://github.com/appium/ruby_lib/commit/7c4e8d16d909112cebd2a80f0d8140723efd644a) search_id, search_value replaced with xml_keys, xml_values #### v0.5.11 2013-06-18 - [891e003](https://github.com/appium/ruby_lib/commit/891e003748038a006121c8a4e0c702c12c405799) Release 0.5.11 - [5e7f381](https://github.com/appium/ruby_lib/commit/5e7f381aa8fc4b64af9103beae67cfc2fc310484) WebView is not a widget - [830c3fb](https://github.com/appium/ruby_lib/commit/830c3fb07e01da64a6934a9a0868861a67326f4f) Add search value #### v0.5.10 2013-06-17 - [16d696a](https://github.com/appium/ruby_lib/commit/16d696aa368bdce198b7ef7a1cc1370f6c5d2ac7) Release 0.5.10 - [5cc0a7a](https://github.com/appium/ruby_lib/commit/5cc0a7a52d43af7690705f889860c2dc4788b892) Add search and resolve id #### v0.5.9 2013-06-11 - [ac76a23](https://github.com/appium/ruby_lib/commit/ac76a23ca4c7f5bb89a833937cc726654fa2df82) Release 0.5.9 - [b377791](https://github.com/appium/ruby_lib/commit/b3777911709538a230d1fd3be31ae21f72040b00) Update readme.md - [893737a](https://github.com/appium/ruby_lib/commit/893737a6033ed7c8e6f1c31f5b45f65b841320c2) Add current_activity #### v0.5.8 2013-06-04 - [91f5c2f](https://github.com/appium/ruby_lib/commit/91f5c2f2bd388c1d4c4e771d2abea3772197de9c) Release 0.5.8 - [b4e592c](https://github.com/appium/ruby_lib/commit/b4e592cc3d101a4ac9f7fa374ae8c75fcdc5218a) Fix call twice - [18e3f7d](https://github.com/appium/ruby_lib/commit/18e3f7d1c6869ba0d2c248b9c242d08c47390346) Prefer existing method before calling driver method - [1f72729](https://github.com/appium/ruby_lib/commit/1f727290c2452833df87a8b4d559bf5c51955a1e) switch_to.alert calls getAlertText so use bridge directly - [9752a3b](https://github.com/appium/ruby_lib/commit/9752a3bdf8173653f6d5c2d412bb7c70f0b5f023) Add tag method #### v0.5.7 2013-06-03 - [669f734](https://github.com/appium/ruby_lib/commit/669f7345b7e8a92e8206b847d4a2263731df3c4b) Release 0.5.7 - [bb5b7a5](https://github.com/appium/ruby_lib/commit/bb5b7a568dab38dc7044e3925274f9f7ee84a362) Add page_class for iOS #### v0.5.6 2013-05-31 - [7c3335c](https://github.com/appium/ruby_lib/commit/7c3335c82e8b96e4a4cf74ae20faf98906b63770) Release 0.5.6 - [b231d8f](https://github.com/appium/ruby_lib/commit/b231d8fbcdd35cc7a027e02a7733d10a616d2f7b) Fix finds #### v0.5.5 2013-05-31 - [e061482](https://github.com/appium/ruby_lib/commit/e061482a0f712914c5fb21da92da357b79e07b87) Release 0.5.5 - [82f9c58](https://github.com/appium/ruby_lib/commit/82f9c580d68189b669d3f5029914f00c8fd17c06) Fix value contains operator - [c5b8d84](https://github.com/appium/ruby_lib/commit/c5b8d849b29f46beebd1aea4ff59f2de6edd9dc6) Update readme.md - [c14fbb3](https://github.com/appium/ruby_lib/commit/c14fbb3c39b0c33a5d42dfe9da5427cebb9ec336) Add version badge #### v0.5.4 2013-05-28 - [9e95106](https://github.com/appium/ruby_lib/commit/9e951061b9da6cee7b90ee310bbbef2b7c660fb1) Release 0.5.4 - [d66020c](https://github.com/appium/ruby_lib/commit/d66020c66b02889d4a96809f41d02d4aa3e4b915) Fix gemspec. yard is required for docs task - [1c6509d](https://github.com/appium/ruby_lib/commit/1c6509ddea68305b47f251e0d0c1ff4a5c1493ee) Add dev task to install gems required for release task - [5106643](https://github.com/appium/ruby_lib/commit/51066439a4bacf7fea4a469044f6c3e2b60356c9) Add Sauce Storage support #### v0.5.3 2013-05-24 - [b24565d](https://github.com/appium/ruby_lib/commit/b24565df67d4f0468ab5e3c1a700711a4c82b80d) Release 0.5.3 - [5c7169a](https://github.com/appium/ruby_lib/commit/5c7169ae5fecc9adf0bd0a8f7fc6aea5a90495a2) Update appium_lib.gemspec - [1a03758](https://github.com/appium/ruby_lib/commit/1a03758dede749f9fd23f00db1be9199c159a6c8) Update readme.md #### v0.5.2 2013-05-24 - [44ffbcb](https://github.com/appium/ruby_lib/commit/44ffbcb4715c8caac2770972c72ca498e751be34) Release 0.5.2 - [61e92f8](https://github.com/appium/ruby_lib/commit/61e92f87e6870be06b34a20dc0dfc64ddfed7f13) Add get_page_class - [cca5db4](https://github.com/appium/ruby_lib/commit/cca5db4d98e00306f99110cd43398b0dc1f5980f) Update tag names #### v0.5.1 2013-05-24 - [1a98819](https://github.com/appium/ruby_lib/commit/1a98819e93e739496f27a6ec2ad4197ca78c08a4) Release 0.5.1 - [2003589](https://github.com/appium/ruby_lib/commit/2003589197a78d54f3d177abbf2335724c090e1e) Fix names on Android #### v0.5.0 2013-05-24 - [de58f71](https://github.com/appium/ruby_lib/commit/de58f7164230d7551df8462d65d0e43a3d0cfdab) Release 0.5.0 - [062a2a2](https://github.com/appium/ruby_lib/commit/062a2a21fc3768c0d19b33d317c7ba5828bcbc3e) Add page_class - [9e1e091](https://github.com/appium/ruby_lib/commit/9e1e091f1cc27d3330faa9c44b8241b720c10595) Add note - [1372009](https://github.com/appium/ruby_lib/commit/1372009afdd62c6c2f57ffa8d9fa4fce3de056b2) Fix method signature - [f0e0954](https://github.com/appium/ruby_lib/commit/f0e0954d8f2c8f941b4f95bf995890454e748c4f) Dynamic is Android only - [8a1a387](https://github.com/appium/ruby_lib/commit/8a1a387e1fe03e9a3e9d0fafd2064fb9cd3759c4) Update docs.md - [eaa5b79](https://github.com/appium/ruby_lib/commit/eaa5b79f6768f3fd0da0637fad46c3dec4cd4ad1) Rename s_first_text s_last_text - [edbd74f](https://github.com/appium/ruby_lib/commit/edbd74fb8a32b53f37c65dd3617afaf6c6bd5641) Add example for screenshot - [73fcb72](https://github.com/appium/ruby_lib/commit/73fcb72d78bf02cb0deaa9af3f65ce074518c4fa) Add params to exists - [558d4af](https://github.com/appium/ruby_lib/commit/558d4afc023243374eadf6187c5036c0ac8dd4ba) Fix opts - [adfdc18](https://github.com/appium/ruby_lib/commit/adfdc18f224dcb98e41630ed354bdc2ac61241d8) Fix gemspec - [299d0c8](https://github.com/appium/ruby_lib/commit/299d0c8085e5117d7cdb5084334fb8e35efad32d) Move appium.txt loading to appium_lib - [aaf54be](https://github.com/appium/ruby_lib/commit/aaf54be45c0b711c4c3a86d3b42a853f1bdc80d1) Fix code format - [9e3a3e9](https://github.com/appium/ruby_lib/commit/9e3a3e9c3321c1fb78d8ed8df9b98f7f99d8c258) Move default wait to init param - [ae9acb1](https://github.com/appium/ruby_lib/commit/ae9acb1fcea3dc2af32032ade35ee9263668e7a8) Update docs - [849594b](https://github.com/appium/ruby_lib/commit/849594bdd87bf6133cbb64c43d0a02f427f17467) Update method comments #### v0.4.2 2013-05-20 - [be814c2](https://github.com/appium/ruby_lib/commit/be814c286bd55fb133f333738da9b0dcd6146b69) Release 0.4.2 - [9d2cfe8](https://github.com/appium/ruby_lib/commit/9d2cfe86b3367fd3f4551962a042fe25da1e31bd) Add page_window for Apptentive - [e9b5e97](https://github.com/appium/ruby_lib/commit/e9b5e97baf7b6a417dc3865b7cc0c163c0165d70) Update docs #### v0.4.1 2013-05-20 - [cd8dd73](https://github.com/appium/ruby_lib/commit/cd8dd73461d6bdb8903a8b3f5bba9ce554a44789) Release 0.4.1 - [9e8cd0a](https://github.com/appium/ruby_lib/commit/9e8cd0a915e6c9c373ebd3a33a653c573f776636) Add status - [978d489](https://github.com/appium/ruby_lib/commit/978d48964361ca36267b866b1fe69d0b09b3f273) Update docs - [eb11923](https://github.com/appium/ruby_lib/commit/eb11923543a1e3e2fe8f19d2f09959cefd16fa05) Fix generic iOS methods #### v0.4.0 2013-05-16 - [70a59fe](https://github.com/appium/ruby_lib/commit/70a59fefcaa4f16ba0e7629f16feaae3e5f8c424) Release 0.4.0 - [b30548e](https://github.com/appium/ruby_lib/commit/b30548e58783bc6b20bd5c0f11e2ae9ddb5faa30) Translate mobile find on Android - [1ea8b85](https://github.com/appium/ruby_lib/commit/1ea8b85ebb7c7531c2791f3c41d0280d947edad0) Screenshot should work on iOS - [3797644](https://github.com/appium/ruby_lib/commit/3797644874ff1e56a8c35f9825e42c8486902984) Update docs - [0e2c119](https://github.com/appium/ruby_lib/commit/0e2c119199535a2e9a8e708453fa068c6445e6ca) Fix release notes - [5c28a2d](https://github.com/appium/ruby_lib/commit/5c28a2debcd8386aab62b48d0b087ed7dac84d8d) Next release will be 0.4.0 - [b9e5044](https://github.com/appium/ruby_lib/commit/b9e5044ddf6f998c09f006d8a6d95a5560f2fdd3) Remove comment - [30c2ada](https://github.com/appium/ruby_lib/commit/30c2adaecb0bca734664192a805968a83f4b7a8b) Update doc links - [d08cd59](https://github.com/appium/ruby_lib/commit/d08cd5944aeda9fa3f3842fd5a259e0385b88166) Add JS doc gen - [61530fb](https://github.com/appium/ruby_lib/commit/61530fb908822cd32be6cb25d94ffb00f68ec87b) Update docs - [ebe6a2f](https://github.com/appium/ruby_lib/commit/ebe6a2fa91a748c0c823dbb969afa51ab3710acd) Update docs.md - [637fef7](https://github.com/appium/ruby_lib/commit/637fef7f7547e6e2b2fd8f70e19ef3f3870cc136) Use element.displayed? not visible #### v0.3.16 2013-05-14 - [fb34a03](https://github.com/appium/ruby_lib/commit/fb34a03ceec0be552f218323bf266fda7f7e060b) Release 0.3.16 - [6e552ae](https://github.com/appium/ruby_lib/commit/6e552ae0d9a66a03ac50caa38f73f3f3dbded317) Selendroid is boolean #### v0.3.15 2013-05-13 - [cc56df8](https://github.com/appium/ruby_lib/commit/cc56df88825ac8e705e740eed7ac8ca42bcc9dd0) Release 0.3.15 - [8613403](https://github.com/appium/ruby_lib/commit/8613403db07435908a149dc296fb92cad8af2e35) Use boolean for .visible on iOS #### v0.3.14 2013-05-13 - [12aa291](https://github.com/appium/ruby_lib/commit/12aa29132a9a88076fbf8c76fbb65b1aa5e1fc96) Release 0.3.14 - [a61b297](https://github.com/appium/ruby_lib/commit/a61b297d387b0c28865b050eaa3d7d59efae2a34) Add .visible for iOS - [6f6dda5](https://github.com/appium/ruby_lib/commit/6f6dda53fb12a483a524370c3d3c729fa1b87be4) Update gemspec #### v0.3.13 2013-05-10 - [7badb99](https://github.com/appium/ruby_lib/commit/7badb998734ee4c4ae0781c5e8f3cfc4b862eeb3) Release 0.3.13 - [efaa0ea](https://github.com/appium/ruby_lib/commit/efaa0eaebe5a045dba8370ec98aea8bdf31637ba) Fix #52 #### v0.3.12 2013-05-10 - [faf3e98](https://github.com/appium/ruby_lib/commit/faf3e98d0d745df9bbbfada93dcfd6b47a585793) Release 0.3.12 - [7ff6b95](https://github.com/appium/ruby_lib/commit/7ff6b955cafc235a554d192cc09014c4400dc27a) Add scroll_to #### v0.3.11 2013-05-09 - [14d705a](https://github.com/appium/ruby_lib/commit/14d705acd527f13e2962e2c04200b6d28fd36cbb) Release 0.3.11 - [ebdae44](https://github.com/appium/ruby_lib/commit/ebdae448b108c76e586ad8f8ae86a1abc495e7e5) Search name and text when using textfield #### v0.3.10 2013-05-07 - [db557df](https://github.com/appium/ruby_lib/commit/db557df9939fa44f2a6bf5d8afd950a2fa4b4178) Release 0.3.10 - [c3adbc5](https://github.com/appium/ruby_lib/commit/c3adbc52f0b049e6b9292ac2ff328160d1820668) Fix name and textfield - [5c26137](https://github.com/appium/ruby_lib/commit/5c261370fd68f363f0ab2f4d70ad486c43dc46fb) Android can't get alert text - [36f68de](https://github.com/appium/ruby_lib/commit/36f68de51954de79754e8f377f4a6dad47361dc1) Add shown attribute to Selendroid page #### v0.3.9 2013-05-06 - [3b4fbb4](https://github.com/appium/ruby_lib/commit/3b4fbb4e6957a92ac4236d5666d932ee9da238e7) Release 0.3.9 - [98b1b1e](https://github.com/appium/ruby_lib/commit/98b1b1e8e0952244c1ca2c8738d7d33af7eb0f68) Fix extra slashes in path #### v0.3.8 2013-05-06 - [e7bc45f](https://github.com/appium/ruby_lib/commit/e7bc45fd88f026dc51237d767da9f9dfa2e05b56) Release 0.3.8 - [dc3a50f](https://github.com/appium/ruby_lib/commit/dc3a50f23ca6ba4978ddb9af1dadf6c6015eb9fb) Use 4.2 not 4.1 - [f8042f1](https://github.com/appium/ruby_lib/commit/f8042f158f046815238463a9ea86cd66ea725942) Fix page Selendroid - [f9866e0](https://github.com/appium/ruby_lib/commit/f9866e034ea9a3744387fb15d5ca3ba221f27429) Load touch methods - [c3f9a2b](https://github.com/appium/ruby_lib/commit/c3f9a2b0300ee238acf4ce750f9b651ff39eb919) Don't set timeout on Selendroid until it's fixed - [d88245e](https://github.com/appium/ruby_lib/commit/d88245efe8fed5927e136719a9747b788dbd0fc2) Add page for Selendroid - [ff63433](https://github.com/appium/ruby_lib/commit/ff63433db6d68170ef135e151d6ac154c3504f4f) Add id method - [c59f7ce](https://github.com/appium/ruby_lib/commit/c59f7cefc76a9f172e6e6494aca275b5687d1a74) Improve debugging #### v0.3.7 2013-05-01 - [edfd20a](https://github.com/appium/ruby_lib/commit/edfd20a6ffdef8484b9f7b5eddb9c21815241d42) Release 0.3.7 - [9f8511c](https://github.com/appium/ruby_lib/commit/9f8511c1416867df606dfb3d058f83ee277ce39a) Remove puts #### v0.3.6 2013-05-01 - [67e5c86](https://github.com/appium/ruby_lib/commit/67e5c867d38251687dc7ebd5de013db5712fcac3) Release 0.3.6 - [a0a46f7](https://github.com/appium/ruby_lib/commit/a0a46f773a57c9ef7b92252afed467bd7cd01b96) Fix wait and add wait_true - [e7cde77](https://github.com/appium/ruby_lib/commit/e7cde775473bd3981cac5b356f78289f832091a9) Add wait example #### v0.3.5 2013-04-30 - [a886ef4](https://github.com/appium/ruby_lib/commit/a886ef4722a902fdef15ecfc7164299399f1d524) Release 0.3.5 - [193eb71](https://github.com/appium/ruby_lib/commit/193eb716023f52506cdf599cff6aae4f4a3c1119) Fix JSON.parse - [54ba323](https://github.com/appium/ruby_lib/commit/54ba323721a704d3ceb34f71dd8e1fcf9069dd78) Use upstream get name contains - [6f66b46](https://github.com/appium/ruby_lib/commit/6f66b46725ee397cc437901e95431ec95935d9c2) Name contains moved upstream - [2d33b5c](https://github.com/appium/ruby_lib/commit/2d33b5ce4078d784f7f6f0ac07651166a466b34c) Update readme.md - [4a1f87e](https://github.com/appium/ruby_lib/commit/4a1f87e1f0524595d7bd15027b4a009a42b5ff83) Update example - [6177c49](https://github.com/appium/ruby_lib/commit/6177c497f9c114203e624f530e51f4f54a61788a) Rename get_wait #### v0.3.4 2013-04-30 - [ffdf104](https://github.com/appium/ruby_lib/commit/ffdf104ffdecb165cfe410976145134768756e30) Release 0.3.4 - [4edc9f6](https://github.com/appium/ruby_lib/commit/4edc9f6097e29d2816dceef546a819fd6ee431d2) Add params to wait - [da1c042](https://github.com/appium/ruby_lib/commit/da1c0424873fa5f859b1ec558356a3ad0721097b) Add selendroid launch support - [f398041](https://github.com/appium/ruby_lib/commit/f398041369884d8068950ab9e703a8a2d750082c) Use symbols for driver opts - [cf09a0d](https://github.com/appium/ruby_lib/commit/cf09a0d1ca8de835043f855cbd74ced9abb5f1b0) Add expected server opts - [fe6c7d7](https://github.com/appium/ruby_lib/commit/fe6c7d71dbaf7f7b383d117918de2498945406d4) Fix os specific patches - [d9b9c1a](https://github.com/appium/ruby_lib/commit/d9b9c1a2fcc1857e0e7c78d250fd59b84726d69b) Improve logging - [3b831b0](https://github.com/appium/ruby_lib/commit/3b831b089e02c4a53585d90ed009f5ad3cb982a7) Return invisible match if no visible result #### v0.3.3 2013-04-27 - [b0ca37c](https://github.com/appium/ruby_lib/commit/b0ca37cfe47318f029e1f2ad498a5c08338016d7) Release 0.3.3 - [e7f55d9](https://github.com/appium/ruby_lib/commit/e7f55d92181660ea188a5123e6e4f447389c8d6d) Add driver method - [6d381fe](https://github.com/appium/ruby_lib/commit/6d381fe029bd9a5c11aa4d1a322d6afb603c6434) Update readme.md - [07da208](https://github.com/appium/ruby_lib/commit/07da208973ea4de64ec9605ef5dd38884771e8c6) Add troubleshooting steps #### v0.3.2 2013-04-26 - [eee6632](https://github.com/appium/ruby_lib/commit/eee6632251c40c8b2d6be9a361f429d7c89762f8) Release 0.3.2 - [b22d747](https://github.com/appium/ruby_lib/commit/b22d7473f03e1b13a1ffd9ddc2ea5ca1396c4642) Default to app_activity if app_wait_activity is not set - [76198ad](https://github.com/appium/ruby_lib/commit/76198ad4d169d836007a247b2ebe8cad5391f512) Fix reset clearing iOS JavaScript - [445519b](https://github.com/appium/ruby_lib/commit/445519b4528c9c253865f76fdac921a22c31fbd7) Use Appium's detailed error messages - [e00964f](https://github.com/appium/ruby_lib/commit/e00964fa7b9ccd047b06f1432ddd1e62170306df) Update readme.md - [ef0b626](https://github.com/appium/ruby_lib/commit/ef0b626940d86fd07dbb86ac16b40dd5b0b5ce4a) Avoid invisible elements #### v0.3.1 2013-04-26 - [e00fc6e](https://github.com/appium/ruby_lib/commit/e00fc6efb8f0c94ac6e196e831980ee96676b645) Release 0.3.1 - [81d762a](https://github.com/appium/ruby_lib/commit/81d762a92293a9d59600154f1f0a5944aee5b439) Check method exists before calling - [4b3f3dc](https://github.com/appium/ruby_lib/commit/4b3f3dc91714b08aae0acee51aa1137c58f59acb) Fix method dispatch - [fa8b679](https://github.com/appium/ruby_lib/commit/fa8b679b816bd1507c7c9de3f301a3b8a7742d8f) Fix iOS name - [5be26c4](https://github.com/appium/ruby_lib/commit/5be26c411fcf75154301749cd790487d3dd71ea9) Add sauce methods and find_name - [b3724d3](https://github.com/appium/ruby_lib/commit/b3724d36a85188c7c8c85dadc313c6c43c8bed59) Add session_id #### v0.3.0 2013-04-25 - [e08e88c](https://github.com/appium/ruby_lib/commit/e08e88c40cc56e132c5db18d9d5862028861d5f2) Release 0.3.0 - [3f4dd63](https://github.com/appium/ruby_lib/commit/3f4dd63ab2ab2e97b457bb188a347af6c74bc7df) Update code style - [9bbb17e](https://github.com/appium/ruby_lib/commit/9bbb17e4079c7db1c033284c3120611f11f33656) Update readme.md - [354bf19](https://github.com/appium/ruby_lib/commit/354bf19090ca6b1a7812d067321452094f7a62c0) Add new usage example - [9668450](https://github.com/appium/ruby_lib/commit/96684503b091af581a78067342106feef5769a92) Restore top level methods - [b095c4a](https://github.com/appium/ruby_lib/commit/b095c4a94109c508fc286801d957e4535e27462d) Rewrite as a real lib - [71628ff](https://github.com/appium/ruby_lib/commit/71628ff13fc84c3b15f0dc3986a75bd3fcb7a28e) Fix page for iOS - [fce0d67](https://github.com/appium/ruby_lib/commit/fce0d676cb78582703934872a0256c55ad55d225) Add force encoding check - [aed2607](https://github.com/appium/ruby_lib/commit/aed26079c25ee2f80c8a1462dde7d589d30e014b) Raise NoSuchElementError on find - [82dc953](https://github.com/appium/ruby_lib/commit/82dc953a302fc4505d6c7c2121da0ccbe71e053a) Add webview support to find - [151edde](https://github.com/appium/ruby_lib/commit/151edde563bb907b07c7896794ecbb81568c3e29) Define no args page for iOS - [b3227f7](https://github.com/appium/ruby_lib/commit/b3227f73175697782c5dbc8f62ad911fcae88965) Quote button name when string - [0c0073d](https://github.com/appium/ruby_lib/commit/0c0073d0785ff64606c7887ec4eb83a8bcc5cafd) Add grid and relative - [3b87251](https://github.com/appium/ruby_lib/commit/3b87251d9e749590873c1bb118c88dd4b8fdaea0) Add note about secure tag on Android - [494f0e3](https://github.com/appium/ruby_lib/commit/494f0e39d9b1ebbafd731b4d311e4cc1cee02266) Add window mapping for Android - [e4d63a5](https://github.com/appium/ruby_lib/commit/e4d63a569c6fede034a1fd411ba9047327389063) Replace classNameMatches with className - [dd82100](https://github.com/appium/ruby_lib/commit/dd821001ee333801a36f2b5c01e4793e47fd037e) Fix find_eles_attr - [de7a1bc](https://github.com/appium/ruby_lib/commit/de7a1bc1112aa3d1930647738d85ae54270685d2) Improve webdriver debug messages - [dff41da](https://github.com/appium/ruby_lib/commit/dff41dae4a0d67200336b3daa677ab73157c0464) Better webdriver debug messages - [d2ca728](https://github.com/appium/ruby_lib/commit/d2ca72880c9bdfb853a5dcd63e3db16fa03d3f1d) Use textContains to fetch first element only - [1cbb69d](https://github.com/appium/ruby_lib/commit/1cbb69d8b9b69cdacfdfef663ab8ff31d506ba50) Check for empty app path - [427e105](https://github.com/appium/ruby_lib/commit/427e105be7865c5a637e62fb597cc034b4cda2ad) Fix format - [40cd10b](https://github.com/appium/ruby_lib/commit/40cd10bf72a080a0a34f43d189befab1b1f953e4) Update get_inspect - [bc1cdb1](https://github.com/appium/ruby_lib/commit/bc1cdb120ccef4598333838cfaf35c54d84ad79a) Add find_eles_attr - [e89f8bd](https://github.com/appium/ruby_lib/commit/e89f8bdad8919471ae12c11343b82c2d04d88027) Use XPath last() - [133cf98](https://github.com/appium/ruby_lib/commit/133cf98bd27c26d1a5438bdf4534149f0f8aef89) Add xpath, xpaths - [435eac0](https://github.com/appium/ruby_lib/commit/435eac0bd8020dd5fc30a9ae163f72ab4fda1565) Fix name - [050734f](https://github.com/appium/ruby_lib/commit/050734f7a64e8d9386b5c2e2ccb0ce653f816437) Update first_ele to use XPath #15 - [f89dcc3](https://github.com/appium/ruby_lib/commit/f89dcc361b8c6762cad541fc9b5a2e1955b1cd27) Update ele_index to use XPath #15 - [763d086](https://github.com/appium/ruby_lib/commit/763d0862135bf9e06ad177c9e3e20a83819b1775) Use mobile method - [09035ab](https://github.com/appium/ruby_lib/commit/09035ab053df980baf43b8d1128f68fe52df37a4) Remove old comment - [2d07ed0](https://github.com/appium/ruby_lib/commit/2d07ed0d5868c734168b31fb47881eaa4c74af1c) Raise instead of puts #### v0.0.30 2013-04-16 - [6d65a9c](https://github.com/appium/ruby_lib/commit/6d65a9c2895b1b66556b12fee4fc9649f558ede1) Release 0.0.30 - [5692f96](https://github.com/appium/ruby_lib/commit/5692f9604a09b6198f8ada7823d8f74858b8af88) Fix quote - [ee17332](https://github.com/appium/ruby_lib/commit/ee173329758ea486d32d6887439de39a749ceba0) Use driver_quit #### v0.0.29 2013-04-15 - [1c1e0ee](https://github.com/appium/ruby_lib/commit/1c1e0eeed8d636dc81d3b74612405722b1134071) Release 0.0.29 - [2278c8e](https://github.com/appium/ruby_lib/commit/2278c8e662d32df86933a63f14dea4df431a95e5) Add wait param to start_driver - [f5f82c0](https://github.com/appium/ruby_lib/commit/f5f82c0f98291e0f8b8ae0baa6285ad4b62cc34e) Default to partial match - [2e7f8c6](https://github.com/appium/ruby_lib/commit/2e7f8c6b09aa433d3712685f6842a052dd4847b3) Update webdriver - [b7b6caa](https://github.com/appium/ruby_lib/commit/b7b6caa8ab0c2683626aed265ee6ec2feece37f0) Use gh_name #### v0.0.28 2013-04-11 - [70606a4](https://github.com/appium/ruby_lib/commit/70606a43cebcd0c19b98a1876fb929f03db7bb0e) Release 0.0.28 - [61d1943](https://github.com/appium/ruby_lib/commit/61d19439c8597ca3562028d6c985370a5d43fa26) Update docs.md - [7676a90](https://github.com/appium/ruby_lib/commit/7676a90af8a1951817fcc8c49ddef46577cf5726) Add iOS name, names, text, texts - [7bc936c](https://github.com/appium/ruby_lib/commit/7bc936c63fff14780595a9a9fd360670d6e00178) Update webdriver - [e3646d3](https://github.com/appium/ruby_lib/commit/e3646d311873f82287e2a14a8c699c2d097c5a6c) Add fast_duration - [22ac58a](https://github.com/appium/ruby_lib/commit/22ac58ab3f48cc51019fafde19efdc012d5b8c2b) Check that app path exists - [217bca9](https://github.com/appium/ruby_lib/commit/217bca9e85c5e5e4a21832c34cc715476b0dd181) Add page for iOS - [2abf365](https://github.com/appium/ruby_lib/commit/2abf365017555c37e95cfa57f0142b0a2fa944a8) Update docs.md - [a1d26ff](https://github.com/appium/ruby_lib/commit/a1d26ff13912e301079cc8ca222013850b660d21) Add link to docs.md - [e4d27c9](https://github.com/appium/ruby_lib/commit/e4d27c95e344ca7b25512044b65cbdbe4a9dce82) Update docs.md - [2cf20a0](https://github.com/appium/ruby_lib/commit/2cf20a026ef33e727b1da360634668ddda70518d) Create docs.md - [e1f470e](https://github.com/appium/ruby_lib/commit/e1f470e0a2b9a6cf94ffa20edbc244e31c0375e8) Add find for Android - [37bb4e9](https://github.com/appium/ruby_lib/commit/37bb4e90b29e5adb4438b287b6387a504c94b5c4) Update comment - [aaeba81](https://github.com/appium/ruby_lib/commit/aaeba817376dd8e3cadeab37d096abc0170b565b) Add order to find - [73b757c](https://github.com/appium/ruby_lib/commit/73b757cd28c5bc85b98d6e747f79f7ee33af5022) Define find and finds to search everything - [ebd6c1b](https://github.com/appium/ruby_lib/commit/ebd6c1bc7d3f8be01fdf5346786c2b5fb2da8deb) Fix text and texts on iOS #### v0.0.27 2013-04-05 - [fb4af20](https://github.com/appium/ruby_lib/commit/fb4af206c114cf8f75fcb41cdbbea0ba728bf7e6) Release 0.0.27 - [ca00d82](https://github.com/appium/ruby_lib/commit/ca00d82fb8e716d5941ec0ee6b38b207329b915e) Fix require - [ad00639](https://github.com/appium/ruby_lib/commit/ad006393ce8b6dc071c98b2edf73c32707d37762) Update readme.md #### v0.0.26 2013-04-04 - [07fed25](https://github.com/appium/ruby_lib/commit/07fed259a743d9f3f3d72bfc8c8b9eac7b26d724) Release 0.0.26 - [7c77faa](https://github.com/appium/ruby_lib/commit/7c77faa7087f9aa4bf2cc387a13b9bb0974d59a1) Add exists method - [27f4ccf](https://github.com/appium/ruby_lib/commit/27f4ccf19f0d4028baf634ccb9538a340c96ebb9) Add alert for Android - [4bb466f](https://github.com/appium/ruby_lib/commit/4bb466f8ed90cb0f015bb627423dba8c91574a4d) Add txt methods - [2d2704a](https://github.com/appium/ruby_lib/commit/2d2704a99318a21c292a636730bca94af87bcc55) Store default wait in var - [8a2bc8a](https://github.com/appium/ruby_lib/commit/8a2bc8aed39639e6c3d51c185d233be6f9760c59) Update release_notes.md - [c504873](https://github.com/appium/ruby_lib/commit/c504873582d4871650e02515ccb68e21bd1486ae) Create release_notes.md - [2e71e47](https://github.com/appium/ruby_lib/commit/2e71e477962c70113b556700cf08c74060d77370) Don't wait in Pry - [3416272](https://github.com/appium/ruby_lib/commit/341627269bf50497ebe4a6e388939d45d53e2032) Update readme.md #### v0.0.25 2013-03-28 - [6a975a6](https://github.com/appium/ruby_lib/commit/6a975a6cc0e97866c3ef6248f0f7d1abbc934577) Release 0.0.25 - [6a8fdce](https://github.com/appium/ruby_lib/commit/6a8fdcea4c8fdc308c7d107e958fbabed9719056) Rename inspect #### v0.0.24 2013-03-28 - [d5bcb94](https://github.com/appium/ruby_lib/commit/d5bcb94966c4a7806a47ee892f3e5ff784a739e2) Release 0.0.24 - [17f9a67](https://github.com/appium/ruby_lib/commit/17f9a67143720dbfc50b34783a11c7bf5c28ea3c) Add .lock to ignore - [9181cb8](https://github.com/appium/ruby_lib/commit/9181cb88f3d1180a16998f27e2236864809c6fcf) Add inspect using JSON dump - [e74dc46](https://github.com/appium/ruby_lib/commit/e74dc468a5d3d81f77c50d3fe41eb9dbebf3d404) Add get_source - [2444290](https://github.com/appium/ruby_lib/commit/24442908f9426b228dc760497ef98f9cf579d4d5) Add name methods #### v0.0.23 2013-03-27 - [789634c](https://github.com/appium/ruby_lib/commit/789634c6b20d4030eaec4d385a85275b3fabfe76) Release 0.0.23 - [6d58a33](https://github.com/appium/ruby_lib/commit/6d58a33bce0bf1ff3c6156717519a2db6a27bb84) Add app-wait-activity #### v0.0.22 2013-03-23 - [bfd7761](https://github.com/appium/ruby_lib/commit/bfd7761c0f2b32e7ab0bbe8372228163181e60b9) Release 0.0.22 #### v0.0.21 2013-03-22 - [4066823](https://github.com/appium/ruby_lib/commit/40668230b89eaa66970889b20305279029048698) Release 0.0.21 #### v0.0.20 2013-03-22 - [ed588a1](https://github.com/appium/ruby_lib/commit/ed588a1ccc67d0efa0d8d56f4f9b08c23b261687) Release 0.0.20 - [a4a7199](https://github.com/appium/ruby_lib/commit/a4a7199dfb609841310ad4e31ccbb56e3ecfa90d) Update readme.md #### v0.0.19 2013-03-22 - [01f2d15](https://github.com/appium/ruby_lib/commit/01f2d150ae3d8e88970b361a8330c6ccc174097d) Release 0.0.19 - [10eec2f](https://github.com/appium/ruby_lib/commit/10eec2f197899395978b73de049aed08ceda55cc) AppLib => AppiumLib - [c1e3b4f](https://github.com/appium/ruby_lib/commit/c1e3b4f0a08be3a0aef65218220f09f4198683bf) AppLib => AppiumLib ================================================ FILE: test/first_test.rb ================================================ # frozen_string_literal: true # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'minitest/autorun' require 'minitest/reporters' require 'minitest' begin Minitest::Reporters.use! [Minitest::Reporters::ProgressReporter.new] rescue Errno::ENOENT # Ignore since Minitest::Reporters::JUnitReporter.new fails in deleting files, sometimes end class SampleTest < Minitest::Test def test_test assert(true) end end