tms-cli 0.0.pre.beta

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 126ea4c79dfe3ba2f0577507e6710dd6a87b54931bd88503ff73f69d87bda43a
4
+ data.tar.gz: f05c3543997e9f3f9e1452d87e99c1a742abcb6bf2fd2ff5703e93bba947e6ca
5
+ SHA512:
6
+ metadata.gz: 99d223285e06a2ec541feed40f9b2462c332deedf529944708491736741a815e6b06306cff1f152c9c818b22b5020ee4b3e480a3c189759ba26e3b2ebe6bf3b9
7
+ data.tar.gz: cf16282634835829b2fdc037c1a0377f290ddf70cf9e5339af5d675dd180f2055b39ae72b76e17aa45bc5e65ffa2f261e021dc19838a2693ea0061569f9aca45
data/bin/tms ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # frozen_string_literal: true
4
+
5
+ require 'lib/tms'
data/lib/.env ADDED
@@ -0,0 +1,11 @@
1
+ TR_USERNAME=core.quality@bukalapak.com
2
+ TR_SECRET=coretebukalapak
3
+ TR_API_KEY=mrVfIsQkG0yhFChoR7j/9r+4GydgMykS7FplZ6/tiXieOIzBKGGRjeI=
4
+ DB_TR_PORT=3306
5
+ DB_TR_USERNAME=usr_testrail_rw
6
+ DB_TR=testrail
7
+ DB_TR_HOST=mysql-tools-prod-testrail-main.mysql.database.azure.com
8
+ DB_TR_PASSWORD=8Z9YJfsUGmSKOnshe6vO/A==
9
+ TR_BASEURL=https://testrail.prod.tools.buka20.com/
10
+ TR_PASSWORD=/rJHEOwcShrdUA==
11
+ BASTION_HOST=bastion.prod.tools.buka20.com
data/lib/cucumber.rb ADDED
@@ -0,0 +1,369 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'testrail/testrail'
4
+ require_relative 'testrail/milestone'
5
+ require_relative 'testrail/testcase'
6
+ require_relative 'testrail/testrun'
7
+ require_relative 'testrail/dataprep'
8
+ require_relative 'testrail/testsuite'
9
+ require_relative 'testrail/testplan'
10
+ require_relative 'testrail/sections'
11
+ require_relative 'testrail/projects'
12
+ require_relative 'testrail/log'
13
+ require_relative 'testrail/testbdd'
14
+
15
+
16
+ module Tms
17
+ module Cucumber
18
+ module_function
19
+
20
+ include Dataprep
21
+ include Milestone
22
+ include Testcase
23
+ include Testrun
24
+ include Testsuite
25
+ include Testplan
26
+ include Sections
27
+ include Projects
28
+ include Log
29
+ include Testbdd
30
+
31
+ # Create test run cucumber test for micorservice project
32
+ # @param project name
33
+ # @param test type (suite)
34
+ # @param squad name
35
+ # @param custom label
36
+ # @param milestone name
37
+ def create_test_run_microservice(project_name, test_type, squad, label, milestone_name)
38
+ # getting project id
39
+ test_type = test_type
40
+ client = Dataprep.client_tr
41
+ tr_version = Dataprep.testrail_version(client, ENV['TR_BASEURL'])
42
+
43
+ project_id = search_project(client, project_name)
44
+ puts 'project_id found: ' + project_id.to_s if !project_id.nil?
45
+
46
+ milestone_id = Milestone.milestone_id(client, project_id, milestone_name, tr_version)
47
+ suite_id = search_suite(client, project_id, test_type)
48
+ case_ids = search_cases(client, project_id, suite_id, squad, label)
49
+ raise 'no cases found' if case_ids.empty?
50
+
51
+ test_run_name = "Test_Run_E2E_#{squad}_#{test_type}"
52
+ response = Testrun.testrun_id_by_milestone(client, project_id, milestone_id)
53
+ find_test_run = response.find { |run| run['name'] == test_run_name }
54
+ run_id = find_test_run&.fetch('id', nil)
55
+ test_run = run_id.nil? ? Testrun.create_testrun(client, project_id, suite_id, milestone_id, case_ids, test_run_name) : run_id
56
+
57
+ getter_testrail_clean_dependencies(test_type, milestone_id, test_run)
58
+
59
+ return test_run
60
+ end
61
+
62
+ # Create test run cucumber test for app project
63
+ # @param project name
64
+ # @param test type (suite)
65
+ # @param squad name
66
+ # @param custom label
67
+ def create_test_run_app(project_name, squad, env_name, test_type, label, pipeline_id, custom_section)
68
+ client = Dataprep.client_tr
69
+ puts project_name.split('_')[1]
70
+ project_id = app_project_id(project_name)
71
+ suite_id = search_suite(client, project_id, squad)
72
+ automation_section_ids = find_automation_section(client, project_id, suite_id, project_name.split('_')[1], env_name, custom_section)
73
+ case_ids = search_cases_by_section_ids(client, project_id, suite_id, automation_section_ids, label)
74
+
75
+ raise 'no cases found' if case_ids.empty?
76
+
77
+ test_run_name = "Test_Run_#{squad}_#{test_type}_#{env_name}_#{pipeline_id}"
78
+ response = Testrun.testrun_id_by_suite(client, project_id, milestone_id = '', suite_id)
79
+ find_test_run = response.find { |run| run['name'] == test_run_name }
80
+ run_id = find_test_run&.fetch('id', nil)
81
+ if run_id.nil?
82
+ puts "Creating #{test_run_name}..."
83
+ test_run = Testrun.create_testrun(client, project_id, suite_id, 0, case_ids, test_run_name)
84
+ else
85
+ puts "Updating #{test_run_name}..."
86
+ test_run = Testrun.update_testrun(client, run_id, milestone_id = '', case_ids)
87
+ end
88
+
89
+ getter_testrail_clean_dependencies(test_type, milestone_id = '', test_run)
90
+
91
+ return test_run
92
+ end
93
+
94
+ # Find sections of automation test
95
+ # @param client testrail
96
+ # @param project id
97
+ # @param suite id
98
+ # @param app name
99
+ # @param environment name
100
+ def find_automation_section(client, project_id, suite_id, app_name, env_name, custom_section)
101
+ sections = Sections.get_sections(client, project_id, suite_id)
102
+ app_section = sections['sections'].find { |section| section['name'].casecmp?(app_name) }
103
+ automation_section = sections['sections'].find{ |section|
104
+ section['name'].casecmp?('automation') && section['parent_id'].eql?(app_section['id'])
105
+ }
106
+
107
+ env_section = sections['sections'].find{ |section|
108
+ section['name'].casecmp?(env_name) && section['parent_id'].eql?(automation_section['id'])
109
+ }
110
+ parent_id = env_section['id']
111
+
112
+ # search for section directory hierarchy
113
+ target_section = {}
114
+ if !custom_section.eql? ""
115
+ sections_directory = custom_section.split('/')
116
+ sections_directory.each do | section_dir |
117
+ target_section = sections['sections'].find { |section|
118
+ section['name'].casecmp?(section_dir) && section['parent_id'].eql?(parent_id)
119
+ }
120
+ parent_id = target_section['id']
121
+ end
122
+ else
123
+ target_section = env_section
124
+ end
125
+
126
+ related_section_ids = find_related_sections(sections['sections'], target_section['id']) << target_section['id']
127
+ end
128
+
129
+ # Get project id
130
+ # @param client testrail
131
+ # @param project id
132
+ # @param suite id
133
+ # @param app name
134
+ # @param environment name
135
+ def app_project_id(app_name)
136
+ project = app_name.split("_")
137
+ platform = project[0]
138
+ project_ids = {
139
+ 'android' => ENV['TR_ANDROID_PROJECT_ID'],
140
+ 'ios' => ENV['TR_IOS_PROJECT_ID']
141
+ }
142
+
143
+ project_id = project_ids[platform] || (raise 'Incorrect app name!')
144
+ end
145
+
146
+ # Return all case ids from sections and filter with label
147
+ # @param client testrail
148
+ # @param project id
149
+ # @param suite id
150
+ # @param section_ids
151
+ # @param label
152
+ def search_cases_by_section_ids(client, project_id, suite_id, section_ids, label)
153
+ case_ids = []
154
+ puts label
155
+
156
+ section_ids.each do |id|
157
+ cases = Testcase.get_cases(client, project_id, suite_id, id)
158
+
159
+ # filter cases with label if any
160
+ filtered_cases =
161
+ if label.eql? ''
162
+ cases
163
+ else
164
+ cases.select { |case_data| case_data['custom_label_id']&.include?(label) }
165
+ end
166
+
167
+ case_ids.concat(filtered_cases.map { |case_data| case_data['id'] })
168
+ end
169
+
170
+ return case_ids
171
+ end
172
+
173
+ # Return project id of a project name
174
+ # @param client testrail
175
+ # @param project name
176
+ def search_project(client, project_name)
177
+ begin
178
+ projects = Projects.get_projects(client)
179
+ filtered_projects = projects.select { |project| project['name'].casecmp?(project_name) }
180
+
181
+ if filtered_projects.empty?
182
+ puts "#{project_name} is not available!"
183
+ else
184
+ return filtered_projects.first['id']
185
+ end
186
+
187
+ rescue StandardError => e
188
+ puts "An error occurred: #{e.message}"
189
+ end
190
+ end
191
+
192
+ # Return suite id of a test type
193
+ # @param client testrail
194
+ # @param project id
195
+ # @param suite name
196
+ def search_suite(client, project_id, suite_name)
197
+ begin
198
+ suites = Testsuite.suites(client, project_id)
199
+ filtered_suites = suites.select { |suite| suite['name'].casecmp?(suite_name) }
200
+
201
+ if filtered_suites.empty?
202
+ puts "#{suite_name} is not available!"
203
+ else
204
+ return filtered_suites.first['id']
205
+ end
206
+
207
+ rescue StandardError => e
208
+ puts "An error occurred: #{e.message}"
209
+ end
210
+ end
211
+
212
+ # Return array of case id from a squad section
213
+ # @param client testrail
214
+ # @param project id
215
+ # @param suite id
216
+ # @param section_name
217
+ # @param custom label
218
+ def search_cases(client, project_id, suite_id, section_name, label)
219
+ sections = Sections.get_sections(client, project_id, suite_id)
220
+ squad_section = sections['sections'].find { |section| section['name'].casecmp?(section_name) }
221
+ raise "squad section #{section_name} not found" if squad_section.eql? nil
222
+
223
+ puts 'squad section: ' + squad_section['id'].to_s
224
+ # search sections related to the squad section
225
+ related_sections_ids = find_related_sections(sections['sections'], squad_section['id']) << squad_section['id']
226
+ puts 'sections related from squad: ' + related_sections_ids.to_s
227
+
228
+ case_ids = []
229
+
230
+ related_sections_ids.each do |id|
231
+ cases = Testcase.get_cases(client, project_id, suite_id, id)
232
+ filtered_cases = []
233
+
234
+ if label.split(',').size > 1
235
+ arr_cases = []
236
+ label.split(',').each do |i|
237
+ tmp_filtered_cases = cases.select { |case_data| case_data['custom_label_id']&.include?(i) }
238
+ arr_cases.concat(tmp_filtered_cases)
239
+ end
240
+ filtered_cases = arr_cases
241
+ else
242
+ filtered_cases = cases.select { |case_data| case_data['custom_label_id']&.include?(label) }
243
+ end
244
+ case_ids.concat(filtered_cases.map { |case_data| case_data['id']})
245
+
246
+ end
247
+
248
+ return case_ids
249
+ end
250
+
251
+ # Return array of section id related to a parent id
252
+ # @param array of sections
253
+ # @param parent id
254
+ def find_related_sections(sections, parent_id)
255
+ child_ids = sections
256
+ .select { |obj| obj['parent_id'] == parent_id }
257
+ .flat_map { |obj| [obj['id']] + find_related_sections(sections, obj['id']) }
258
+
259
+ child_ids
260
+ end
261
+
262
+ # Download series of bdd cases from a test run
263
+ # @aram test run id
264
+ def feature_download(run_id)
265
+ client = Dataprep.client_tr
266
+ puts 'Get test cases for test run id: ' + run_id.to_s
267
+ num_test = 0
268
+ # Create the folder if it doesn't exist
269
+ folder_path = FileUtils.mkdir_p('scenarios')
270
+
271
+ tests = Testrun.test_ids(client, run_id)
272
+ puts "Downloading #{tests.size} test cases..."
273
+ tests.each do |test|
274
+ puts "downloading #{test['title']} feature..."
275
+ response_data = Testbdd.get_bdd(client, test['case_id'])
276
+
277
+ # handle test case with scenario outline included
278
+ response_data = Testbdd.get_case(client, test['case_id']) if response_data.include? ('Scenario Outline')
279
+
280
+ # Append test id as a feature label
281
+ # Handle if a feature already have labels
282
+ if response_data[0] == "@"
283
+ response_data = "@TESTID_#{test['id']} " + response_data
284
+ else
285
+ response_data = "@TESTID_#{test['id']}\n " + response_data
286
+ end
287
+
288
+ # Writes the data to a feature file
289
+ Dataprep.create_file("#{test['case_id']}.feature", folder_path, response_data)
290
+ end
291
+ end
292
+
293
+ # Download series of bdd cases from a test case directly (without create test run) on microservice
294
+ # @param project_name
295
+ # @param suite_name
296
+ # @param section_name
297
+ # @param label
298
+ def micr_download_feature_only(project_name, suite_name, squad, label)
299
+ client = Dataprep.client_tr
300
+
301
+ project_id = search_project(client, project_name)
302
+ suite_id = search_suite(client, project_id, suite_name)
303
+ case_ids = search_cases(client, project_id, suite_id, squad, label)
304
+ raise 'no cases found' if case_ids.empty?
305
+
306
+ download_features_to_local(client, case_ids)
307
+
308
+ getter_testrail_clean_dependencies(suite_name, '', '')
309
+ end
310
+
311
+ # Download series of bdd cases from a test case directly (without create test run) on apps
312
+ # @param project_name
313
+ # @param suite_name
314
+ # @param section_name
315
+ # @param label
316
+ def app_download_feature_only(project_name, squad, env_name, test_type, label, custom_section)
317
+ client = Dataprep.client_tr
318
+ puts project_name.split('_')[1]
319
+
320
+ project_id = app_project_id(project_name)
321
+ suite_id = search_suite(client, project_id, squad)
322
+ automation_section_ids = find_automation_section(client, project_id, suite_id, project_name.split('_')[1], env_name, custom_section)
323
+ case_ids = search_cases_by_section_ids(client, project_id, suite_id, automation_section_ids, label)
324
+ raise 'no cases found' if case_ids.empty?
325
+
326
+ download_features_to_local(client, case_ids)
327
+
328
+ getter_testrail_clean_dependencies(test_type, '', '')
329
+ end
330
+
331
+ # Download test cases to local storaged
332
+ # @param case_ids
333
+ def download_features_to_local(client, case_ids)
334
+ # Create the folder if it doesn't exist
335
+ folder_path = FileUtils.mkdir_p('scenarios')
336
+
337
+ puts "Download #{case_ids.size} test cases"
338
+ puts "This test will not create Milestone and Test Runs on Testrail"
339
+ case_ids.each do |cases|
340
+ response_data = Testbdd.get_bdd(client, cases)
341
+
342
+ # handle test case with scenario outline included
343
+ response_data = Testbdd.get_case(client, cases) if response_data.include? ('Scenario Outline')
344
+
345
+ # Writes the data to a feature file
346
+ Dataprep.create_file("#{cases}.feature", folder_path, response_data)
347
+ end
348
+ end
349
+
350
+ def getter_testrail_clean_dependencies(test_type, milestone_id, run_id)
351
+ test_type_upper = test_type.upcase
352
+ test_type_final = test_type_upper.gsub(/\s*AUTOMATION\s*/, '')
353
+ puts "Test Type: #{test_type_final}"
354
+ # Define your environment variables as a hash
355
+ env_variables = {
356
+ "TESTRAIL_TEST_TYPE" => test_type_final,
357
+ "TESTRAIL_#{test_type_final}_MILESTONE_ID" => milestone_id,
358
+ "TESTRAIL_#{test_type_final}_RUN_ID" => run_id
359
+ }
360
+
361
+ begin
362
+ Dataprep.create_file_env("testrail-data-post-test", env_variables)
363
+ rescue => e
364
+ puts "Create env failed: #{e.message}"
365
+ exit 1
366
+ end
367
+ end
368
+ end
369
+ end
data/lib/db/mysql.rb ADDED
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../util/script/generate-password'
4
+ require 'mysql2'
5
+
6
+ module Tms
7
+ module Database
8
+ module_function
9
+
10
+ include GeneratePassword
11
+
12
+ # This method will create client database
13
+ def connect_db
14
+ db_host = ENV['DB_TR_HOST']
15
+ db_port = ENV['DB_TR_PORT']
16
+ db_user = ENV['DB_TR_USERNAME']
17
+ db_pass = GeneratePassword.decrypt(ENV['DB_TR_PASSWORD'], ENV['TR_SECRET'])
18
+ db_name = ENV['DB_TR']
19
+ Mysql2::Client.new(:host => db_host, :port => db_port, :username => db_user, :password => db_pass, :database => db_name)
20
+ end
21
+
22
+ # This method will validate test runner on database
23
+ def runner_type(project_id, section_name)
24
+ test_runner = ''
25
+ connect_db.query("SELECT runner from runner_type where project_id=#{project_id} and test_type='#{section_name}'").each do |row|
26
+ test_runner = row['runner']
27
+ end
28
+ test_runner
29
+ end
30
+
31
+ # This method will insert test runner if not exist
32
+ def insert_runner_type(project_id, test_types_and_runner)
33
+ val = test_types_and_runner.split(',')
34
+ db_client = connect_db
35
+ response = db_client.query("SELECT * from runner_type where project_id=#{project_id} and test_type='#{val[0]}' and runner='#{val[1]}'")
36
+ if response.size.eql?(0)
37
+ db_client.query("INSERT INTO runner_type(project_id,test_type,runner) VALUE(#{project_id},'#{val[0]}','#{val[1]}');")
38
+ else
39
+ Log.info("Test type '#{val[0]}' with runner '#{val[1]}' already exist on project id '#{project_id}'")
40
+ end
41
+ end
42
+
43
+ # This method will generate config ssh and connect database from local via jump bastion
44
+ def jump_bastion(email_azure)
45
+ puts 'connect to vpn buka 2.0 ...'
46
+ mysql_prod_host = ENV['DB_TR_HOST']
47
+ mysql_prod_bastion = ENV['BASTION_HOST']
48
+ ENV.merge!('DB_TR_HOST' => '127.0.0.1')
49
+ ENV.merge!('DB_TR_PORT' => '3307')
50
+
51
+ `rm -rf ~/.ssh/id_rsa.pub-aadcert.pub && rm -rf azure-ssh-config`
52
+ `az ssh cert --public-key-file ~/.ssh/id_rsa.pub`
53
+ config = "
54
+ Host vault-core-dev
55
+ HostName bastion.dev.core.buka20.com
56
+ LocalForward 8200 vault.dev.core.buka20.com:8200
57
+
58
+ Host vault-core-stg
59
+ HostName bastion.stg.core.buka20.com
60
+ LocalForward 8200 vault.stg.core.buka20.com:8200
61
+
62
+ Host vault-core-prod
63
+ HostName bastion.prod.core.buka20.com
64
+ LocalForward 8200 vault.prod.core.buka20.com:8200
65
+
66
+ Host vault-o2o-dev
67
+ HostName bastion.dev.o2o.buka20.com
68
+ LocalForward 8200 vault.dev.o2o.buka20.com:8200
69
+
70
+ Host vault-o2o-stg
71
+ HostName bastion.stg.o2o.buka20.com
72
+ LocalForward 8200 vault.stg.o2o.buka20.com:8200
73
+
74
+ Host vault-o2o-prod
75
+ HostName bastion.prod.o2o.buka20.com
76
+ LocalForward 8200 vault.prod.o2o.buka20.com:8200
77
+
78
+ Host vault-tools-stg
79
+ HostName bastion.stg.tools.buka20.com
80
+ LocalForward 8200 vault.stg.tools.buka20.com:8200
81
+
82
+ Host vault-tools-prod
83
+ HostName bastion.prod.tools.buka20.com
84
+ LocalForward 8200 vault.prod.tools.buka20.com:8200
85
+
86
+ Host *
87
+ User #{email_azure}
88
+ CertificateFile ~/.ssh/id_rsa.pub-aadcert.pub
89
+ StrictHostKeyChecking no
90
+ UserKnownHostsFile /dev/null"
91
+
92
+ ssh_conf_file = File.new("azure_config", "w")
93
+ ssh_conf_file.puts(config)
94
+ ssh_conf_file.close
95
+
96
+ `ssh -F azure_config -NL 3307:#{mysql_prod_host}:3306 #{mysql_prod_bastion} & echo $! > ./pid.file & sleep 5`
97
+ end
98
+
99
+ # This method will stop jump bastion for disconnect database from local
100
+ def stop_jump_bastion
101
+ puts 'disconnect to vpn buka 2.0 ...'
102
+ pid = `cat pid.file`
103
+ `kill #{pid}`
104
+ `rm -rf pid.file`
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../testrail/testrail'
4
+ require_relative '../testrail/testcase'
5
+
6
+ module Tms
7
+ module Cucumber
8
+ module_function
9
+
10
+ include Testcase
11
+
12
+ # TODO: Will refer to import_data_bdd instead, after squad migrate test automation to Testrail completely
13
+ def import_data(client, project_id, suite_id, section_id, report_data_hash, tr_version)
14
+ # looping the feature
15
+ report_data_hash.map do |report_data_result|
16
+ # looping the test cases with get key elements
17
+ report_data_result['elements'].map do |test_result|
18
+ # looping the report when keyword is scenario and scenario outline
19
+ if(test_result['keyword'].downcase == 'scenario' || test_result['keyword'].downcase == 'scenario outline')
20
+ test_title = test_result['keyword'].downcase == 'scenario outline' ? test_result['id'] : test_result['name']
21
+ scenario = check_status_and_error_message(test_result['steps'], test_title)
22
+ test_status = scenario[0]['status']
23
+
24
+ # if status is "pending", should get status from object "after" instead
25
+ # since in cucumber report "pending" turn out as "failed" on summary result
26
+ if test_status == 'pending'
27
+ test_status = test_result['after'][0]['result']['status']
28
+ end
29
+
30
+ test_status_id = Testcase.get_status_id(test_status)
31
+ error_comment = scenario[0]['error_message']
32
+ refs = get_refs_id(test_result['tags']) || ''
33
+
34
+ Testcase.validate_testcase(client, section_id, test_title, test_status_id, refs, tr_version, error_comment)
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ def import_data_bdd(client, project_id, suite_id, section_id, report_data_hash, tr_version)
41
+ # looping the feature
42
+ report_data_hash.map do |report_data_result|
43
+ # looping the test cases with get key elements
44
+ report_data_result['elements'].map do |test_result|
45
+ # looping the report when keyword is scenario and scenario outline
46
+ if(test_result['keyword'].downcase == 'scenario' || test_result['keyword'].downcase == 'scenario outline')
47
+ test_title = test_result['keyword'].downcase == 'scenario outline' ? test_result['id'] : test_result['name']
48
+ scenario = check_status_and_error_message(test_result['steps'], test_title)
49
+ labels = test_result['tags'][0]['name']
50
+ test_status = scenario[0]['status']
51
+
52
+ test_status_id = Testcase.get_status_id(test_status)
53
+ error_comment = scenario[0]['error_message']
54
+ refs = get_refs_id(test_result['tags']) || ''
55
+
56
+ if labels.include?('@TESTID_')
57
+ test_id = labels.gsub('@TESTID_','')
58
+ Results.add_result(client, test_id, test_status_id, error_comment)
59
+ end
60
+ Testcase.validate_testcase_bdd(client, section_id, test_id, refs, tr_version)
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ def check_status_and_error_message(steps, test_title)
67
+ result_scenario = []
68
+ isSuccess = true
69
+ error_message = ''
70
+ test_result = {}
71
+ list_status = ['passed', 'skipped', 'failed', 'undefined', 'pending']
72
+
73
+ #looping each steps in scenario
74
+ steps.map do |scenario|
75
+ status = scenario['result']['status']
76
+ # check if status failed or skipped then save the status failed and pending and not continue the looping
77
+ # save the status and error message
78
+ # if failed then get the error message from json and if skipped then the error message will be empty
79
+ if list_status.include?(status)
80
+ if status.downcase == 'failed' || status.downcase == 'undefined' || status.downcase == 'skipped'
81
+ isSuccess = false
82
+ error_message = scenario['result']['error_message'] || ''
83
+ test_result['status']= 'failed'
84
+ test_result['error_message']= error_message
85
+ break
86
+ end
87
+ else
88
+ puts "invalid status is in test case with title = #{test_title}"
89
+ puts "status = #{status}"
90
+ isSuccess = false
91
+ test_result['status'] = 'invalid status'
92
+ test_result['error_message'] = error_message
93
+ break
94
+ end
95
+ end
96
+
97
+ # after looping all the steps if there is no failed and skipeed then the status will be passed and error message will be empty
98
+ if isSuccess == true
99
+ test_result['status'] = 'passed'
100
+ test_result['error_message'] = error_message
101
+ end
102
+
103
+ return result_scenario.push(test_result)
104
+ end
105
+
106
+ def get_refs_id(elements)
107
+ jira_id = ''
108
+
109
+ # looping the tag element and find prefix @TEST or @CUCUMBER
110
+ elements.map do |element|
111
+ tag = element['name']
112
+ if tag.include?("@TEST_") || tag.include?("@CUCUMBER_")
113
+ # split the tag name with _ and save the value on index 1 that have value of JIRA ID
114
+ array_jira_id = tag.split("_")
115
+ jira_id = array_jira_id[1]
116
+ break
117
+ end
118
+ end
119
+ return jira_id
120
+ end
121
+
122
+ end
123
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+ require_relative '../testrail/testrail'
3
+
4
+ module Tms
5
+ module Feature
6
+ module_function
7
+
8
+ def parsing_feature(file)
9
+ updated_bdd_scenario = ''
10
+ feature_file = File.read(file)
11
+
12
+ bdd_refs = feature_file.lines.first.scan(/@[\w-]+/).join(',').gsub('@','')
13
+
14
+ # Extract test title from local file
15
+ bdd_title = feature_file.match(/Feature:(.+)/)[1]
16
+ # Extract custom label and BDD scenario from local file
17
+ bdd_label = feature_file.match(/Feature:.+?\n\s*(.+?)\n/m)[1].scan(/@\S+/).join(' ')
18
+ bdd_scenario = bdd_label + "\n" + feature_file.match(/(?:Scenario Outline|Scenario):(.+?)(?=Scenario(?:Outline|:)|\z)/m)[0]
19
+
20
+ [bdd_refs, bdd_title, bdd_label, bdd_scenario]
21
+ end
22
+
23
+ def update_bdd(client, case_id, file)
24
+ bdd_refs, bdd_title, bdd_label, bdd_scenario = parsing_feature(file)
25
+ Testcase.update_case(client, case_id, bdd_refs, bdd_title, bdd_label, bdd_scenario)
26
+ end
27
+
28
+ def add_case(client, section_id, file)
29
+ bdd_refs, bdd_title, bdd_label, bdd_scenario = parsing_feature(file)
30
+ Testcase.add_case(client, section_id, bdd_refs, bdd_title, bdd_label, bdd_scenario)
31
+ end
32
+
33
+ end
34
+ end