kraken-mobile 1.0.4 → 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|