SurfCustomCalabash 0.2.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|