calabash 2.0.0.pre1 → 2.0.0.prelegacy2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -38
  3. data/lib/calabash.rb +18 -5
  4. data/lib/calabash/android.rb +3 -0
  5. data/lib/calabash/android/adb.rb +25 -1
  6. data/lib/calabash/android/application.rb +14 -3
  7. data/lib/calabash/android/build/builder.rb +15 -2
  8. data/lib/calabash/android/build/java_keystore.rb +10 -0
  9. data/lib/calabash/android/build/resigner.rb +4 -0
  10. data/lib/calabash/android/build/test_server.rb +2 -0
  11. data/lib/calabash/android/defaults.rb +1 -0
  12. data/lib/calabash/android/device.rb +42 -1
  13. data/lib/calabash/android/environment.rb +10 -0
  14. data/lib/calabash/android/interactions.rb +2 -0
  15. data/lib/calabash/android/legacy.rb +149 -0
  16. data/lib/calabash/android/lib/TestServer.apk +0 -0
  17. data/lib/calabash/android/life_cycle.rb +1 -0
  18. data/lib/calabash/android/physical_buttons.rb +8 -0
  19. data/lib/calabash/android/screenshot.rb +1 -0
  20. data/lib/calabash/android/scroll.rb +110 -0
  21. data/lib/calabash/android/server.rb +3 -1
  22. data/lib/calabash/android/text.rb +6 -0
  23. data/lib/calabash/application.rb +29 -0
  24. data/lib/calabash/cli/build.rb +15 -1
  25. data/lib/calabash/cli/console.rb +9 -5
  26. data/lib/calabash/cli/generate.rb +3 -0
  27. data/lib/calabash/cli/helpers.rb +7 -1
  28. data/lib/calabash/cli/resign.rb +1 -0
  29. data/lib/calabash/cli/run.rb +10 -6
  30. data/lib/calabash/cli/setup_keystore.rb +2 -0
  31. data/lib/calabash/color.rb +7 -0
  32. data/lib/calabash/defaults.rb +1 -0
  33. data/lib/calabash/device.rb +7 -0
  34. data/lib/calabash/environment.rb +1 -0
  35. data/lib/calabash/http/retriable_client.rb +2 -0
  36. data/lib/calabash/interactions.rb +1 -0
  37. data/lib/calabash/ios.rb +2 -0
  38. data/lib/calabash/ios/application.rb +8 -1
  39. data/lib/calabash/ios/conditions.rb +3 -0
  40. data/lib/calabash/ios/date_picker.rb +412 -0
  41. data/lib/calabash/ios/defaults.rb +1 -0
  42. data/lib/calabash/ios/device.rb +1 -0
  43. data/lib/calabash/ios/device/device_implementation.rb +16 -11
  44. data/lib/calabash/ios/device/ipad_1x_2x_mixin.rb +253 -0
  45. data/lib/calabash/ios/device/keyboard_mixin.rb +2 -0
  46. data/lib/calabash/ios/device/rotation_mixin.rb +1 -0
  47. data/lib/calabash/ios/device/routes/condition_route_mixin.rb +1 -0
  48. data/lib/calabash/ios/device/routes/map_route_mixin.rb +1 -0
  49. data/lib/calabash/ios/device/routes/response_parser.rb +1 -0
  50. data/lib/calabash/ios/device/routes/uia_route_mixin.rb +44 -6
  51. data/lib/calabash/ios/device/text_mixin.rb +2 -0
  52. data/lib/calabash/ios/device/uia_keyboard_mixin.rb +9 -0
  53. data/lib/calabash/ios/device/uia_mixin.rb +1 -0
  54. data/lib/calabash/ios/interactions.rb +30 -1
  55. data/lib/calabash/ios/runtime.rb +8 -0
  56. data/lib/calabash/ios/text.rb +5 -45
  57. data/lib/calabash/legacy.rb +7 -0
  58. data/lib/calabash/lib/skeleton/config/cucumber.yml +1 -3
  59. data/lib/calabash/lib/skeleton/features/support/env.rb +15 -1
  60. data/lib/calabash/life_cycle.rb +19 -2
  61. data/lib/calabash/location.rb +2 -0
  62. data/lib/calabash/page.rb +13 -0
  63. data/lib/calabash/patch.rb +1 -0
  64. data/lib/calabash/query_result.rb +4 -0
  65. data/lib/calabash/text.rb +53 -0
  66. data/lib/calabash/utility.rb +4 -4
  67. data/lib/calabash/version.rb +1 -1
  68. data/lib/calabash/wait.rb +4 -0
  69. metadata +119 -115
