fastlane-plugin-test_center 3.1.3 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/fastlane/plugin/test_center/actions/collate_html_reports.rb +169 -0
- data/lib/fastlane/plugin/test_center/actions/multi_scan.rb +6 -0
- data/lib/fastlane/plugin/test_center/helper/correcting_scan_helper.rb +18 -0
- data/lib/fastlane/plugin/test_center/helper/reportname_helper.rb +20 -0
- data/lib/fastlane/plugin/test_center/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1d20795b34c16cec61b3f6356cda1307dd6dc849
|
4
|
+
data.tar.gz: 0171b56560823d9da202a0caa98cfec51d897e3e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 531270afbe621592914946811f17f69bc5798198dfa53466ba9c312551f33c7412a1b9be1c2f4ceebc74f399ed0eca83a30b2a10d39db98889437a829c5f1413
|
7
|
+
data.tar.gz: 2168773f546018afa810fc5c66984081448b22886ed7f846c091625519ff558827562b51d1732cfd6ed4eb5968c74719b73eee8699c7510c74dd2b9850b80805
|
@@ -0,0 +1,169 @@
|
|
1
|
+
module Fastlane
|
2
|
+
module Actions
|
3
|
+
class CollateHtmlReportsAction < Action
|
4
|
+
def self.run(params)
|
5
|
+
report_filepaths = params[:reports]
|
6
|
+
if report_filepaths.size == 1
|
7
|
+
FileUtils.cp(report_filepaths[0], params[:collated_report])
|
8
|
+
else
|
9
|
+
reports = report_filepaths.map { |report_filepath| REXML::Document.new(File.new(report_filepath)) }
|
10
|
+
|
11
|
+
# copy any missing testsuites
|
12
|
+
target_report = reports.shift
|
13
|
+
reports.each do |report|
|
14
|
+
report.elements.each("//section[contains(@class, 'test-suite')]") do |testsuite|
|
15
|
+
collate_testsuite(testsuite_from_report(target_report, testsuite), testsuite)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
update_testsuites_status(target_report)
|
19
|
+
update_test_counts(target_report)
|
20
|
+
|
21
|
+
FileUtils.mkdir_p(File.dirname(params[:collated_report]))
|
22
|
+
|
23
|
+
File.open(params[:collated_report], 'w') do |f|
|
24
|
+
target_report.write(f, 2)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.testsuite_from_report(report, testsuite)
|
30
|
+
testsuite_name = testsuite.attributes['id']
|
31
|
+
REXML::XPath.first(report, "//section[contains(@class, 'test-suite') and @id='#{testsuite_name}']")
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.testcases_from_testsuite(testsuite)
|
35
|
+
REXML::XPath.match(testsuite, ".//*[contains(@class, 'tests')]//*[contains(@class, 'test')]//*[contains(@class, 'title')]")
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.testcase_from_testsuite(testsuite, testcase_name)
|
39
|
+
REXML::XPath.first(testsuite, "*[contains(@class, 'test')]//*[text()='#{testcase_name}']/../..")
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.collate_testsuite(target_testsuite, testsuite)
|
43
|
+
if target_testsuite
|
44
|
+
testcases = testcases_from_testsuite(testsuite)
|
45
|
+
testcases.each do |testcase|
|
46
|
+
testresult = testcase.parent.parent
|
47
|
+
target_testresult = testcase_from_testsuite(target_testsuite, testcase.text)
|
48
|
+
collate_testresults(target_testresult, testresult)
|
49
|
+
end
|
50
|
+
else
|
51
|
+
testable = REXML::XPath.first(target_report, "//section[@id='test-suites']")
|
52
|
+
testable << testsuite
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.collate_testresults(target_testresult, testresult)
|
57
|
+
if target_testresult
|
58
|
+
collate_testresult_details(target_testresult, testresult)
|
59
|
+
target_testresult.parent.replace_child(target_testresult, testresult)
|
60
|
+
else
|
61
|
+
target_testresult << testresult
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.collate_testresult_details(target_testresult, testresult)
|
66
|
+
target_testdetails = details_for_testresult(target_testresult)
|
67
|
+
testdetails = details_for_testresult(testresult)
|
68
|
+
|
69
|
+
if target_testdetails
|
70
|
+
if testdetails
|
71
|
+
target_testresult.parent.replace_child(target_testdetails, testdetails)
|
72
|
+
else
|
73
|
+
target_testresult.parent.delete_element(target_testdetails)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.update_testsuites_status(report)
|
79
|
+
report.elements.each("//section[contains(@class, 'test-suite')]") do |testsuite|
|
80
|
+
failing_tests_xpath = "./*[contains(@class, 'tests')]//*[" \
|
81
|
+
"contains(@class, 'failing')]"
|
82
|
+
|
83
|
+
class_attributes = testsuite.attributes['class']
|
84
|
+
test_failures = REXML::XPath.match(testsuite, failing_tests_xpath)
|
85
|
+
test_status = test_failures.size.zero? ? 'passing' : 'failing'
|
86
|
+
|
87
|
+
testsuite.attributes['class'] = class_attributes.sub('failing', test_status)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.update_test_counts(report)
|
92
|
+
tests_xpath = "//*[contains(@class, 'tests')]//*[contains(@class, 'test')]//*[contains(@class, 'title')]"
|
93
|
+
tests = REXML::XPath.match(report, tests_xpath)
|
94
|
+
|
95
|
+
failing_tests_xpath = "//*[contains(@class, 'tests')]//*[" \
|
96
|
+
"contains(@class, 'details') and " \
|
97
|
+
"contains(@class, 'failing')]"
|
98
|
+
|
99
|
+
test_failures = REXML::XPath.match(report, failing_tests_xpath)
|
100
|
+
REXML::XPath.first(report, ".//*[@id='test-count']/span").text = tests.size
|
101
|
+
REXML::XPath.first(report, ".//*[@id='fail-count']/span").text = test_failures.size
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.details_for_testresult(testresult)
|
105
|
+
testcase = REXML::XPath.first(testresult, ".//*[contains(@class, 'title')]")
|
106
|
+
|
107
|
+
xpath = "../*[" \
|
108
|
+
"contains(@class, 'details') and " \
|
109
|
+
"contains(@class, 'failing') and " \
|
110
|
+
"contains(@class, '#{testcase.text}')]"
|
111
|
+
|
112
|
+
REXML::XPath.first(testresult, xpath)
|
113
|
+
end
|
114
|
+
|
115
|
+
#####################################################
|
116
|
+
# @!group Documentation
|
117
|
+
#####################################################
|
118
|
+
|
119
|
+
def self.description
|
120
|
+
"Combines and combines tests from multiple html report files"
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.details
|
124
|
+
"The first HTML report is used as the base report. Testcases " \
|
125
|
+
"from other reports are added if they do not already exist, or " \
|
126
|
+
"if the testcases already exist, they are replaced." \
|
127
|
+
"" \
|
128
|
+
"This is done because it is assumed that fragile tests, when " \
|
129
|
+
"re-run will often succeed due to less interference from other " \
|
130
|
+
"tests and the subsequent HTML reports will have more passed tests." \
|
131
|
+
""
|
132
|
+
end
|
133
|
+
|
134
|
+
def self.available_options
|
135
|
+
[
|
136
|
+
FastlaneCore::ConfigItem.new(
|
137
|
+
key: :reports,
|
138
|
+
env_name: 'COLLATE_HTML_REPORTS_REPORTS',
|
139
|
+
description: 'An array of HTML reports to collate. The first report is used as the base into which other reports are merged in',
|
140
|
+
optional: false,
|
141
|
+
type: Array,
|
142
|
+
verify_block: proc do |reports|
|
143
|
+
UI.user_error!('No HTML report files found') if reports.empty?
|
144
|
+
reports.each do |report|
|
145
|
+
UI.user_error!("Error: HTML report not found: '#{report}'") unless File.exist?(report)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
),
|
149
|
+
FastlaneCore::ConfigItem.new(
|
150
|
+
key: :collated_report,
|
151
|
+
env_name: 'COLLATE_HTML_REPORTS_COLLATED_REPORT',
|
152
|
+
description: 'The final HTML report file where all testcases will be merged into',
|
153
|
+
optional: true,
|
154
|
+
default_value: 'result.html',
|
155
|
+
type: String
|
156
|
+
)
|
157
|
+
]
|
158
|
+
end
|
159
|
+
|
160
|
+
def self.authors
|
161
|
+
["lyndsey-ferguson/@lyndseydf"]
|
162
|
+
end
|
163
|
+
|
164
|
+
def self.is_supported?(platform)
|
165
|
+
platform == :ios
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -52,6 +52,12 @@ module Fastlane
|
|
52
52
|
passing_testcount += junit_results[:passing].size
|
53
53
|
failure_details.merge!(junit_results[:failure_details])
|
54
54
|
end
|
55
|
+
|
56
|
+
if reportnamer.includes_html?
|
57
|
+
report_files += Dir.glob("#{scan_options[:output_directory]}/**/*#{reportnamer.html_filextension}").map do |relative_filepath|
|
58
|
+
File.absolute_path(relative_filepath)
|
59
|
+
end
|
60
|
+
end
|
55
61
|
{
|
56
62
|
result: tests_passed,
|
57
63
|
total_tests: passing_testcount + failed_tests.size,
|
@@ -107,6 +107,24 @@ module TestCenter
|
|
107
107
|
end
|
108
108
|
retried_junit_reportfiles = Dir.glob("#{output_directory}/**/*-[1-9]*#{reportnamer.junit_filextension}")
|
109
109
|
FileUtils.rm_f(retried_junit_reportfiles)
|
110
|
+
|
111
|
+
if reportnamer.includes_html?
|
112
|
+
report_files = Dir.glob("#{output_directory}/*#{reportnamer.html_filextension}").map do |relative_filepath|
|
113
|
+
File.absolute_path(relative_filepath)
|
114
|
+
end
|
115
|
+
if report_files.size > 1
|
116
|
+
config = FastlaneCore::Configuration.create(
|
117
|
+
Fastlane::Actions::CollateHtmlReportsAction.available_options,
|
118
|
+
{
|
119
|
+
reports: report_files.sort { |f1, f2| File.mtime(f1) <=> File.mtime(f2) },
|
120
|
+
collated_report: File.absolute_path(File.join(output_directory, reportnamer.html_reportname))
|
121
|
+
}
|
122
|
+
)
|
123
|
+
Fastlane::Actions::CollateHtmlReportsAction.run(config)
|
124
|
+
end
|
125
|
+
retried_html_reportfiles = Dir.glob("#{output_directory}/**/*-[1-9]*#{reportnamer.html_filextension}")
|
126
|
+
FileUtils.rm_f(retried_html_reportfiles)
|
127
|
+
end
|
110
128
|
end
|
111
129
|
|
112
130
|
def correcting_scan(scan_run_options, batch, reportnamer)
|
@@ -64,6 +64,26 @@ module TestCenter
|
|
64
64
|
File.extname(junit_reportname)
|
65
65
|
end
|
66
66
|
|
67
|
+
# --- HTML ---
|
68
|
+
# TODO: what to do when there are no html output types?
|
69
|
+
def includes_html?
|
70
|
+
@output_types.split(',').find_index('html') != nil
|
71
|
+
end
|
72
|
+
|
73
|
+
def html_last_reportname
|
74
|
+
html_index = @output_types.split(',').find_index('html')
|
75
|
+
numbered_filename(@output_files.to_s.split(',')[html_index])
|
76
|
+
end
|
77
|
+
|
78
|
+
def html_reportname
|
79
|
+
html_index = @output_types.split(',').find_index('html')
|
80
|
+
@output_files.to_s.split(',')[html_index]
|
81
|
+
end
|
82
|
+
|
83
|
+
def html_filextension
|
84
|
+
File.extname(html_reportname)
|
85
|
+
end
|
86
|
+
|
67
87
|
def increment
|
68
88
|
@report_count += 1
|
69
89
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastlane-plugin-test_center
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lyndsey Ferguson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-04-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: plist
|
@@ -195,6 +195,7 @@ files:
|
|
195
195
|
- LICENSE
|
196
196
|
- README.md
|
197
197
|
- lib/fastlane/plugin/test_center.rb
|
198
|
+
- lib/fastlane/plugin/test_center/actions/collate_html_reports.rb
|
198
199
|
- lib/fastlane/plugin/test_center/actions/collate_junit_reports.rb
|
199
200
|
- lib/fastlane/plugin/test_center/actions/multi_scan.rb
|
200
201
|
- lib/fastlane/plugin/test_center/actions/suppress_tests.rb
|