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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b0486d5117e1539891943e8ea57c81984fbf67b3
4
- data.tar.gz: 255a3287ae7045eb149d5009e38bb68dd4c6767c
3
+ metadata.gz: 1d20795b34c16cec61b3f6356cda1307dd6dc849
4
+ data.tar.gz: 0171b56560823d9da202a0caa98cfec51d897e3e
5
5
  SHA512:
6
- metadata.gz: a44d876d906e83f449dd63f09c335b1bad8db33e3006b02b18cdbef9bc122a5b9dbe1ee35020414c1f3143644aa5e29125285baa041c6d564082eaa66b98c896
7
- data.tar.gz: 6963a55aaac02d7ce83fdf5d98a7d2ffb998f3b26f276318308c4f2e8c84211c6e518e7ab5ebe75ce5c4b855c079e6391fc1d5565cf96702d02fb0730faba7ac
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
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module TestCenter
3
- VERSION = "3.1.3"
3
+ VERSION = "3.2.0"
4
4
  end
5
5
  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.1.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-03-27 00:00:00.000000000 Z
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