testrail_rspec 0.0.1 → 0.0.2
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 +1 -1
- data/lib/testrail_rspec.rb +141 -143
- data/lib/testrail_rspec/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 17b37cac0d137dcd55f241b808e8ba02fa234a07
|
4
|
+
data.tar.gz: 5891b2058f8bf42d9d925a51262de4a18e9c89ae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d4c0abc08cc139acc854f1d176f8fde321eb793dd2c882fec3523a52b71d13ac38022f2f1d910f7d5168969b4dbcf4727b6dc976f44eacc1e4b3266284e10faa
|
7
|
+
data.tar.gz: 21bea9900fd213c483d0634ace6a3d393aa1868437f6fc33617a32ab0dd59dd3a9d816723ccf0fb46e3a900a18f155671d2afe8a33dd82cc4a0c11a7a071730f
|
data/README.md
CHANGED
data/lib/testrail_rspec.rb
CHANGED
@@ -6,177 +6,175 @@ require 'rubytree'
|
|
6
6
|
require "testrail_rspec/version"
|
7
7
|
require "testrail_rspec/client"
|
8
8
|
|
9
|
-
|
9
|
+
class TestrailRspec < RSpec::Core::Formatters::BaseTextFormatter
|
10
10
|
|
11
11
|
RSpec.configuration.add_setting :testrail_formatter_options, :default => {}
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
# # :start_dump
|
13
|
+
RSpec::Core::Formatters.register self, :start, :close, :dump_summary
|
14
|
+
# # :example_started, :example_passed,
|
15
|
+
# # :example_pending, :example_failed,
|
16
|
+
# :dump_failures, :dump_pending
|
17
|
+
# # :start_dump
|
19
18
|
|
20
19
|
|
21
|
-
|
20
|
+
# TODO: after exporter is done and working remove unnecessary overriden methods
|
22
21
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
22
|
+
def initialize(output)
|
23
|
+
@options = {}
|
24
|
+
@project_id = nil
|
25
|
+
super(output)
|
26
|
+
end
|
28
27
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
28
|
+
# To start
|
29
|
+
def start(notification)
|
30
|
+
@options = RSpec.configuration.testrail_formatter_options
|
31
|
+
@client = TestrailRspec::Client.new(@options)
|
32
|
+
@client.get_projects.each { |project| @project_id = project['id'] if project['name'] == @options[:project] }
|
34
33
|
|
35
|
-
|
34
|
+
puts "TestRail Exporter [INFO] Executing #{notification.count} tests. Loaded in #{notification.load_time}"
|
36
35
|
|
37
|
-
|
38
|
-
|
36
|
+
super
|
37
|
+
end
|
38
|
+
|
39
|
+
# Once per example group <-----------------------------------------------------------------------------
|
40
|
+
# def example_group_started(notification)
|
41
|
+
# groups = []
|
42
|
+
# current_group = notification.group
|
43
|
+
# until current_group.top_level?
|
44
|
+
# groups << current_group
|
45
|
+
# current_group = current_group.parent if current_group.parent_groups.size > 1
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# groups << current_group
|
49
|
+
#
|
50
|
+
# unless groups[0].examples.empty?
|
51
|
+
# groups.reverse.each_with_index do |group, idx|
|
52
|
+
# puts (idx == 0 ? "Spec: " : "") + (' ' *2 * idx) + "#{group.description}"
|
53
|
+
# end
|
54
|
+
# puts (' ' *2 * groups.size) + groups[0].examples.map(&:description).join("\n" + (' ' *2 * groups.size))
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# super
|
58
|
+
# end
|
59
|
+
|
60
|
+
# Once per example <-----------------------------------------------------------------------------------
|
61
|
+
# def example_started(notification)
|
62
|
+
# puts " - case: #{notification.example.description}"
|
63
|
+
# end
|
64
|
+
|
65
|
+
# One of these per example <---------------------------------------------------------------------------
|
66
|
+
# def example_passed(passed)
|
67
|
+
# puts "\tpass: #{passed.example.description}"
|
68
|
+
# end
|
69
|
+
|
70
|
+
# def example_failed(failure)
|
71
|
+
# puts "\tfail: #{failure.example.description}"
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# def example_pending(pending)
|
75
|
+
# puts "\tpend: #{pending.example.description}"
|
76
|
+
# end
|
77
|
+
|
78
|
+
# Optionally at any time <------------------------------------------------------------------------------
|
79
|
+
# def message(notification)
|
80
|
+
# puts "msg notification: #{notification.inspect}"
|
81
|
+
# super
|
82
|
+
# end
|
83
|
+
|
84
|
+
# At the end of the suite <-----------------------------------------------------------------------------
|
85
|
+
# def stop(notification)
|
86
|
+
# puts "stop notification: #{notification.inspect}"
|
87
|
+
# end
|
88
|
+
|
89
|
+
# def start_dump(null_notification)
|
90
|
+
# puts "start_dump notification: #{null_notification.inspect}"
|
91
|
+
# end
|
92
|
+
#
|
93
|
+
def dump_pending(notification)
|
94
|
+
# puts "dump pend notification: #{notification.inspect}"
|
95
|
+
# super
|
96
|
+
end
|
39
97
|
|
40
|
-
|
41
|
-
#
|
42
|
-
#
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
#
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
#
|
51
|
-
# unless groups[0].examples.empty?
|
52
|
-
# groups.reverse.each_with_index do |group, idx|
|
53
|
-
# puts (idx == 0 ? "Spec: " : "") + (' ' *2 * idx) + "#{group.description}"
|
54
|
-
# end
|
55
|
-
# puts (' ' *2 * groups.size) + groups[0].examples.map(&:description).join("\n" + (' ' *2 * groups.size))
|
56
|
-
# end
|
57
|
-
#
|
58
|
-
# super
|
59
|
-
# end
|
60
|
-
|
61
|
-
# Once per example <-----------------------------------------------------------------------------------
|
62
|
-
# def example_started(notification)
|
63
|
-
# puts " - case: #{notification.example.description}"
|
64
|
-
# end
|
65
|
-
|
66
|
-
# One of these per example <---------------------------------------------------------------------------
|
67
|
-
# def example_passed(passed)
|
68
|
-
# puts "\tpass: #{passed.example.description}"
|
69
|
-
# end
|
70
|
-
|
71
|
-
# def example_failed(failure)
|
72
|
-
# puts "\tfail: #{failure.example.description}"
|
73
|
-
# end
|
74
|
-
#
|
75
|
-
# def example_pending(pending)
|
76
|
-
# puts "\tpend: #{pending.example.description}"
|
77
|
-
# end
|
78
|
-
|
79
|
-
# Optionally at any time <------------------------------------------------------------------------------
|
80
|
-
# def message(notification)
|
81
|
-
# puts "msg notification: #{notification.inspect}"
|
82
|
-
# super
|
83
|
-
# end
|
84
|
-
|
85
|
-
# At the end of the suite <-----------------------------------------------------------------------------
|
86
|
-
# def stop(notification)
|
87
|
-
# puts "stop notification: #{notification.inspect}"
|
88
|
-
# end
|
89
|
-
|
90
|
-
# def start_dump(null_notification)
|
91
|
-
# puts "start_dump notification: #{null_notification.inspect}"
|
92
|
-
# end
|
93
|
-
#
|
94
|
-
def dump_pending(notification)
|
95
|
-
# puts "dump pend notification: #{notification.inspect}"
|
96
|
-
# super
|
98
|
+
def dump_failures(notification)
|
99
|
+
# puts "dump fail notification: #{notification.inspect}"
|
100
|
+
# super
|
101
|
+
end
|
102
|
+
|
103
|
+
def dump_summary(notification)
|
104
|
+
# Create project if it is not present / could do it setting controlled
|
105
|
+
if @project_id.nil?
|
106
|
+
puts "TestRail Exporter [INFO] Creating project: #{@options[:project]}"
|
107
|
+
@project_id = @client.add_project(@options[:project])['id']
|
97
108
|
end
|
98
109
|
|
99
|
-
|
100
|
-
|
101
|
-
# super
|
110
|
+
suites = Hash.new do |h,k|
|
111
|
+
h[k] = Tree::TreeNode.new(k, @client.find_or_create_suite(k, @project_id) )
|
102
112
|
end
|
103
113
|
|
104
|
-
def dump_summary(notification)
|
105
|
-
# Create project if it is not present / could do it setting controlled
|
106
|
-
if @project_id.nil?
|
107
|
-
puts "TestRail Exporter [INFO] Creating project: #{@options[:project]}"
|
108
|
-
@project_id = @client.add_project(@options[:project])['id']
|
109
|
-
end
|
110
114
|
|
111
|
-
|
112
|
-
|
113
|
-
|
115
|
+
notification.examples.each do |example|
|
116
|
+
build_hierarchy_tree!(suites, example)
|
117
|
+
end
|
114
118
|
|
119
|
+
suites.each { |_, suite| update_test_run(suite) }
|
115
120
|
|
116
|
-
|
117
|
-
|
118
|
-
end
|
121
|
+
super
|
122
|
+
end
|
119
123
|
|
120
|
-
|
124
|
+
def close(null_notification)
|
125
|
+
# TODO: could close any open connection
|
126
|
+
puts "TestRail Exporter [INFO] Closing..."
|
127
|
+
super
|
128
|
+
end
|
121
129
|
|
122
|
-
|
123
|
-
end
|
130
|
+
private
|
124
131
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
132
|
+
def get_path_for(node)
|
133
|
+
asc_arr = node.is_a?(RSpec::Core::Example) ? [node.description] : []
|
134
|
+
parent = (node.respond_to? :parent) ? node.parent : node.example_group
|
135
|
+
asc_arr << parent.description
|
136
|
+
asc_arr.push(*get_path_for(parent)) unless parent.top_level?
|
137
|
+
node.is_a?(RSpec::Core::Example) ? asc_arr.reverse : asc_arr
|
138
|
+
end
|
130
139
|
|
131
|
-
|
140
|
+
def build_hierarchy_tree!(suites, example)
|
141
|
+
path = get_path_for(example)
|
132
142
|
|
133
|
-
|
134
|
-
|
135
|
-
parent = (node.respond_to? :parent) ? node.parent : node.example_group
|
136
|
-
asc_arr << parent.description
|
137
|
-
asc_arr.push(*get_path_for(parent)) unless parent.top_level?
|
138
|
-
node.is_a?(RSpec::Core::Example) ? asc_arr.reverse : asc_arr
|
139
|
-
end
|
143
|
+
parent_node = suite_node = suites[path.shift]
|
144
|
+
path.unshift('Direct cases') unless path.size > 1
|
140
145
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
path.unshift('Direct cases') unless path.size > 1
|
146
|
-
|
147
|
-
path.each_with_index do |item, idx|
|
148
|
-
child_node = (parent_node.children.map(&:name).include? item) ? parent_node[item] : nil
|
149
|
-
if child_node and (idx + 1 == path.size)
|
150
|
-
puts "TestRail Exporter [INFO] Second case with same path and name detected:\n\t#{suite_node.content['name']} -> #{path.join(' -> ')}"
|
151
|
-
end
|
152
|
-
|
153
|
-
unless child_node
|
154
|
-
child_node = if idx + 1 == path.size
|
155
|
-
Tree::TreeNode.new(item, { case: @client.find_or_create_case(item, parent_node.content, idx), result: example })
|
156
|
-
else
|
157
|
-
Tree::TreeNode.new(item, @client.find_or_create_section(item, suite_node.content, parent_node.content, idx))
|
158
|
-
end
|
159
|
-
parent_node << child_node
|
160
|
-
end
|
161
|
-
parent_node = child_node
|
146
|
+
path.each_with_index do |item, idx|
|
147
|
+
child_node = (parent_node.children.map(&:name).include? item) ? parent_node[item] : nil
|
148
|
+
if child_node and (idx + 1 == path.size)
|
149
|
+
puts "TestRail Exporter [INFO] Second case with same path and name detected:\n\t#{suite_node.content['name']} -> #{path.join(' -> ')}"
|
162
150
|
end
|
163
151
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
{
|
172
|
-
case_id: test.content[:case]['id'],
|
173
|
-
status_id: TestrailRspec::STATUS[test_result.status],
|
174
|
-
elapsed: (run_time_seconds == 0) ? nil : "#{run_time_seconds}s"
|
175
|
-
}
|
152
|
+
unless child_node
|
153
|
+
child_node = if idx + 1 == path.size
|
154
|
+
Tree::TreeNode.new(item, { case: @client.find_or_create_case(item, parent_node.content, idx), result: example })
|
155
|
+
else
|
156
|
+
Tree::TreeNode.new(item, @client.find_or_create_section(item, suite_node.content, parent_node.content, idx))
|
157
|
+
end
|
158
|
+
parent_node << child_node
|
176
159
|
end
|
177
|
-
|
160
|
+
parent_node = child_node
|
178
161
|
end
|
179
162
|
|
163
|
+
end
|
180
164
|
|
165
|
+
def update_test_run(suite)
|
166
|
+
run_id = @client.create_run(suite.content)['id']
|
167
|
+
results = suite.each_leaf.map do |test|
|
168
|
+
test_result = test.content[:result].execution_result
|
169
|
+
run_time_seconds = test_result.run_time.round(0)
|
170
|
+
{
|
171
|
+
case_id: test.content[:case]['id'],
|
172
|
+
status_id: TestrailRspec::STATUS[test_result.status],
|
173
|
+
elapsed: (run_time_seconds == 0) ? nil : "#{run_time_seconds}s"
|
174
|
+
}
|
175
|
+
end
|
176
|
+
@client.add_results_for_cases(run_id, results)
|
181
177
|
end
|
178
|
+
|
179
|
+
|
182
180
|
end
|