kraken-mobile 1.0.2 → 1.0.9

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 (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