kraken-mobile 1.0.2 → 1.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +251 -75
  3. data/bin/kraken-mobile +64 -67
  4. data/bin/kraken_mobile_calabash_android.rb +39 -0
  5. data/bin/kraken_mobile_helpers.rb +107 -0
  6. data/bin/kraken_mobile_setup.rb +138 -0
  7. data/calabash-android-features-skeleton/step_definitions/mobile_steps.rb +1 -0
  8. data/calabash-android-features-skeleton/support/app_installation_hooks.rb +2 -0
  9. data/calabash-android-features-skeleton/support/app_life_cycle_hooks.rb +3 -4
  10. data/calabash-android-features-skeleton/support/env.rb +1 -1
  11. data/calabash-android-features-skeleton/web/step_definitions/web_steps.rb +3 -0
  12. data/calabash-android-features-skeleton/web/support/app_life_cycle_hooks.rb +15 -0
  13. data/lib/kraken-mobile/device_process.rb +130 -0
  14. data/lib/kraken-mobile/helpers/devices_helper/adb_helper.rb +100 -105
  15. data/lib/kraken-mobile/helpers/kraken_faker.rb +108 -0
  16. data/lib/kraken-mobile/helpers/reporter.rb +3 -0
  17. data/lib/kraken-mobile/hooks/mobile_kraken_hooks.rb +15 -0
  18. data/lib/kraken-mobile/hooks/mobile_operations.rb +36 -0
  19. data/lib/kraken-mobile/hooks/web_operations.rb +33 -0
  20. data/lib/kraken-mobile/mobile/adb.rb +66 -0
  21. data/lib/kraken-mobile/mobile/android_commands.rb +43 -0
  22. data/lib/kraken-mobile/mobile/mobile_process.rb +101 -0
  23. data/lib/kraken-mobile/models/android_device.rb +121 -0
  24. data/lib/kraken-mobile/models/device.rb +113 -31
  25. data/lib/kraken-mobile/models/feature_file.rb +135 -0
  26. data/lib/kraken-mobile/models/feature_scenario.rb +24 -0
  27. data/lib/kraken-mobile/models/web_device.rb +89 -0
  28. data/lib/kraken-mobile/monkeys/mobile/android_monkey.rb +30 -0
  29. data/lib/kraken-mobile/monkeys/mobile/kraken_android_monkey.rb +54 -0
  30. data/lib/kraken-mobile/monkeys/web/web_monkey.rb +63 -0
  31. data/lib/kraken-mobile/runners/calabash/android/monkey_helper.rb +2 -2
  32. data/lib/kraken-mobile/runners/calabash/android/steps/communication_steps.rb +18 -2
  33. data/lib/kraken-mobile/runners/calabash/monkey/monkey_runner.rb +2 -2
  34. data/lib/kraken-mobile/steps/general_steps.rb +83 -0
  35. data/lib/kraken-mobile/steps/mobile/kraken_steps.rb +72 -0
  36. data/lib/kraken-mobile/steps/web/kraken_steps.rb +109 -0
  37. data/lib/kraken-mobile/test_scenario.rb +227 -0
  38. data/lib/kraken-mobile/utils/feature_reader.rb +17 -0
  39. data/lib/kraken-mobile/utils/k.rb +68 -0
  40. data/lib/kraken-mobile/utils/mobile_cucumber.rb +2 -0
  41. data/lib/kraken-mobile/utils/reporter.rb +500 -0
  42. data/lib/kraken-mobile/version.rb +2 -2
  43. data/lib/kraken-mobile/web/web_process.rb +41 -0
  44. data/lib/kraken_mobile.rb +81 -0
  45. data/reporter/assets/images/krakenThumbnail.jpg +0 -0
  46. data/reporter/feature_report.html.erb +5 -1
  47. data/reporter/index.html.erb +13 -7
  48. metadata +94 -13
  49. data/bin/kraken-mobile-calabash-android.rb +0 -85
  50. data/bin/kraken-mobile-generate.rb +0 -19
  51. data/bin/kraken-mobile-helpers.rb +0 -48
  52. data/bin/kraken-mobile-setup.rb +0 -50
  53. data/calabash-android-features-skeleton/step_definitions/kraken_steps.rb +0 -1
  54. data/lib/kraken-mobile.rb +0 -29