@@ -15,6 +15,16 @@ module Calabash
15
15
  # @!visibility private
16
16
  class InvalidJavaSDKHome < RuntimeError; end
17
17
 
18
+ # A URI that points to the embedded Calabash server in the app under test.
19
+ #
20
+ # The default value is 'http://localhost:34777'.
21
+ #
22
+ # You can control the value of this variable by setting the `CAL_ENDPOINT`
23
+ # variable.
24
+ #
25
+ # @todo Maybe rename this to CAL_SERVER_URL or CAL_SERVER?
26
+ DEVICE_ENDPOINT = URI.parse((variable('CAL_ENDPOINT') || 'http://127.0.0.1:34777'))
27
+
18
28
  private
19
29
 
20
30
  def self.set_android_dependencies(android_dependencies)
@@ -3,6 +3,8 @@ require 'time'
3
3
 
4
4
  module Calabash
5
5
  module Android
6
+
7
+ # Interactions with your app that are specific to Android.
6
8
  module Interactions
7
9
  # Go back. If the keyboard is shown, it will be dismissed.
8
10
  def go_back
@@ -0,0 +1,149 @@
1
+ if ENV["APP_PATH"]
2
+ Calabash::Environment::APP_PATH = ENV["APP_PATH"]
3
+ end
4
+
5
+ if ENV["TEST_APP_PATH"]
6
+ Calabash::Environment::TEST_SERVER_PATH = ENV["TEST_APP_PATH"]
7
+ end
8
+
9
+
10
+ module Calabash
11
+ module Android
12
+ class Device < Calabash::Device
13
+ def screen_on?
14
+ true
15
+ end
16
+
17
+ def installed_apps
18
+ packages = installed_packages
19
+
20
+ packages.map{|p| {package: p, path: ''}}
21
+ end
22
+
23
+ def md5_checksum(file_path)
24
+ "samplechecksum"
25
+ end
26
+
27
+ def adb_install_app(application)
28
+ @logger.log "Patch: Installing #{application.path}"
29
+
30
+ begin
31
+ result = adb.command("install #{application.path}", timeout: 60)
32
+ rescue ADB::ADBCallError => e
33
+ raise "Failed to install the application on device: '#{e.message}'"
34
+ end
35
+
36
+ if result.lines.last.downcase.chomp != 'success'
37
+ raise "Could not install app '#{application.identifier}': #{result.chomp}"
38
+ end
39
+
40
+ unless installed_packages.include?(application.identifier)
41
+ raise "App '#{application.identifier}' was not installed"
42
+ end
43
+ end
44
+
45
+ def _start_app(application, options={})
46
+ env_options = {}
47
+
48
+ options.fetch(:extras, {}).each do |k, v|
49
+ env_options[k] = v
50
+ end
51
+
52
+ env_options[:target_package] = application.identifier
53
+
54
+ if options[:activity]
55
+ env_options[:main_activity] = options[:activity]
56
+ end
57
+
58
+ env_options[:test_server_port] = server.test_server_port
59
+ env_options[:class] = options.fetch(:class, 'sh.calaba.instrumentationbackend.InstrumentationBackend')
60
+
61
+ if application.test_server.nil?
62
+ raise 'Invalid application. No test-server set.'
63
+ end
64
+
65
+ unless app_installed?(application.identifier)
66
+ raise "The application '#{application.identifier}' is not installed"
67
+ end
68
+
69
+ unless app_installed?(application.test_server.identifier)
70
+ raise "The test-server '#{application.test_server.identifier}' is not installed"
71
+ end
72
+
73
+ installed_app = installed_apps.find{|app| app[:package] == application.identifier}
74
+ installed_app_md5_checksum = md5_checksum(installed_app[:path])
75
+
76
+ if application.md5_checksum != installed_app_md5_checksum
77
+ raise "The specified app is not the same as the installed app (#{application.md5_checksum} != #{installed_app_md5_checksum})."
78
+ end
79
+
80
+ installed_test_server = installed_apps.find{|app| app[:package] == application.test_server.identifier}
81
+ installed_test_server_md5_checksum = md5_checksum(installed_test_server[:path])
82
+
83
+ if application.test_server.md5_checksum != installed_test_server_md5_checksum
84
+ raise "The specified test-server is not the same as the installed test-server (#{application.test_server.md5_checksum} != #{installed_test_server_md5_checksum})."
85
+ end
86
+
87
+ # We have to forward the port ourselves, as an old test-server could be
88
+ # running on the old port. If the retriable client was able to
89
+ # determine if the port had been forwarded, we would not need this.
90
+ port_forward(server.endpoint.port, server.test_server_port)
91
+
92
+ # For now, the test-server cannot rebind an existing socket.
93
+ # So we have to stop any running Calabash servers from the client
94
+ # for now.
95
+ if test_server_responding?
96
+ @logger.log("A test-server is already running on port #{server.test_server_port}")
97
+ @logger.log("Trying to stop it")
98
+
99
+ begin
100
+ _stop_app
101
+ rescue => _
102
+ raise 'Failed to stop old running test-server'
103
+ end
104
+ end
105
+
106
+ extras = ''
107
+
108
+ env_options.each_pair do |key, val|
109
+ extras = "#{extras} -e #{key.to_s} #{val.to_s}"
110
+ end
111
+
112
+ begin
113
+ instrument(application,
114
+ 'sh.calaba.instrumentationbackend.CalabashInstrumentationTestRunner',
115
+ extras)
116
+ rescue ADB::ADBCallError => e
117
+ raise "Failed to start the application: '#{e.stderr.lines.first.chomp}'"
118
+ end
119
+
120
+ begin
121
+ Retriable.retriable(tries: 30, interval: 1, timeout: 30, on: RetryError) do
122
+ unless test_server_responding?
123
+ raise RetryError
124
+ end
125
+ end
126
+ rescue RetryError => _
127
+ @logger.log('Could not contact test-server', :error)
128
+ @logger.log('For information, see the adb logcat', :error)
129
+ raise 'Could not contact test-server'
130
+ end
131
+
132
+ begin
133
+ Retriable.retriable(tries: 10, interval: 1, timeout: 10) do
134
+ unless test_server_ready?
135
+ raise RetryError
136
+ end
137
+ end
138
+ rescue RetryError => _
139
+ @logger.log('Test-server was never ready', :error)
140
+ @logger.log('For information, see the adb logcat', :error)
141
+ raise 'Test-server was never ready'
142
+ end
143
+
144
+ # Return true to avoid cluttering the console
145
+ true
146
+ end
147
+ end
148
+ end
149
+ end
@@ -1,5 +1,6 @@
1
1
  module Calabash
