kraken-mobile 1.0.1 → 1.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +251 -77
- 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 +91 -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/css/scenario_index.css +20 -0
- data/reporter/assets/images/krakenThumbnail.jpg +0 -0
- data/reporter/assets/js/sankey.js +56 -24
- data/reporter/feature_report.html.erb +5 -1
- data/reporter/index.html.erb +15 -8
- data/reporter/scenario_report.html.erb +73 -31
- metadata +95 -14
- 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
@@ -2,156 +2,151 @@ require 'kraken-mobile/models/device'
|
|
2
2
|
require 'kraken-mobile/constants'
|
3
3
|
|
4
4
|
module KrakenMobile
|
5
|
-
|
6
|
-
|
7
|
-
# ADB command that returns all phones and
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
5
|
+
module DevicesHelper
|
6
|
+
class AdbHelper
|
7
|
+
# ADB command that returns all phones and
|
8
|
+
# emulators connected to the computer.
|
9
|
+
|
10
|
+
def adb_devices_l
|
11
|
+
`adb devices -l`
|
12
|
+
end
|
13
|
+
|
14
|
+
def file_content(file_name, device_id)
|
13
15
|
`adb -s #{device_id} shell "cat /sdcard/#{file_name} 2> /dev/null"`
|
14
16
|
end
|
15
17
|
|
16
|
-
def write_content_to_device
|
18
|
+
def write_content_to_device(content, file_name, device_id)
|
17
19
|
`adb -s #{device_id} shell "echo "#{content}" > /sdcard/#{file_name}"`
|
18
20
|
end
|
19
21
|
|
20
|
-
def create_file_in_device
|
22
|
+
def create_file_in_device(file_name, device_id)
|
21
23
|
`adb -s #{device_id} shell "> /sdcard/#{file_name}"`
|
22
24
|
end
|
23
25
|
|
24
|
-
def delete_file_in_device
|
26
|
+
def delete_file_in_device(file_name, device_id)
|
25
27
|
`adb -s #{device_id} shell "rm -rf /sdcard/#{file_name}"`
|
26
28
|
end
|
27
29
|
|
28
|
-
def device_screen_size
|
30
|
+
def device_screen_size(device_id)
|
29
31
|
`adb -s #{device_id} shell wm size`
|
30
32
|
end
|
31
33
|
|
32
|
-
def device_sdk_version
|
34
|
+
def device_sdk_version(device_id)
|
33
35
|
`adb -s #{device_id} shell getprop ro.build.version.sdk`
|
34
36
|
end
|
35
37
|
|
36
|
-
def device_orientation
|
38
|
+
def device_orientation(device_id)
|
37
39
|
`adb -s #{device_id} shell dumpsys input | grep 'SurfaceOrientation' | awk '{ print $2 }'`
|
38
40
|
end
|
39
41
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
42
|
+
def device_connected?(device_id)
|
43
|
+
adb_devices_l.include?(device_id)
|
44
|
+
rescue StandardError => _e
|
45
|
+
false
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns an array with all the devices and emulators
|
49
|
+
# connected to the computer.
|
50
|
+
def connected_devices
|
51
|
+
devices = []
|
52
|
+
adb_devices_l.split("\n").each do |line|
|
53
|
+
line_id = extract_device_id(line)
|
54
|
+
line_model = extract_device_model(line)
|
55
|
+
if line_id && line_model
|
56
|
+
device = Models::Device.new(line_id, line_model, devices.size + 1)
|
57
|
+
devices << device
|
58
|
+
end
|
45
59
|
end
|
60
|
+
devices
|
61
|
+
rescue StandardError => _e
|
62
|
+
[]
|
46
63
|
end
|
47
64
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
devices = []
|
52
|
-
list =
|
53
|
-
adb_devices_l.split("\n").each do |line|
|
54
|
-
line_id = extract_device_id(line)
|
55
|
-
line_model = extract_device_model(line)
|
56
|
-
if line_id && line_model
|
57
|
-
device = Models::Device.new(line_id, line_model, devices.size + 1)
|
58
|
-
devices << device
|
59
|
-
end
|
60
|
-
end
|
61
|
-
devices
|
62
|
-
rescue
|
63
|
-
[]
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def read_file_content file_name, device_id
|
68
|
-
begin
|
69
|
-
raise "Device #{device_id} not found" unless is_device_connected(device_id)
|
70
|
-
content = file_content("#{file_name}.txt", device_id)
|
71
|
-
content.strip
|
72
|
-
rescue
|
73
|
-
""
|
65
|
+
def read_file_content(file_name, device_id)
|
66
|
+
unless device_connected?(device_id)
|
67
|
+
raise "Device #{device_id} not found"
|
74
68
|
end
|
69
|
+
|
70
|
+
content = file_content("#{file_name}.txt", device_id)
|
71
|
+
content.strip
|
72
|
+
rescue StandardError => _e
|
73
|
+
''
|
75
74
|
end
|
76
75
|
|
77
|
-
def write_content_to_file
|
78
|
-
|
79
|
-
raise "Device #{device_id} not found"
|
80
|
-
write_content_to_device(content, "#{file_name}.txt", device_id)
|
81
|
-
true
|
82
|
-
rescue
|
83
|
-
false
|
76
|
+
def write_content_to_file(content, file_name, device_id)
|
77
|
+
unless device_connected?(device_id)
|
78
|
+
raise "Device #{device_id} not found"
|
84
79
|
end
|
80
|
+
|
81
|
+
write_content_to_device(content, "#{file_name}.txt", device_id)
|
82
|
+
true
|
83
|
+
rescue StandardError => _e
|
84
|
+
false
|
85
85
|
end
|
86
86
|
|
87
|
-
def create_file
|
88
|
-
|
89
|
-
raise "Device #{device_id} not found"
|
90
|
-
create_file_in_device("#{file_name}.txt", device_id)
|
91
|
-
true
|
92
|
-
rescue
|
93
|
-
false
|
87
|
+
def create_file(file_name, device_id)
|
88
|
+
unless device_connected?(device_id)
|
89
|
+
raise "Device #{device_id} not found"
|
94
90
|
end
|
91
|
+
|
92
|
+
create_file_in_device("#{file_name}.txt", device_id)
|
93
|
+
true
|
94
|
+
rescue StandardError => _e
|
95
|
+
false
|
95
96
|
end
|
96
97
|
|
97
|
-
def delete_file
|
98
|
-
|
99
|
-
raise "Device #{device_id} not found"
|
100
|
-
delete_file_in_device("#{file_name}.txt", device_id)
|
101
|
-
true
|
102
|
-
rescue
|
103
|
-
false
|
98
|
+
def delete_file(file_name, device_id)
|
99
|
+
unless device_connected?(device_id)
|
100
|
+
raise "Device #{device_id} not found"
|
104
101
|
end
|
102
|
+
|
103
|
+
delete_file_in_device("#{file_name}.txt", device_id)
|
104
|
+
true
|
105
|
+
rescue StandardError => _e
|
106
|
+
false
|
105
107
|
end
|
106
108
|
|
107
109
|
# Returns height, width
|
108
|
-
def screen_size
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
else
|
118
|
-
return size_parts[0].to_i, size_parts[1].to_i
|
119
|
-
end
|
120
|
-
rescue
|
121
|
-
return 0,0
|
110
|
+
def screen_size(device_id)
|
111
|
+
adb_size = device_screen_size device_id
|
112
|
+
parts = adb_size.strip!.split(' ')
|
113
|
+
size = parts[parts.count - 1]
|
114
|
+
return [0, 0] unless size.include?('x')
|
115
|
+
|
116
|
+
size_parts = size.split('x')
|
117
|
+
if orientation(device_id) == KrakenMobile::Constants::PORTRAIT
|
118
|
+
return size_parts[1].to_i, size_parts[0].to_i
|
122
119
|
end
|
120
|
+
|
121
|
+
[size_parts[0].to_i, size_parts[1].to_i]
|
122
|
+
rescue StandardError => _e
|
123
|
+
[0, 0]
|
123
124
|
end
|
124
125
|
|
125
|
-
def sdk_version
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
return "N/A"
|
130
|
-
end
|
126
|
+
def sdk_version(device_id)
|
127
|
+
device_sdk_version device_id
|
128
|
+
rescue StandardError => _e
|
129
|
+
'N/A'
|
131
130
|
end
|
132
131
|
|
133
|
-
def orientation
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
return KrakenMobile::Constants::PORTRAIT
|
139
|
-
end
|
132
|
+
def orientation(device_id)
|
133
|
+
adb_orientation = device_orientation(device_id).strip!
|
134
|
+
adb_orientation.to_i
|
135
|
+
rescue StandardError => _e
|
136
|
+
KrakenMobile::Constants::PORTRAIT
|
140
137
|
end
|
141
138
|
|
142
139
|
# Parses the device id from the ADB devices command.
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
end
|
147
|
-
end
|
140
|
+
def extract_device_id(line)
|
141
|
+
return line.split(' ').first if line.match(/device(?!s)/)
|
142
|
+
end
|
148
143
|
|
149
144
|
# Parses the device model from the ADB devices command.
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
145
|
+
def extract_device_model(line)
|
146
|
+
return unless line.match(/device(?!s)/)
|
147
|
+
|
148
|
+
line.scan(/model:(.*) device/).flatten.first
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
157
152
|
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'faker'
|
2
|
+
require 'kraken-mobile/utils/k.rb'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
class KrakenFaker
|
6
|
+
#-------------------------------
|
7
|
+
# Fields
|
8
|
+
#-------------------------------
|
9
|
+
attr_accessor :process_id
|
10
|
+
|
11
|
+
#-------------------------------
|
12
|
+
# Constructors
|
13
|
+
#-------------------------------
|
14
|
+
def initialize(process_id:)
|
15
|
+
raise 'ERROR: Can\'t create faker for null process id' if process_id.nil?
|
16
|
+
|
17
|
+
@process_id = process_id
|
18
|
+
end
|
19
|
+
|
20
|
+
#-------------------------------
|
21
|
+
# Helpers
|
22
|
+
#-------------------------------
|
23
|
+
def generate_value_for_key(key:)
|
24
|
+
value = if key.start_with?('$name')
|
25
|
+
generate_name
|
26
|
+
elsif key.start_with?('$number')
|
27
|
+
generate_number
|
28
|
+
elsif key.start_with?('$email')
|
29
|
+
generate_email
|
30
|
+
elsif key.start_with?('$string')
|
31
|
+
generate_string
|
32
|
+
elsif key.start_with?('$date')
|
33
|
+
generate_date
|
34
|
+
else
|
35
|
+
raise 'ERROR: Faker key not supported'
|
36
|
+
end
|
37
|
+
save_key_value_in_dictionary(key: key, value: value)
|
38
|
+
value
|
39
|
+
end
|
40
|
+
|
41
|
+
def reuse_value_for_key(key:)
|
42
|
+
dictionary = dictionary_json
|
43
|
+
key = key.delete_prefix('$')
|
44
|
+
|
45
|
+
raise 'ERROR: Key does not exist' if dictionary[process_id.to_s].nil?
|
46
|
+
if dictionary[process_id.to_s][key.to_s].nil?
|
47
|
+
raise 'ERROR: Key does not exist'
|
48
|
+
end
|
49
|
+
|
50
|
+
dictionary[process_id.to_s][key.to_s]
|
51
|
+
end
|
52
|
+
|
53
|
+
def dictionary_json
|
54
|
+
create_dictionary_json_file unless dictionary_json_file_exists?
|
55
|
+
|
56
|
+
absolute_dictionary_path = File.expand_path(K::DICTIONARY_PATH)
|
57
|
+
file = open(absolute_dictionary_path)
|
58
|
+
content = file.read
|
59
|
+
file.close
|
60
|
+
JSON.parse(content)
|
61
|
+
end
|
62
|
+
|
63
|
+
def create_dictionary_json_file
|
64
|
+
absolute_dictionary_path = File.expand_path(K::DICTIONARY_PATH)
|
65
|
+
File.open(absolute_dictionary_path, 'w') do |f|
|
66
|
+
f.puts({}.to_json)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def dictionary_json_file_exists?
|
71
|
+
absolute_dictionary_path = File.expand_path(K::DICTIONARY_PATH)
|
72
|
+
File.file?(absolute_dictionary_path)
|
73
|
+
end
|
74
|
+
|
75
|
+
def save_key_value_in_dictionary(key:, value:)
|
76
|
+
current_json = dictionary_json
|
77
|
+
current_json[process_id.to_s] = {} if current_json[process_id.to_s].nil?
|
78
|
+
current_json[process_id.to_s][key.to_s] = value
|
79
|
+
|
80
|
+
absolute_dictionary_path = File.expand_path(K::DICTIONARY_PATH)
|
81
|
+
open(absolute_dictionary_path, 'w') do |f|
|
82
|
+
f.puts(current_json.to_json)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
#-------------------------------
|
87
|
+
# Generators
|
88
|
+
#-------------------------------
|
89
|
+
def generate_name
|
90
|
+
Faker::Name.first_name
|
91
|
+
end
|
92
|
+
|
93
|
+
def generate_number
|
94
|
+
Faker::Number.number(digits: rand(10))
|
95
|
+
end
|
96
|
+
|
97
|
+
def generate_email
|
98
|
+
Faker::Internet.email
|
99
|
+
end
|
100
|
+
|
101
|
+
def generate_string
|
102
|
+
Faker::String.random(length: rand(100))
|
103
|
+
end
|
104
|
+
|
105
|
+
def generate_date
|
106
|
+
Faker::Date.in_date_period.to_s
|
107
|
+
end
|
108
|
+
end
|
@@ -26,6 +26,7 @@ module KrakenMobile
|
|
26
26
|
# Variables
|
27
27
|
report_file = open("#{KrakenMobile::Constants::REPORT_PATH}/#{@execution_id}/#{KrakenMobile::Constants::REPORT_DEVICES_FILE_NAME}.json")
|
28
28
|
content = report_file.read
|
29
|
+
report_file.close
|
29
30
|
@devices = JSON.parse(content)
|
30
31
|
devices_report = report_by_devices(@devices)
|
31
32
|
@features_report = fetures_from_report_by_devices devices_report
|
@@ -45,6 +46,7 @@ module KrakenMobile
|
|
45
46
|
@apk_path = device.config["apk_path"] ? device.config["apk_path"] : @options[:apk_path]
|
46
47
|
report_file = open("#{KrakenMobile::Constants::REPORT_PATH}/#{@execution_id}/#{device.id}/#{KrakenMobile::Constants::REPORT_FILE_NAME}.json")
|
47
48
|
content = report_file.read
|
49
|
+
report_file.close
|
48
50
|
@features = JSON.parse(content)
|
49
51
|
@total_scenarios = total_scenarios @features
|
50
52
|
@device = device
|
@@ -70,6 +72,7 @@ module KrakenMobile
|
|
70
72
|
next if !File.exists?("#{KrakenMobile::Constants::REPORT_PATH}/#{@execution_id}/#{device['id']}/#{KrakenMobile::Constants::REPORT_FILE_NAME}.json")
|
71
73
|
report_file = open("#{KrakenMobile::Constants::REPORT_PATH}/#{@execution_id}/#{device['id']}/#{KrakenMobile::Constants::REPORT_FILE_NAME}.json")
|
72
74
|
content = report_file.read
|
75
|
+
report_file.close
|
73
76
|
devices_report[device['user']] = JSON.parse(content)
|
74
77
|
devices_report[device['user']].each do |d| d["device_model"] = device["model"] if !d["device_model"] end
|
75
78
|
devices_report[device['user']].each do |d| d["device_id"] = device["id"] if !d["device_id"] end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'calabash-android/management/adb'
|
2
|
+
require 'calabash-android/operations'
|
3
|
+
|
4
|
+
Before do |scenario|
|
5
|
+
# install_app_with_calabash
|
6
|
+
@scenario_tags = scenario.source_tag_names
|
7
|
+
end
|
8
|
+
|
9
|
+
After do |scenario|
|
10
|
+
@scenario_tags = scenario.source_tag_names
|
11
|
+
end
|
12
|
+
|
13
|
+
AfterStep do |_scenario|
|
14
|
+
screenshot_embed
|
15
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'calabash-android/management/adb'
|
2
|
+
require 'calabash-android/operations'
|
3
|
+
require 'kraken-mobile/test_scenario'
|
4
|
+
|
5
|
+
def start_test_kraken_server_in_background
|
6
|
+
start_test_server_in_background
|
7
|
+
|
8
|
+
DeviceProcess.notify_process_state(
|
9
|
+
process_id: process_id,
|
10
|
+
state: K::PROCESS_STATES[:ready_to_start]
|
11
|
+
)
|
12
|
+
|
13
|
+
Timeout.timeout(K::DEFAULT_START_TIMEOUT_SECONDS, RuntimeError) do
|
14
|
+
sleep(1) until TestScenario.ready_to_start?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def shutdown_test_kraken_server
|
19
|
+
DeviceProcess.notify_process_state(
|
20
|
+
process_id: process_id,
|
21
|
+
state: K::PROCESS_STATES[:ready_to_finish]
|
22
|
+
)
|
23
|
+
|
24
|
+
Timeout.timeout(K::DEFAULT_FINISH_TIMEOUT_SECONDS, RuntimeError) do
|
25
|
+
sleep(1) until TestScenario.ready_to_finish?
|
26
|
+
end
|
27
|
+
|
28
|
+
shutdown_test_server
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def process_id
|
34
|
+
tag_process_id = @scenario_tags.grep(/@user/).first
|
35
|
+
tag_process_id.delete_prefix('@user')
|
36
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'kraken-mobile/test_scenario'
|
2
|
+
|
3
|
+
def start_test_kraken_server_in_background(scenario:)
|
4
|
+
@scenario_tags = scenario.source_tag_names
|
5
|
+
DeviceProcess.notify_process_state(
|
6
|
+
process_id: process_id(scenario: scenario),
|
7
|
+
state: K::PROCESS_STATES[:ready_to_start]
|
8
|
+
)
|
9
|
+
|
10
|
+
Timeout.timeout(K::DEFAULT_START_TIMEOUT_SECONDS, RuntimeError) do
|
11
|
+
sleep(1) until TestScenario.ready_to_start?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def shutdown_test_kraken_server(scenario:)
|
16
|
+
@scenario_tags = scenario.source_tag_names
|
17
|
+
DeviceProcess.notify_process_state(
|
18
|
+
process_id: process_id(scenario: scenario),
|
19
|
+
state: K::PROCESS_STATES[:ready_to_finish]
|
20
|
+
)
|
21
|
+
|
22
|
+
Timeout.timeout(K::DEFAULT_FINISH_TIMEOUT_SECONDS, RuntimeError) do
|
23
|
+
sleep(1) until TestScenario.ready_to_finish?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def process_id(scenario:)
|
30
|
+
scenario_tags = scenario.source_tag_names
|
31
|
+
tag_process_id = scenario_tags.grep(/@user/).first
|
32
|
+
tag_process_id.delete_prefix('@user')
|
33
|
+
end
|