@@ -0,0 +1,39 @@
1
+ @features_dir = File.join(FileUtils.pwd, 'features')
2
+ @support_dir = File.join(@features_dir, 'support')
3
+ @source_dir = File.join(
4
+ File.dirname(__FILE__),
5
+ '..',
6
+ 'calabash-android-features-skeleton'
7
+ )
8
+
9
+ def handle_calabash_android(config_path, properties_path)
10
+ require 'kraken-mobile/constants'
11
+ require 'calabash-android/helpers'
12
+
13
+ kraken = KrakenApp.new(
14
+ apk_path: user_entered_apk_path,
15
+ properties_path: format_properties(properties_path),
16
+ config_path: format_config(config_path)
17
+ )
18
+ kraken.start
19
+ end
20
+
21
+ private
22
+
23
+ def format_properties(properties_path)
24
+ return if properties_path.nil?
25
+
26
+ properties_absolute_path = File.expand_path(properties_path)
27
+ ensure_properties_is_valid(properties_absolute_path)
28
+
29
+ properties_absolute_path
30
+ end
31
+
32
+ def format_config(config_path)
33
+ return if config_path.nil?
34
+
35
+ config_absolute_path = File.expand_path(config_path)
36
+ ensure_configuration_is_valid(config_absolute_path)
37
+
38
+ config_absolute_path
39
+ end
@@ -0,0 +1,107 @@
1
+ require 'rubygems'
2
+ require 'fileutils'
3
+
4
+ #-------------------------------
5
+ # Helpers
6
+ #-------------------------------
7
+
8
+ def print_usage
9
+ puts <<USAGE
10
+ Usage: kraken-mobile <command-name> [parameters] [options]
11
+ <command-name> can be one of
12
+ run <apk>
13
+ runs Cucumber in the current folder with the environment needed.
14
+ version
15
+ prints the gem version.
16
+ devices
17
+ prints the list of devices attached.
18
+ setup
19
+ creates kraken-settings file specifying in what devices the tests are going to be run.
20
+ gen
21
+ generate a features folder structure.
22
+ resign <apk>
23
+ resigns the app with the currently configured keystore.
24
+ USAGE
25
+ end
26
+
27
+ def print_devices
28
+ puts 'List of devices attached'
29
+ ADB.connected_devices.each_with_index do |device, index|
30
+ puts "user#{index + 1} - #{device.to_s.split(K::SEPARATOR).join(' - ')}"
31
+ end
32
+ end
33
+
34
+ def apk_file?(file_path)
35
+ file_path.end_with?('.apk') && File.exist?(file_path)
36
+ end
37
+
38
+ def relative_to_full_path(file_path)
39
+ File.expand_path(file_path)
40
+ end
41
+
42
+ def msg(title, &block)
43
+ puts "\n" + '-' * 10 + title + '-' * 10
44
+ block.call
45
+ puts '-' * 10 + '-------' + '-' * 10 + "\n"
46
+ end
47
+
48
+ def scaffold_folder_structure
49
+ if File.exist?(@features_dir)
50
+ puts 'A features directory already exists. Stopping...'
51
+ exit 1
52
+ end
53
+
54
+ msg('Question') do
55
+ puts 'I\'m about to create a subdirectory called features.'
56
+ puts 'features will contain all your kraken tests.'
57
+ puts 'Please hit return to confirm that\'s what you want.'
58
+ end
59
+ exit 2 unless STDIN.gets.chomp == ''
60
+
61
+ FileUtils.cp_r(@source_dir, @features_dir)
62
+
63
+ msg('Info') do
64
+ puts "features subdirectory created. \n"
65
+ end
66
+ end
67
+
68
+ def ensure_apk_is_specified
69
+ return if !ARGV.empty? && apk_file?(ARGV.first)
70
+
71
+ puts 'The first parameter must be the path to a valid apk file.'
72
+ exit 1
73
+ end
74
+
75
+ def ensure_configuration_is_valid(configuration)
76
+ return if File.exist?(configuration) &&
77
+ File.file?(configuration) &&
78
+ configuration.end_with?('.json')
79
+
80
+ puts 'The path of the configuration file is not valid.'
81
+ exit 1
82
+ end
83
+
84
+ def ensure_properties_is_valid(properties)
85
+ return if File.exist?(properties) &&
86
+ File.file?(properties) &&
87
+ properties.end_with?('.json')
88
+
89
+ puts 'The path of the properties file is not valid.'
90
+ exit 1
91
+ end
92
+
93
+ def ensure_android_sdk_installed
94
+ return unless ENV['ANDROID_HOME'].nil?
95
+
96
+ puts 'To use Kraken you need to have installed Android SDK first. '\
97
+ 'Make sure you have the environment variable ANDROID_HOME configured'
98
+ exit 1
99
+ end
100
+
101
+ def ensure_java_installed
102
+ return unless ENV['ANDROID_HOME'].nil?
103
+
104
+ puts 'To use Kraken you need to have installed Java first.'\
105
+ 'Make sure you have the environment variable JAVA_HOME configured'
106
+ exit 1
107
+ end
@@ -0,0 +1,138 @@
1
+ require 'io/console'
2
+ require 'tty-prompt'
3
+ $LOAD_PATH << File.expand_path('../lib', __dir__)
4
+ require 'kraken-mobile/utils/k.rb'
5
+
6
+ class KrakenSetup
7
+ WEB_IDENTIFIER = 'Web'.freeze
8
+ IS_WEB_AVAILABLE_FOR_SELECTION = true
9
+
10
+ attr_accessor :prompt
11
+ attr_accessor :devices_connected_id
12
+ attr_accessor :settings
13
+
14
+ def initialize
15
+ @prompt = TTY::Prompt.new
16
+ @available_devices_ids = available_devices_ids_for_select
17
+ @settings = {}
18
+ end
19
+
20
+ def run
21
+ number_of_devices_required.times do |index|
22
+ user_id = index + 1
23
+ selected_device_id = select_device_for_user_with_id(user_id)
24
+ if selected_device_id == WEB_IDENTIFIER
25
+ handle_web_setup_for_user_with_id(user_id)
26
+ else
27
+ handle_mobile_setup_for_user_with_id(user_id, selected_device_id)
28
+ end
29
+ end
30
+ save_user_settings_to_file
31
+ end
32
+
33
+ private
34
+
35
+ def handle_web_setup_for_user_with_id(user_id)
36
+ save_web_device_settings_for_user_with_id(user_id: user_id)
37
+ end
38
+
39
+ def handle_mobile_setup_for_user_with_id(user_id, device_id)
40
+ selected_apk = select_apk_for_user_with_id(user_id)
41
+ save_mobile_device_settings_for_user_with_id(
42
+ user_id: user_id, apk: selected_apk,
43
+ device_id: device_id
44
+ )
45
+ delete_selected_device_id_from_available_devices(device_id)
46
+ end
47
+
48
+ def save_user_settings_to_file
49
+ open('kraken_mobile_settings.json', 'w') do |f|
50
+ f.puts @settings.to_json
51
+ end
52
+
53
+ puts 'Saved your settings to .kraken_mobile_settings. You can edit '\
54
+ 'the settings manually or run this setup script again'
55
+ end
56
+
57
+ def number_of_devices_required
58
+ number_of_devices = -1
59
+ max_devices = max_number_of_devices
60
+ while number_of_devices <= 0 || number_of_devices > max_number_of_devices
61
+ number_of_devices = @prompt.ask(
62
+ 'How many devices do you want to use?', convert: :int
63
+ )
64
+
65
+ if number_of_devices.zero?
66
+ @prompt.error('Number of devices can\'t be less than 1.')
67
+ end
68
+
69
+ if number_of_devices > max_devices
70
+ @prompt.error(
71
+ "You can run Kraken only in #{max_devices} device" \
72
+ "#{max_devices > 1 ? 's' : ''}"
73
+ )
74
+ end
75
+ end
76
+ number_of_devices
77
+ end
78
+
79
+ def delete_selected_device_id_from_available_devices(device_id)
80
+ @available_devices_ids.delete(device_id)
81
+ end
82
+
83
+ def save_mobile_device_settings_for_user_with_id(
84
+ user_id:, apk:, device_id:
85
+ )
86
+ device = ADB.connected_devices.select { |d| d.id == device_id }.first
87
+ @settings[user_id] = {
88
+ id: device_id,
89
+ model: device.model,
90
+ type: K::ANDROID_DEVICE,
91
+ config: {
92
+ apk_path: apk
93
+ }
94
+ }
95
+ end
96
+
97
+ def save_web_device_settings_for_user_with_id(user_id:)
98
+ device = WebDevice.factory_create
99
+ @settings[user_id] = {
100
+ id: device.id,
101
+ model: device.model,
102
+ type: K::WEB_DEVICE,
103
+ config: {}
104
+ }
105
+ end
106
+
107
+ def select_apk_for_user_with_id(id)
108
+ valid_apk = false
109
+
110
+ until valid_apk
111
+ entered_text = @prompt.ask(
112
+ "What APK user #{id} is going to run?", required: true
113
+ )
114
+ entered_apk_path = File.expand_path(entered_text)
115
+ valid_apk = apk_file?(File.expand_path(entered_apk_path))
116
+ @prompt.error('APK path is not valid.') unless valid_apk
117
+ end
118
+ entered_apk_path
119
+ end
120
+
121
+ def select_device_for_user_with_id(id)
122
+ @prompt.select(
123
+ "Choose your user #{id}", @available_devices_ids
124
+ )
125
+ end
126
+
127
+ def available_devices_ids_for_select
128
+ devices_connected_id = ADB.connected_devices.map(&:id)
129
+ devices_connected_id << WEB_IDENTIFIER if IS_WEB_AVAILABLE_FOR_SELECTION
130
+ devices_connected_id
131
+ end
132
+
133
+ def max_number_of_devices
134
+ return 100 if IS_WEB_AVAILABLE_FOR_SELECTION
135
+
136
+ ADB.connected_devices.count
137
+ end
138
+ end
@@ -0,0 +1 @@
1
+ require 'kraken-mobile/steps/mobile/kraken_steps'
@@ -14,6 +14,8 @@ Before do |scenario|
14
14
  else