2
2
  module Android
3
+ # Android specific life cyle methods.
3
4
  module LifeCycle
4
5
  # Resume an application. If the application is already focused, nothing
5
6
  # will happen.
@@ -7,35 +7,43 @@ module Calabash
7
7
  # @!visibility private
8
8
  module PhysicalButtons
9
9
 
10
+ # @!visibility private
10
11
  def press_button(key)
11
12
  Device.default.perform_action('press_key', key)
12
13
  true
13
14
  end
14
15
 
16
+ # @!visibility private
15
17
  def press_back_button
16
18
  press_button('KEYCODE_BACK')
17
19
  end
18
20
 
21
+ # @!visibility private
19
22
  def press_menu_button
20
23
  press_button('KEYCODE_MENU')
21
24
  end
22
25
 
26
+ # @!visibility private
23
27
  def press_down_button
24
28
  press_button('KEYCODE_DPAD_DOWN')
25
29
  end
26
30
 
31
+ # @!visibility private
27
32
  def press_up_button
28
33
  press_button('KEYCODE_DPAD_UP')
29
34
  end
30
35
 
36
+ # @!visibility private
31
37
  def press_left_button
32
38
  press_button('KEYCODE_DPAD_LEFT')
33
39
  end
34
40
 
41
+ # @!visibility private
35
42
  def press_right_button
36
43
  press_button('KEYCODE_DPAD_RIGHT')
37
44
  end
38
45
 
46
+ # @!visibility private
39
47
  def press_enter_button
40
48
  press_button('KEYCODE_ENTER')
