kraken-mobile 1.0.4 → 1.0.5
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 +4 -4
- data/README.md +45 -11
- data/bin/kraken-mobile +55 -67
- data/bin/kraken_mobile_calabash_android.rb +39 -0
- data/bin/kraken_mobile_helpers.rb +91 -0
- data/bin/kraken_mobile_setup.rb +134 -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 +94 -0
- data/lib/kraken-mobile/helpers/devices_helper/adb_helper.rb +100 -105
- data/lib/kraken-mobile/helpers/kraken_faker.rb +107 -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 +82 -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 +108 -0
- data/lib/kraken-mobile/models/feature_scenario.rb +24 -0
- data/lib/kraken-mobile/models/web_device.rb +86 -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/runners/calabash/android/steps/communication_steps.rb +15 -0
- data/lib/kraken-mobile/steps/general_steps.rb +82 -0
- data/lib/kraken-mobile/steps/mobile/kraken_steps.rb +72 -0
- data/lib/kraken-mobile/steps/web/kraken_steps.rb +81 -0
- data/lib/kraken-mobile/test_scenario.rb +193 -0
- data/lib/kraken-mobile/utils/feature_reader.rb +17 -0
- data/lib/kraken-mobile/utils/k.rb +67 -0
- data/lib/kraken-mobile/utils/mobile_cucumber.rb +2 -0
- data/lib/kraken-mobile/utils/reporter.rb +453 -0
- data/lib/kraken-mobile/version.rb +2 -2
- data/lib/kraken-mobile/web/web_process.rb +39 -0
- data/lib/kraken_mobile.rb +77 -0
- data/reporter/index.html.erb +6 -6
- metadata +89 -9
- 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 @@
|
|
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,94 @@
|
|
1
|
+
# Abstract class
|
2
|
+
class DeviceProcess
|
3
|
+
attr_accessor :id
|
4
|
+
attr_accessor :device
|
5
|
+
attr_accessor :test_scenario
|
6
|
+
|
7
|
+
#-------------------------------
|
8
|
+
# Constructors
|
9
|
+
#-------------------------------
|
10
|
+
def initialize(id:, device:, test_scenario:)
|
11
|
+
@id = id
|
12
|
+
@device = device
|
13
|
+
@test_scenario = test_scenario
|
14
|
+
end
|
15
|
+
|
16
|
+
#-------------------------------
|
17
|
+
# Required methods
|
18
|
+
#-------------------------------
|
19
|
+
def before_execute
|
20
|
+
raise 'ERROR: before_execute not implemented.'
|
21
|
+
end
|
22
|
+
|
23
|
+
def execute
|
24
|
+
raise 'ERROR: execute not implemented.'
|
25
|
+
end
|
26
|
+
|
27
|
+
def after_execute
|
28
|
+
raise 'ERROR: after_execute not implemented.'
|
29
|
+
end
|
30
|
+
|
31
|
+
def run
|
32
|
+
before_execute
|
33
|
+
execute
|
34
|
+
after_execute
|
35
|
+
end
|
36
|
+
|
37
|
+
#-------------------------------
|
38
|
+
# Methods
|
39
|
+
#-------------------------------
|
40
|
+
def register_process_to_directory
|
41
|
+
File.open(K::DIRECTORY_PATH, 'a') do |file|
|
42
|
+
file.puts("#{id}#{K::SEPARATOR}#{device}")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def notify_ready_to_start
|
47
|
+
File.open(K::DIRECTORY_PATH, 'a') do |file|
|
48
|
+
file.puts("#{id}#{K::SEPARATOR}#{device}")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.directory
|
53
|
+
return [] unless File.exist?(K::DIRECTORY_PATH)
|
54
|
+
|
55
|
+
directory = nil
|
56
|
+
File.open(K::DIRECTORY_PATH, 'r') do |file|
|
57
|
+
directory = file.each_line.map(&:to_s).map(&:strip)
|
58
|
+
end
|
59
|
+
|
60
|
+
directory || []
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.registered_process_ids
|
64
|
+
directory = DeviceProcess.directory
|
65
|
+
directory.map do |entry|
|
66
|
+
info = entry.strip.split(K::SEPARATOR)
|
67
|
+
info[0]
|
68
|
+
end.compact.uniq
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.notify_process_state(process_id:, state:)
|
72
|
+
raise 'ERROR: Process id can\'t be nil.' if process_id.nil?
|
73
|
+
|
74
|
+
file_path = K::PROCESS_STATE_FILE_PATH[state]
|
75
|
+
raise 'ERROR: State does not exist.' if file_path.nil?
|
76
|
+
|
77
|
+
File.open(file_path, 'a') do |file|
|
78
|
+
file.puts(process_id)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.processes_in_state(state)
|
83
|
+
file_path = K::PROCESS_STATE_FILE_PATH[state]
|
84
|
+
return [] if file_path.nil?
|
85
|
+
return [] unless File.exist?(file_path)
|
86
|
+
|
87
|
+
devices_ready = nil
|
88
|
+
File.open(file_path, 'r') do |file|
|
89
|
+
devices_ready = file.each_line.map(&:to_s).map(&:strip)
|
90
|
+
end
|
91
|
+
|
92
|
+
devices_ready || []
|
93
|
+
end
|
94
|
+
end
|
@@ -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,107 @@
|
|
1
|
+
require 'faker'
|
2
|
+
require 'kraken-mobile/utils/k'
|
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
|
+
JSON.parse(content)
|
60
|
+
end
|
61
|
+
|
62
|
+
def create_dictionary_json_file
|
63
|
+
absolute_dictionary_path = File.expand_path(K::DICTIONARY_PATH)
|
64
|
+
File.open(absolute_dictionary_path, 'w') do |f|
|
65
|
+
f.puts({}.to_json)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def dictionary_json_file_exists?
|
70
|
+
absolute_dictionary_path = File.expand_path(K::DICTIONARY_PATH)
|
71
|
+
File.file?(absolute_dictionary_path)
|
72
|
+
end
|
73
|
+
|
74
|
+
def save_key_value_in_dictionary(key:, value:)
|
75
|
+
current_json = dictionary_json
|
76
|
+
current_json[process_id.to_s] = {} if current_json[process_id.to_s].nil?
|
77
|
+
current_json[process_id.to_s][key.to_s] = value
|
78
|
+
|
79
|
+
absolute_dictionary_path = File.expand_path(K::DICTIONARY_PATH)
|
80
|
+
open(absolute_dictionary_path, 'w') do |f|
|
81
|
+
f.puts(current_json.to_json)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
#-------------------------------
|
86
|
+
# Generators
|
87
|
+
#-------------------------------
|
88
|
+
def generate_name
|
89
|
+
Faker::Name.first_name
|
90
|
+
end
|
91
|
+
|
92
|
+
def generate_number
|
93
|
+
Faker::Number.number(digits: rand(10))
|
94
|
+
end
|
95
|
+
|
96
|
+
def generate_email
|
97
|
+
Faker::Internet.email
|
98
|
+
end
|
99
|
+
|
100
|
+
def generate_string
|
101
|
+
Faker::String.random(length: rand(100))
|
102
|
+
end
|
103
|
+
|
104
|
+
def generate_date
|
105
|
+
Faker::Date.in_date_period.to_s
|
106
|
+
end
|
107
|
+
end
|