calabash 2.0.0.pre1 → 2.0.0.prelegacy2

Sign up to get free protection for your applications and to get access to all the features.
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')