41
49
  end
@@ -2,6 +2,7 @@ module Calabash
2
2
  module Android
3
3
  # @!visibility private
4
4
  module Screenshot
5
+ # @!visibility private
5
6
  SCREENSHOT_JAR_PATH = File.join(File.dirname(__FILE__), 'lib', 'screenshot_taker.jar')
6
7
  end
7
8
  end
@@ -1,5 +1,115 @@
1
1
  module Calabash
2
2
  module Android
3
+ # Scrolling invokes methods on the views to get to the right items. This
4
+ # behaviour is not doable by the users. For real gestures interacting with
5
+ # the screen, see {Calabash::Gestures}.
6
+ module Scroll
7
+ # Scroll the first view matched by `query` in `direction`.
8
+ #
9
+ # @param [String, Hash, Calabash::Query] query A query describing the
10
+ # view to scroll.
11
+ # @param [Symbol] direction The direction to scroll. Valid directions are:
12
+ # :up, :down, :left, and :right
13
+ def scroll(query, direction)
14
+ allowed_directions = [:up, :down, :left, :right]
3
15
 
16
+ dir_symbol = direction.to_sym
17
+
18
+ unless allowed_directions.include?(dir_symbol)
19
+ raise ArgumentError,
20
+ "Expected '#{direction}' to be one of #{allowed_directions.join(',')}"
21
+ end
22
+
23
+ view = wait_for_view(query, timeout: Calabash::Gestures::DEFAULT_GESTURE_WAIT_TIMEOUT)
24
+
25
+ result = query("#{Query.new(query)} index:0", :getFirstVisiblePosition)
26
+
27
+ if result.length == 0
28
+ raise "Failed to scroll view '#{query}'"
29
+ end
30
+
31
+ if result.first.is_a?(Hash) && result.first.has_key?("error")
32
+ # View is not of type android.widget.AbsListView
33
+ scroll_x = 0
34
+ scroll_y = 0
35
+ width = view['rect']['width']
36
+ height = view['rect']['height']
37
+
38
+ if direction == :up
39
+ scroll_y = -height / 2
40
+ elsif direction == :down
41
+ scroll_y = height / 2
42
+ elsif direction == :left
43
+ scroll_x = -width / 2
44
+ elsif direction == :right
45
+ scroll_x = width / 2
46
+ end
47
+
48
+ result = query("#{Query.new(query)} index:0", {scrollBy: [scroll_x.to_i, scroll_y.to_i]})
49
+
50
+ if result.length == 0
51
+ raise "Failed to scroll view '#{query}'"
52
+ end
53
+
54
+ if result.first.is_a?(Hash) && result.first.has_key?('error')
55
+ raise "Failed to scroll view: #{result.first['error']}"
56
+ end
57
+ else
58
+ # View is of type android.widget.AbsListView
59
+ unless [:up, :down].include?(dir_symbol)
60
+ raise ArgumentError,
61
+ "Can only scroll listviews :up or :down, not #{direction}"
62
+ end
63
+
64
+ first_position = result.first.to_i
65
+ result = query("#{Query.new(query)} index:0", :getLastVisiblePosition)
66
+
67
+ if result.length == 0
68
+ raise "Failed to scroll view '#{Query.new(query)}'"
69
+ end
70
+
71
+ last_position = result.first.to_i
72
+
73
+
74
+ selection_index = if direction == :up
75
+ [first_position + [first_position - last_position + 1, -1].min, 0].max
76
+ elsif direction == :down
77
+ first_position + [last_position - first_position, 1].max
78
+ end
79
+
80
+ result = query("#{Query.new(query)} index:0", setSelection: selection_index)
81
+
82
+ if result.length == 0
83
+ raise "Failed to scroll view '#{query}'"
84
+ end
85
+ end
86
+
87
+ true
88
+ end
89
+
90
+ # Scroll to `item` in `query`. If `query` matches multiple views, the
91
+ # first view matching `query` is scrolled.
92
+ #
93
+ # @param [String, Hash, Calabash::Query] query A query describing the
94
+ # view to scroll.
95
+ # @param [Numeric] item The item number to scroll to. This value is
96
+ # 0-indexed.
97
+ def scroll_to_row(query, item)
98
+ wait_for_view(query, timeout: Calabash::Gestures::DEFAULT_GESTURE_WAIT_TIMEOUT)
99
+ result = query("#{Query.new(query)} index:0", setSelection: item)
100
+
101
+ if result.length == 0
102
+ raise "Failed to scroll view '#{query}'"
103
+ end
104
+
105
+ result.length.times do |i|
106
+ if result[i].is_a?(Hash) && result[i].has_key?('error')
107
+ raise "Unable to scroll view number '#{i}' matching '#{query}'. #{result[i]['error']}"
108
+ end
109
+ end
110
+
111
+ true
112
+ end
113
+ end
4
114
  end
