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.
- checksums.yaml +5 -5
- data/README.md +251 -75
- data/bin/kraken-mobile +64 -67
- data/bin/kraken_mobile_calabash_android.rb +39 -0
- data/bin/kraken_mobile_helpers.rb +107 -0
- data/bin/kraken_mobile_setup.rb +138 -0
- data/calabash-android-features-skeleton/step_definitions/mobile_steps.rb +1 -0
- data/calabash-android-features-skeleton/support/app_installation_hooks.rb +2 -0
- data/calabash-android-features-skeleton/support/app_life_cycle_hooks.rb +3 -4
- data/calabash-android-features-skeleton/support/env.rb +1 -1
- data/calabash-android-features-skeleton/web/step_definitions/web_steps.rb +3 -0
- data/calabash-android-features-skeleton/web/support/app_life_cycle_hooks.rb +15 -0
- data/lib/kraken-mobile/device_process.rb +130 -0
- data/lib/kraken-mobile/helpers/devices_helper/adb_helper.rb +100 -105
- data/lib/kraken-mobile/helpers/kraken_faker.rb +108 -0
- data/lib/kraken-mobile/helpers/reporter.rb +3 -0
- data/lib/kraken-mobile/hooks/mobile_kraken_hooks.rb +15 -0
- data/lib/kraken-mobile/hooks/mobile_operations.rb +36 -0
- data/lib/kraken-mobile/hooks/web_operations.rb +33 -0
- data/lib/kraken-mobile/mobile/adb.rb +66 -0
- data/lib/kraken-mobile/mobile/android_commands.rb +43 -0
- data/lib/kraken-mobile/mobile/mobile_process.rb +101 -0
- data/lib/kraken-mobile/models/android_device.rb +121 -0
- data/lib/kraken-mobile/models/device.rb +113 -31
- data/lib/kraken-mobile/models/feature_file.rb +135 -0
- data/lib/kraken-mobile/models/feature_scenario.rb +24 -0
- data/lib/kraken-mobile/models/web_device.rb +89 -0
- data/lib/kraken-mobile/monkeys/mobile/android_monkey.rb +30 -0
- data/lib/kraken-mobile/monkeys/mobile/kraken_android_monkey.rb +54 -0
- data/lib/kraken-mobile/monkeys/web/web_monkey.rb +63 -0
- data/lib/kraken-mobile/runners/calabash/android/monkey_helper.rb +2 -2
- data/lib/kraken-mobile/runners/calabash/android/steps/communication_steps.rb +18 -2
- data/lib/kraken-mobile/runners/calabash/monkey/monkey_runner.rb +2 -2
- data/lib/kraken-mobile/steps/general_steps.rb +83 -0
- data/lib/kraken-mobile/steps/mobile/kraken_steps.rb +72 -0
- data/lib/kraken-mobile/steps/web/kraken_steps.rb +109 -0
- data/lib/kraken-mobile/test_scenario.rb +227 -0
- data/lib/kraken-mobile/utils/feature_reader.rb +17 -0
- data/lib/kraken-mobile/utils/k.rb +68 -0
- data/lib/kraken-mobile/utils/mobile_cucumber.rb +2 -0
- data/lib/kraken-mobile/utils/reporter.rb +500 -0
- data/lib/kraken-mobile/version.rb +2 -2
- data/lib/kraken-mobile/web/web_process.rb +41 -0
- data/lib/kraken_mobile.rb +81 -0
- data/reporter/assets/images/krakenThumbnail.jpg +0 -0
- data/reporter/feature_report.html.erb +5 -1
- data/reporter/index.html.erb +13 -7
- metadata +94 -13
- data/bin/kraken-mobile-calabash-android.rb +0 -85
- data/bin/kraken-mobile-generate.rb +0 -19
- data/bin/kraken-mobile-helpers.rb +0 -48
- data/bin/kraken-mobile-setup.rb +0 -50
- data/calabash-android-features-skeleton/step_definitions/kraken_steps.rb +0 -1
- 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'
|
@@ -1,10 +1,9 @@
|
|
1
|
-
require 'kraken-mobile/
|
1
|
+
require 'kraken-mobile/hooks/mobile_operations'
|
2
2
|
|
3
3
|
Before do |scenario|
|
4
|
-
|
4
|
+
start_test_kraken_server_in_background
|
5
5
|
end
|
6
6
|
|
7
7
|
After do |scenario|
|
8
|
-
|
9
|
-
uninstall_app_with_calabash
|
8
|
+
shutdown_test_kraken_server
|
10
9
|
end
|
@@ -1 +1 @@
|
|
1
|
-
require 'kraken-mobile/
|
1
|
+
require 'kraken-mobile/utils/mobile_cucumber'
|
@@ -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
|