fastlane-plugin-test_center 3.1.3 → 3.2.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/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
|