5
115
  end
@@ -2,8 +2,10 @@ module Calabash
2
2
  module Android
3
3
  # A representation of the Calabash Android test server.
4
4
  class Server < ::Calabash::Server
5
+ # The default Android test server.
5
6
  def self.default
6
- Server.new(URI.parse('http://127.0.0.1:33765'))
7
+ endpoint = Environment::DEVICE_ENDPOINT
8
+ Server.new(endpoint)
7
9
  end
8
10
  end
9
11
  end
@@ -1,5 +1,6 @@
1
1
  module Calabash
2
2
  module Android
3
+ # Android specific text-related actions.
3
4
  module Text
4
5
  # Dismisses the current keyboard. This is equivalent to the user
5
6
  # pressing the back button if the keyboard is showing. If the keyboard is
@@ -41,6 +42,11 @@ module Calabash
41
42
  Device.default.perform_action('press_user_action_button', action_key.to_s)
42
43
  end
43
44
  end
45
+
46
+ # @!visibility private
47
+ def _keyboard_visible?
48
+ Device.default.keyboard_visible?
49
+ end
44
50
  end
45
51
  end
46
52
  end
@@ -21,6 +21,21 @@ module Calabash
21
21
 
22
22
  attr_reader :path
23
23
 
24
+ # Get the application from the default environment.
25
+ def self.default_from_environment
26
+ application_path = Environment::APP_PATH
27
+
28
+ if application_path.nil?
29
+ raise 'No application path is set. Specify application with environment variable CAL_APP'
30
+ end
31
+
32
+ unless File.exist?(application_path)
33
+ raise "Application '#{application_path}' does not exist"
34
+ end
35
+
36
+ Application.from_path(application_path)
37
+ end
38
+
24
39
  # Create an application from a path
25
40
  #
26
41
  # @return [Calabash::Android::Application, Calabash::IOS::Application] An
@@ -51,6 +66,20 @@ module Calabash
51
66
  ensure_application_path
52
67
  end
53
68
 
69
+ # Is this application an android application
70
+ #
71
+ # @return [Boolean] true if this application is an android application
72
+ def android_application?
73
+ false
74
+ end
75
+
76
+ # Is this application an iOS application
77
+ #
78
+ # @return [Boolean] true if this application is an iOS application
79
+ def ios_application?
80
+ false
81
+ end
82
+
54
83
  # @!visibility private
55
84
  def to_s
56
85
  "#<Application #{path}>"
@@ -2,10 +2,24 @@ module Calabash
2
2
  module CLI
3
3
  # @!visibility private
4
4
  module Build
5
+ # @!visibility private
5
6
  def parse_build_arguments!
6
7
  fail('Should only build test-server for Android') unless @platform.nil? || @platform == :android
7
8
 
8
9
  application = @arguments.shift
10
+ test_server_path = nil
11
+
12
+ arg = @arguments.shift
13
+
14
+ if arg != nil
15
+ if arg == '-o'
16
+ test_server_path = @arguments.shift
17
+
18
+ if test_server_path == nil
19
+ raise 'Expected an output path for the test-server'
20
+ end
21
+ end
22
+ end
9
23
 
10
24
  if application.nil?
11
25
  fail('Must supply application as first parameter to build', :build)
@@ -18,7 +32,7 @@ module Calabash
18
32
  case extension
19
33
  when '.apk'
20
34
  set_platform!(:android)
21
- Calabash::Android::Build::Builder.new(application_path).build
35
+ Calabash::Android::Build::Builder.new(application_path).build(test_server_path)
22
36
  when '.ipa', '.app'
23
37
  set_platform!(:ios)
24
38
  fail('Should only build test-server for Android')