15
15
  log 'First scenario in feature - reinstalling apps'
16
16
  end
17
+
18
+ ensure_app_installed
17
19
  clear_app_data
18
20
  FeatureMemory.feature = feature
19
21
  FeatureMemory.invocation = 1
@@ -1,10 +1,9 @@
1
- require 'kraken-mobile/runners/calabash/android/Operations'
1
+ require 'kraken-mobile/hooks/mobile_operations'
2
2
 
3
3
  Before do |scenario|
4
- start_kraken_test_server_in_background scenario
4
+ start_test_kraken_server_in_background
5
5
  end
6
6
 
7
7
  After do |scenario|
8
- shutdown_kraken_test_server scenario
9
- uninstall_app_with_calabash
8
+ shutdown_test_kraken_server
10
9
  end
@@ -1 +1 @@
1
- require 'kraken-mobile/runners/calabash/android/cucumber'
1
+ require 'kraken-mobile/utils/mobile_cucumber'
@@ -0,0 +1,3 @@
1
+ if ENV["ADB_DEVICE_ARG"].nil?
2
+ require 'kraken-mobile/steps/web/kraken_steps'
3
+ end
@@ -0,0 +1,15 @@
1
+ if ENV["ADB_DEVICE_ARG"].nil?
2
+ require 'kraken-mobile/hooks/web_operations'
3
+
4
+ Before do |scenario|
5
+ start_test_kraken_server_in_background(
6
+ scenario: scenario
7
+ )
8
+ end
9
+
10
+ After do |scenario|
11
+ shutdown_test_kraken_server(
12
+ scenario: scenario
13
+ )
14
+ end
15
+ end
@@ -0,0 +1,130 @@
1
+ require 'fileutils'
2
+
3
+ # Abstract class
4
+ class DeviceProcess
5
+ attr_accessor :id
6
+ attr_accessor :device
7
+ attr_accessor :test_scenario
8
+
9
+ #-------------------------------
10
+ # Constructors
11
+ #-------------------------------
12
+ def initialize(id:, device:, test_scenario:)
13
+ @id = id
14
+ @device = device
15
+ @test_scenario = test_scenario
16
+ end
17
+
18
+ #-------------------------------
19
+ # Required methods
20
+ #-------------------------------
21
+ def before_execute
22
+ raise 'ERROR: before_execute not implemented.'
23
+ end
24
+
25
+ def execute
26
+ raise 'ERROR: execute not implemented.'
27
+ end
28
+
29
+ def after_execute
30
+ raise 'ERROR: after_execute not implemented.'
31
+ end
32
+
33
+ def run
34
+ before_execute
35
+ execute
36
+ after_execute
37
+ end
38
+
39
+ #-------------------------------
40
+ # Methods
41
+ #-------------------------------
42
+ def register_process_to_directory
43
+ File.open(K::DIRECTORY_PATH, 'a') do |file|
44
+ file.puts("#{id}#{K::SEPARATOR}#{device}")
45
+ end
46
+ end
47
+
48
+ def unregister_process_from_directory
49
+ File.open(K::DIRECTORY_PATH, 'r') do |f|
50
+ File.open("#{K::DIRECTORY_PATH}.tmp", 'w') do |f2|
51
+ f.each_line do |line|
52
+ f2.write(line) unless line.start_with?(
53
+ "#{id}#{K::SEPARATOR}#{device}"
54
+ )
55
+ end
56
+ end
57
+ end
58
+ FileUtils.mv("#{K::DIRECTORY_PATH}.tmp", K::DIRECTORY_PATH)
59
+ end
60
+
61
+ def notify_ready_to_start
62
+ File.open(K::DIRECTORY_PATH, 'a') do |file|
63
+ file.puts("#{id}#{K::SEPARATOR}#{device}")
64
+ end
65
+ end
66
+
67
+ def running_on_windows?
68
+ RbConfig::CONFIG['host_os'] =~ /cygwin|mswin|mingw|bccwin|wince|emx/
69
+ end
70
+
71
+ def exporting_command_for_environment_variables(variables = {})
72
+ commands = variables.map do |key, value|
73
+ if running_on_windows?
74
+ "(SET \"#{key}=#{value}\")"
75
+ else
76
+ "#{key}=#{value};export #{key}"
77
+ end
78
+ end
79
+ commands.join(terminal_command_separator)
80
+ end
81
+
82
+ def self.directory
83
+ return [] unless File.exist?(K::DIRECTORY_PATH)
84
+
85
+ directory = nil
86
+ File.open(K::DIRECTORY_PATH, 'r') do |file|
87
+ directory = file.each_line.map(&:to_s).map(&:strip)
88
+ end
89
+
90
+ directory || []
91
+ end
92
+
93
+ def self.registered_process_ids
94
+ directory = DeviceProcess.directory
95
+ directory.map do |entry|
96
+ info = entry.strip.split(K::SEPARATOR)
97
+ info[0]
98
+ end.compact.uniq
99
+ end
100
+
101
+ def self.notify_process_state(process_id:, state:)
102
+ raise 'ERROR: Process id can\'t be nil.' if process_id.nil?
103
+
104
+ file_path = K::PROCESS_STATE_FILE_PATH[state]
105
+ raise 'ERROR: State does not exist.' if file_path.nil?
106
+
107
+ File.open(file_path, 'a') do |file|
108
+ file.puts(process_id)
109
+ end
110
+ end
111
+
112
+ def self.processes_in_state(state)
113
+ file_path = K::PROCESS_STATE_FILE_PATH[state]
114
+ return [] if file_path.nil?
115
+ return [] unless File.exist?(file_path)
116
+
117
+ devices_ready = nil
118
+ File.open(file_path, 'r') do |file|
119
+ devices_ready = file.each_line.map(&:to_s).map(&:strip)
120
+ end
121
+
122
+ devices_ready || []
123
+ end
124
+
125
+ def terminal_command_separator
126
+ return ' & ' if running_on_windows?
127
+
128
+ ';'
129
+ end
130
+ end