├── .gitignore ├── .gitmodules ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── azure-pipelines.yml ├── bin ├── ci │ ├── travis │ │ └── run.sh │ └── windows.bat └── publish-calabash-docs.sh ├── build.properties ├── changelog ├── .gitkeep ├── 0.5.10.md ├── 0.5.11.md ├── 0.5.12.md ├── 0.5.15.md ├── 0.5.2.md ├── 0.5.3.md ├── 0.5.4.md ├── 0.5.5.md ├── 0.5.6.md ├── 0.5.7.md ├── 0.5.8.md ├── 0.5.9.md ├── 0.6.0.md ├── 0.7.0.md ├── 0.7.3.md ├── 0.8.0.md ├── 0.8.1.md ├── 0.8.2.md ├── 0.8.3.md ├── 0.8.4.md └── 0.9.0.md ├── deprecated_actions.md ├── documentation ├── installation.md └── ruby_api.md ├── migrating_to_calabash_0.5.md └── ruby-gem ├── .calabash_settings ├── .rspec ├── .yardopts ├── CHANGES.txt ├── ENVIRONMENT_VARIABLES.md ├── Gemfile ├── Guardfile ├── LICENSE ├── README_YARDOC.md ├── Rakefile ├── api ├── .gitignore ├── Gemfile ├── Gemfile.lock └── features │ ├── clearing_text.feature │ ├── entering_text.feature │ ├── location_mocking.feature │ ├── querying.feature │ ├── steps │ ├── clearing_text.rb │ ├── entering_text.rb │ ├── location_mocking.rb │ ├── querying.rb │ ├── shared.rb │ ├── shared_keyboard.rb │ └── tapping.rb │ ├── support │ ├── apps │ │ └── general.apk │ ├── env.rb │ └── hooks.rb │ └── tapping.feature ├── bin ├── calabash-android ├── calabash-android-build.rb ├── calabash-android-console.rb ├── calabash-android-generate.rb ├── calabash-android-helpers.rb ├── calabash-android-run.rb └── calabash-android-setup.rb ├── calabash-android.gemspec ├── epl-v10.html ├── features-skeleton ├── my_first.feature ├── step_definitions │ └── calabash_steps.rb └── support │ ├── app_installation_hooks.rb │ ├── app_life_cycle_hooks.rb │ ├── env.rb │ └── hooks.rb ├── integration-tests ├── .gitignore ├── .irb-history ├── Gemfile ├── NativeTestApp │ ├── .gitignore │ ├── app │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── assets │ │ │ ├── web_view.html │ │ │ ├── web_view_multiscroll.html │ │ │ ├── web_view_scroll.html │ │ │ └── web_view_swipe.html │ │ │ ├── java │ │ │ └── com │ │ │ │ └── xamarin │ │ │ │ └── xtcandroidsample │ │ │ │ ├── DatePickerActivity.java │ │ │ │ ├── DirectionalSwipeActivity.java │ │ │ │ ├── DragAndDropActivity.java │ │ │ │ ├── HorizontalScrollActivity.java │ │ │ │ ├── ListViewActivity.java │ │ │ │ ├── LocationActivity.java │ │ │ │ ├── MainActivity.java │ │ │ │ ├── MultiScroll.java │ │ │ │ ├── NativeCrash.java │ │ │ │ ├── RecycleViewActivity.java │ │ │ │ ├── RecycleViewAdapter.java │ │ │ │ ├── ScollplicatedActivity.java │ │ │ │ ├── ScrollActivity.java │ │ │ │ ├── ScrollShortActivity.java │ │ │ │ ├── ScrollWebViewActivity.java │ │ │ │ ├── Settings.java │ │ │ │ ├── SpellCheckActivity.java │ │ │ │ ├── SwipeWebViewActivity.java │ │ │ │ ├── TextfieldsActivity.java │ │ │ │ ├── ViewDataActivity.java │ │ │ │ ├── ViewsActivity.java │ │ │ │ ├── WebViewActivity.java │ │ │ │ └── orientations │ │ │ │ ├── LandscapeActivity.java │ │ │ │ ├── OrientationsActivity.java │ │ │ │ ├── PortraitActivity.java │ │ │ │ ├── ReverseLandscapeActivity.java │ │ │ │ └── ReversePortraitActivity.java │ │ │ └── res │ │ │ ├── drawable-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── drawable-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── drawable-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── drawable-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── drawable │ │ │ └── red.png │ │ │ ├── layout │ │ │ ├── activity_drag_and_drop.xml │ │ │ ├── activity_horizontal_scroll.xml │ │ │ ├── activity_landscape.xml │ │ │ ├── activity_main.xml │ │ │ ├── activity_multi_scroll.xml │ │ │ ├── activity_orientations.xml │ │ │ ├── activity_portrait.xml │ │ │ ├── activity_recycle_view_activity.xml │ │ │ ├── activity_reverse_landscape.xml │ │ │ ├── activity_reverse_portrait.xml │ │ │ ├── activity_scollplicated_activty.xml │ │ │ ├── activity_scroll_short.xml │ │ │ ├── activity_textfields.xml │ │ │ ├── date_picker_sample.xml │ │ │ ├── dialog_layout.xml │ │ │ ├── directional_swipe_sample.xml │ │ │ ├── location_activity.xml │ │ │ ├── scroll_sample.xml │ │ │ ├── scroll_web_view.xml │ │ │ ├── spell_check_sample.xml │ │ │ ├── swipe_web_view.xml │ │ │ ├── view_data.xml │ │ │ ├── views_sample.xml │ │ │ └── web_view_sample.xml │ │ │ ├── menu │ │ │ ├── directional_swipe.xml │ │ │ ├── landscape.xml │ │ │ ├── main.xml │ │ │ ├── menu_horizontal_scroll.xml │ │ │ ├── menu_list_view_example.xml │ │ │ ├── menu_recycle_view_example.xml │ │ │ ├── menu_scroll_short.xml │ │ │ ├── menu_textfields.xml │ │ │ ├── multi_scroll.xml │ │ │ ├── orientations.xml │ │ │ ├── portrait.xml │ │ │ ├── reverse_landscape.xml │ │ │ ├── reverse_portrait.xml │ │ │ ├── scollplicated_activty.xml │ │ │ ├── scroll.xml │ │ │ ├── spell_check.xml │ │ │ ├── view_data.xml │ │ │ └── views.xml │ │ │ ├── values-sw600dp │ │ │ └── dimens.xml │ │ │ ├── values-sw720dp-land │ │ │ └── dimens.xml │ │ │ ├── values-v11 │ │ │ └── styles.xml │ │ │ ├── values-v14 │ │ │ └── styles.xml │ │ │ ├── values-w820dp │ │ │ └── dimens.xml │ │ │ └── values │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle ├── README.md ├── config │ └── cucumber.yml └── features │ ├── main.feature │ ├── orientations.feature │ ├── steps │ ├── calabash.rb │ ├── orientation.rb │ ├── sample.rb │ └── webview.rb │ ├── support │ ├── app_installation_hooks.rb │ ├── app_life_cycle_hooks.rb │ ├── data │ │ ├── iframe.html │ │ └── page_with_iframe.html │ ├── env.rb │ ├── helpers.rb │ └── hooks.rb │ └── webview.feature ├── irbrc ├── lib ├── calabash-android.rb └── calabash-android │ ├── abase.rb │ ├── calabash_steps.rb │ ├── canned_steps.md │ ├── color_helper.rb │ ├── cucumber.rb │ ├── defaults.rb │ ├── dependencies.rb │ ├── deprecated_actions.map │ ├── dot_dir.rb │ ├── drag_helpers.rb │ ├── env.rb │ ├── environment.rb │ ├── environment_helpers.rb │ ├── gestures.rb │ ├── helpers.rb │ ├── java_keystore.rb │ ├── lib │ ├── AXMLPrinter2.jar │ ├── AndroidManifest.xml │ ├── TestServer.apk │ ├── manifest_extractor.jar │ └── screenshotTaker.jar │ ├── logging.rb │ ├── management │ ├── adb.rb │ └── app_installation.rb │ ├── monkey_helpers.rb │ ├── operations.rb │ ├── removed_actions.txt │ ├── retry.rb │ ├── steps │ ├── assert_steps.rb │ ├── check_box_steps.rb │ ├── context_menu_steps.rb │ ├── date_picker_steps.rb │ ├── enter_text_steps.rb │ ├── l10n_steps.rb │ ├── location_steps.rb │ ├── map_steps.rb │ ├── navigation_steps.rb │ ├── press_button_steps.rb │ ├── progress_steps.rb │ ├── screenshot_steps.rb │ ├── search_steps.rb │ ├── spinner_steps.rb │ └── time_picker_steps.rb │ ├── store │ └── preferences.rb │ ├── text_helpers.rb │ ├── touch_helpers.rb │ ├── usage_tracker.rb │ ├── utils.rb │ ├── version.rb │ └── wait_helpers.rb └── spec ├── lib ├── dot_dir_spec.rb ├── environment_spec.rb ├── logging_spec.rb ├── retryable_spec.rb ├── store │ └── preferences_spec.rb ├── usage_tracker_spec.rb ├── utils_spec.rb ├── version_spec.rb └── wait_helpers_spec.rb └── spec_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | gen 3 | staging 4 | instrumentation_backend/.settings 5 | instrumentation_backend/assets/foo.bar 6 | *.swp 7 | *.*~ 8 | **/.DS_STORE 9 | ruby-gem/pkg 10 | ruby-gem/test-server/out 11 | calabash-android-*.gem 12 | .idea 13 | *.iml 14 | 15 | # For a library or gem, ignore these files since the code is intended to run in 16 | # multiple environments; otherwise, check them in. 17 | Gemfile.lock 18 | .ruby-version 19 | .ruby-gemset 20 | .bundle 21 | 22 | # rspec 23 | ruby-gem/spec/reports 24 | ruby-gem/tmp 25 | 26 | # emacs and vim 27 | (.*/)?\#[^/]*\#$ 28 | tags 29 | 30 | # mergetools 31 | *.orig 32 | 33 | # Documentation cache and generated files: 34 | .yardoc 35 | _yardoc 36 | doc 37 | rdoc 38 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calabash/calabash-android/4ff3f08420264e71b6f0cf1db845327d7672c213/.gitmodules -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | 3 | # Container based: faster 4 | sudo: false 5 | 6 | os: 7 | - linux 8 | - osx 9 | 10 | rvm: 11 | - 2.7.1 12 | 13 | env: 14 | - CI_NO_ANDROID_RUNTIME=1 15 | 16 | script: 17 | - bin/ci/travis/run.sh 18 | 19 | notifications: 20 | email: 21 | recipients: 22 | - josmoo@microsoft.com 23 | on_success: change 24 | on_failure: always 25 | slack: 26 | rooms: 27 | secure: fZynvMX0+leWS5FRv8aDaMGhV5dbxGhs3ed6slhLfB6oEUlS9u+VGT1jZuKCSODW4E4Ao2xUziVdRwe/cCIYkgbuIlhJtb/gUI0lIlx7bBC17/8uydFcthukA/KYw8kyArWZkEyC+eixQhixju3BUYAylbepgRtA62DUnbxyh5Q= 28 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | 3 | To avoid duplicates, please search existing issues before reporting a 4 | new one. 5 | 6 | Github Issues is intended for reporting bugs and feature suggestions. If 7 | you have a question or need support, please use [Stack 8 | Overflow](https://stackoverflow.com/questions/tagged/calabash) or join 9 | the conversation on [Gitter](https://gitter.im/calabash/calabash0x?utm_source=share-link&utm_medium=link&utm_campaign=share-link). 10 | 11 | ## Etiquette and Code of Conduct 12 | 13 | All contributors must adhere to the [Microsoft Open Source Code of 14 | Conduct](https://opensource.microsoft.com/codeofconduct/). For more 15 | information see the [Code of Conduct 16 | FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact 17 | opencode@microsoft.com with any additional questions or comments. 18 | 19 | ## Legal 20 | 21 | Users who wish to contribute will be prompted to sign a Microsoft 22 | Contributor License Agreement (CLA). A copy of the CLA can be found at 23 | https://cla.microsoft.com/cladoc/microsoft-contribution-license-agreement.pdf. 24 | 25 | Please consult the LICENSE file in this project for copyright and 26 | license details. 27 | 28 | ## Releasing 29 | 30 | ``` 31 | $ cd path/to/calabash-android-server 32 | $ git checkout develop 33 | $ git pull 34 | $ git fetch --tags 35 | $ git checkout -b tag/1.2.3 1.2.3 36 | 37 | $ cd path/calabash-android/ruby-gem 38 | $ git checkout master 39 | $ git pull 40 | $ git checkout -b release/1.2.3 41 | 42 | 1. Bump the ruby version in lib/calabash-android/version.rb 43 | 2. Build the TestServer.apk. 44 | $ rake build_server 45 | 3. Update the CHANGELOG. 46 | 4. Check the README for items to update. 47 | 5. Make pull request, get a review, and merge. 48 | 49 | $ git checkout master 50 | $ git pull 51 | $ rake release 52 | 53 | Announce the release on the public channels. 54 | ``` 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Calabash-android Copyright (2012) LessPainful ApS. All rights reserved. 2 | The use and distribution terms for this software are covered by the 3 | Eclipse Public License 1.0 4 | (http://opensource.org/licenses/eclipse-1.0.php) which can be found in 5 | the file epl-v10.html at the root of this distribution. By using this 6 | software in any fashion, you are agreeing to be bound by the terms of 7 | this license. You must not remove this notice, or any other, from 8 | this software. -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - name: EOCompliance-Mac 3 | value: true 4 | 5 | jobs: 6 | - job: 7 | strategy: 8 | matrix: 9 | Mojave: 10 | IMAGE_POOL: 'macOS-10.14' 11 | Ubuntu-16: 12 | IMAGE_POOL: 'ubuntu-16.04' 13 | pool: 14 | vmImage: $(IMAGE_POOL) 15 | 16 | steps: 17 | - task: Gradle@2 18 | inputs: 19 | workingDirectory: 'ruby-gem/integration-tests/NativeTestApp' 20 | gradleWrapperFile: 'ruby-gem/integration-tests/NativeTestApp/gradlew' 21 | gradleOptions: '-Xmx3072m' 22 | publishJUnitResults: false 23 | tasks: 'assemble' 24 | -------------------------------------------------------------------------------- /bin/ci/travis/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd ruby-gem 4 | 5 | touch lib/calabash-android/lib/TestServer.apk 6 | touch lib/calabash-android/lib/AndroidManifest.xml 7 | 8 | bundle update 9 | 10 | gem build calabash-android.gemspec 11 | 12 | bundle exec rake unit 13 | 14 | -------------------------------------------------------------------------------- /bin/ci/windows.bat: -------------------------------------------------------------------------------- 1 | call cd ruby-gem 2 | call gem update --system 3 | call bundle update 4 | call bundle exec rspec spec 5 | -------------------------------------------------------------------------------- /bin/publish-calabash-docs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | SERVER=calabashapi.xamarin.com 6 | 7 | cd ruby-gem 8 | 9 | echo "INFO: cleaning local documentation artifacts." 10 | rm -rf doc.tar 11 | 12 | echo "INFO: generate docs with yard." 13 | bundle exec rake yard 14 | 15 | echo "INFO: clearing artifacts in $SERVER:~/." 16 | ssh $SERVER 'rm -rf doc.tar; rm -rf doc' 17 | 18 | echo "INFO: creating a tarball to upload." 19 | tar -cf doc.tar doc 20 | 21 | echo "INFO: copying tarball to $SERVER" 22 | scp doc.tar $SERVER:~/ 23 | 24 | echo "INFO: expanding $SERVER:~/doc.tar" 25 | ssh $SERVER 'tar -xf doc.tar' 26 | 27 | echo "INFO: deleting calabash docs." 28 | ssh $SERVER 'sudo rm -rf /srv/www/calabashapi.xamarin.com/android' 29 | 30 | echo "INFO: staging new calabash docs." 31 | ssh $SERVER 'sudo mv doc /srv/www/calabashapi.xamarin.com/android' 32 | 33 | echo "INFO: cleaning remote artifacts." 34 | ssh $SERVER 'rm -rf doc.tar; rm -rf doc' 35 | 36 | echo "INFO: cleaning local artifacts." 37 | rm -rf doc.tar 38 | 39 | echo "INFO: done!" 40 | -------------------------------------------------------------------------------- /build.properties: -------------------------------------------------------------------------------- 1 | tested.package_name=sh.calabash.test 2 | tested.main_activity=sh.calabash.test.activities.LoginActivity 3 | tested.project.apk=YourApp.apk 4 | 5 | #You might have to update these values 6 | android.api.level=8 7 | 8 | key.store=${user.home}/.android/debug.keystore 9 | key.store.password=android 10 | key.alias=androiddebugkey 11 | key.alias.password=android 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /changelog/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calabash/calabash-android/4ff3f08420264e71b6f0cf1db845327d7672c213/changelog/.gitkeep -------------------------------------------------------------------------------- /changelog/0.5.10.md: -------------------------------------------------------------------------------- 1 | # Release notes for calabash-android 0.5.10 2 | 3 | **Fix**: Building and signing not working if the language of the host computer was not English. -------------------------------------------------------------------------------- /changelog/0.5.11.md: -------------------------------------------------------------------------------- 1 | # Release notes for calabash-android 0.5.11 2 | 3 | **Change** the way Calabash-Android (re)signs applications: 4 | 5 | Use the encryption of the supplied keystore, and always use SHA1 as the digest algorithm. This is equivalent to how Android Studio behaves. If given a keystore with the signing algorithm SHA256withDSA, Calabash-Android will sign an application using SHA1withDSA. 6 | 7 | -------------------------------------------------------------------------------- /changelog/0.5.12.md: -------------------------------------------------------------------------------- 1 | # Release notes for calabash-android 0.5.12 2 | 3 | **Fix** Calabash WebView queries not working for new Android System WebViews in Lollipop and M. 4 | -------------------------------------------------------------------------------- /changelog/0.5.15.md: -------------------------------------------------------------------------------- 1 | # Release notes for calabash-android 0.5.15 2 | 3 | **Fix** Do not depend on any specific version of Cucumber. Calabash-Android can now be used with any version of Cucumber without any hassles. 4 | 5 | **Change** Grant all permissions when installing an app on Marshmallow. When an application is installed on an M device, all requested permissions are granted when installing. -------------------------------------------------------------------------------- /changelog/0.5.3.md: -------------------------------------------------------------------------------- 1 | # Release notes for calabash-android 0.5.3 2 | 3 | **Add** ability to evaluate javascript in webviews specified by a query. Example: `evaluate_javascript("WebView", "return document.body.style.backgroundColor;")` 4 | 5 | **Add** methods to clear text in a specified view or the view that has focus. Works for webviews as well. Examples: 6 | 7 | ```ruby 8 | clear_text # Clear the text in the view that currently has focus 9 | clear_text_in("EditText id:'input'") 10 | ``` 11 | 12 | **Fix** depend on a non-beta version of cucumber 13 | 14 | **Update** handle keystores better. Calabash Android will not try to determine the alias of the keystore if no alias is specified. -------------------------------------------------------------------------------- /changelog/0.5.4.md: -------------------------------------------------------------------------------- 1 | # Release notes for calabash-android 0.5.4 2 | 3 | This version is only a fix of changes introduced in 0.5.3 4 | 5 | **Fix** handle the old usage of `clear_text` better. `clear_text` was changed in 0.5.3 and `clear_text_in` is the new equivalent method. Notice that `clear_text_in` now only clears the text of the first view found, not all. To replicate the old behaviour, use `query(query, setText: '')` -------------------------------------------------------------------------------- /changelog/0.5.5.md: -------------------------------------------------------------------------------- 1 | # Release notes for calabash-android 0.5.5 2 | 3 | **Fix** Support for the newest versions of Cordova. 4 | 5 | **Change** `press_user_action_button` now defaults to enter key (newline) in input fields with multiple lines. Keyboards will often have multiple user actions (e.g. next and newline). You can test such actions by specifying which action to use e.g. `press_user_action_button('next')` 6 | 7 | **Fix** Properly delegate all callbacks to the origin Web Chrome Client of the WebView being tested. 8 | 9 | **Fix** Run queries on the UI thread of the views. The query command could hang indefinitely in certain situations before this fix. 10 | 11 | -------------------------------------------------------------------------------- /changelog/0.5.6.md: -------------------------------------------------------------------------------- 1 | # Release notes for calabash-android 0.5.6 2 | 3 | **Add:** Support for Crosswalk. Example: `query("cordovawebview css:'*'")` 4 | 5 | **Add:** Support cordova Web Views of custom class name 6 | 7 | **Change:** Show errors in tree (dump) instead of failing 8 | 9 | **Change:** Don't fail JSON parsing on empty beans 10 | 11 | **Change:** Rescue 'awesome print' LoadError in irbrc; don't fail silently 12 | 13 | **Fix:** Backdoor not finding any method to invoke in activities. 14 | 15 | **Fix:** Backddor not accepting null. 16 | 17 | **Add:** Allow somewhat more loose definition for compat with x-platform tests 18 | 19 | **Add:** TCP-requests to local servers -------------------------------------------------------------------------------- /changelog/0.5.7.md: -------------------------------------------------------------------------------- 1 | # Release notes for calabash-android 0.5.7 2 | 3 | **Fix:** Replaced calls to retriable with Retriable.retriable to be forward compatible with retriable >= 1.4.1 and < 2.0. -------------------------------------------------------------------------------- /changelog/0.5.8.md: -------------------------------------------------------------------------------- 1 | # Release notes for calabash-android 0.5.8 2 | 3 | **Fix:** `screenshot_embed` would fail as `embed` was not defined when using `include` to include Calabash. 4 | 5 | **Fix:** Do not depend on ANY retriable version >= 2 6 | 7 | **Fix:** Possible NPE in WebView queries 8 | -------------------------------------------------------------------------------- /changelog/0.5.9.md: -------------------------------------------------------------------------------- 1 | # Release notes for calabash-android 0.5.9 2 | 3 | **Fix**: Crosswalk queries returning wrong coordinates (and gestures thus failing). 4 | 5 | **Fix**: default_device is now persisted across implementers of `Calabash::Android::Operations`. set_default_device was not working when called inside modules or pages. This means that the default device will only be instantiated *once!* If you are relying on the default device being instantiated between features, you might need to reset the default device (set it to nil). 6 | 7 | **Fix**: Remove all rescues of `Exception`. This could cause all sorts of errors, like Timeouts not timing out. 8 | 9 | **Add**: Support for signing with DSA certificates. 10 | 11 | **Add**: Support for indexes in css/xpath queries. Example: `query("WebView css:'button' index:2")` 12 | -------------------------------------------------------------------------------- /changelog/0.6.0.md: -------------------------------------------------------------------------------- 1 | # Release notes for Calabash-Android 0.6.0 2 | 3 | These are the changes introduced in 0.6.0 in comparison to 0.5.15 4 | 5 | **Fix** Android sometimes did not return the correct coordinates of views. This would cause Calabash to regard that view as invisible (as its coordinates were outside the screen). Users experienced a "flakiness" in the calabash queries because of this. The test-server now has a reimplemented version of the Android coordinate method, which fixes this issue. 6 | 7 | **Add** Query optimisation. Users might experience a big performance boost when querying against views. The test-server now analyses the query and optimises accordingly. For example by filtering by visibility after the predicate in `query("* id:'my_id'")`. 8 | 9 | **Change** The test-server now has better parameter recognition. This enables users to invoke methods with `float`, `char` etc. parameter types. 10 | 11 | **Add** `keyboard_visible?` and `wait_for_keyboard` methods. If the device is not using a soft keyboard (hardware or an emulator) these will always return true. 12 | 13 | **Add** Usage tracking. See [this announcement](https://github.com/calabash/calabash-android/issues/655) for details. 14 | 15 | **Change** `enter_text` now waits for the keyboard to be visible. It also always appends text. 16 | 17 | **Add** `set_selection` methods that sets the selection of the currently focused view. 18 | 19 | **Change** The wait default ops are now unfrozen 20 | 21 | **Fix** A lot of small fixes have been made. -------------------------------------------------------------------------------- /changelog/0.7.0.md: -------------------------------------------------------------------------------- 1 | # Release notes for Calabash-Android 0.7.0 2 | 3 | These are the changes introduced in 0.7.0 in comparison to 0.6.0 4 | 5 | **Change** Better dependency detection. Calabash-Android will now look for the Java and Android dependencies in more places and with better versioning. 6 | 7 | **Add** Iframe selectors. Similar to a recently added feature in Calabash-iOS, you can now query for elements inside iframes. 8 | 9 | Example: `query("webview css:'iframe' index:2 css:'#element_in_iframe")` 10 | 11 | Example: `touch("webview css:'iframe' css:'#my_view' {textContent LIKE '*foo*'}"")` 12 | 13 | **Fix** Webviews reporting coordinates that were off. The scale and scrolling of webviews should now be reported correctly. 14 | 15 | **Fix** Parameter recognizion in the test-server. The string "000" etc. are no longer treated as numbers. -------------------------------------------------------------------------------- /changelog/0.7.3.md: -------------------------------------------------------------------------------- 1 | # Release notes for Calabash-Android 0.7.3 2 | 3 | These are the changes introduced in 0.7.3 in comparison to 0.7.0 4 | 5 | **Add** Enable mock locations for installed applications on Android Marshmallow (you cannot set this thourgh a manifest permission in M). 6 | 7 | **Change** Mock all GPS providers on the device. 8 | 9 | **Fix** `evaluate_javascript` not working. 10 | 11 | **Fix** If the webview currently has no body (loading another webpage or transitioning) `query("webview css:'*")` now returns no elements instead of failing. 12 | 13 | **Add** Better exception reporting from evaluated javascript. 14 | -------------------------------------------------------------------------------- /changelog/0.8.0.md: -------------------------------------------------------------------------------- 1 | # Release notes for Calabash-Android 0.8.0 2 | 3 | These are the changes introduced in 0.8.0 in comparison to 0.7.3 4 | 5 | **Notice** The life cycle of the test-server has changed. You should in general always use the test-server that is shipped with Calabash-Android, but no previous test-server is compatible with this version. Run `bundle exec calabash-android build ` to generate a test-server APK for your application. `calabash-android run/console ` does this automatically. 6 | 7 | This release contains a lot of test-server improvements and changes. Not all new test-server features have been exposed in the client yet. 8 | 9 | **Add** ability to start the application with a given intent. This can be used to test other paths to your applications like deeplinks or opening the app from a notification. Example usage: 10 | 11 | ``` 12 | start_test_server_in_background(intent: {action: "android.intent.action.VIEW", data: "http://link", package: "my.app"}) 13 | ``` 14 | 15 | You should use the same intent that Android uses to start you application 16 | 17 | **Add** ability to perform Calabash interactions before starting the actual application. Example usage: 18 | 19 | ``` 20 | # Mock location coordinates before the app is launched 21 | start_test_server_in_background do 22 | set_gps_coordinates(22,22) 23 | end 24 | ``` 25 | 26 | This feature is still experimental. 27 | 28 | **Fix** Android N support is now available. Text entry was broken for N. 29 | 30 | Since Android N is still in beta, Calabash cannot promise to be fully compatible with N. With this release there are no known N issues, please report then on our Github page. 31 | 32 | **Change** The default start intent (main activity or launchable activity) is now detected on the test-server if none is given. 33 | 34 | **Fix** Better dependency detection. Calabash-Android now reports with a better error message if Android tooling is not available. 35 | 36 | **Improve** view detection. Calabash-Android now always aims to report any visible view, also those not rendered in an active dialogue [Example](https://github.com/calabash/calabash-android/blob/25c382c0f7ac2357c9db5192750cb977c4dafe3d/ruby-gem/api/features/querying.feature#L36) 37 | 38 | **Improve** Current activity detection. Previously the current activity might not have been properly detected. 39 | 40 | **Improve** Start-up time (ie `start_test_server_in_background` is quicker) 41 | 42 | **Add** `set_activity_orientation(orientation)` and `get_activity_orientation` methods exposing the action. Added reverse_portrait and reverse_landscape. get_activity_orientation can now report reverse_portrait and reverse_landscape. Notice that these interactions still are not fully equivalent to a user rotating the physical device. 43 | 44 | **Add** Support for latest Crosswalk version 45 | 46 | **Change** Location is now being mocked for only the active providers. If a device does not support GPS locations but supports wifi locations, only the wifi provider will be mocked. 47 | 48 | **Change** Location mocking now uses the default settings of all providers (cost, accuracy, power requirement etc.) -------------------------------------------------------------------------------- /changelog/0.8.1.md: -------------------------------------------------------------------------------- 1 | # Release notes for Calabash-Android 0.8.1 2 | 3 | These are the changes introduced in 0.8.1 in comparison to 0.8.0 4 | 5 | **Fix** WindowManagerService detection when the current Activity is not completely initialized. This would cause queries to fail. Issue #766. 6 | 7 | **Fix** Queries for qualified classes were being cached. This means that if a consecutive query for a specific class was executed before the class was loaded, it would continue to return no results. -------------------------------------------------------------------------------- /changelog/0.8.2.md: -------------------------------------------------------------------------------- 1 | # Release notes for Calabash-Android 0.8.2 2 | 3 | These are the changes introduced in 0.8.2 in comparison to 0.8.1 4 | 5 | **Fix** Some apps take longer than 15 seconds to start-up. The timeout is increased to 60 seconds. -------------------------------------------------------------------------------- /changelog/0.8.3.md: -------------------------------------------------------------------------------- 1 | # Release notes for Calabash-Android 0.8.3 2 | 3 | These are the changes introduced in 0.8.3 in comparison to 0.8.2 4 | 5 | **Fix** Calabash-server not connecting to applications that were blocking their handler (this fixes a regression from 0.7.3) 6 | 7 | **Fix** Entering/clearing text not working on the latest Android system web view. 8 | 9 | **Add** Silence rubyzip invalid date warnings (lastest Android gradle build uses invalid dates) 10 | 11 | **Fix** Web queries for SVG elements misbehaving -------------------------------------------------------------------------------- /changelog/0.8.4.md: -------------------------------------------------------------------------------- 1 | # Release notes for Calabash-Android 0.8.4 2 | 3 | Calabash-Android 0.8.4 is a quickfix to fix a regression in `calabash-android run ` without having run `calabash-android build ` beforehand. 4 | 5 | 6 | ## Release notes for Calabash-Android 0.8.3 7 | 8 | These are the changes introduced in 0.8.3 in comparison to 0.8.2 9 | 10 | **Fix** Calabash-server not connecting to applications that were blocking their handler (this fixes a regression from 0.7.3) 11 | 12 | **Fix** Entering/clearing text not working on the latest Android system web view. 13 | 14 | **Add** Silence rubyzip invalid date warnings (lastest Android gradle build uses invalid dates) 15 | 16 | **Fix** Web queries for SVG elements misbehaving -------------------------------------------------------------------------------- /changelog/0.9.0.md: -------------------------------------------------------------------------------- 1 | # Release notes for Calabash-Android 0.9.0 2 | 3 | These are the changes introduced in 0.9.0 in comparison to 0.8.4 4 | 5 | **Change** Clearing now uses ClearAppData2, which is more identical to reinstalling an application, and only removes accounts belonging to the app under test. 6 | 7 | **Add** Method `ensure_app_installed` which ensures the application and test-server are installed. It does not reinstall if the apps are installed. Use with `clear_app_data` for drastic speed improvements. 8 | 9 | Example: 10 | 11 | ``` 12 | ensure_app_installed 13 | clear_app_data 14 | ``` 15 | 16 | **Fix** Unable to parse ADB output if ADB was not already running (first ADB command) 17 | 18 | **Change** Use SHA1 output of JDK tool for fingerprinting, as some JDK keytools seem not to output MD5 fingerprints. 19 | 20 | **Change** Default skeleton now uses ensure_app_installed/clear_app_data instead of reinstalling. 21 | -------------------------------------------------------------------------------- /deprecated_actions.md: -------------------------------------------------------------------------------- 1 | Deprecation of actions that can be implemented using Ruby API 2 | ============================================================= 3 | 4 | To clean up the API and the test server I plan to remove all the actions that can easily be implemented using the Ruby API. 5 | So far the actions has been very poorly documented and working inconsistently because they have been implemented over time, by different people and started out as a mapping to Robotium methods. 6 | Predefined steps that are using a deprecated action will be re-implemented using the Ruby API. Some predefined steps might be removed during this cleanup. 7 | 8 | I think this will inevitable break backwards compatibility but we should try to make the impact minimal. 9 | 10 | The cleanup will be done in two phases each will bump the minor version. I imagine it will be executed like this: 11 | 12 | * **0.5.x** 13 | 1. A number of actions will be flagged as deprecated and a warning will be printed every time one of these actions are invoked. 14 | 2. All predefined step that use the deprecated actions will be reimplemented using the Ruby API. 15 | 3. Predefined steps that does not "feel right" will be marked as deprecated. Predefined steps are for beginners only and should be easy to use and not support complex interactions or verifications. 16 | 17 | * **0.6.x** 18 | 1. Deprecated actions will be removed. 19 | 2. Deprecated steps will be removed. 20 | 21 | Please comment below if you have any opinion to this plan. -------------------------------------------------------------------------------- /documentation/installation.md: -------------------------------------------------------------------------------- 1 | Installation 2 | ============ 3 | 4 | For an in-depth guide see [the Xamarin docs for Calabash installation](https://developer.xamarin.com/guides/testcloud/calabash/configuring/) 5 | 6 | ### Prerequisites 7 | You need to have Ruby installed. Verify your installation by running ruby -v in a terminal - it should print "ruby 2.0.0" (or higher). We recommend using a managed version of Ruby like rbenv or rvm. 8 | 9 | If you are on Windows you can get Ruby from [RubyInstaller.org](http://rubyinstaller.org/) 10 | 11 | You'll also need to have the Java Development Kit (JDK) installed and available. Calabash will attempt to automatically find this from registry keys on windows, or monodroid config elsewhere, but you can also specify it explicitly by setting the `JAVA_HOME` environment variable to its location (e.g. C:\Program Files\Java\jdk1.8.0_20), or having the JDK binaries themselves (i.e. C:\Program Files\Java\jdk1.8.0_20\bin) in your path. 12 | 13 | You should have the Android SDK installed. You can download it from [here](http://developer.android.com/sdk/index.html). Create an environment variable with the name : `ANDROID_HOME` and its value pointing to the location of the unzipped downloaded SDK. 14 | 15 | To compile Calabash-Android from source, you will also need to have Ant installed and added to your path. It can be downloaded from [here](https://ant.apache.org/bindownload.cgi). 16 | 17 | ### Installation 18 | 19 | We recommend *always* using Bundler to manage your version of Calabash. 20 | 21 | Install `bundler` by running 22 | 23 | - `gem install bundler` 24 | 25 | Create a file called "Gemfile" in the working directory. The Gemfile will contain all your Ruby dependencies. 26 | 27 | As an example: 28 | 29 | ```ruby 30 | # Contents of Gemfile 31 | source "https://rubygems.org" 32 | 33 | gem 'calabash-android' 34 | gem 'cucumber' 35 | ``` 36 | 37 | Install using `bundle install`. Remeber to regularly update your Calabash/Cucumber dependencies by running `bundle update`. 38 | 39 | Run *all* commands by prefixing `bundler exec`, e.g. `bundle exec calabash-android run ...` or `bundle exec calabash-android console`... 40 | 41 | You should *never* install gems with sudo. If you are having issues installing bundler, we recommend using the Calabash Sandbox or using a managed version of Ruby, e.g. rbenv or rvm. 42 | -------------------------------------------------------------------------------- /ruby-gem/.calabash_settings: -------------------------------------------------------------------------------- 1 | {"package_name":"","activity_name":"","app_path":"","api_level":"","keystore_location":"","keystore_password":"","keystore_alias":"","keystore_alias_password":""} 2 | -------------------------------------------------------------------------------- /ruby-gem/.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | #--warnings 3 | #--backtrace 4 | --format documentation 5 | --format RspecJunitFormatter 6 | --out spec/reports/rspec.xml 7 | --require spec_helper 8 | -------------------------------------------------------------------------------- /ruby-gem/.yardopts: -------------------------------------------------------------------------------- 1 | --markup=markdown 2 | --no-private 3 | lib/**/*.rb - LICENSE ENVIRONMENT_VARIABLES.md lib/**/*.md 4 | -------------------------------------------------------------------------------- /ruby-gem/ENVIRONMENT_VARIABLES.md: -------------------------------------------------------------------------------- 1 | ## Calabash Android Environment Variables 2 | 3 | Calabash Android references Unix environment variables to control its runtime behavior. 4 | 5 | ## Conventions 6 | 7 | Paths or values with spaces need double or single quotes. 8 | 9 | #### Example: Quoting values with spaces. 10 | 11 | ``` 12 | APP_PATH="~/path with/a spaces/in it" # Correct! 13 | APP_PATH=~/path with/a spaces/in it # Incorrect. 14 | ``` 15 | 16 | ## Environment Variables 17 | 18 | ### `ADB_DEVICE_ARG` 19 | 20 | #### Example 21 | 22 | ``` 23 | ADB_DEVICE_ARG=4df7ee16Xa083009 24 | ADB_DEVICE_ARG=C4F12B41QB6E89E 25 | ``` 26 | 27 | ### `APP_PATH` 28 | 29 | The path to apk that is being tested. 30 | 31 | Use this variable if your apk is located in a non-default location or your environment requires special configuration (e.g. example a CI environment). 32 | 33 | ### `MAIN_ACTIVITY` 34 | 35 | Calabash Android will automatically try to detect the main activity of 36 | the application. Use this variable to specify an alternative main activity. 37 | 38 | #### Example 39 | 40 | ``` 41 | MAIN_ACTIVITY="com.example.myactivity" calabash-android run example.apk 42 | ``` 43 | 44 | ### `CALABASH_IRBRC` 45 | 46 | Use this variable to load a custom .irbrc when opening calabash-ios console. This is useful if you have multiple calabash projects and want to share an .irbrc across all of them. 47 | 48 | #### .irbrc load order rules 49 | 50 | 1. If `CALABASH_IRBRC` is defined, then that .irbrc is loaded. 51 | 2. If there is a .irbrc in the directory where `console` is called, then that file is loaded. 52 | 3. Otherwise, the defaults scripts/.irbrc is loaded. 53 | 54 | #### Special 55 | 56 | Calling `calabash-ios console` sets the `IRBRC` environment variable. 57 | 58 | #### Example 59 | 60 | ``` 61 | $ CALABASH_IRBRC="~/.irbrc-calabash" calabash-ios console 62 | ``` 63 | 64 | ### `RESET_BETWEEN_SCENARIOS` 65 | 66 | Use this variable to reset your app's data between cucumber Scenarios. 67 | 68 | #### Pro Tip: Reset the app data before certain Scenarios. 69 | 70 | Use a `Before` hook + a `tag` to control when calabash will reset the app data. 71 | 72 | ### `SCREENSHOT_PATH` 73 | 74 | Use this variable to apply a 'prefix' to a screenshot when saving. See the examples. 75 | 76 | #### Note 77 | 78 | The behavior of this variable is subject to change. 79 | 80 | #### Special 81 | 82 | If the the *path* portion of SCREENSHOT_PATH does not exist, `screenshot` will raise an error. 83 | 84 | @see {Calabash::Android::Operations#screenshot} 85 | 86 | #### Example: Specify a prefix 87 | 88 | ``` 89 | SCREENSHOT_PATH=galaxy_s5_ => galaxy_s5_screenshot_0.png 90 | SCREENSHOT_PATH="screenshots/nexus5-" => screenshots/nexus5-screenshot_0.png 91 | ``` 92 | 93 | #### Example: Specify a directory 94 | 95 | ``` 96 | # correct! 97 | SCREENSHOT_PATH=/path/to/a/directory/ => path/to/a/directory/screenshot_0.png 98 | # incorrect :( 99 | SCREENSHOT_PATH=/path/to/a/directory => path/to/a/directoryscreenshot_0.png 100 | ``` 101 | 102 | ### `TEST_APP_PATH` 103 | 104 | Calabash Android will detect the test-server apt based on the checksum of the application and the Calabash Android version. 105 | 106 | Use this variable if your test-server is located in a non-default location or environment requires special configuration (e.g. example a CI environment). 107 | -------------------------------------------------------------------------------- /ruby-gem/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | # Specify your gem's dependencies in calabash-android.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /ruby-gem/Guardfile: -------------------------------------------------------------------------------- 1 | # $ brew install terminal-notifier 2 | notification :terminal_notifier, sticky: false, priority: 0 if `uname` =~ /Darwin/ 3 | logger level: :info 4 | clearing :on 5 | 6 | guard 'bundler' do 7 | watch('Gemfile') 8 | watch(/^.+\.gemspec/) 9 | end 10 | 11 | # NOTE: This Guardfile only watches unit specs. 12 | 13 | options = 14 | { 15 | cmd: 'bundle exec rspec', 16 | spec_paths: ['spec/lib'], 17 | failed_mode: :focus, 18 | all_after_pass: true, 19 | all_on_start: true 20 | } 21 | 22 | guard(:rspec, options) do 23 | watch(%r{^spec/.+_spec\.rb$}) 24 | watch(%r{^lib/calabash-android/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" } 25 | watch('spec/spec_helper.rb') { 'spec/lib' } 26 | end 27 | 28 | -------------------------------------------------------------------------------- /ruby-gem/LICENSE: -------------------------------------------------------------------------------- 1 | calabash-android 2 | Copyright (c) LessPainful. All rights reserved. 3 | The use and distribution terms for this software are covered by the 4 | Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 5 | which can be found in the file epl-v10.html at the root of this distribution. 6 | By using this software in any fashion, you are agreeing to be bound by 7 | the terms of this license. 8 | You must not remove this notice, or any other, from this software. 9 | -------------------------------------------------------------------------------- /ruby-gem/api/.gitignore: -------------------------------------------------------------------------------- 1 | test_servers 2 | .irb-history 3 | !Gemfile.lock 4 | -------------------------------------------------------------------------------- /ruby-gem/api/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'json', '2.3.0' 4 | gem 'xamarin-test-cloud', '~> 2.0' 5 | gem 'cucumber', '~> 2.0.0' 6 | gem 'calabash-android', path: '../' 7 | -------------------------------------------------------------------------------- /ruby-gem/api/Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: .. 3 | specs: 4 | calabash-android (0.9.26) 5 | awesome_print (~> 1.2) 6 | cucumber 7 | escape (~> 0.0.4) 8 | httpclient (>= 2.7.1, < 3.0) 9 | json 10 | rubyzip (= 1.3.0) 11 | slowhandcuke (~> 0.0.3) 12 | 13 | GEM 14 | remote: https://rubygems.org/ 15 | specs: 16 | awesome_print (1.9.2) 17 | builder (3.2.3) 18 | cucumber (2.0.2) 19 | builder (>= 2.1.2) 20 | cucumber-core (~> 1.2.0) 21 | diff-lcs (>= 1.1.3) 22 | gherkin (~> 2.12) 23 | multi_json (>= 1.7.5, < 2.0) 24 | multi_test (>= 0.1.2) 25 | cucumber-core (1.2.0) 26 | gherkin (~> 2.12.0) 27 | diff-lcs (1.3) 28 | escape (0.0.4) 29 | gherkin (2.12.2) 30 | multi_json (~> 1.3) 31 | httpclient (2.8.3) 32 | json (2.3.0) 33 | mime-types (3.2.2) 34 | mime-types-data (~> 3.2015) 35 | mime-types-data (3.2019.0331) 36 | multi_json (1.13.1) 37 | multi_test (0.1.2) 38 | retriable (2.0.2) 39 | rubyzip (1.3.0) 40 | slowhandcuke (0.0.3) 41 | cucumber 42 | thor (0.20.3) 43 | xamarin-test-cloud (2.3.0) 44 | bundler 45 | httpclient (>= 2.7.1, < 3.0) 46 | json 47 | mime-types (>= 2.99, < 4.0) 48 | retriable (>= 1.3.3.1, < 2.1) 49 | rubyzip (~> 1.1) 50 | thor (>= 0.18.1, < 1.0) 51 | 52 | PLATFORMS 53 | ruby 54 | 55 | DEPENDENCIES 56 | calabash-android! 57 | cucumber (~> 2.0.0) 58 | json (= 2.3.0) 59 | xamarin-test-cloud (~> 2.0) 60 | 61 | BUNDLED WITH 62 | 2.3.16 63 | -------------------------------------------------------------------------------- /ruby-gem/api/features/clearing_text.feature: -------------------------------------------------------------------------------- 1 | @keyboard 2 | Feature: Clearing text 3 | 4 | Calabash is capable of entering text in any view that is editable, this 5 | includes both webviews and native views. Calabash simulates a keyboard 6 | and gesture interaction, causing the same app behaviour as a user clearing 7 | the field. 8 | 9 | Scenario: Clearing text in a view 10 | Given an editable view with text in it 11 | When the user asks to clear the text of the view 12 | Then the view is focused by tapping it 13 | And the text is cleared using selection and the keyboard 14 | 15 | Scenario: Entering text into a webview 16 | Given a webview with an editable element with text in it 17 | When the user asks to clear the text of the element 18 | Then the webview element is focused by tapping it 19 | And the text is cleared using selection and the keyboard 20 | -------------------------------------------------------------------------------- /ruby-gem/api/features/entering_text.feature: -------------------------------------------------------------------------------- 1 | @keyboard 2 | Feature: Text entry 3 | 4 | Calabash is capable of entering text into any view that is editable, this 5 | includes both webviews and native views. Calabash simulates a keyboard 6 | interaction, causing the same app behaviour as a user typing. 7 | 8 | https://developer.xamarin.com/guides/testcloud/calabash/calabash-query-syntax/#Entering_text 9 | 10 | Scenario: Entering text into a view 11 | Given an editable view 12 | When the user asks to enter text 13 | Then the view is focused by tapping it 14 | And text is entered using the keyboard 15 | 16 | Scenario: Entering text into a webview 17 | Given a webview with an editable field 18 | When the user asks to enter text 19 | Then the webview element is focused by tapping it 20 | And text is entered using the keyboard 21 | -------------------------------------------------------------------------------- /ruby-gem/api/features/location_mocking.feature: -------------------------------------------------------------------------------- 1 | Feature: Mocking the location of the application 2 | 3 | Calabash is able to mock the location of the application. It will mock all 4 | active providers. These are often GPS and wifi. 5 | 6 | 7 | Scenario Outline: Mocking the location of the device 8 | Given the application is listening for coordinates based on 9 | When Calabash is asked to mock the location to certain coordinates 10 | Then the application will believe the device is current at those coordinates 11 | Examples: 12 | | type | 13 | | GPS | 14 | | wifi | 15 | 16 | 17 | Scenario Outline: Mocking the location of the device twice 18 | Given the application is listening for coordinates based on 19 | When Calabash is asked to mock the location to certain coordinates 20 | Then the application will believe the device is current at those coordinates 21 | When Calabash is asked to mock the location again 22 | Then the application will believe the device is current at the new coordinates 23 | Examples: 24 | | type | 25 | | GPS | 26 | | wifi | -------------------------------------------------------------------------------- /ruby-gem/api/features/querying.feature: -------------------------------------------------------------------------------- 1 | @querying 2 | Feature: Querying 3 | 4 | Calabash is capable of querying for all views rendered by the application 5 | under test. The queries can match for any predicate by invoking a method on 6 | the view. They can match for class names of the native views. They can match 7 | for a certain position in the view hierarchy, i.e. ancestors, parents, 8 | descendants, children, or siblings. It can also match for visibility. 9 | 10 | Scenario: Querying for a native view by id 11 | Given a screen with a view with some id 12 | When Calabash queries for a any view with that id 13 | Then the list of results should contain that element 14 | 15 | Scenario: Querying for a native view by text 16 | Given a screen with a view with some text 17 | When Calabash queries for a any view with that text 18 | Then the list of results should contain that element 19 | 20 | Scenario: Querying for a native view by simple class name 21 | Given a screen with a view of some class 22 | When Calabash queries for any view of that particular class 23 | Then the list of results should contain that element 24 | 25 | Scenario: Querying for a native view by class name using inheritance 26 | Given a screen with a view of some class that inherits from another class 27 | When Calabash queries for any view of the fully qualified parent class 28 | Then the list of results should contain that element 29 | 30 | Scenario: Querying for webview elements using css 31 | Given a webview with an element in it with some html id 32 | When Calabash queries for a any element in the webview with that html id 33 | Then the list of results should contain that element 34 | 35 | Scenario: Querying for elements in a dialogue 36 | Given a dialogue is rendered on screen 37 | When Calabash queries for elements 38 | Then the list of results should contain both elements from the dialogue as well as elements outside the dialogue 39 | 40 | # Calabash searches for visible elements by default 41 | Scenario: Querying for a native view that is invisible without specifying any visibility 42 | Given a screen with a view that is invisible 43 | When Calabash queries for the invisible view 44 | Then the list of results should not contain that element 45 | 46 | Scenario: Querying for a native view that is invisible by specifying any visibility 47 | Given a screen with a view that is invisible 48 | When Calabash queries for the invisible view with the query specifying any visibility 49 | Then the list of results should contain that element 50 | -------------------------------------------------------------------------------- /ruby-gem/api/features/steps/clearing_text.rb: -------------------------------------------------------------------------------- 1 | Given(/^an editable view with text in it$/) do 2 | goto_native_editable_view 3 | 4 | results = query(native_editable_query, setText: "Some sample text") 5 | 6 | if results.length == 0 7 | raise "View for query '#{native_editable_query}' not found" 8 | end 9 | 10 | @type = :native 11 | end 12 | 13 | When(/^the user asks to clear the text of the view$/) do 14 | clear_text_in(native_editable_query) 15 | end 16 | 17 | Then(/^the text is cleared using selection and the keyboard$/) do 18 | if type == :native 19 | result = native_editable_text 20 | elsif type == :webview 21 | result = webview_editable_text 22 | else 23 | raise "Unknown type '#{type}'" 24 | end 25 | 26 | if result != "" 27 | raise "Text was not cleared. Expected '' got '#{result}'" 28 | end 29 | end 30 | 31 | Given(/^a webview with an editable element with text in it$/) do 32 | goto_webview_editable_element 33 | evaluate_javascript("webview", "document.getElementById('inputText').value = 'Some sample text'") 34 | 35 | @type = :webview 36 | end 37 | 38 | When(/^the user asks to clear the text of the element$/) do 39 | clear_text_in(webview_editable_query) 40 | end -------------------------------------------------------------------------------- /ruby-gem/api/features/steps/entering_text.rb: -------------------------------------------------------------------------------- 1 | Given(/^an editable view$/) do 2 | goto_native_editable_view 3 | 4 | @type = :native 5 | end 6 | 7 | When(/^the user asks to enter text$/) do 8 | text_to_enter = 'Some sample text' 9 | 10 | if type == :native 11 | enter_text(native_editable_query, text_to_enter) 12 | elsif type == :webview 13 | enter_text(webview_editable_query, text_to_enter) 14 | else 15 | raise "Unknown type '#{type}'" 16 | end 17 | end 18 | 19 | Then(/^text is entered using the keyboard$/) do 20 | expected_text = 'Some sample text' 21 | 22 | if type == :native 23 | result = native_editable_text 24 | elsif type == :webview 25 | result = webview_editable_text 26 | else 27 | raise "Unknown type '#{type}'" 28 | end 29 | 30 | if result != expected_text 31 | raise "Text was not entered. Expected '#{expected_text}' got '#{result}'" 32 | end 33 | end 34 | 35 | Given(/^a webview with an editable field$/) do 36 | goto_webview_editable_element 37 | 38 | @type = :webview 39 | end -------------------------------------------------------------------------------- /ruby-gem/api/features/steps/location_mocking.rb: -------------------------------------------------------------------------------- 1 | module LocationMocking 2 | EXPECTED_LATITUDE = 22.47 3 | EXPECTED_LONGITUDE = -53.2 4 | EXPECTED_LATITUDE_TWICE = -9.3 5 | EXPECTED_LONGITUDE_TWICE = 10.92 6 | end 7 | 8 | def expect_coordinates(latitude, longitude) 9 | wait_for_element_exists("* id:'latitude' text:'#{latitude}'", 10 | timeout_message: "Latitude was '#{query("* id:'latitude'", :getText).first}'. Expected #{latitude}") 11 | wait_for_element_exists("* id:'longitude' text:'#{longitude}'", 12 | timeout_message: "Latitude was '#{query("* id:'longitude'", :getText).first}'. Expected #{longitude}") 13 | end 14 | 15 | Given(/^the application is listening for coordinates based on (\w+)$/) do |type| 16 | @skip_location = false 17 | 18 | # Cannot mock locations on this particular device 19 | if (ENV["XTC_DEVICE_NAME"] || "").include?("Kindle Fire HD 8.9") 20 | $stdout.puts "Skipping as device is kindle fire HD 8.9. '#{ENV["XTC_DEVICE_NAME"]}'" 21 | @skip_location = true 22 | end 23 | 24 | pan_up_to_see("* id:'buttonGotoLocation'", 5) 25 | touch("* id:'buttonGotoLocation'") 26 | 27 | if type == "GPS" 28 | unless query("* index:10", :getContext, :getPackageManager, hasSystemFeature: ["android.hardware.location.gps"]).first 29 | @skip_location = true 30 | end 31 | 32 | touch("* id:'gps'") 33 | elsif type == "wifi" 34 | unless query("* index:10", :getContext, :getPackageManager, hasSystemFeature: ["android.hardware.location.network"]).first 35 | @skip_location = true 36 | end 37 | 38 | touch("* id:'wifi'") 39 | else 40 | raise "Unknown type '#{type}'" 41 | end 42 | 43 | if @skip_location 44 | $stdout.puts "Test is skipped" 45 | query("android.widget.TextView", setText: ["Skipped"]) 46 | end 47 | end 48 | 49 | When(/^Calabash is asked to mock the location to certain coordinates$/) do 50 | unless @skip_location 51 | set_gps_coordinates(LocationMocking::EXPECTED_LATITUDE, LocationMocking::EXPECTED_LONGITUDE) 52 | end 53 | end 54 | 55 | Then(/^the application will believe the device is current at those coordinates$/) do 56 | unless @skip_location 57 | expect_coordinates(LocationMocking::EXPECTED_LATITUDE, LocationMocking::EXPECTED_LONGITUDE) 58 | end 59 | end 60 | 61 | When(/^Calabash is asked to mock the location again$/) do 62 | unless @skip_location 63 | set_gps_coordinates(LocationMocking::EXPECTED_LATITUDE_TWICE, LocationMocking::EXPECTED_LONGITUDE_TWICE) 64 | end 65 | end 66 | 67 | Then(/^the application will believe the device is current at the new coordinates$/) do 68 | unless @skip_location 69 | expect_coordinates(LocationMocking::EXPECTED_LATITUDE_TWICE, LocationMocking::EXPECTED_LONGITUDE_TWICE) 70 | end 71 | end -------------------------------------------------------------------------------- /ruby-gem/api/features/steps/querying.rb: -------------------------------------------------------------------------------- 1 | Given(/^a screen with a view with some id$/) do 2 | 3 | end 4 | 5 | When(/^Calabash queries for a any view with that id$/) do 6 | pan_up_to_see("* id:'buttonGotoDatePicker'", 5) 7 | @query_results = query("* id:'buttonGotoDatePicker'") 8 | @expect = {'id' => 'buttonGotoDatePicker'} 9 | end 10 | 11 | Then(/^the list of results (should|should not) contain that element$/) do |boolean| 12 | should_match = boolean == 'should' 13 | 14 | @query_results.select{|e| e[@expect.keys.first] == @expect.values.first} 15 | 16 | if should_match 17 | if @query_results.empty? 18 | raise "Element was not in results, expected it to be" 19 | end 20 | else 21 | unless @query_results.empty? 22 | raise "Element was in results, expected it not to be" 23 | end 24 | end 25 | end 26 | 27 | Given(/^a screen with a view that is invisible$/) do 28 | pan_up_to_see("* id:'buttonScrollplicated'", 5) 29 | touch("* id:'buttonScrollplicated'") 30 | wait_for_element_exists("all * id:'twoButton'") 31 | end 32 | 33 | When(/^Calabash queries for the invisible view$/) do 34 | @query_results = query("* id:'twoButton'") 35 | @expect = {'id' => 'twoButton'} 36 | end 37 | 38 | When(/^Calabash queries for the invisible view with the query specifying any visibility$/) do 39 | @query_results = query("all * id:'twoButton'") 40 | @expect = {'id' => 'twoButton'} 41 | end 42 | 43 | Given(/^a screen with a view of some class$/) do 44 | pan_up_to_see("* id:'imageButton'", 5) 45 | end 46 | 47 | When(/^Calabash queries for any view of that particular class$/) do 48 | @query_results = query("ImageButton") 49 | @expect = {'class' => 'android.widget.ImageButton'} 50 | end 51 | 52 | Given(/^a screen with a view of some class that inherits from another class$/) do 53 | pan_up_to_see("* id:'imageButton'", 5) 54 | end 55 | 56 | When(/^Calabash queries for any view of the fully qualified parent class$/) do 57 | @query_results = query("android.widget.ImageView") 58 | @expect = {'class' => 'android.widget.ImageButton'} 59 | end 60 | 61 | Given(/^a screen with a view with some text$/) do 62 | pan_up_to_see("* text:'Directional Swipe Measurer'", 5) 63 | end 64 | 65 | When(/^Calabash queries for a any view with that text$/) do 66 | @query_results = query("* text:'Directional Swipe Measurer'") 67 | @expect = {'text' => 'Directional Swipe Measurer'} 68 | end 69 | 70 | Given(/^a webview with an element in it with some html id$/) do 71 | goto_webview_editable_element 72 | end 73 | 74 | When(/^Calabash queries for a any element in the webview with that html id$/) do 75 | @query_results = query("webview css:'#inputText'") 76 | @expect = {'id' => 'inputText'} 77 | end 78 | 79 | 80 | Then(/^the list of results should contain both elements from the dialogue as well as elements outside the dialogue$/) do 81 | inside = @query_results.find {|e| e['id'] == 'button2'} 82 | outside = @query_results.find {|e| e['id'] == @top_most_button_id} 83 | 84 | unless inside && outside 85 | raise "Both elements from the dialogue as well as elements outside the dialogue were not returned. Inside: #{inside}, outside (#{@top_most_button_id}): #{outside}" 86 | end 87 | end 88 | 89 | When(/^Calabash queries for elements$/) do 90 | @query_results = query("*") 91 | end -------------------------------------------------------------------------------- /ruby-gem/api/features/steps/shared.rb: -------------------------------------------------------------------------------- 1 | def pan_up_to_see(query, tries) 2 | tries.times do |i| 3 | if i == tries-1 4 | raise "Could not find '#{query}' by panning up" 5 | end 6 | 7 | if element_exists(query) 8 | break 9 | end 10 | 11 | pan_up 12 | end 13 | end 14 | 15 | Given(/^a dialogue is rendered on screen$/) do 16 | pan_up_to_see("* id:'imageButton'", 5) 17 | @top_most_button_id = query("button").first[:id] 18 | touch("* id:'imageButton'") 19 | wait_for_element_exists("* id:'button2'") 20 | end 21 | -------------------------------------------------------------------------------- /ruby-gem/api/features/steps/shared_keyboard.rb: -------------------------------------------------------------------------------- 1 | def native_editable_query 2 | "* id:'editTextFirst'" 3 | end 4 | 5 | def webview_editable_query 6 | "webview css:'#inputText'" 7 | end 8 | 9 | def native_editable_text 10 | results = query(native_editable_query, :getText) 11 | 12 | if results.length == 0 13 | raise "View for query '#{native_editable_query}' not found" 14 | end 15 | 16 | results.first 17 | end 18 | 19 | def webview_editable_text 20 | results = evaluate_javascript("webview", "return document.getElementById('inputText').value") 21 | 22 | if results.length == 0 23 | raise "View for query '#{webview_editable_query}' not found" 24 | end 25 | 26 | results.first 27 | end 28 | 29 | def type 30 | @type 31 | end 32 | 33 | def goto_native_editable_view 34 | touch("* id:'buttonGotoViewsSample'") 35 | 36 | pan_up_to_see(native_editable_query, 5) 37 | end 38 | 39 | def goto_webview_editable_element 40 | touch("* id:'buttonGotoWebView'") 41 | wait_for_element_exists(webview_editable_query) 42 | end 43 | 44 | Then(/^the view is focused by tapping it$/) do 45 | # Intentionally left blank 46 | end 47 | 48 | Then(/^the webview element is focused by tapping it$/) do 49 | # Intentionally left blank 50 | end -------------------------------------------------------------------------------- /ruby-gem/api/features/steps/tapping.rb: -------------------------------------------------------------------------------- 1 | Given(/^any visible view$/) do 2 | pan_up_to_see("* id:'buttonGotoOrientations'", 5) 3 | @type = :native 4 | end 5 | 6 | When(/^Calabash is asked to tap it$/) do 7 | if type == :native 8 | touch("* id:'buttonGotoOrientations'") 9 | elsif type == :webview 10 | evaluate_javascript("webview", "document.getElementById('inputButton').addEventListener('click', 11 | function() {document.body.innerHTML = '

