SurfCustomCalabash 0.2.0 → 1.0.0
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/CHANGELOG.md +11 -0
- data/README.md +68 -4
- data/SurfCustomCalabash.gemspec +3 -3
- data/bin/SurfCustomCalabash +54 -0
- data/bin/surf-calabash-console.rb +62 -0
- data/bin/surf-calabash-gen.rb +17 -0
- data/bin/surf-calabash-helpers.rb +34 -0
- data/lib/SurfCustomCalabash/CommonMethods.rb +3 -3
- data/lib/SurfCustomCalabash/DroidMethods.rb +2 -1
- data/lib/SurfCustomCalabash/IosMethods.rb +2 -2
- data/lib/SurfCustomCalabash/version.rb +1 -1
- data/sources/Backdoors list b/data/sources/Backdoors → list +0 -0
- data/sources/Gemfile +27 -0
- data/sources/Scripts/and.sh +5 -0
- data/sources/Scripts/ca.sh +5 -0
- data/sources/Scripts/ci.sh +5 -0
- data/sources/Scripts/data +7 -0
- data/sources/Scripts/fa.sh +6 -0
- data/sources/Scripts/fi.sh +5 -0
- data/sources/Scripts/get_apk.rb +68 -0
- data/sources/Scripts/get_scenarios.rb +193 -0
- data/sources/Scripts/import_scenarios.rb +172 -0
- data/sources/Scripts/ios.sh +5 -0
- data/sources/Scripts/parallel_android_smoke.sh +4 -0
- data/sources/Scripts/parallel_android_test.sh +4 -0
- data/sources/Scripts/ra.sh +12 -0
- data/sources/Scripts/ri.sh +9 -0
- data/sources/Scripts/smoke_and.sh +5 -0
- data/sources/Scripts/smoke_ios.sh +5 -0
- data/sources/Scripts/ta.sh +5 -0
- data/sources/Scripts/ti.sh +5 -0
- data/sources/Scripts/to_exec.sh +19 -0
- data/sources/Scripts/update.sh +24 -0
- data/sources/Scripts/update_exec.rb +96 -0
- data/sources/TestFolder/small.gif +0 -0
- data/sources/ci/JenkinsfileUiTestAndroid.groovy +22 -0
- data/sources/ci/JenkinsfileUiTestIos.groovy +23 -0
- data/sources/config/cucumber.yml +24 -0
- data/sources/features/android/pages/standard/DroidCommon.rb +33 -0
- data/sources/features/android/pages/standard/Init_android.rb +8 -0
- data/sources/features/android/pages/test.rb +43 -0
- data/sources/features/android/support/app_life_cycle_hooks.rb +147 -0
- data/sources/features/android/support/log_hooks_and.rb +40 -0
- data/sources/features/android/support/video_hooks_and.rb +110 -0
- data/sources/features/ios/pages/standard/Init_ios.rb +5 -0
- data/sources/features/ios/pages/standard/IosCommon.rb +30 -0
- data/sources/features/ios/pages/test.rb +37 -0
- data/sources/features/ios/support/01_launch.rb +194 -0
- data/sources/features/ios/support/log_hooks_ios.rb +40 -0
- data/sources/features/ios/support/video_hooks_ios.rb +58 -0
- data/sources/features/net/net.rb +28 -0
- data/sources/features/net/screentest_api.rb +186 -0
- data/sources/features/scenarios/eng.feature +8 -0
- data/sources/features/scenarios/rus.feature +8 -0
- data/sources/features/step_definitions/test.rb +43 -0
- data/sources/features/support/credentials.rb +11 -0
- data/sources/features/support/env.rb +8 -0
- data/sources/features/support/hooks.rb +21 -0
- data/sources/features/support/localization.rb +8 -0
- data/sources/find_id.rb +95 -0
- data/sources/group_steps.rb +39 -0
- data/sources/irbrcs/android/irbrc +105 -0
- data/sources/irbrcs/ios/irbrc +132 -0
- data/sources/start.sh +134 -0
- metadata +63 -6
- data/bin/console +0 -14
- data/bin/setup +0 -8
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
|
3
|
+
# we use API-method for a clearing state
|
4
|
+
|
5
|
+
def delete_all_posts_from_profile
|
6
|
+
|
7
|
+
token = $user[:accesstoken]
|
8
|
+
user_id = $user[:userid]
|
9
|
+
|
10
|
+
response_posts = RestClient.get 'https://test/users/' + user_id + '/posts?filter=0&limit=100&offset=0',
|
11
|
+
{'access-token' => token}
|
12
|
+
|
13
|
+
post_id = Array.new
|
14
|
+
post_id.clear
|
15
|
+
|
16
|
+
list_post = JSON.parse(response_posts.body)
|
17
|
+
post_items = list_post['items']
|
18
|
+
post_items.each {|value| post_id << value['id']}
|
19
|
+
|
20
|
+
for i in 0..post_id.length - 1
|
21
|
+
|
22
|
+
RestClient.delete 'https://test/posts/' + post_id[i].to_s,
|
23
|
+
{'access-token' => token}
|
24
|
+
|
25
|
+
sleep(1.5)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
require 'csv'
|
3
|
+
require 'base64'
|
4
|
+
require 'benchmark'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
$main_big_boom_address = "https://snaptest.ps.surfstudio.ru/api/"
|
8
|
+
$api_mark_as_not_finished = "mark_not_finished/"
|
9
|
+
$api_create_execution = "create_execution/"
|
10
|
+
$api_create_feature = "create_feature/"
|
11
|
+
$api_create_step = "create_step/"
|
12
|
+
$api_compare = "compare/"
|
13
|
+
$api_add_video = "add_video/"
|
14
|
+
$stack_trace_file_name = "stacktrace.log"
|
15
|
+
|
16
|
+
#запрос POST возвращающий весь response
|
17
|
+
def request_post(address, json = {})
|
18
|
+
begin
|
19
|
+
headers = {content_type: :json, accept: :json, Authorization: $token}
|
20
|
+
RestClient::Request.execute(
|
21
|
+
:url => $main_big_boom_address + address,
|
22
|
+
:method => :post,
|
23
|
+
:headers => headers,
|
24
|
+
:payload => json.to_json,
|
25
|
+
:verify_ssl => false
|
26
|
+
)
|
27
|
+
rescue RestClient::ExceptionWithResponse => e
|
28
|
+
if e.http_code == 401
|
29
|
+
fail("Указан недействительный Api-Key")
|
30
|
+
else
|
31
|
+
print(e.http_body)
|
32
|
+
fail("Запрос завершился не успешно: #{e.http_code}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# формируем json и отправляем post запрос create_execution, полученный execution_id сохраняем в глобальную переменную
|
38
|
+
def create_execution_base(execution_name, device, app_version, os_version)
|
39
|
+
object = {
|
40
|
+
'execution_name' => execution_name.to_s,
|
41
|
+
'device' => device.to_s,
|
42
|
+
'app_version' => app_version.to_s,
|
43
|
+
'os_version' => os_version.to_s
|
44
|
+
}
|
45
|
+
get_execution_data = request_post($api_create_execution, object)
|
46
|
+
execution_data = JSON.parse(get_execution_data)
|
47
|
+
$execution_id = execution_data['execution_id']
|
48
|
+
end
|
49
|
+
|
50
|
+
# формируем json и отправляем post запрос create_feature, полученный feature_id сохраняем в глобальную переменную
|
51
|
+
def create_feature_base(execution_id, feature_name)
|
52
|
+
object = {
|
53
|
+
'execution_id' => execution_id,
|
54
|
+
'feature_name' => feature_name.to_s
|
55
|
+
}
|
56
|
+
get_feature_data = request_post($api_create_feature, object)
|
57
|
+
feature_data = JSON.parse(get_feature_data)
|
58
|
+
$feature_id = feature_data['feature_id']
|
59
|
+
end
|
60
|
+
|
61
|
+
# временный запрос для фикса бд
|
62
|
+
def fix_ids
|
63
|
+
object = {}
|
64
|
+
get_api_key
|
65
|
+
fix_ids = request_post($api_fix_image_paths, object)
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
# формируем json и отправляем post запрос create_step, полученный step_id сохраняем в глобальную переменную
|
70
|
+
def create_step_base(feature_id, step_name, device, resolution)
|
71
|
+
object = {
|
72
|
+
'feature_id' => feature_id,
|
73
|
+
'step_name' => step_name.to_s,
|
74
|
+
'device' => device.to_s,
|
75
|
+
'resolution' => resolution
|
76
|
+
}
|
77
|
+
get_step_data = request_post($api_create_step, object)
|
78
|
+
body_step_data = JSON.parse(get_step_data)
|
79
|
+
$step_id = body_step_data['step_id']
|
80
|
+
end
|
81
|
+
|
82
|
+
# формируем json и отправляем post запрос mark feature as not finished
|
83
|
+
def compare_base(step_id, screenshot)
|
84
|
+
object = {
|
85
|
+
'step_id' => step_id,
|
86
|
+
'photo' => screenshot.to_s,
|
87
|
+
}
|
88
|
+
request_post($api_compare, object)
|
89
|
+
end
|
90
|
+
|
91
|
+
# формируем json и отправляем post запрос mark feature as not finished
|
92
|
+
def video_base(feature_id, video)
|
93
|
+
object = {
|
94
|
+
'feature_id' => feature_id,
|
95
|
+
'video' => video.to_s,
|
96
|
+
}
|
97
|
+
request_post($api_add_video, object)
|
98
|
+
end
|
99
|
+
|
100
|
+
# формируем json и отправляем post запрос помечающий фичу как not finished
|
101
|
+
def mark_feature_as_not_finished(feature_id = $feature_id)
|
102
|
+
begin
|
103
|
+
stack_trace = File.readlines($stack_trace_file_name).drop(1)
|
104
|
+
rescue
|
105
|
+
stack_trace = "file with stack trace not found"
|
106
|
+
end
|
107
|
+
object = {
|
108
|
+
'feature_id' => feature_id,
|
109
|
+
'stack_trace' => stack_trace.to_s
|
110
|
+
}
|
111
|
+
request_post($api_mark_as_not_finished, object)
|
112
|
+
end
|
113
|
+
|
114
|
+
# создаём прогон с передаваемым названием и сохраняем его id в глобальную переменную
|
115
|
+
def create_execution(execution_name)
|
116
|
+
get_api_key
|
117
|
+
$main.get_device_data
|
118
|
+
$execution_id = create_execution_base(execution_name, $device_name, $app_version, $os_version)
|
119
|
+
end
|
120
|
+
|
121
|
+
# создаём фичу с передаваемым названием и сохраняем его id в глобальную переменную
|
122
|
+
def create_feature(execution_id = $execution_id, feature_name)
|
123
|
+
$feature_id = create_feature_base(execution_id, feature_name)
|
124
|
+
end
|
125
|
+
|
126
|
+
# создаём шаг, делаем скриншот с устройства и запускаем процесс сравнения на сервере
|
127
|
+
def create_test_step(step_name)
|
128
|
+
create_step(step_name)
|
129
|
+
screenshot_path = take_screenshot(step_name)
|
130
|
+
img_base64 = file_to_base64(screenshot_path)
|
131
|
+
File.delete(screenshot_path)
|
132
|
+
compare(img_base64)
|
133
|
+
end
|
134
|
+
|
135
|
+
# создаём шаг в созданном прогоне с передаваемым названием и сохраняем его id в глобальную переменную
|
136
|
+
def create_step(feature_id = $feature_id, step_name)
|
137
|
+
$step_id = create_step_base(feature_id, step_name, $device_name, $resolution)
|
138
|
+
end
|
139
|
+
|
140
|
+
# запускаем процесс сравнения на бэке, отправляем айди шага и скриншот для сравнения
|
141
|
+
def compare(step_id = $step_id, screenshot)
|
142
|
+
compare_base(step_id, screenshot)
|
143
|
+
end
|
144
|
+
|
145
|
+
# создаём шаг, делаем скриншот с устройства и запускаем процесс сравнения на сервере
|
146
|
+
def send_video(feature_id = $feature_id, video_path)
|
147
|
+
sleep(2)
|
148
|
+
video_base64 = file_to_base64(video_path)
|
149
|
+
video_base(feature_id, video_base64)
|
150
|
+
#File.delete(video_path)
|
151
|
+
end
|
152
|
+
|
153
|
+
# достаём из файла api key и сохраняем его в глобальную переменную
|
154
|
+
def get_api_key
|
155
|
+
file_path = "./api_key.txt"
|
156
|
+
if File.exist?(file_path)
|
157
|
+
file = File.new("./api_key.txt","r:UTF-8")
|
158
|
+
api_key = file.readlines
|
159
|
+
$token = "Api-Key #{api_key[0]}"
|
160
|
+
file.close
|
161
|
+
else
|
162
|
+
fail("Файл с Api Key не найден.")
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# сделать скриншот и записать его куда надо
|
167
|
+
def take_screenshot(name)
|
168
|
+
path = './reports/'
|
169
|
+
name = "#{name}.png"
|
170
|
+
screenshot_path = screenshot(:prefix => path, :name => name)
|
171
|
+
end
|
172
|
+
|
173
|
+
# на входе получаем фото или видео и кодируем его в base64
|
174
|
+
def file_to_base64(file_path)
|
175
|
+
base64_file =
|
176
|
+
File.open(file_path, "rb") do |file|
|
177
|
+
Base64.strict_encode64(file.read)
|
178
|
+
end
|
179
|
+
return base64_file
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
# очищаем файл в котором находится весь вывод, если этот файл существует
|
184
|
+
def clear_file_with_stack_trace
|
185
|
+
File.open($stack_trace_file_name, 'w'){ |file| file.truncate(0) } if File.exists?($stack_trace_file_name)
|
186
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
#language: ru
|
2
|
+
# Definitions or Ruby for all steps in Gherkin
|
3
|
+
|
4
|
+
И (/^Я запускаю приложение$/) do
|
5
|
+
wait_for do
|
6
|
+
!query('*').empty?
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
And (/^I start the application$/) do
|
12
|
+
wait_for do
|
13
|
+
!query('*').empty?
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
Тогда(/^Я использую Gmail для авторизации$/) do
|
19
|
+
$user = CREDENTIALS[:twitter]
|
20
|
+
$test.wait_element($test.auth_field)
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
Тогда(/^Я использую Gmail для авторизации$/) do
|
25
|
+
$user = CREDENTIALS[:twitter]
|
26
|
+
$test.wait_element($test.auth_field)
|
27
|
+
$test.authorize("#{$user[:token].to_s}%#{$user[:number].to_s}")
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
And(/^I use gmail for authorization$/) do
|
32
|
+
$user = CREDENTIALS[:twitter]
|
33
|
+
$test.wait_element($test.auth_field)
|
34
|
+
$test.authorize("#{$user[:token].to_s}%#{$user[:number].to_s}")
|
35
|
+
end
|
36
|
+
|
37
|
+
И(/^Я авторизуюсь от разных пользователей$/) do
|
38
|
+
if ENV['PLATFORM'] == 'ios'
|
39
|
+
steps %Q{И Я авторизуюсь под пользователем для ios}
|
40
|
+
elsif ENV['PLATFORM'] == 'android'
|
41
|
+
steps %Q{И Я авторизуюсь под пользователем для android}
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
if ENV['PLATFORM'] == 'ios'
|
2
|
+
require 'calabash-cucumber/cucumber'
|
3
|
+
require_relative '../ios/pages/standard/IosCommon'
|
4
|
+
elsif ENV['PLATFORM'] == 'android'
|
5
|
+
require 'calabash-android/cucumber'
|
6
|
+
require_relative '../../features/android/pages/standard/DroidCommon'
|
7
|
+
end
|
8
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#On the start execution we should create all Page objects.
|
2
|
+
|
3
|
+
if ENV['PLATFORM'] == 'ios'
|
4
|
+
|
5
|
+
Before do |scenario|
|
6
|
+
init_ios
|
7
|
+
end
|
8
|
+
|
9
|
+
elsif ENV['PLATFORM'] == 'android'
|
10
|
+
|
11
|
+
Before do |scenario|
|
12
|
+
init_android
|
13
|
+
end
|
14
|
+
|
15
|
+
else Kernel.puts('Error in hooks.rb file!')
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
|
data/sources/find_id.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
class Find
|
2
|
+
|
3
|
+
def find_id_dev(path)
|
4
|
+
|
5
|
+
sub_lines = Array.new
|
6
|
+
|
7
|
+
# path to dir with r-files
|
8
|
+
file_names = Dir["#{path}/**/R.java"]
|
9
|
+
|
10
|
+
file_names.each do |name|
|
11
|
+
Kernel.puts(name)
|
12
|
+
|
13
|
+
lines = Array.new
|
14
|
+
text=File.open(name).read
|
15
|
+
text.gsub!(/\r\n?/, "\n")
|
16
|
+
text.each_line do |line|
|
17
|
+
lines.push(line)
|
18
|
+
end
|
19
|
+
|
20
|
+
if !lines.index{|x| x.match(/public static final class id {/)}.nil?
|
21
|
+
|
22
|
+
start_push = false
|
23
|
+
lines.each do |x|
|
24
|
+
if !x.match(/public static final class id {/).nil?
|
25
|
+
start_push = true
|
26
|
+
elsif !x.match(/\s}/).nil?
|
27
|
+
start_push = false
|
28
|
+
end
|
29
|
+
if start_push and x.match(/public static final class id {/).nil? and x.match(/}/).nil?
|
30
|
+
x.sub! /.*int/, ''
|
31
|
+
x.sub! /\=.*/, ''
|
32
|
+
sub_lines.push(x.strip)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
sub_lines.uniq!
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
p sub_lines.length
|
40
|
+
return sub_lines
|
41
|
+
end
|
42
|
+
|
43
|
+
def find_id_test(path)
|
44
|
+
sub_lines = Array.new
|
45
|
+
|
46
|
+
file_names = Dir["#{path}/**/*.rb"]
|
47
|
+
file_names.each do |name|
|
48
|
+
|
49
|
+
Kernel.puts(name)
|
50
|
+
|
51
|
+
lines = Array.new
|
52
|
+
text=File.open(name).read
|
53
|
+
text.gsub!(/\r\n?/, "\n")
|
54
|
+
text.each_line do |line|
|
55
|
+
lines.push(line)
|
56
|
+
end
|
57
|
+
|
58
|
+
if !lines.index{|x| x.match(/def initialize/)}.nil?
|
59
|
+
|
60
|
+
start_push = false
|
61
|
+
lines.each do |x|
|
62
|
+
if !x.match(/\@/).nil?
|
63
|
+
start_push = true
|
64
|
+
elsif !x.match(/end}/).nil?
|
65
|
+
start_push = false
|
66
|
+
end
|
67
|
+
if start_push and !x.match(/@/).nil? and
|
68
|
+
!x.match(/\* id/).nil? and
|
69
|
+
x.match(/CONTAINS/).nil? and
|
70
|
+
x.match(/\.widget/).nil? and
|
71
|
+
x.match(/\.BEGINSWITH/).nil? and
|
72
|
+
x.match(/text:/).nil? and
|
73
|
+
x.sub! /.*\* id:'/, ''
|
74
|
+
x.sub! /'".*/, ''
|
75
|
+
x.sub! /' index:.*/, ''
|
76
|
+
sub_lines.push(x.strip)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
sub_lines.uniq!
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
p sub_lines.length
|
85
|
+
return sub_lines
|
86
|
+
end
|
87
|
+
|
88
|
+
def get_miss_id(dev_path, test_path)
|
89
|
+
miss_id = find_id_test(test_path) - find_id_dev(dev_path)
|
90
|
+
|
91
|
+
File.open("miss_id.txt", "w+") do |f|
|
92
|
+
miss_id.each{|x| f.puts(x)}
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
class GroupScenarios
|
4
|
+
|
5
|
+
# get all failed scenarios
|
6
|
+
def parse_json(json_file)
|
7
|
+
file = File.read(json_file)
|
8
|
+
data_hash = JSON.parse(file)
|
9
|
+
|
10
|
+
failed_steps = Hash.new
|
11
|
+
|
12
|
+
data_hash.each do |feature|
|
13
|
+
feature['elements'].each do |scenarios|
|
14
|
+
scenarios['steps'].each do |steps|
|
15
|
+
if steps['result']['status'] == 'failed'
|
16
|
+
hash_key = scenarios['name']
|
17
|
+
failed_steps[hash_key] = steps['name']
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
return failed_steps
|
24
|
+
end
|
25
|
+
|
26
|
+
def group_failed_scenarios(json_file, output_file)
|
27
|
+
group_hash = parse_json(json_file).group_by{ |k, v| v}
|
28
|
+
File.open(output_file, "w:UTF-8") do |file|
|
29
|
+
group_hash.each do |step, values|
|
30
|
+
count = values.count
|
31
|
+
file.puts("\nНа шаге '#{step}' упало #{count} сценария:")
|
32
|
+
values.each do |element|
|
33
|
+
element.delete(step)
|
34
|
+
file.puts(" #{element[0]}")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|