CLICKED

'})") 12 | touch("webview css:'#inputButton'") 13 | else 14 | raise "Unknown type '#{type}'" 15 | end 16 | end 17 | 18 | Then(/^it will perform a tap gesture on the coordinates of the view$/) do 19 | wait_for_element_exists("* id:'buttonGotoPortraitActivity'") 20 | end 21 | 22 | Given(/^any visible webview element$/) do 23 | goto_webview_editable_element 24 | @type = :webview 25 | end 26 | 27 | Then(/^it will perform a tap gesture on the coordinates of the element$/) do 28 | wait_for_element_exists("webview css:'*' {textContent LIKE 'CLICKED'}") 29 | end 30 | 31 | When(/^Calabash is asked to tap an element in the dialogue$/) do 32 | touch("* id:'button1'") 33 | end 34 | 35 | Then(/^it will perform a tap gesture on the coordinates of the view in the dialogue$/) do 36 | wait_for_element_does_not_exist("* id:'button1'") 37 | end -------------------------------------------------------------------------------- /ruby-gem/api/features/support/apps/general.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calabash/calabash-android/4ff3f08420264e71b6f0cf1db845327d7672c213/ruby-gem/api/features/support/apps/general.apk -------------------------------------------------------------------------------- /ruby-gem/api/features/support/env.rb: -------------------------------------------------------------------------------- 1 | require 'calabash-android/operations' 2 | 3 | World(Calabash::Android::Operations) -------------------------------------------------------------------------------- /ruby-gem/api/features/support/hooks.rb: -------------------------------------------------------------------------------- 1 | $_calabash_installed_app = false 2 | 3 | def go_back_to_see(query, tries) 4 | tries.times do |i| 5 | if i == tries-1 6 | raise "Could not find '#{query}' by going back" 7 | end 8 | 9 | if element_exists(query) 10 | break 11 | end 12 | 13 | sleep 0.1 14 | press_back_button 15 | end 16 | end 17 | 18 | Before do 19 | unless $_calabash_installed_app 20 | reinstall_apps 21 | $_calabash_installed_app = true 22 | end 23 | 24 | start_test_server_in_background 25 | end 26 | -------------------------------------------------------------------------------- /ruby-gem/api/features/tapping.feature: -------------------------------------------------------------------------------- 1 | @gesture 2 | Feature: Tapping 3 | 4 | Calabash is capable of tapping any visible native view and webview element. 5 | It simulates a user gesture based on the coordinates returned by the query. 6 | 7 | Scenario: Tapping on a native view 8 | Given any visible view 9 | When Calabash is asked to tap it 10 | Then it will perform a tap gesture on the coordinates of the view 11 | 12 | Scenario: Tapping on a webview element 13 | Given any visible webview element 14 | When Calabash is asked to tap it 15 | Then it will perform a tap gesture on the coordinates of the element 16 | 17 | Scenario: Tapping elements in a dialogue 18 | Given a dialogue is rendered on screen 19 | When Calabash is asked to tap an element in the dialogue 20 | Then it will perform a tap gesture on the coordinates of the view in the dialogue -------------------------------------------------------------------------------- /ruby-gem/bin/calabash-android-build.rb: -------------------------------------------------------------------------------- 1 | def calabash_build(app) 2 | apk_fingerprint = fingerprint_from_apk(app) 3 | calabash_log "#{app} was signed with a certificate with fingerprint #{apk_fingerprint}" 4 | 5 | keystores = JavaKeystore.get_keystores 6 | if keystores.empty? 7 | puts "No keystores found." 8 | puts "Please create one or run calabash-android setup to configure calabash-android to use an existing keystore." 9 | exit 1 10 | end 11 | keystore = keystores.find { |k| k.fingerprint == apk_fingerprint} 12 | 13 | unless keystore 14 | puts "#{app} is not signed with any of the available keystores." 15 | puts "Tried the following keystores:" 16 | keystores.each do |k| 17 | puts k.location 18 | end 19 | puts "" 20 | puts "You can resign the app with #{keystores.first.location} by running: 21 | calabash-android resign #{app}" 22 | 23 | puts "" 24 | puts "Notice that resigning an app might break some functionality." 25 | puts "Getting a copy of the certificate used when the app was built will in general be more reliable." 26 | 27 | exit 1 28 | end 29 | 30 | test_server_file_name = test_server_path(app) 31 | FileUtils.mkdir_p File.dirname(test_server_file_name) unless File.exist? File.dirname(test_server_file_name) 32 | 33 | unsigned_test_apk = File.join(File.dirname(__FILE__), '..', 'lib/calabash-android/lib/TestServer.apk') 34 | test_server_manifest = File.join(File.dirname(__FILE__), '..', 'lib', 'calabash-android', 'lib', 'AndroidManifest.xml') 35 | 36 | Dir.mktmpdir do |workspace_dir| 37 | Dir.chdir(workspace_dir) do 38 | FileUtils.cp(unsigned_test_apk, "TestServer.apk") 39 | FileUtils.cp(test_server_manifest, "AndroidManifest.xml") 40 | 41 | unless system %Q{"#{RbConfig.ruby}" -pi.bak -e "gsub(/#targetPackage#/, '#{package_name(app)}')" AndroidManifest.xml} 42 | raise "Could not replace package name in manifest" 43 | end 44 | 45 | unless system %Q{"#{RbConfig.ruby}" -pi.bak -e "gsub(/#testPackage#/, '#{package_name(app)}.test')" AndroidManifest.xml} 46 | raise "Could not replace test package name in manifest" 47 | end 48 | 49 | unless system %Q{"#{Calabash::Android::Dependencies.aapt_path}" package -M AndroidManifest.xml -I "#{Calabash::Android::Dependencies.android_jar_path}" -F dummy.apk} 50 | raise "Could not create dummy.apk" 51 | end 52 | 53 | Calabash::Utils.with_silent_zip do 54 | Zip::File.new("dummy.apk").extract("AndroidManifest.xml","customAndroidManifest.xml") 55 | Zip::File.open("TestServer.apk") do |zip_file| 56 | begin 57 | check_file("AndroidManifest.xml") 58 | manifest_exists = true 59 | rescue 60 | manifest_exists = false 61 | end 62 | 63 | if manifest_exists 64 | zip_file.remove("AndroidManifest.xml") 65 | end 66 | 67 | zip_file.add("AndroidManifest.xml", "customAndroidManifest.xml") 68 | end 69 | end 70 | end 71 | keystore.sign_apk("#{workspace_dir}/TestServer.apk", test_server_file_name) 72 | begin 73 | 74 | rescue => e 75 | calabash_log e 76 | raise "Could not sign test server" 77 | end 78 | end 79 | puts "Done signing the test server. Moved it to #{test_server_file_name}" 80 | end 81 | -------------------------------------------------------------------------------- /ruby-gem/bin/calabash-android-console.rb: -------------------------------------------------------------------------------- 1 | def calabash_console(app_path = nil) 2 | test_server_path = test_server_path(app_path) 3 | 4 | 5 | path = ENV['CALABASH_IRBRC'] 6 | unless path 7 | if File.exist?('.irbrc') 8 | path = File.expand_path('.irbrc') 9 | end 10 | end 11 | 12 | unless path 13 | path = File.expand_path(File.join(File.dirname(__FILE__), '..', 'irbrc')) 14 | end 15 | 16 | ENV['IRBRC'] = path 17 | 18 | unless ENV['APP_PATH'] 19 | ENV['APP_PATH'] = app_path 20 | end 21 | 22 | unless ENV['TEST_APP_PATH'] 23 | ENV['TEST_APP_PATH'] = test_server_path 24 | end 25 | 26 | build_test_server_if_needed(app_path) 27 | 28 | puts 'Starting calabash-android console...' 29 | puts "Loading #{ENV['IRBRC']}" 30 | puts 'Running irb...' 31 | exec('irb') 32 | 33 | end -------------------------------------------------------------------------------- /ruby-gem/bin/calabash-android-generate.rb: -------------------------------------------------------------------------------- 1 | 2 | def calabash_scaffold 3 | if File.exists?(@features_dir) 4 | puts "A features directory already exists. Stopping..." 5 | exit 1 6 | end 7 | msg("Question") do 8 | puts "I'm about to create a subdirectory called features." 9 | puts "features will contain all your calabash tests." 10 | puts "Please hit return to confirm that's what you want." 11 | end 12 | exit 2 unless STDIN.gets.chomp == '' 13 | 14 | FileUtils.cp_r(@source_dir, @features_dir) 15 | 16 | msg("Info") do 17 | puts "features subdirectory created. \n" 18 | end 19 | 20 | end 21 | -------------------------------------------------------------------------------- /ruby-gem/bin/calabash-android-helpers.rb: -------------------------------------------------------------------------------- 1 | require 'tempfile' 2 | require 'json' 3 | require "rubygems" 4 | 5 | 6 | def msg(title, &block) 7 | puts "\n" + "-"*10 + title + "-"*10 8 | block.call 9 | puts "-"*10 + "-------" + "-"*10 + "\n" 10 | end 11 | 12 | def print_usage 13 | puts < [parameters] [options] 15 | can be one of 16 | help 17 | prints more detailed help information. 18 | gen 19 | generate a features folder structure. 20 | setup 21 | sets up a non-default keystore to use with this test project. 22 | resign 23 | resigns the app with the currently configured keystore. 24 | build 25 | builds the test server that will be used when testing the app. 26 | run 27 | runs Cucumber in the current folder with the environment needed. 28 | version 29 | prints the gem version 30 | 31 | can be 32 | -v, --verbose 33 | Turns on verbose logging 34 | EOF 35 | end 36 | 37 | def print_help 38 | print_usage 39 | end 40 | 41 | def is_json?(str) 42 | str[0..0] == '{' 43 | end 44 | -------------------------------------------------------------------------------- /ruby-gem/bin/calabash-android-run.rb: -------------------------------------------------------------------------------- 1 | def calabash_run(app_path = nil) 2 | 3 | old_runner = "android.test.InstrumentationTestRunner" 4 | new_rummer = "sh.calaba.instrumentationbackend.CalabashInstrumentationTestRunner" 5 | f = "features/support/app_life_cycle_hooks.rb" 6 | 7 | if File.exist?(f) and IO.read(f).include? old_runner 8 | puts "Calabash has been updated" 9 | puts "Please do the following to update your project:" 10 | puts "1) Open #{f} in a text editor" 11 | puts "2) Replace #{old_runner} with #{new_rummer}" 12 | exit 1 13 | end 14 | 15 | if app_path 16 | build_test_server_if_needed(app_path) 17 | 18 | test_server_path = test_server_path(app_path) 19 | 20 | env = "APP_PATH=\"#{app_path}\" TEST_APP_PATH=\"#{test_server_path}\"" 21 | 22 | if ENV['MAIN_ACTIVITY'] 23 | env = "#{env} MAIN_ACTIVITY=#{ENV['MAIN_ACTIVITY']}" 24 | end 25 | else 26 | env = "" 27 | end 28 | 29 | STDOUT.sync = true 30 | arguments = ARGV - ["--no-build"] 31 | cmd = "\"#{RbConfig.ruby}\" -S cucumber #{arguments.join(" ")} #{env}" 32 | calabash_log cmd 33 | exit_code = system(cmd) 34 | 35 | sleep(1) 36 | exit_code 37 | end -------------------------------------------------------------------------------- /ruby-gem/bin/calabash-android-setup.rb: -------------------------------------------------------------------------------- 1 | require "calabash-android/version" 2 | require "io/console" 3 | 4 | def calabash_setup 5 | @settings = {} 6 | 7 | puts "Please enter keystore information to use a custom keystore instead of the default" 8 | 9 | ask_for_setting(:keystore_location, "Please enter keystore location") 10 | ask_for_setting(:keystore_password, "Please enter the password for the keystore", true) 11 | ask_for_setting(:keystore_alias, "Please enter the alias") 12 | 13 | open('.calabash_settings', 'w') do |f| 14 | f.puts @settings.to_json 15 | end 16 | puts "Saved your settings to .calabash_settings. You can edit the settings manually or run this setup script again" 17 | end 18 | 19 | def ask_for_setting(key, msg, secure = false) 20 | puts msg 21 | @settings[key] = (!secure ? STDIN.gets : STDIN.noecho(&:gets)).chomp 22 | end 23 | -------------------------------------------------------------------------------- /ruby-gem/calabash-android.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | Gem::Specification.new do |s| 4 | s.name = "calabash-android" 5 | s.version = begin 6 | file = "#{File.expand_path(File.join(File.dirname(__FILE__), 7 | "lib", "calabash-android", 8 | "version.rb"))}" 9 | m = Module.new 10 | m.module_eval IO.read(file).force_encoding("utf-8") 11 | version = m::Calabash::Android::VERSION 12 | unless /(\d+\.\d+\.\d+(\.pre\d+)?)/.match(version) 13 | raise %Q{ 14 | Could not parse constant Calabash::Android::VERSION: '#{version}' 15 | into a valid version, e.g. 1.2.3 or 1.2.3.pre10 16 | } 17 | end 18 | version 19 | end 20 | s.platform = Gem::Platform::RUBY 21 | s.license = "EPL-1.0" 22 | s.authors = ["Jonas Maturana Larsen"] 23 | s.email = ["jonas@lesspainful.com"] 24 | s.homepage = "http://github.com/calabash" 25 | s.summary = %q{Client for calabash-android for automated functional testing on Android} 26 | s.description = %q{calabash-android drives tests for native and hybrid Android apps. } 27 | s.executables = "calabash-android" 28 | s.require_paths = ["lib"] 29 | s.files = lambda do 30 | # This should be in lib/calabash-android somewhere 31 | ["irbrc"] + 32 | Dir.glob("bin/**/*.rb") + ["bin/calabash-android"] + 33 | Dir.glob('lib/**/*.rb') + 34 | ["lib/calabash-android/deprecated_actions.map", 35 | "lib/calabash-android/removed_actions.txt"] + 36 | Dir.glob("test-server/calabash-js/src/*.js") + 37 | Dir.glob("lib/**/*.jar") + 38 | Dir.glob("features-skeleton/**/*.*") + 39 | ["epl-v10.html", "LICENSE"] + 40 | ["lib/calabash-android/lib/TestServer.apk", 41 | "lib/calabash-android/lib/AndroidManifest.xml"] 42 | end.call 43 | 44 | s.add_dependency( 'json' ) 45 | s.add_dependency( 'cucumber' ) 46 | s.add_dependency( "slowhandcuke", '~> 0.0.3') 47 | s.add_dependency( "rubyzip", "1.3.0") 48 | s.add_dependency( "awesome_print", '~> 1.2') 49 | s.add_dependency( 'httpclient', '>= 2.7.1', '< 3.0') 50 | s.add_dependency( 'escape', '~> 0.0.4') 51 | 52 | s.add_development_dependency( 'rake', '13.0.3' ) 53 | s.add_development_dependency( 'yard', '>= 0.9.12', '< 1.0' ) 54 | puts RUBY_PLATFORM 55 | if RUBY_PLATFORM[/darwin/] || RUBY_PLATFORM["linux"] 56 | s.add_development_dependency( 'redcarpet', '~> 3.1' ) 57 | end 58 | s.add_development_dependency( "rspec_junit_formatter" ) 59 | s.add_development_dependency( "rspec", "~> 3.0" ) 60 | s.add_development_dependency( "pry" ) 61 | s.add_development_dependency( "pry-nav" ) 62 | s.add_development_dependency( "guard-rspec" ) 63 | s.add_development_dependency( "guard-bundler" ) 64 | # Pin to 3.0.6; >= 3.1.0 requires ruby 2.2. This is guard dependency. 65 | s.add_development_dependency("listen", "3.0.6") 66 | s.add_development_dependency( "growl" ) 67 | s.add_development_dependency( "stub_env" ) 68 | end 69 | -------------------------------------------------------------------------------- /ruby-gem/features-skeleton/my_first.feature: -------------------------------------------------------------------------------- 1 | Feature: Login feature 2 | 3 | Scenario: As a valid user I can log into my app 4 | When I press "Login" 5 | Then I see "Welcome to coolest app ever" 6 | -------------------------------------------------------------------------------- /ruby-gem/features-skeleton/step_definitions/calabash_steps.rb: -------------------------------------------------------------------------------- 1 | require 'calabash-android/calabash_steps' -------------------------------------------------------------------------------- /ruby-gem/features-skeleton/support/app_installation_hooks.rb: -------------------------------------------------------------------------------- 1 | require 'calabash-android/management/app_installation' 2 | 3 | AfterConfiguration do |config| 4 | FeatureMemory.feature = nil 5 | end 6 | 7 | Before do |scenario| 8 | scenario = scenario.scenario_outline if scenario.respond_to?(:scenario_outline) 9 | 10 | feature = scenario.feature 11 | if FeatureMemory.feature != feature || ENV['RESET_BETWEEN_SCENARIOS'] == '1' 12 | if ENV['RESET_BETWEEN_SCENARIOS'] == '1' 13 | calabash_log 'New scenario - reinstalling apps' 14 | else 15 | calabash_log 'First scenario in feature - reinstalling apps' 16 | end 17 | 18 | ensure_app_installed 19 | clear_app_data 20 | FeatureMemory.feature = feature 21 | FeatureMemory.invocation = 1 22 | else 23 | FeatureMemory.invocation += 1 24 | end 25 | end 26 | 27 | FeatureMemory = Struct.new(:feature, :invocation).new 28 | -------------------------------------------------------------------------------- /ruby-gem/features-skeleton/support/app_life_cycle_hooks.rb: -------------------------------------------------------------------------------- 1 | require 'calabash-android/management/adb' 2 | require 'calabash-android/operations' 3 | 4 | Before do |scenario| 5 | start_test_server_in_background 6 | end 7 | 8 | After do |scenario| 9 | if scenario.failed? 10 | screenshot_embed 11 | end 12 | shutdown_test_server 13 | end 14 | -------------------------------------------------------------------------------- /ruby-gem/features-skeleton/support/env.rb: -------------------------------------------------------------------------------- 1 | require 'calabash-android/cucumber' 2 | -------------------------------------------------------------------------------- /ruby-gem/features-skeleton/support/hooks.rb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calabash/calabash-android/4ff3f08420264e71b6f0cf1db845327d7672c213/ruby-gem/features-skeleton/support/hooks.rb -------------------------------------------------------------------------------- /ruby-gem/integration-tests/.gitignore: -------------------------------------------------------------------------------- 1 | # macOS 2 | .DS_STORE 3 | 4 | # emacs and vim 5 | (.*/)?\#[^/]*\#$ 6 | tags 7 | 8 | test_servers 9 | *.png 10 | !NativeTestApp/**/*.png 11 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/.irb-history: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calabash/calabash-android/4ff3f08420264e71b6f0cf1db845327d7672c213/ruby-gem/integration-tests/.irb-history -------------------------------------------------------------------------------- /ruby-gem/integration-tests/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem "calabash-android", path: "../" 4 | gem "xamarin-test-cloud", "~> 2.3" 5 | gem "pry" 6 | gem "pry-nav" 7 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | defaultConfig { 6 | minSdkVersion 8 7 | //noinspection ExpiredTargetSdkVersion 8 | targetSdkVersion 23 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | 14 | lintOptions { 15 | checkReleaseBuilds false 16 | } 17 | 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | 25 | applicationVariants.all { variant -> 26 | variant.outputs.all { 27 | outputFileName = "NativeTestApp.apk" 28 | } 29 | } 30 | 31 | defaultConfig { 32 | vectorDrawables.useSupportLibrary = true 33 | } 34 | 35 | } 36 | 37 | dependencies { 38 | implementation fileTree(dir: 'libs', include: ['*.jar']) 39 | implementation 'net.java.dev.jna:jna:4.5.1@aar' 40 | implementation 'com.android.support:appcompat-v7:23.4.0' 41 | implementation 'com.android.support:recyclerview-v7:23.4.0' 42 | } 43 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/assets/web_view.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Webview test project 5 | 25 | 45 | 46 | 47 |
48 |
49 |
50 |
51 | 52 | 53 |
54 |
55 |
56 | <RESULT> 57 |
58 |
59 | 60 | 61 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/assets/web_view_multiscroll.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 |
This is first line
11 |
This is line 2
12 |
This is line 3
13 |
This is line 4
14 |
This is line 5
15 |
This is line 6
16 |
This is line 7
17 |
This is line 8
18 |
This is line 9
19 |
This is line 10
20 |
This is line 11
21 |
This is line 12
22 |
This is line 13
23 |
This is line 14
24 |
This is line 15
25 |
This is line 16
26 |
This is line 17
27 |
This is line 18
28 |
This is line 19
29 |
This last line
30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/assets/web_view_scroll.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 |
This is first line
11 |
12 |
This is line 2
13 |
far right
14 |
15 |
This is line 3
16 |
This is line 4
17 |
This is line 5
18 |
This is line 6
19 |
This is line 7
20 |
This is line 8
21 |
This is line 9
22 |
This is line 10
23 |
This is line 11
24 |
This is line 12
25 |
This is line 13
26 |
This is line 14
27 |
This is line 15
28 |
This is line 16
29 |
This is line 17
30 |
This is line 18
31 |
This is line 19
32 |
This last line
33 |
34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/DatePickerActivity.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | import android.widget.Button; 8 | import android.widget.DatePicker; 9 | import android.widget.TimePicker; 10 | 11 | public class DatePickerActivity extends Activity { 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState){ 14 | super.onCreate(savedInstanceState); 15 | setContentView(R.layout.date_picker_sample); 16 | DatePicker datePicker = (DatePicker)this.findViewById(R.id.datePicker); 17 | datePicker.init(Settings.pickedDate.getYear() + 1900, Settings.pickedDate.getMonth(), Settings.pickedDate.getDay(), null); 18 | 19 | TimePicker timePicker = (TimePicker)this.findViewById(R.id.timePicker); 20 | timePicker.setCurrentHour(Settings.pickedDate.getHours()); 21 | timePicker.setCurrentMinute(Settings.pickedDate.getMinutes()); 22 | } 23 | 24 | /* View action functions */ 25 | public void onButtonClick(View view) { 26 | assert view.getClass().isInstance(Button.class); 27 | 28 | Button button = (Button)view; 29 | 30 | switch(button.getId()) { 31 | case R.id.buttonCancel: 32 | finish(); 33 | break; 34 | 35 | case R.id.buttonSave: 36 | DatePicker datePicker = (DatePicker)this.findViewById(R.id.datePicker); 37 | TimePicker timePicker = (TimePicker)this.findViewById(R.id.timePicker); 38 | Settings.pickedDate.setYear(datePicker.getYear() - 1900); 39 | Settings.pickedDate.setMonth(datePicker.getMonth()); 40 | Settings.pickedDate.setDate(datePicker.getDayOfMonth()); 41 | Settings.pickedDate.setHours(timePicker.getCurrentHour()); 42 | Settings.pickedDate.setMinutes(timePicker.getCurrentMinute()); 43 | Settings.pickedDate.setSeconds(0); 44 | finish(); 45 | break; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/DirectionalSwipeActivity.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample; 2 | 3 | import android.os.Bundle; 4 | import android.app.Activity; 5 | import android.view.GestureDetector; 6 | import android.view.GestureDetector.SimpleOnGestureListener; 7 | import android.view.MotionEvent; 8 | import android.view.View; 9 | import android.widget.TextView; 10 | 11 | public class DirectionalSwipeActivity extends Activity { 12 | private GestureDetector gestureDetector; 13 | View.OnTouchListener gestureListener; 14 | 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(R.layout.directional_swipe_sample); 19 | 20 | this.gestureDetector = new GestureDetector(this, new GestureListener()); 21 | 22 | this.gestureListener = new View.OnTouchListener() { 23 | public boolean onTouch(View v, MotionEvent event) { 24 | return gestureDetector.onTouchEvent(event); 25 | } 26 | }; 27 | 28 | this.findViewById(R.id.relativeLayout).setOnTouchListener(this.gestureListener); 29 | } 30 | 31 | public void onSwipe(String message) { 32 | TextView textView = (TextView)this.findViewById(R.id.textViewHeader); 33 | textView.setText(message); 34 | } 35 | 36 | private class GestureListener extends SimpleOnGestureListener { 37 | @Override 38 | public boolean onDown(MotionEvent e) { 39 | return true; 40 | } 41 | 42 | @Override 43 | public boolean onFling(MotionEvent motionEventA, MotionEvent motionEventB, float vX, float vY) { 44 | boolean directionRight = (motionEventA.getX() < motionEventB.getX()); 45 | boolean directionDown = (motionEventA.getY() < motionEventB.getY()); 46 | 47 | float deltaX = Math.abs(motionEventB.getX() - motionEventA.getX()); 48 | float deltaY = Math.abs(motionEventB.getY() - motionEventA.getY()); 49 | 50 | float speedX = Math.abs(vX); 51 | float speedY = Math.abs(vY); 52 | 53 | boolean horizontal = (deltaX > deltaY); 54 | 55 | if ((horizontal && (speedX < 200 || deltaX < 100)) || (!horizontal && (speedY < 200 || deltaY < 100))) { 56 | return false; 57 | } 58 | 59 | String output = ""; 60 | 61 | if (horizontal) { 62 | if (directionRight) { 63 | output = "Right Swipe"; 64 | } else { 65 | output = "Left Swipe"; 66 | } 67 | } else { 68 | if (directionDown) { 69 | output = "Down Swipe"; 70 | } else { 71 | output = "Up Swipe"; 72 | } 73 | } 74 | 75 | DirectionalSwipeActivity.this.onSwipe(output); 76 | 77 | return true; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/DragAndDropActivity.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample; 2 | 3 | import android.graphics.Color; 4 | import android.graphics.Rect; 5 | import android.os.Bundle; 6 | import android.app.Activity; 7 | import android.widget.*; 8 | import android.view.*; 9 | 10 | public class DragAndDropActivity extends Activity implements View.OnTouchListener { 11 | RelativeLayout dragAndDropActivity; 12 | ImageView redImageView; 13 | TextView targetTextView; 14 | 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(R.layout.activity_drag_and_drop); 19 | 20 | dragAndDropActivity = (RelativeLayout)findViewById(R.id.dragAndDropActivity); 21 | dragAndDropActivity.setOnTouchListener(this); 22 | 23 | redImageView = (ImageView) findViewById(R.id.redImageView); 24 | redImageView.setOnTouchListener(this); 25 | 26 | targetTextView = (TextView)findViewById(R.id.targetTextView); 27 | } 28 | 29 | private boolean dragging = false; 30 | private Rect hitRect = new Rect(); 31 | 32 | @Override 33 | public boolean onTouch(View v, MotionEvent event) { 34 | boolean eventConsumed = true; 35 | int x = (int)event.getX(); 36 | int y = (int)event.getY(); 37 | 38 | int action = event.getAction(); 39 | if (action == MotionEvent.ACTION_DOWN) { 40 | if (v == redImageView) { 41 | dragging = true; 42 | eventConsumed = false; 43 | } 44 | } else if (action == MotionEvent.ACTION_UP) { 45 | if (dragging) { 46 | targetTextView.getHitRect(hitRect); 47 | if (hitRect.contains(x, y)) { 48 | targetTextView.setBackgroundColor(Color.parseColor("#FFAB3933")); 49 | targetTextView.setText("red"); 50 | } 51 | setAbsoluteLocation(redImageView, 0, 0); 52 | } 53 | dragging = false; 54 | eventConsumed = false; 55 | } else if (action == MotionEvent.ACTION_MOVE) { 56 | if (v != redImageView) { 57 | if (dragging) { 58 | setAbsoluteLocationCentered(redImageView, x, y); 59 | } 60 | } 61 | } 62 | 63 | return eventConsumed; 64 | } 65 | 66 | private void setAbsoluteLocationCentered(View v, int x, int y) { 67 | setAbsoluteLocation(v, x - v.getWidth() / 2, y - v.getHeight() / 2); 68 | } 69 | 70 | private void setAbsoluteLocation(View v, int x, int y) { 71 | RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams)v.getLayoutParams(); 72 | layoutParams.leftMargin = x; 73 | layoutParams.topMargin = y; 74 | v.setLayoutParams(layoutParams); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/HorizontalScrollActivity.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample; 2 | 3 | import android.support.v7.app.ActionBarActivity; 4 | import android.os.Bundle; 5 | import android.view.Display; 6 | import android.view.Menu; 7 | import android.view.MenuItem; 8 | import android.widget.AbsoluteLayout; 9 | import android.widget.Button; 10 | import android.widget.FrameLayout; 11 | 12 | 13 | public class HorizontalScrollActivity extends ActionBarActivity { 14 | 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(R.layout.activity_horizontal_scroll); 19 | 20 | Display display = getWindowManager().getDefaultDisplay(); 21 | 22 | AbsoluteLayout absoluteLayout = (AbsoluteLayout) findViewById(R.id.horizontalScrollAbs); 23 | Button start = (Button) findViewById(R.id.buttonStart); 24 | Button center = (Button) findViewById(R.id.buttonCenter); 25 | Button end = (Button) findViewById(R.id.buttonEnd); 26 | 27 | FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) absoluteLayout.getLayoutParams(); 28 | lp.width = display.getWidth() * 2 + 100; 29 | changeX(display.getWidth(), 0, start); 30 | changeX(display.getWidth(), 1, center); 31 | changeX(display.getWidth(), 2, end); 32 | absoluteLayout.requestLayout(); 33 | } 34 | 35 | private void changeX(int width, int i, Button button) { 36 | AbsoluteLayout.LayoutParams lp = (AbsoluteLayout.LayoutParams) button.getLayoutParams(); 37 | lp.x = i * width; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/ListViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample; 2 | 3 | import android.app.Activity; 4 | import android.app.ListActivity; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.util.TypedValue; 8 | import android.view.Display; 9 | import android.widget.ListAdapter; 10 | import android.widget.SimpleAdapter; 11 | 12 | import java.util.ArrayList; 13 | import java.util.HashMap; 14 | import java.util.List; 15 | import java.util.Map; 16 | 17 | public class ListViewActivity extends ListActivity { 18 | 19 | private static List> createData(int normalItems) { 20 | ArrayList> data = new ArrayList>(); 21 | 22 | for(int i = 0; i < normalItems; i++) { 23 | String value = "Item " + i; 24 | Map element = new HashMap(); 25 | element.put("key", value); 26 | data.add(element); 27 | } 28 | Map lastElement = new HashMap(); 29 | lastElement.put("key", "TheEnd"); 30 | data.add(lastElement); 31 | return data; 32 | } 33 | 34 | private static List> getScreenFullPlusListData(Activity activity, int screens) { 35 | Display display = activity.getWindowManager().getDefaultDisplay(); 36 | float height = display.getHeight(); 37 | 38 | float listItemHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 64, activity.getResources().getDisplayMetrics()); 39 | return createData(screens * (int) ((height/listItemHeight) + 4)); 40 | } 41 | 42 | @Override 43 | protected void onCreate(Bundle savedInstanceState) { 44 | super.onCreate(savedInstanceState); 45 | 46 | Intent intent = getIntent(); 47 | int screens = intent.getIntExtra(MainActivity.SCREENS, 1); 48 | 49 | ListAdapter adapter = new SimpleAdapter(this, getScreenFullPlusListData(this, screens), android.R.layout.simple_list_item_1, new String[] {"key"}, new int[] {android.R.id.text1}); 50 | setListAdapter(adapter); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/LocationActivity.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.location.Location; 6 | import android.location.LocationManager; 7 | import android.os.Bundle; 8 | import android.view.View; 9 | import android.widget.TextView; 10 | 11 | import java.util.concurrent.atomic.AtomicReference; 12 | 13 | 14 | public class LocationActivity extends Activity { 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(R.layout.location_activity); 19 | 20 | // Acquire a reference to the system Location Manager 21 | final LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE); 22 | 23 | final AtomicReference provider = new AtomicReference(); 24 | 25 | new Thread(new Runnable() { 26 | @Override 27 | public void run() { 28 | while (true) { 29 | String providerValue = provider.get(); 30 | 31 | if (providerValue == null) { 32 | continue; 33 | } 34 | 35 | onLocationChanged(locationManager.getLastKnownLocation(providerValue)); 36 | 37 | try { 38 | Thread.sleep(1000); 39 | } catch (InterruptedException e) { 40 | e.printStackTrace(); 41 | } 42 | } 43 | 44 | } 45 | }).start(); 46 | 47 | findViewById(R.id.wifi).setOnClickListener(new View.OnClickListener() { 48 | @Override 49 | public void onClick(View view) { 50 | provider.set(LocationManager.NETWORK_PROVIDER); 51 | } 52 | }); 53 | 54 | findViewById(R.id.gps).setOnClickListener(new View.OnClickListener() { 55 | @Override 56 | public void onClick(View view) { 57 | provider.set(LocationManager.GPS_PROVIDER); 58 | } 59 | }); 60 | 61 | 62 | } 63 | 64 | 65 | public void onLocationChanged(final Location location) { 66 | runOnUiThread(new Runnable() { 67 | @Override 68 | public void run() { 69 | ((TextView) findViewById(R.id.latitude)).setText(String.valueOf(location.getLatitude())); 70 | ((TextView) findViewById(R.id.longitude)).setText(String.valueOf(location.getLongitude())); 71 | ((TextView) findViewById(R.id.altitude)).setText(String.valueOf(location.getAltitude())); 72 | ((TextView) findViewById(R.id.bearing)).setText(String.valueOf(location.getBearing())); 73 | ((TextView) findViewById(R.id.speed)).setText(String.valueOf(location.getSpeed())); 74 | } 75 | }); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/MultiScroll.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample; 2 | 3 | import android.support.v7.app.ActionBarActivity; 4 | import android.os.Bundle; 5 | import android.util.DisplayMetrics; 6 | import android.view.Display; 7 | import android.view.Menu; 8 | import android.view.MenuItem; 9 | import android.view.View; 10 | import android.webkit.WebView; 11 | import android.widget.TextView; 12 | 13 | import java.io.InputStream; 14 | 15 | 16 | public class MultiScroll extends ActionBarActivity { 17 | 18 | @Override 19 | protected void onCreate(Bundle savedInstanceState) { 20 | super.onCreate(savedInstanceState); 21 | setContentView(R.layout.activity_multi_scroll); 22 | Display display = getWindowManager().getDefaultDisplay(); 23 | int viewHeight = display.getHeight()/3; 24 | 25 | try { 26 | // All the logic is within the same try clause as we do not want to display any visual change on error 27 | InputStream is = getAssets().open("web_view_multiscroll.html"); 28 | int size = is.available(); 29 | byte[] buffer = new byte[size]; 30 | is.read(buffer); 31 | String content = new String(buffer, "UTF-8"); 32 | 33 | DisplayMetrics metrics = new DisplayMetrics(); 34 | display.getMetrics(metrics); 35 | 36 | content = content.replace("HEIGHT", Integer.toString(Math.round(viewHeight / metrics.density))); 37 | 38 | WebView webView = (WebView)this.findViewById(R.id.scrollViewCenter); 39 | // Note: The base URL parameter is not used 40 | webView.loadDataWithBaseURL("file:///android_assets/web_view_multiscroll.html", content, "text/html", "UTF-8", null); 41 | } catch (Exception e) { 42 | // Ignore 43 | } 44 | 45 | 46 | int[] viewToResize = new int[] {R.id.textView, R.id.textView1, R.id.textViewBottom, 47 | R.id.t2extView, R.id.t2extView1, R.id.t2extViewBottom }; 48 | 49 | for (int id : viewToResize) { 50 | View stretch = findViewById(id); 51 | stretch.getLayoutParams().height = viewHeight; 52 | stretch.requestLayout(); 53 | } 54 | 55 | } 56 | 57 | 58 | @Override 59 | public boolean onCreateOptionsMenu(Menu menu) { 60 | // Inflate the menu; this adds items to the action bar if it is present. 61 | getMenuInflater().inflate(R.menu.multi_scroll, menu); 62 | return true; 63 | } 64 | 65 | @Override 66 | public boolean onOptionsItemSelected(MenuItem item) { 67 | // Handle action bar item clicks here. The action bar will 68 | // automatically handle clicks on the Home/Up button, so long 69 | // as you specify a parent activity in AndroidManifest.xml. 70 | int id = item.getItemId(); 71 | if (id == R.id.action_settings) { 72 | return true; 73 | } 74 | return super.onOptionsItemSelected(item); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/NativeCrash.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample; 2 | 3 | import com.sun.jna.Pointer; 4 | 5 | public class NativeCrash { 6 | static { 7 | System.loadLibrary("jnidispatch"); 8 | } 9 | 10 | public static void crash() { 11 | Pointer pointer = new Pointer(1); 12 | pointer.setMemory(0, 1, (byte) 1); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/RecycleViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.support.v7.app.ActionBarActivity; 6 | import android.os.Bundle; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.util.TypedValue; 10 | import android.view.Display; 11 | import android.view.Menu; 12 | import android.view.MenuItem; 13 | 14 | public class RecycleViewActivity extends ActionBarActivity { 15 | 16 | private static String[] createData(int normalItems) { 17 | String[] data = new String[normalItems + 1]; 18 | 19 | for(int i = 0; i < normalItems; i++) { 20 | String value = "Item " + i; 21 | data[i] = value; 22 | } 23 | data[normalItems] = "TheEnd"; 24 | return data; 25 | } 26 | 27 | private static String[] getScreenFullPlusListData(Activity activity, int screens) { 28 | Display display = activity.getWindowManager().getDefaultDisplay(); 29 | float height = display.getHeight(); 30 | 31 | float listItemHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 64, activity.getResources().getDisplayMetrics()); 32 | return createData(screens * (int) ((height/listItemHeight) + 4)); 33 | } 34 | 35 | @Override 36 | protected void onCreate(Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | setContentView(R.layout.activity_recycle_view_activity); 39 | 40 | 41 | RecyclerView mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view); 42 | 43 | // use this setting to improve performance if you know that changes 44 | // in content do not change the layout size of the RecyclerView 45 | mRecyclerView.setHasFixedSize(true); 46 | 47 | // use a linear layout manager 48 | LinearLayoutManager mLayoutManager = new LinearLayoutManager(this); 49 | mRecyclerView.setLayoutManager(mLayoutManager); 50 | 51 | Intent intent = getIntent(); 52 | int screens = intent.getIntExtra(MainActivity.SCREENS, 1); 53 | 54 | 55 | // specify an adapter (see also next example) 56 | RecycleViewAdapter mAdapter = new RecycleViewAdapter(getScreenFullPlusListData(this, screens)); 57 | mRecyclerView.setAdapter(mAdapter); 58 | } 59 | 60 | @Override 61 | public boolean onCreateOptionsMenu(Menu menu) { 62 | // Inflate the menu; this adds items to the action bar if it is present. 63 | getMenuInflater().inflate(R.menu.menu_recycle_view_example, menu); 64 | return true; 65 | } 66 | 67 | @Override 68 | public boolean onOptionsItemSelected(MenuItem item) { 69 | // Handle action bar item clicks here. The action bar will 70 | // automatically handle clicks on the Home/Up button, so long 71 | // as you specify a parent activity in AndroidManifest.xml. 72 | int id = item.getItemId(); 73 | 74 | //noinspection SimplifiableIfStatement 75 | if (id == R.id.action_settings) { 76 | return true; 77 | } 78 | 79 | return super.onOptionsItemSelected(item); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/RecycleViewAdapter.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample; 2 | 3 | import android.app.Activity; 4 | import android.util.TypedValue; 5 | import android.view.Display; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.TextView; 10 | import android.support.v7.widget.RecyclerView; 11 | 12 | import java.util.ArrayList; 13 | import java.util.HashMap; 14 | import java.util.List; 15 | import java.util.Map; 16 | 17 | /** 18 | * Created by john7doe on 01/07/15. 19 | */ 20 | public class RecycleViewAdapter extends RecyclerView.Adapter { 21 | private String[] mDataset; 22 | 23 | // Provide a reference to the views for each data item 24 | // Complex data items may need more than one view per item, and 25 | // you provide access to all the views for a data item in a view holder 26 | public static class ViewHolder extends RecyclerView.ViewHolder { 27 | // each data item is just a string in this case 28 | public TextView mTextView; 29 | public ViewHolder(TextView v) { 30 | super(v); 31 | mTextView = v; 32 | } 33 | } 34 | 35 | // Provide a suitable constructor (depends on the kind of dataset) 36 | public RecycleViewAdapter(String[] myDataset) { 37 | mDataset = myDataset; 38 | } 39 | 40 | // Create new views (invoked by the layout manager) 41 | @Override 42 | public RecycleViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, 43 | int viewType) { 44 | // create a new view 45 | View v = LayoutInflater.from(parent.getContext()) 46 | .inflate(android.R.layout.simple_list_item_1, parent, false); 47 | ViewHolder vh = new ViewHolder((TextView)v); 48 | return vh; 49 | } 50 | 51 | // Replace the contents of a view (invoked by the layout manager) 52 | @Override 53 | public void onBindViewHolder(ViewHolder holder, int position) { 54 | // - get element from your dataset at this position 55 | // - replace the contents of the view with that element 56 | holder.mTextView.setText(mDataset[position]); 57 | 58 | } 59 | 60 | // Return the size of your dataset (invoked by the layout manager) 61 | @Override 62 | public int getItemCount() { 63 | return mDataset.length; 64 | } 65 | } 66 | 67 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/ScollplicatedActivity.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample; 2 | 3 | import android.app.Activity; 4 | import android.support.v7.app.ActionBarActivity; 5 | import android.support.v7.app.ActionBar; 6 | import android.support.v4.app.Fragment; 7 | import android.os.Bundle; 8 | import android.view.Display; 9 | import android.view.LayoutInflater; 10 | import android.view.Menu; 11 | import android.view.MenuItem; 12 | import android.view.View; 13 | import android.view.ViewGroup; 14 | import android.os.Build; 15 | import android.webkit.WebView; 16 | import android.widget.AbsoluteLayout; 17 | import android.widget.Button; 18 | import android.widget.TextView; 19 | 20 | import java.io.InputStream; 21 | 22 | public class ScollplicatedActivity extends Activity { 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | setContentView(R.layout.activity_scollplicated_activty); 28 | 29 | final TextView title = (TextView) findViewById(R.id.textView1); 30 | 31 | int[] buttons = new int[] {R.id.oneButton, R.id.testingButton, R.id.twoButton, R.id.middleButton}; 32 | 33 | 34 | moveAndResize(R.id.oneButton, 3, 3, 0, 0); 35 | moveAndResize(R.id.twoButton, 0, 3, 0, 0); 36 | moveAndResize(R.id.middleButton, 1, 1, 2, 1); 37 | 38 | 39 | for(int buttonId: buttons) { 40 | Button button = (Button) findViewById(buttonId); 41 | button.setOnClickListener(new View.OnClickListener() { 42 | @Override 43 | public void onClick(View view) { 44 | title.setText(view.getResources().getResourceEntryName(view.getId())); 45 | } 46 | }); 47 | 48 | } 49 | } 50 | 51 | private void moveAndResize(int id, int x, int y, int w, int h) { 52 | Display display = getWindowManager().getDefaultDisplay(); 53 | View v = (View) findViewById(id); 54 | AbsoluteLayout.LayoutParams layoutParams = (AbsoluteLayout.LayoutParams) v.getLayoutParams(); 55 | layoutParams.x = x * display.getWidth(); 56 | layoutParams.y = y * display.getHeight(); 57 | if(w != 0) 58 | { 59 | layoutParams.width = w * display.getWidth(); 60 | } 61 | if(h != 0) 62 | { 63 | layoutParams.height = h * display.getHeight(); 64 | } 65 | v.requestLayout(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/ScrollActivity.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample; 2 | 3 | import android.os.Bundle; 4 | import android.app.Activity; 5 | 6 | public class ScrollActivity extends Activity { 7 | 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | setContentView(R.layout.scroll_sample); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/ScrollShortActivity.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample; 2 | 3 | import android.app.Activity; 4 | import android.support.v7.app.ActionBarActivity; 5 | import android.os.Bundle; 6 | import android.view.Display; 7 | import android.view.Menu; 8 | import android.view.MenuItem; 9 | import android.view.View; 10 | 11 | 12 | public class ScrollShortActivity extends Activity { 13 | 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | setContentView(R.layout.activity_scroll_short); 18 | Display display = getWindowManager().getDefaultDisplay(); 19 | View stretch = findViewById(R.id.textViewStretch); 20 | 21 | stretch.getLayoutParams().height = display.getHeight(); 22 | stretch.requestLayout(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/ScrollWebViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.util.DisplayMetrics; 6 | import android.view.Display; 7 | import android.webkit.WebSettings; 8 | import android.webkit.WebView; 9 | 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | 13 | /** 14 | * Created by john7doe on 04/10/14. 15 | */ 16 | public class ScrollWebViewActivity extends Activity { 17 | @Override 18 | public void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | Display display = getWindowManager().getDefaultDisplay(); 21 | 22 | 23 | try { 24 | // All the logic is within the same try clause as we do not want to display any visual change on error 25 | InputStream is = getAssets().open("web_view_scroll.html"); 26 | int size = is.available(); 27 | byte[] buffer = new byte[size]; 28 | is.read(buffer); 29 | String content = new String(buffer, "UTF-8"); 30 | DisplayMetrics metrics = new DisplayMetrics(); 31 | display.getMetrics(metrics); 32 | float twoScaled = 2 / metrics.density; 33 | content = content.replace("HEIGHT", Integer.toString(Math.round(display.getHeight() * twoScaled))); 34 | content = content.replace("WIDTH", Integer.toString(Math.round(display.getWidth() * twoScaled))); 35 | 36 | this.setContentView(R.layout.scroll_web_view); 37 | 38 | WebView webView = (WebView)this.findViewById(R.id.webViewScroll); 39 | // Note: The base URL parameter is not used 40 | webView.loadDataWithBaseURL("file:///android_assets/web_view.html", content, "text/html", "UTF-8", null); 41 | } catch (IOException e) { 42 | e.printStackTrace(); 43 | } 44 | 45 | 46 | } 47 | } -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/Settings.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample; 2 | 3 | import android.app.Application; 4 | 5 | import java.util.Date; 6 | 7 | 8 | public class Settings extends Application { 9 | public static Date pickedDate; 10 | public static String spellCheckedInput; 11 | public static String radioSelectedValue; 12 | public static boolean checkBoxChecked; 13 | public static int seekBarProgress; 14 | 15 | @Override 16 | public void onCreate() { 17 | Settings.pickedDate = new Date(); 18 | Settings.spellCheckedInput = ""; 19 | Settings.radioSelectedValue = ""; 20 | Settings.checkBoxChecked = false; 21 | Settings.seekBarProgress = 0; 22 | 23 | super.onCreate(); 24 | } 25 | } -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/SpellCheckActivity.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.app.Activity; 6 | import android.view.View; 7 | import android.widget.Button; 8 | import android.widget.EditText; 9 | import android.widget.TextView; 10 | 11 | public class SpellCheckActivity extends Activity { 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) { 14 | super.onCreate(savedInstanceState); 15 | setContentView(R.layout.spell_check_sample); 16 | EditText textViewSpellCheckedInput = (EditText)this.findViewById(R.id.editTextSpellChecked); 17 | textViewSpellCheckedInput.setText(Settings.spellCheckedInput); 18 | textViewSpellCheckedInput.setSelection(textViewSpellCheckedInput.getText().length()); 19 | } 20 | 21 | /* View action functions */ 22 | public void onButtonClick(View view) { 23 | assert view.getClass().isInstance(Button.class); 24 | 25 | Button button = (Button)view; 26 | 27 | switch(button.getId()) { 28 | case R.id.buttonCancel: 29 | finish(); 30 | break; 31 | 32 | case R.id.buttonSave: 33 | EditText editText = (EditText)this.findViewById(R.id.editTextSpellChecked); 34 | Settings.spellCheckedInput = editText.getText().toString(); 35 | finish(); 36 | break; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/SwipeWebViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Build; 6 | import android.os.Bundle; 7 | import android.util.DisplayMetrics; 8 | import android.view.Display; 9 | import android.webkit.WebSettings; 10 | import android.webkit.WebView; 11 | 12 | import java.io.IOException; 13 | import java.io.InputStream; 14 | 15 | /** 16 | * Created by davidl on 10/29/16. 17 | */ 18 | public class SwipeWebViewActivity extends Activity { 19 | @Override 20 | public void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | Display display = getWindowManager().getDefaultDisplay(); 23 | 24 | 25 | try { 26 | // All the logic is within the same try clause as we do not want to display any visual change on error 27 | InputStream is = getAssets().open("web_view_swipe.html"); 28 | int size = is.available(); 29 | byte[] buffer = new byte[size]; 30 | is.read(buffer); 31 | String content = new String(buffer, "UTF-8"); 32 | DisplayMetrics metrics = new DisplayMetrics(); 33 | display.getMetrics(metrics); 34 | float twoScaled = 2 / metrics.density; 35 | content = content.replace("HEIGHT", Integer.toString(Math.round(display.getHeight() * twoScaled))); 36 | content = content.replace("WIDTH", Integer.toString(Math.round(display.getWidth() * twoScaled))); 37 | 38 | this.setContentView(R.layout.swipe_web_view); 39 | 40 | WebView webView = (WebView)this.findViewById(R.id.webViewScroll); 41 | // Note: The base URL parameter is not used 42 | webView.loadDataWithBaseURL("file:///android_assets/web_view.html", content, "text/html", "UTF-8", null); 43 | WebSettings settings = webView.getSettings(); 44 | settings.setJavaScriptEnabled(true); 45 | } catch (IOException e) { 46 | e.printStackTrace(); 47 | } 48 | 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/TextfieldsActivity.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.view.Menu; 6 | import android.view.MenuItem; 7 | 8 | 9 | public class TextfieldsActivity extends Activity { 10 | 11 | @Override 12 | protected void onCreate(Bundle savedInstanceState) { 13 | super.onCreate(savedInstanceState); 14 | setContentView(R.layout.activity_textfields); 15 | } 16 | 17 | @Override 18 | public boolean onCreateOptionsMenu(Menu menu) { 19 | // Inflate the menu; this adds items to the action bar if it is present. 20 | getMenuInflater().inflate(R.menu.menu_textfields, menu); 21 | return true; 22 | } 23 | 24 | @Override 25 | public boolean onOptionsItemSelected(MenuItem item) { 26 | // Handle action bar item clicks here. The action bar will 27 | // automatically handle clicks on the Home/Up button, so long 28 | // as you specify a parent activity in AndroidManifest.xml. 29 | int id = item.getItemId(); 30 | 31 | //noinspection SimplifiableIfStatement 32 | if (id == R.id.action_settings) { 33 | return true; 34 | } 35 | 36 | return super.onOptionsItemSelected(item); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/WebViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Build; 6 | import android.os.Bundle; 7 | import android.view.Menu; 8 | import android.webkit.WebSettings; 9 | import android.webkit.WebView; 10 | 11 | import java.io.IOException; 12 | import java.io.InputStream; 13 | 14 | public class WebViewActivity extends Activity { 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState){ 17 | super.onCreate(savedInstanceState); 18 | 19 | try { 20 | this.setContentView(R.layout.web_view_sample); 21 | 22 | WebView webView = (WebView)this.findViewById(R.id.webView); 23 | WebSettings webSettings = webView.getSettings(); 24 | webSettings.setJavaScriptEnabled(true); 25 | 26 | Intent intent = getIntent(); 27 | boolean showFrames = intent.getBooleanExtra(MainActivity.FRAMES, false); 28 | 29 | if (showFrames) { 30 | if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD_MR1) 31 | { 32 | webView.loadUrl("https://xtcruntimeartifacts.blob.core.windows.net/calabash-files/webpages-for-tests/page.html"); 33 | } 34 | else { 35 | webView.loadData( 36 | "

" 37 | + "Old Android doesn't support the SSL cert used by the frames test page. :(" 38 | + "

", 39 | "text/html; charset=UTF-8", 40 | null 41 | ); 42 | } 43 | } else { 44 | // All the logic is within the same try clause as we do not want to display any visual change on error 45 | InputStream is = getAssets().open("web_view.html"); 46 | int size = is.available(); 47 | byte[] buffer = new byte[size]; 48 | is.read(buffer); 49 | String content = new String(buffer, "UTF-8"); 50 | // Note: The base URL parameter is not used 51 | webView.loadDataWithBaseURL("file:///android_assets/web_view.html", content, "text/html", "UTF-8", null); 52 | } 53 | } catch (IOException e) { 54 | e.printStackTrace(); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/orientations/LandscapeActivity.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample.orientations; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | 6 | import com.xamarin.xtcandroidsample.R; 7 | 8 | public class LandscapeActivity extends Activity { 9 | 10 | @Override 11 | protected void onCreate(Bundle savedInstanceState) { 12 | super.onCreate(savedInstanceState); 13 | setContentView(R.layout.activity_landscape); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/orientations/OrientationsActivity.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample.orientations; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | 8 | import com.xamarin.xtcandroidsample.R; 9 | 10 | public class OrientationsActivity extends Activity { 11 | 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) { 14 | super.onCreate(savedInstanceState); 15 | setContentView(R.layout.activity_orientations); 16 | } 17 | 18 | public void goToPortraitActivity(View view) { 19 | startActivity(new Intent(this, PortraitActivity.class)); 20 | } 21 | 22 | public void goToReversePortraitActivity(View view) { 23 | startActivity(new Intent(this, ReversePortraitActivity.class)); 24 | } 25 | 26 | public void goToLandscapeActivity(View view) { 27 | startActivity(new Intent(this, LandscapeActivity.class)); 28 | } 29 | 30 | public void goToReverseLandscapeActivity(View view) { 31 | startActivity(new Intent(this, ReverseLandscapeActivity.class)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/orientations/PortraitActivity.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample.orientations; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | 6 | import com.xamarin.xtcandroidsample.R; 7 | 8 | public class PortraitActivity extends Activity { 9 | 10 | @Override 11 | protected void onCreate(Bundle savedInstanceState) { 12 | super.onCreate(savedInstanceState); 13 | setContentView(R.layout.activity_portrait); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/orientations/ReverseLandscapeActivity.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample.orientations; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | 6 | import com.xamarin.xtcandroidsample.R; 7 | 8 | public class ReverseLandscapeActivity extends Activity { 9 | 10 | @Override 11 | protected void onCreate(Bundle savedInstanceState) { 12 | super.onCreate(savedInstanceState); 13 | setContentView(R.layout.activity_reverse_landscape); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/java/com/xamarin/xtcandroidsample/orientations/ReversePortraitActivity.java: -------------------------------------------------------------------------------- 1 | package com.xamarin.xtcandroidsample.orientations; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | 6 | import com.xamarin.xtcandroidsample.R; 7 | 8 | public class ReversePortraitActivity extends Activity { 9 | 10 | @Override 11 | protected void onCreate(Bundle savedInstanceState) { 12 | super.onCreate(savedInstanceState); 13 | setContentView(R.layout.activity_reverse_portrait); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calabash/calabash-android/4ff3f08420264e71b6f0cf1db845327d7672c213/ruby-gem/integration-tests/NativeTestApp/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calabash/calabash-android/4ff3f08420264e71b6f0cf1db845327d7672c213/ruby-gem/integration-tests/NativeTestApp/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calabash/calabash-android/4ff3f08420264e71b6f0cf1db845327d7672c213/ruby-gem/integration-tests/NativeTestApp/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calabash/calabash-android/4ff3f08420264e71b6f0cf1db845327d7672c213/ruby-gem/integration-tests/NativeTestApp/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/res/drawable/red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calabash/calabash-android/4ff3f08420264e71b6f0cf1db845327d7672c213/ruby-gem/integration-tests/NativeTestApp/app/src/main/res/drawable/red.png -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/res/layout/activity_drag_and_drop.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 25 | 26 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/NativeTestApp/app/src/main/res/layout/activity_horizontal_scroll.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 16 | 20 | 6 | 7 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/features/support/data/page_with_iframe.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

I have an iframe

4 | 6 | 7 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/features/support/env.rb: -------------------------------------------------------------------------------- 1 | require 'calabash-android/color_helper' 2 | require 'calabash-android/operations' 3 | 4 | World(Calabash::Android::ColorHelper) 5 | World(Calabash::Android::Operations) 6 | 7 | ENV['TEST_APP_PATH'] = test_server_path(ENV['APP_PATH']) 8 | 9 | # Pry is not allowed on the Xamarin Test Cloud. This will force a validation 10 | # error if you mistakenly submit a binding.pry to the Test Cloud. 11 | if !ENV['XAMARIN_TEST_CLOUD'] 12 | require 'pry' 13 | Pry.config.history.file = '.pry-history' 14 | require 'pry-nav' 15 | end 16 | -------------------------------------------------------------------------------- /ruby-gem/integration-tests/features/support/helpers.rb: -------------------------------------------------------------------------------- 1 | def ensure_app_installed 2 | unless $app_installed 3 | reinstall_apps 4 | end 5 | 6 | $app_installed = true 7 | end -------------------------------------------------------------------------------- /ruby-gem/integration-tests/features/support/hooks.rb: -------------------------------------------------------------------------------- 1 | def save 2 | scroll_to_push_button 'Save' 3 | end 4 | 5 | def scroll_to_push_button(name) 6 | q = "button marked:'#{name}'" 7 | 8 | while query(q).empty? do 9 | scroll_down 10 | sleep 1 11 | end 12 | 13 | touch q 14 | end -------------------------------------------------------------------------------- /ruby-gem/integration-tests/features/webview.feature: -------------------------------------------------------------------------------- 1 | @webview 2 | Feature: Webviews 3 | # A user should be able to query for elements within an iframe. e.g. query("ww css:'iframe' css:'...'") 4 | Scenario: Querying for elements inside a non-cross domain iframe 5 | Given I am in a webview with an iframe 6 | When I search for elements inside an iframe 7 | Then I should be able to interact with them 8 | 9 | # A user should get a good error message in an exception when executing invalid javascript 10 | Scenario: Evaluating bad javascript 11 | Given I have a webview available 12 | When I evaluate bad javascript 13 | Then I should get an error with an javascript exception 14 | 15 | # A user should get no elements when the webview has no body, not an exception 16 | Scenario: Querying for elements with no document.body 17 | Given I have a webview available 18 | And it has no body 19 | When I query for elements 20 | Then none should be returned -------------------------------------------------------------------------------- /ruby-gem/irbrc: -------------------------------------------------------------------------------- 1 | begin 2 | require 'rubygems' 3 | require 'irb/completion' 4 | require 'irb/ext/save-history' 5 | 6 | begin 7 | require 'awesome_print' 8 | rescue LoadError => e 9 | msg = ["Caught a LoadError: could not load 'awesome_print'", 10 | "#{e}", 11 | '', 12 | 'Use bundler (recommended) or uninstall awesome_print.', 13 | '', 14 | '# Use bundler (recommended)', 15 | '$ bundle update', 16 | '$ bundle exec calabash-android console ', 17 | '', 18 | '# Uninstall', 19 | '$ gem update --system', 20 | '$ gem uninstall -Vax --force --no-abort-on-dependent awesome_print'] 21 | puts msg 22 | exit(1) 23 | end 24 | 25 | AwesomePrint.irb! 26 | 27 | ARGV.concat [ "--readline", 28 | "--prompt-mode", 29 | "simple" ] 30 | 31 | # 50 entries in the list 32 | IRB.conf[:SAVE_HISTORY] = 50 33 | 34 | # Store results in home directory with specified file name 35 | IRB.conf[:HISTORY_FILE] = ".irb-history" 36 | 37 | require 'calabash-android/defaults' 38 | require 'calabash-android/operations' 39 | rescue Exception => e 40 | puts "Error loading Calabash irbrc: #{e}" 41 | exit(1) 42 | end 43 | 44 | module Calabash 45 | module Android 46 | module Operations 47 | def embed(*args) 48 | puts "Embed is a Cucumber method and is not available in this console." 49 | end 50 | end 51 | end 52 | end 53 | 54 | module Cucumber 55 | class << self 56 | wants_to_quit = false 57 | end 58 | end 59 | 60 | extend Calabash::Android::Operations 61 | 62 | 63 | def preferences 64 | Calabash::Android::Preferences.new 65 | end 66 | 67 | def disable_usage_tracking 68 | preferences.usage_tracking = "none" 69 | puts "Calabash will not collect usage information." 70 | "none" 71 | end 72 | 73 | def enable_usage_tracking(level="system_info") 74 | preferences.usage_tracking = level 75 | puts "Calabash will collect statistics using the '#{level}' rule." 76 | level 77 | end 78 | 79 | -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android.rb: -------------------------------------------------------------------------------- 1 | require 'calabash-android/utils' 2 | require 'calabash-android/defaults' 3 | require 'calabash-android/environment' 4 | require 'calabash-android/dot_dir' 5 | require 'calabash-android/logging' 6 | require 'calabash-android/store/preferences' 7 | require 'calabash-android/usage_tracker' 8 | require 'calabash-android/operations' 9 | require 'calabash-android/version' 10 | require 'calabash-android/abase' 11 | -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/abase.rb: -------------------------------------------------------------------------------- 1 | class Calabash::ABase 2 | include Calabash::Android::Operations 3 | 4 | 5 | attr_accessor :world, :transition_duration 6 | 7 | def initialize(world, transition_duration=0.5) 8 | self.world = world 9 | self.transition_duration = transition_duration 10 | end 11 | 12 | def trait 13 | raise "You should define a trait method or a title method" unless respond_to?(:title) 14 | "* marked:'#{self.title}'" 15 | end 16 | 17 | def current_page? 18 | element_exists(trait) 19 | end 20 | 21 | def page(clz, *args) 22 | clz.new(world, *args) 23 | end 24 | 25 | def await(wait_opts={}) 26 | wait_for_elements_exist([trait], wait_opts) 27 | self 28 | end 29 | 30 | ## 31 | # Performs a transition from receiver page to another by performing a +:tap+ gesture 32 | # or a user specified +:action+. 33 | # Caller must supply a hash of options +transition_options+ to describe the transition. 34 | # Transition options may have the following keys 35 | # 36 | # +:tap+: A uiquery used to perform a tap gesture to begin transition 37 | # +:action+: A proc to use begin transition (either :tap or :action must be supplied) 38 | # +:page+: A page object or page object class to transition to (target page). If a class is provided this 39 | # is instantiated using the +page+ method of self. If no +:page+ is supplied, +self+ is used. 40 | # +:await+: If specified and truthy will await the +:page+ after performing gesture (usually to wait 41 | # for animation to finish) 42 | # +:tap_options+: If +:tap+ is provided used to pass as options to touch 43 | # +:wait_options+: When awaiting target page, pass these options to the +await+ method 44 | # 45 | # Returns the transition target page 46 | # 47 | # Note it is assumed that the target page is a Calabash::ABase (or acts accordingly) 48 | def transition(transition_options={}) 49 | uiquery = transition_options[:tap] 50 | action = transition_options[:action] 51 | page_arg = transition_options[:page] 52 | should_await = transition_options.has_key?(:await) ? transition_options[:await] : true 53 | 54 | if action.nil? && uiquery.nil? 55 | raise "Called transition without providing a gesture (:tap or :action) #{transition_options}" 56 | end 57 | 58 | if uiquery 59 | tap_options = transition_options[:tap_options] || {} 60 | touch(uiquery, tap_options) 61 | else 62 | action.call() 63 | end 64 | 65 | page_obj = page_arg.is_a?(Class) ? page(page_arg) : page_arg 66 | page_obj ||= self 67 | 68 | if should_await 69 | unless page_obj == self 70 | wait_opts = transition_options[:wait_options] || {} 71 | page_obj.await(wait_opts) 72 | end 73 | end 74 | 75 | page_obj 76 | end 77 | 78 | def await_screenshot(wait_opts={}, screenshot_opts={}) 79 | await(wait_opts) 80 | screenshot_embed(screenshot_opts) 81 | end 82 | 83 | 84 | protected 85 | def method_missing(name, *args, &block) 86 | world.send(name, *args, &block) 87 | end 88 | 89 | end 90 | -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/calabash_steps.rb: -------------------------------------------------------------------------------- 1 | require 'calabash-android/steps/assert_steps' 2 | require 'calabash-android/steps/check_box_steps' 3 | require 'calabash-android/steps/context_menu_steps' 4 | require 'calabash-android/steps/date_picker_steps' 5 | require 'calabash-android/steps/enter_text_steps' 6 | require 'calabash-android/steps/location_steps' 7 | require 'calabash-android/steps/navigation_steps' 8 | require 'calabash-android/steps/press_button_steps' 9 | require 'calabash-android/steps/progress_steps' 10 | require 'calabash-android/steps/screenshot_steps' 11 | require 'calabash-android/steps/search_steps' 12 | require 'calabash-android/steps/spinner_steps' 13 | require 'calabash-android/steps/time_picker_steps' 14 | 15 | -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/color_helper.rb: -------------------------------------------------------------------------------- 1 | module Calabash module Android 2 | 3 | module ColorHelper 4 | def colorize(text, color_code) 5 | "\e[#{color_code}m#{text}\e[0m" 6 | end 7 | 8 | def red(text); colorize(text, 31); end 9 | def green(text); colorize(text, 32); end 10 | def blue(text); colorize(text, 34); end 11 | end 12 | 13 | end end 14 | -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/cucumber.rb: -------------------------------------------------------------------------------- 1 | require 'calabash-android/color_helper' 2 | require 'calabash-android/operations' 3 | 4 | World(Calabash::Android::ColorHelper) 5 | World(Calabash::Android::Operations) 6 | 7 | AfterConfiguration do 8 | require 'calabash-android/calabash_steps' 9 | end 10 | -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/defaults.rb: -------------------------------------------------------------------------------- 1 | module Calabash 2 | module Android 3 | module Defaults 4 | def self.query_timeout 5 | (ENV['CALABASH_DEFAULT_TIMEOUT'] && ENV['CALABASH_DEFAULT_TIMEOUT'].to_i) || 5 6 | end 7 | end 8 | end 9 | end -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/deprecated_actions.map: -------------------------------------------------------------------------------- 1 | send_key_enter,press_enter_button 2 | send_key_left,press_left_button 3 | send_key_right,press_right_button 4 | send_key_up,press_up_button 5 | send_key_down,press_down_button 6 | press_menu,press_menu_button 7 | go_back,press_back_button 8 | backdoor,backdoor(method_name, arguments) 9 | execute_javascript, evaluate_javascript(query, javascript) 10 | execute_async_javascript, evaluate_javascript(query, javascript) 11 | -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/dot_dir.rb: -------------------------------------------------------------------------------- 1 | module Calabash 2 | module Android 3 | # A module for managing the ~/.calabash directory. 4 | module DotDir 5 | def self.directory 6 | home = Calabash::Android::Environment.user_home_directory 7 | dir = File.join(home, ".calabash") 8 | if !File.exist?(dir) 9 | FileUtils.mkdir_p(dir) 10 | end 11 | dir 12 | end 13 | end 14 | end 15 | end 16 | 17 | 18 | -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/drag_helpers.rb: -------------------------------------------------------------------------------- 1 | require 'calabash-android/env' 2 | require 'calabash-android/monkey_helpers' 3 | 4 | module Calabash 5 | module Android 6 | module DragHelpers 7 | include Calabash::Android::EnvironmentHelpers 8 | include Calabash::Android::MonkeyHelpers 9 | 10 | def drag_coordinates(from_x, from_y, to_x, to_y, steps=10, hold_time=0.5, hang_time=0.5) 11 | calabash_log "Dragging from #{from_x},#{from_y} to #{to_x},#{to_y}" 12 | monkey_move_from(from_x, from_y, 13 | to_x, to_y, 14 | hold_time: hold_time, 15 | hang_time: hang_time, 16 | steps: steps) 17 | end 18 | 19 | def drag_and_drop(from_query, to_query, steps=10, hold_time=0.5, hang_time=0.5) 20 | wait_for_element_exists(from_query) 21 | wait_for_element_exists(to_query) 22 | 23 | from_results = query(from_query) 24 | to_results = query(to_query) 25 | 26 | if from_results.any? 27 | if to_results.any? 28 | from_rect = from_results.first['rect'] 29 | to_rect = to_results.first['rect'] 30 | from_x = from_rect['center_x'] 31 | from_y = from_rect['center_y'] 32 | to_x = to_rect['center_x'] 33 | to_y = to_rect['center_y'] 34 | 35 | monkey_move_from(from_x, from_y, to_x, to_y, hold_time: hold_time, hang_time: hang_time, steps: steps) 36 | else 37 | raise "No matching elements for: #{to_query}" 38 | end 39 | else 40 | raise "No matching elements for: #{from_query}" 41 | end 42 | end 43 | end 44 | end 45 | end -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/environment_helpers.rb: -------------------------------------------------------------------------------- 1 | module Calabash 2 | module Android 3 | module EnvironmentHelpers 4 | # Are we running in the Xamarin Test Cloud? 5 | # 6 | # @return [Boolean] Returns true if cucumber is running in the test cloud. 7 | def xamarin_test_cloud? 8 | ENV['XAMARIN_TEST_CLOUD'] == '1' 9 | end 10 | end 11 | end 12 | end -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/lib/AXMLPrinter2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calabash/calabash-android/4ff3f08420264e71b6f0cf1db845327d7672c213/ruby-gem/lib/calabash-android/lib/AXMLPrinter2.jar -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/lib/TestServer.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calabash/calabash-android/4ff3f08420264e71b6f0cf1db845327d7672c213/ruby-gem/lib/calabash-android/lib/TestServer.apk -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/lib/manifest_extractor.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calabash/calabash-android/4ff3f08420264e71b6f0cf1db845327d7672c213/ruby-gem/lib/calabash-android/lib/manifest_extractor.jar -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/lib/screenshotTaker.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calabash/calabash-android/4ff3f08420264e71b6f0cf1db845327d7672c213/ruby-gem/lib/calabash-android/lib/screenshotTaker.jar -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/logging.rb: -------------------------------------------------------------------------------- 1 | module Calabash 2 | module Android 3 | module Logging 4 | require "fileutils" 5 | 6 | # These methods are not part of the API. 7 | # 8 | # They may change at any time. 9 | 10 | # !@visibility private 11 | # blue 12 | def self.log_warn(msg) 13 | puts self.blue(" WARN: #{msg}") if msg 14 | end 15 | 16 | # !@visibility private 17 | # magenta 18 | def self.log_debug(msg) 19 | if Calabash::Android::Environment.debug? 20 | puts self.magenta("DEBUG: #{msg}") if msg 21 | end 22 | end 23 | 24 | # !@visibility private 25 | # green 26 | def self.log_info(msg) 27 | puts self.green(" INFO: #{msg}") if msg 28 | end 29 | 30 | # !@visibility private 31 | # red 32 | def self.log_error(msg) 33 | puts self.red("ERROR: #{msg}") if msg 34 | end 35 | 36 | # !@visibility private 37 | def self.log_to_file(message) 38 | timestamp = self.timestamp 39 | 40 | begin 41 | File.open(self.calabash_log_file, "a:UTF-8") do |file| 42 | message.split($-0).each do |line| 43 | file.write("#{timestamp} #{line}#{$-0}") 44 | end 45 | end 46 | rescue => e 47 | message = 48 | %Q{Could not write: 49 | 50 | #{message} 51 | 52 | to calabash.log because: 53 | 54 | #{e} 55 | } 56 | self.log_debug(message) 57 | end 58 | end 59 | 60 | private 61 | 62 | # @!visibility private 63 | def self.colorize(string, color) 64 | if Calabash::Android::Environment.windows? 65 | string 66 | elsif Calabash::Android::Environment.xtc? 67 | string 68 | else 69 | "\033[#{color}m#{string}\033[0m" 70 | end 71 | end 72 | 73 | # @!visibility private 74 | def self.red(string) 75 | colorize(string, 31) 76 | end 77 | 78 | # @!visibility private 79 | def self.blue(string) 80 | colorize(string, 34) 81 | end 82 | 83 | # @!visibility private 84 | def self.magenta(string) 85 | colorize(string, 35) 86 | end 87 | 88 | # @!visibility private 89 | def self.cyan(string) 90 | colorize(string, 36) 91 | end 92 | 93 | # @!visibility private 94 | def self.green(string) 95 | colorize(string, 32) 96 | end 97 | 98 | # @!visibility private 99 | def self.timestamp 100 | Time.now.strftime("%Y-%m-%d_%H-%M-%S") 101 | end 102 | 103 | # @!visibility private 104 | def self.logs_directory 105 | path = File.join(Calabash::Android::DotDir.directory, "logs") 106 | FileUtils.mkdir_p(path) 107 | path 108 | end 109 | 110 | # @!visibility private 111 | def self.calabash_log_file 112 | path = File.join(self.logs_directory, "calabash.log") 113 | if !File.exist?(path) 114 | FileUtils.touch(path) 115 | end 116 | path 117 | end 118 | end 119 | end 120 | end 121 | -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/management/adb.rb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calabash/calabash-android/4ff3f08420264e71b6f0cf1db845327d7672c213/ruby-gem/lib/calabash-android/management/adb.rb -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/management/app_installation.rb: -------------------------------------------------------------------------------- 1 | #Will be deleted. Only here because skeletons might refer to it. -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/removed_actions.txt: -------------------------------------------------------------------------------- 1 | inspect_current_dialog 2 | assert_view_property 3 | get_view_property 4 | press_image_button_description 5 | press_image_button_number 6 | click_on_view_by_id 7 | wait 8 | wait_for_text 9 | wait_for_no_progress_bars 10 | press_button_with_text 11 | press_button_number 12 | wait_for_view_by_id 13 | toggle_numbered_checkbox 14 | has_view 15 | is_enabled 16 | wait_for_button 17 | wait_for_view 18 | press 19 | click_on_text 20 | click_on_view_by_description 21 | press_long_on_text 22 | get_text_by_id 23 | click_by_selector 24 | select_item_from_named_spinner 25 | get_selected_spinner_item_text 26 | press_list_item 27 | long_press_list_item 28 | get_list_data 29 | get_list_item_text 30 | get_list_item_properties 31 | press_long_on_text_and_select_with_index 32 | press_long_on_text_and_select_with_text 33 | assert_text 34 | assert_text_in_textview 35 | long_press_on_view_by_id 36 | press_long_on_text_and_select_with_id 37 | enter_query_into_numbered_field 38 | select_from_menu 39 | clear_id_field 40 | clear_numbered_field 41 | clear_named_field 42 | enter_text_into_named_field 43 | enter_text_into_id_field 44 | enter_text_into_numbered_field 45 | assert_no_duplicates_in_grid 46 | select_tab 47 | wait_for_dialog_to_close 48 | wait_for_screen 49 | wait_for_tab 50 | set_text 51 | scroll_down 52 | scroll_up 53 | set_date_with_description 54 | set_date_with_index 55 | set_time_with_description 56 | set_time_with_index 57 | -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/retry.rb: -------------------------------------------------------------------------------- 1 | module Calabash 2 | module Android 3 | module Retry 4 | def self.retry(opts, &blk) 5 | tries = opts[:tries] 6 | interval = opts[:interval] 7 | 8 | tries.times do |try| 9 | begin 10 | blk.call 11 | return 12 | 13 | rescue => e 14 | if (try + 1) >= tries 15 | raise 16 | else 17 | sleep interval 18 | end 19 | end 20 | end 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/steps/assert_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I see the text "([^\"]*)"$/ do |text| 2 | wait_for_text(text, timeout: 10) 3 | end 4 | 5 | Then /^I see "([^\"]*)"$/ do |text| 6 | wait_for_text(text, timeout: 10) 7 | end 8 | 9 | Then /^I should see "([^\"]*)"$/ do |text| 10 | wait_for_text(text, timeout: 10) 11 | end 12 | 13 | Then /^I should see text containing "([^\"]*)"$/ do |text| 14 | wait_for_text(text, timeout: 10) 15 | end 16 | 17 | 18 | 19 | Then /^I should not see "([^\"]*)"$/ do |text| 20 | wait_for_text_to_disappear(text, timeout: 10) 21 | end 22 | 23 | Then /^I don't see the text "([^\"]*)"$/ do |text| 24 | wait_for_text_to_disappear(text, timeout: 10) 25 | end 26 | 27 | Then /^I don't see "([^\"]*)"$/ do |text| 28 | wait_for_text_to_disappear(text, timeout: 10) 29 | end 30 | -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/steps/check_box_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I toggle checkbox number (\d+)$/ do |index| 2 | tap_when_element_exists("android.widget.CheckBox index:#{index.to_i-1}") 3 | end 4 | -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/steps/context_menu_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I long press "([^\"]*)" and select item number (\d+)$/ do |text, index| 2 | step_deprecated 3 | 4 | long_press_when_element_exists("* {text CONTAINS[c] '#{text}'}") 5 | tap_when_element_exists("com.android.internal.view.menu.ListMenuItemView android.widget.TextView index:#{index.to_i - 1}") 6 | end 7 | 8 | Then /^I long press "([^\"]*)" and select "([^\"]*)"$/ do |text, identifier| 9 | step_deprecated 10 | 11 | long_press_when_element_exists("* {text CONTAINS[c] '#{text}'}") 12 | tap_when_element_exists("com.android.internal.view.menu.ListMenuItemView android.widget.TextView marked:'#{identifier}'") 13 | end 14 | 15 | Then /^I long press "([^\"]*)"$/ do |text| 16 | long_press_when_element_exists("* {text CONTAINS[c] '#{text}'}") 17 | end 18 | -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/steps/date_picker_steps.rb: -------------------------------------------------------------------------------- 1 | 2 | Given /^I set the date to "(\d\d-\d\d-\d\d\d\d)" on DatePicker with index ([^\"]*)$/ do |date, index| 3 | set_date("android.widget.DatePicker index:#{index.to_i-1}", date) 4 | end 5 | 6 | Given /^I set the "([^\"]*)" date to "(\d\d-\d\d-\d\d\d\d)"$/ do |content_description, date| 7 | set_date("android.widget.DatePicker {contentDescription LIKE[c] '#{content_description}'}", date) 8 | end -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/steps/enter_text_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I enter "([^\"]*)" as "([^\"]*)"$/ do |text, content_description| 2 | enter_text("android.widget.EditText {contentDescription LIKE[c] '#{content_description}'}", text) 3 | end 4 | 5 | Then /^I enter "([^\"]*)" into "([^\"]*)"$/ do |text, content_description| 6 | enter_text("android.widget.EditText {contentDescription LIKE[c] '#{content_description}'}", text) 7 | end 8 | 9 | Then /^I enter "([^\"]*)" into input field number (\d+)$/ do |text, index| 10 | enter_text("android.widget.EditText index:#{index.to_i-1}", text) 11 | end 12 | 13 | Then /^I enter text "([^\"]*)" into field with id "([^\"]*)"$/ do |text, id| 14 | enter_text("android.widget.EditText id:'#{id}'", text) 15 | end 16 | 17 | Then /^I clear "([^\"]*)"$/ do |identifier| 18 | clear_text_in("android.widget.EditText marked:'#{identifier}'}") 19 | end 20 | 21 | Then /^I clear input field number (\d+)$/ do |index| 22 | clear_text_in("android.widget.EditText index:#{index.to_i-1}") 23 | end 24 | 25 | Then /^I clear input field with id "([^\"]*)"$/ do |id| 26 | clear_text_in("android.widget.EditText id:'#{id}'") 27 | end 28 | -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/steps/l10n_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I press text of translated l10n?key "?([^\"]*)"?$/ do |l10nkey| 2 | perform_action('press_l10n_element', l10nkey) 3 | end 4 | 5 | Then /^I press button of translated l10n?key "?([^\"]*)"?$/ do |l10nkey| 6 | perform_action('press_l10n_element', l10nkey,'button') 7 | end 8 | 9 | Then /^I press menu item of translated l10n?key "?([^\"]*)"?$/ do |l10nkey| 10 | perform_action('press_l10n_element', l10nkey,'menu_item') 11 | end 12 | 13 | Then /^I press toggle button of translated l10n?key "?([^\"]*)"?$/ do |l10nkey| 14 | perform_action('press_l10n_element', l10nkey,'toggle_button') 15 | end 16 | 17 | Then /^I wait for the translated "?([^\"]*)"? l10n?key to appear$/ do |l10nkey| 18 | perform_action('wait_for_l10n_element', l10nkey) 19 | end -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/steps/location_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I am in "([^\"]*)"$/ do |location| 2 | set_gps_coordinates_from_location(location) 3 | end 4 | 5 | Then /^I am at "([^\"]*)"$/ do |location| 6 | set_gps_coordinates_from_location(location) 7 | end 8 | 9 | Then /^I go to "([^\"]*)"$/ do |location| 10 | set_gps_coordinates_from_location(location) 11 | end 12 | 13 | Then /^I am at ([-+]?[0-9]*\.?[0-9]+), ([-+]?[0-9]*\.?[0-9]+)$/ do |latitude, longitude| 14 | set_gps_coordinates(latitude, longitude) 15 | end 16 | 17 | Then /^I go to ([-+]?[0-9]*\.?[0-9]+), ([-+]?[0-9]*\.?[0-9]+)$/ do |latitude, longitude| 18 | set_gps_coordinates(latitude, longitude) 19 | end 20 | -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/steps/map_steps.rb: -------------------------------------------------------------------------------- 1 | When /^I centre the map at (-?\d+\.\d+), (-?\d+\.\d+)$/ do | lat, lon | 2 | perform_action('set_map_center', lat, lon) 3 | end 4 | 5 | When /^I pan the map to (-?\d+\.\d+), (-?\d+\.\d+)$/ do | lat, lon | 6 | perform_action('pan_map_to', lat, lon) 7 | sleep(1) 8 | end 9 | 10 | When /^(?:I )?set the map zoom level to (\d+)$/ do | zoom | 11 | perform_action('set_map_zoom', zoom) 12 | sleep(0.2) 13 | end 14 | 15 | When /^(?:I )?zoom (in|out) on the map$/ do | zoom | 16 | perform_action('set_map_zoom', zoom) 17 | sleep(0.2) 18 | end 19 | 20 | Then /^the map zoom level should be (\d+)$/ do | zoom | 21 | result = perform_action('get_map_zoom') 22 | raise StandardError.new( "The map's zoom level should be #{zoom} but is #{result['message']}" ) unless zoom.eql?( result['message'] ) 23 | end 24 | 25 | When /^I tap the map marker "([^\"]*)"$/ do | marker_title | 26 | perform_action('tap_map_marker_by_title', marker_title, 60000) 27 | end 28 | 29 | When /^I double tap the map marker "([^\"]*)"$/ do | marker_title | 30 | perform_action('tap_map_marker_by_title', marker_title, 60000) 31 | sleep(0.4) 32 | perform_action('tap_map_marker_by_title', marker_title, 100) 33 | end 34 | 35 | When /^I tap away from the markers$/ do 36 | perform_action('tap_map_away_from_markers') 37 | end 38 | 39 | Then /^I should see the following markers:$/ do | marker_table | 40 | verify_map_markers( marker_table ) 41 | end 42 | 43 | Then /^the map should be centred at (-?\d+\.\d+), (-?\d+\.\d+)$/ do | lat, lon | 44 | result = perform_action('get_map_center') 45 | bonus_info = result['bonusInformation'] 46 | actual_lat = bonus_info[0].to_f 47 | actual_lon = bonus_info[1].to_f 48 | lat = lat.to_f 49 | lon = lon.to_f 50 | tol = 0.00001 51 | if( (lat - actual_lat).abs > tol || (lon - actual_lon).abs > tol ) 52 | raise StandardError.new( "The map should have been centred on: #{lat},#{lon} but was actually centred on #{bonus_info.inspect}" ) 53 | end 54 | end 55 | 56 | Then /^the map marker "([^\"]*)" should be highlighted$/ do | marker_title | 57 | result = perform_action('get_map_marker', marker_title) 58 | result = result['message'] 59 | result = JSON.parse( result ) 60 | raise StandardError.new( "The marker '#{marker_title}' was found, but is not highlighted" ) unless result['focused'] 61 | end 62 | -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/steps/navigation_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I go back$/ do 2 | press_back_button 3 | end 4 | 5 | Then /^I press the menu key$/ do 6 | press_menu_button 7 | end 8 | 9 | Then /^I press the enter button$/ do 10 | press_user_action_button 11 | # Or, possibly, press_enter_button 12 | end 13 | 14 | 15 | Then /^I swipe left$/ do 16 | perform_action('swipe', 'left') 17 | end 18 | 19 | Then /^I swipe right$/ do 20 | perform_action('swipe', 'right') 21 | end 22 | 23 | Then /^I select "([^\"]*)" from the menu$/ do |identifier| 24 | select_options_menu_item(identifier) 25 | end 26 | 27 | Then /^I select tab number (\d+)$/ do | tab | 28 | touch("android.widget.TabWidget descendant TextView index:#{tab.to_i-1}") 29 | end 30 | 31 | # @param - the "tag" associated with the tab, or the text within the tab label 32 | Then /^I select the "([^\"]*)" tab$/ do | tab | 33 | touch("android.widget.TabWidget descendant TextView {text LIKE[c] '#{tab}'}") 34 | end 35 | 36 | Then /^I scroll down$/ do 37 | scroll_down 38 | end 39 | 40 | Then /^I scroll up$/ do 41 | scroll_up 42 | end 43 | 44 | Then /^I drag from (\d+):(\d+) to (\d+):(\d+) moving with (\d+) steps$/ do |from_x, from_y, to_x, to_y, steps| 45 | perform_action('drag', from_x, to_x, from_y, to_y, steps) 46 | end 47 | 48 | -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/steps/press_button_steps.rb: -------------------------------------------------------------------------------- 1 | Given /^I press the "([^\"]*)" button$/ do |text| 2 | tap_when_element_exists("android.widget.Button {text CONTAINS[c] '#{text}'}") 3 | end 4 | 5 | Then /^I press button number (\d+)$/ do |index| 6 | tap_when_element_exists("android.widget.Button index:#{index.to_i-1}") 7 | end 8 | 9 | Then /^I press image button number (\d+)$/ do |index| 10 | tap_when_element_exists("android.widget.ImageButton index:#{index.to_i-1}") 11 | end 12 | 13 | Then /^I press view with id "([^\"]*)"$/ do |id| 14 | tap_when_element_exists("* id:'#{id}'") 15 | end 16 | 17 | Then /^I press "([^\"]*)"$/ do |identifier| 18 | tap_when_element_exists("* marked:'#{identifier}'") 19 | end 20 | 21 | Then /^I click on screen (\d+)% from the left and (\d+)% from the top$/ do |x, y| 22 | perform_action('click_on_screen', x, y) 23 | end 24 | 25 | Then /^I touch the "([^\"]*)" text$/ do |text| 26 | tap_when_element_exists("* {text CONTAINS[c] '#{text}'}") 27 | end 28 | 29 | Then /^I press list item number (\d+)$/ do |index| 30 | step_deprecated 31 | 32 | tap_when_element_exists("android.widget.ListView index:0 android.widget.TextView index:#{index.to_i-1}") 33 | end 34 | 35 | Then /^I long press list item number (\d+)$/ do |index| 36 | step_deprecated 37 | 38 | long_press_when_element_exists("android.widget.ListView index:0 android.widget.TextView index:#{index.to_i-1}") 39 | end 40 | -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/steps/progress_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I wait for progress$/ do 2 | wait_for_element_does_not_exist("android.widget.ProgressBar") 3 | end 4 | 5 | Then /^I wait$/ do 6 | sleep 2 7 | end 8 | 9 | 10 | Then /^I wait for (\d+) seconds$/ do |seconds| 11 | sleep(seconds.to_i) 12 | end 13 | 14 | Then /^I wait for 1 second$/ do 15 | sleep 1 16 | end 17 | 18 | Then /^I wait for a second$/ do 19 | sleep 1 20 | end 21 | 22 | Then /^I wait for "([^\"]*)" to appear$/ do |text| 23 | wait_for_text(text) 24 | end 25 | 26 | Then /^I wait up to (\d+) seconds for "([^\"]*)" to appear$/ do |timeout, text| 27 | wait_for_text(text, timeout: timeout.to_i) 28 | end 29 | 30 | Then /^I wait to see "([^\"]*)"$/ do |text| 31 | wait_for_text(text) 32 | end 33 | 34 | Then /^I wait up to (\d+) seconds to see "([^\"]*)"$/ do |timeout, text| 35 | wait_for_text(text, timeout: timeout.to_i) 36 | end 37 | 38 | Then /^I wait for the "([^\"]*)" button to appear$/ do |identifier| 39 | wait_for_element_exists("android.widget.Button marked:'#{identifier}'"); 40 | end 41 | 42 | Then /^I wait for the view with id "([^\"]*)" to appear$/ do |id| 43 | wait_for_element_exists("* id:'#{id}'") 44 | end 45 | 46 | Then /^I wait for the "([^\"]*)" view to appear$/ do |text| 47 | wait_for_element_exists("* marked:'#{text}'") 48 | end 49 | 50 | 51 | Then /^I wait for the "([^\"]*)" screen to appear$/ do |activity_name| 52 | wait_for_activity(activity_name) 53 | end 54 | 55 | Then /^I wait upto (\d+) seconds for the "([^\"]*)" screen to appear$/ do |timeout, activity_name| 56 | wait_for_activity(activity_name, timeout: timeout.to_i) 57 | end 58 | 59 | Then /^I wait up to (\d+) seconds for the "([^\"]*)" screen to appear$/ do |timeout, activity_name| 60 | wait_for_activity(activity_name, timeout: timeout.to_i) 61 | end 62 | 63 | # @param - the "tag" associated with the tab, or the text within the tab label 64 | Then /^I wait for the "([^\"]*)" tab to appear$/ do |tab| 65 | wait_for do 66 | query("android.widget.TabWidget descendant TextView {text LIKE[c] '#{tab}'}", :isSelected).first 67 | end 68 | end -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/steps/screenshot_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^take picture$/ do 2 | screenshot_embed 3 | end 4 | 5 | Then /^I take a picture$/ do 6 | screenshot_embed 7 | end 8 | 9 | Then /^I take a screenshot$/ do 10 | screenshot_embed 11 | end 12 | -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/steps/search_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I enter "([^\"]*)" into search field$/ do |text| 2 | enter_text("android.widget.SearchView index:0", text) 3 | end 4 | 5 | Then /^I enter "([^\"]*)" into search field number (\d+)$/ do |text, number| 6 | enter_text("android.widget.SearchView index:#{number.to_i-1}", text) 7 | end 8 | -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/steps/spinner_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I select "([^\"]*)" from "([^\"]*)"$/ do |item_identifier, spinner_identifier| 2 | spinner = query("android.widget.Spinner marked:'#{spinner_identifier}'") 3 | 4 | if spinner.empty? 5 | tap_when_element_exists("android.widget.Spinner * marked:'#{spinner_identifier}'") 6 | else 7 | touch(spinner) 8 | end 9 | 10 | tap_when_element_exists("android.widget.PopupWindow$PopupViewContainer * marked:'#{item_identifier}'") 11 | end -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/steps/time_picker_steps.rb: -------------------------------------------------------------------------------- 1 | 2 | Given /^I set the time to "(\d\d:\d\d)" on TimePicker with index ([^\"]*)$/ do |time, index| 3 | set_time("android.widget.TimePicker index:#{index.to_i-1}", time) 4 | end 5 | 6 | Given /^I set the "([^\"]*)" time to "(\d\d:\d\d)"$/ do |content_description, time| 7 | set_time("android.widget.TimePicker {contentDescription LIKE[c] '#{content_description}'}", time) 8 | end 9 | -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/text_helpers.rb: -------------------------------------------------------------------------------- 1 | module Calabash 2 | module Android 3 | module TextHelpers 4 | def has_text?(text) 5 | !query("* {text CONTAINS[c] '#{text}'}").empty? 6 | end 7 | 8 | def assert_text(text, should_find = true) 9 | raise "Text \"#{text}\" was #{should_find ? 'not ' : ''}found." if has_text?(text) ^ should_find 10 | 11 | true 12 | end 13 | 14 | def keyboard_enter_text(text, options = {}) 15 | wait_for_keyboard 16 | perform_action('keyboard_enter_text', text) 17 | end 18 | 19 | def keyboard_enter_char(character, options = {}) 20 | keyboard_enter_text(character[0,1], options) 21 | end 22 | 23 | # Appends `text` into the first view matching `uiquery`. 24 | def enter_text(uiquery, text, options = {}) 25 | tap_when_element_exists(uiquery, options) 26 | sleep 0.5 27 | set_selection(-1, -1) 28 | keyboard_enter_text(text, options) 29 | end 30 | 31 | def clear_text_in(query_string, options={}) 32 | touch(query_string, options) 33 | sleep 0.5 34 | clear_text(options) 35 | end 36 | 37 | # Clears the text of the currently focused view. 38 | def clear_text(options={}) 39 | set_selection(-1, -1) 40 | sleep 0.1 41 | perform_action("delete_surrounding_text", -1, 0) 42 | end 43 | 44 | def escape_backslashes(str) 45 | backslash = "\\" 46 | str.gsub(backslash, backslash*4) 47 | end 48 | 49 | def escape_newlines(str) 50 | newline = "\n" 51 | str.gsub(newline, "\\n") 52 | end 53 | 54 | def escape_quotes(str) 55 | str.gsub("'", "\\\\'") 56 | end 57 | 58 | def escape_string(str) 59 | escape_newlines(escape_quotes(escape_backslashes(str))) 60 | end 61 | 62 | # Sets the selection of the currently focused view. 63 | # 64 | # @param [Integer] selection_start The start of the selection, can be 65 | # negative to begin counting from the end of the string. 66 | # @param [Integer] selection_end The end of the selection, can be 67 | # negative to begin counting from the end of the string. 68 | def set_selection(selection_start, selection_end) 69 | perform_action("set_selection", selection_start, selection_end) 70 | end 71 | 72 | def keyboard_visible? 73 | input_method = `#{default_device.adb_command} shell dumpsys input_method`.force_encoding('UTF-8') 74 | shown = input_method.each_line.grep(/mInputShown\s*=\s*(.*)/){$1}.first.chomp 75 | 76 | if shown == "true" 77 | true 78 | elsif shown == "false" 79 | false 80 | else 81 | raise "Could not detect keyboard visibility. '#{shown}'" 82 | end 83 | end 84 | 85 | def wait_for_keyboard(opt={}) 86 | params = opt.clone 87 | params[:timeout_message] ||= "Timed out waiting for the keyboard to appear" 88 | params[:timeout] ||= 5 89 | 90 | wait_for(params) do 91 | keyboard_visible? 92 | end 93 | end 94 | end 95 | end 96 | end 97 | -------------------------------------------------------------------------------- /ruby-gem/lib/calabash-android/utils.rb: -------------------------------------------------------------------------------- 1 | require 'zip' 2 | 3 | module Calabash 4 | module Utils 5 | def self.with_silent_zip(&block) 6 | previous_value = false 7 | 8 | if Zip.respond_to?(:warn_invalid_date) 9 | previous_value = Zip.warn_invalid_date 10 | end 11 | 12 | if Zip.respond_to?(:warn_invalid_date=) 13 | Zip.warn_invalid_date = false 14 | end 15 | 16 | r = block.call 17 | 18 | if Zip.respond_to?(:warn_invalid_date=) 19 | Zip.warn_invalid_date = previous_value 20 | end 21 | 22 | r 23 | end 24 | end 25 | end -------------------------------------------------------------------------------- /ruby-gem/spec/lib/dot_dir_spec.rb: -------------------------------------------------------------------------------- 1 | describe Calabash::Android::DotDir do 2 | 3 | let(:home_dir) { "./tmp/dot-calabash-examples" } 4 | let(:dot_dir) { File.join(home_dir, ".calabash") } 5 | 6 | before do 7 | allow(Calabash::Android::Environment).to receive(:user_home_directory).and_return home_dir 8 | FileUtils.rm_rf(home_dir) 9 | end 10 | 11 | it ".directory" do 12 | path = Calabash::Android::DotDir.directory 13 | 14 | expect(File.exist?(path)).to be_truthy 15 | end 16 | end 17 | 18 | -------------------------------------------------------------------------------- /ruby-gem/spec/lib/retryable_spec.rb: -------------------------------------------------------------------------------- 1 | require 'stringio' 2 | 3 | describe Calabash::Android::Retry do 4 | describe "#retry" do 5 | it 'retries' do 6 | expect { 7 | Calabash::Android::Retry.retry({ tries: 2, interval: 0.01 }) do 8 | raise "foo" 9 | end 10 | }.to raise_error(RuntimeError) 11 | end 12 | 13 | it 'succeeds' do 14 | expect { 15 | nr = 0 16 | Calabash::Android::Retry.retry({ tries: 2, interval: 0.01 }) do 17 | nr = nr + 1 18 | if nr == 2 19 | :ok 20 | else 21 | raise :fail 22 | end 23 | end 24 | }.not_to raise_error 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /ruby-gem/spec/lib/utils_spec.rb: -------------------------------------------------------------------------------- 1 | describe Calabash::Utils do 2 | describe 'with_silent_zip' do 3 | it 'is a method that takes a block and evaluates it' do 4 | expect(Calabash::Utils.with_silent_zip do 5 | 2+2 6 | end).to eq(4) 7 | end 8 | 9 | it 'disables zip warnings about invalid date if zip responds to it' do 10 | stub_const("Zip", Module.new do 11 | @warn_invalid_date = true 12 | 13 | def self.warn_invalid_date 14 | @warn_invalid_date 15 | end 16 | 17 | def self.warn_invalid_date=(value) 18 | @warn_invalid_date = value 19 | end 20 | end) 21 | 22 | expect(Calabash::Utils.with_silent_zip do 23 | Zip.warn_invalid_date 24 | end).to eq(false) 25 | end 26 | 27 | it 'does not try to disable zip warnings about invalid date if zip does not respond to it' do 28 | stub_const("Zip", Module.new do 29 | end) 30 | 31 | expect(Calabash::Utils.with_silent_zip do 32 | 2+2 33 | end).to eq(4) 34 | end 35 | 36 | it 'resets zip warnings about invalid date if zip responds to it' do 37 | stub_const("Zip", Module.new do 38 | @warn_invalid_date = :default_value 39 | 40 | def self.warn_invalid_date 41 | @warn_invalid_date 42 | end 43 | 44 | def self.warn_invalid_date=(value) 45 | @warn_invalid_date = value 46 | end 47 | end) 48 | 49 | expect(Calabash::Utils.with_silent_zip do 50 | Zip.warn_invalid_date 51 | end).to eq(false) 52 | 53 | expect(Zip.warn_invalid_date).to eq(:default_value) 54 | end 55 | end 56 | end -------------------------------------------------------------------------------- /ruby-gem/spec/lib/wait_helpers_spec.rb: -------------------------------------------------------------------------------- 1 | 2 | describe Calabash::Android::WaitHelpers do 3 | 4 | it "can override DEFAULT_OPTS" do 5 | original = Calabash::Android::WaitHelpers::DEFAULT_OPTS[:timeout] 6 | begin 7 | Calabash::Android::WaitHelpers::DEFAULT_OPTS[:timeout] = 10 8 | expect(Calabash::Android::WaitHelpers::DEFAULT_OPTS[:timeout]).to be == 10 9 | ensure 10 | Calabash::Android::WaitHelpers::DEFAULT_OPTS[:timeout] = original 11 | end 12 | end 13 | end 14 | 15 | --------------------------------------------------------------------------------