nanonano87-cucumber_statistics 0.0.1

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.
Files changed (34) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitignore +20 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +3 -0
  7. data/LICENSE.txt +46 -0
  8. data/README.md +44 -0
  9. data/Rakefile +7 -0
  10. data/cucumber_statistics.gemspec +38 -0
  11. data/lib/cucumber_statistics.rb +8 -0
  12. data/lib/cucumber_statistics/autoload.rb +5 -0
  13. data/lib/cucumber_statistics/configuration.rb +56 -0
  14. data/lib/cucumber_statistics/feature_statistics.rb +28 -0
  15. data/lib/cucumber_statistics/formatter.rb +101 -0
  16. data/lib/cucumber_statistics/overall_statistics.rb +29 -0
  17. data/lib/cucumber_statistics/renderer.rb +30 -0
  18. data/lib/cucumber_statistics/renderer_helper.rb +102 -0
  19. data/lib/cucumber_statistics/scenario_statistics.rb +28 -0
  20. data/lib/cucumber_statistics/step_statistics.rb +91 -0
  21. data/lib/cucumber_statistics/unused_steps.rb +18 -0
  22. data/lib/cucumber_statistics/version.rb +3 -0
  23. data/lib/cucumber_statistics/view/combined_statistics.html +299 -0
  24. data/lib/cucumber_statistics/view/combined_statistics.html.haml +169 -0
  25. data/notes.txt +9 -0
  26. data/spec/cucumber_statistics/configuration_spec.rb +20 -0
  27. data/spec/cucumber_statistics/feature_statistics_spec.rb +78 -0
  28. data/spec/cucumber_statistics/renderer_helper_spec.rb +27 -0
  29. data/spec/cucumber_statistics/renderer_spec.rb +71 -0
  30. data/spec/cucumber_statistics/scenario_statistics_spec.rb +86 -0
  31. data/spec/cucumber_statistics/step_statistics_spec.rb +199 -0
  32. data/spec/cucumber_statistics/unused_steps_spec.rb +39 -0
  33. data/spec/spec_helper.rb +9 -0
  34. metadata +184 -0
@@ -0,0 +1,102 @@
1
+ module CucumberStatistics
2
+
3
+ class RendererHelper
4
+
5
+ def name_td(results)
6
+ %{<td title="#{results[1][:file]}">#{results[0]}</td>}
7
+ end
8
+
9
+ def scenario_file_td(name, scenario_name)
10
+ %{<td title="#{scenario_name}">#{name}</td>}
11
+ end
12
+
13
+ def std_file_td(file_name, name)
14
+ %{<td title="#{name}">#{file_name}</td>}
15
+ end
16
+
17
+ def time_td(results, metric, *warning_results)
18
+ duration = results[1][metric]
19
+
20
+ %{<td #{warning_class(results, warning_results)} data-value="#{duration}" title="#{duration}">#{format(duration)}</td>}
21
+ end
22
+
23
+ def scenario_time_td(duration)
24
+ %{<td data-value="#{duration}" title="#{duration}">#{format(duration)}</td>}
25
+ end
26
+
27
+ def std_time_td(duration)
28
+ %{<td data-value="#{duration}" title="#{duration}">#{format(duration)}</td>}
29
+ end
30
+
31
+ def alert_info_text(overall_statistics)
32
+ <<-HTML
33
+ <span>
34
+ #{overall_statistics.feature_count} Features,
35
+ #{overall_statistics.scenario_count} Scenarios,
36
+ #{overall_statistics.step_count} Steps completed in #{format(overall_statistics.duration)}.
37
+ <span class='text-muted pull-right small'>
38
+ Finished on #{format_date_time(overall_statistics.end_time)}
39
+ </span>
40
+ </span>
41
+ HTML
42
+ end
43
+
44
+ def warning_class(results, warning_results)
45
+
46
+ if warning_results.nil? || warning_results.empty?
47
+ should_warn = false
48
+ else
49
+ should_warn = (results[0].eql? warning_results[0][0])
50
+ end
51
+ if should_warn
52
+ %{class="danger"}
53
+ else
54
+ ''
55
+ end
56
+ end
57
+
58
+ def count_td(results, metric)
59
+ value = results[1][metric]
60
+ %{<td data-value="#{value}">#{value}</td>}
61
+ end
62
+
63
+ def format (ts)
64
+
65
+ return '-' if ts.nil? || ts == 0
66
+
67
+ #find the seconds
68
+ seconds = ts % 60
69
+
70
+ #find the minutes
71
+ minutes = (ts / 60) % 60
72
+
73
+ #find the hours
74
+ hours = (ts/3600)
75
+
76
+ formatted_h = hours.to_i
77
+ formatted_m = minutes.to_i
78
+ formatted_s = seconds.to_i
79
+ formatted_ms = Time.at(seconds).utc.strftime("%3N")
80
+
81
+ # http://apidock.com/ruby/DateTime/strftime
82
+ if hours >= 1
83
+ #result = Time.at(ts).utc.strftime("%Hh %Mm %S.%3Ns")
84
+ result = "#{formatted_h}h #{formatted_m}m #{formatted_s}.#{formatted_ms}s"
85
+ elsif minutes >= 1
86
+ #result = Time.at(ts).utc.strftime("%Mm %S.%3Ns")
87
+ result = "#{formatted_m}m #{formatted_s}.#{formatted_ms}s"
88
+ elsif formatted_ms.to_i == 0 && formatted_s == 0 && formatted_h == 0
89
+ result = "< #{formatted_s}.#{formatted_ms}s"
90
+ else
91
+ #result = Time.at(ts).utc.strftime("%S.%3Ns")
92
+ result = "#{formatted_s}.#{formatted_ms}s"
93
+ end
94
+
95
+ result
96
+ end
97
+
98
+ def format_date_time (time)
99
+ time.strftime("%m/%d/%Y at %I:%M%p")
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,28 @@
1
+ module CucumberStatistics
2
+ class ScenarioStatistics
3
+ def initialize
4
+ @all = Hash.new
5
+ end
6
+
7
+ def record scenario_name, duration, file_colon_line
8
+ short_file_colon_line = file_colon_line[file_colon_line.index('features').to_i..-1]
9
+
10
+ scenario_result = @all[short_file_colon_line]
11
+ scenario_result ||= Hash.new
12
+ scenario_result[:duration] = duration
13
+ scenario_result[:scenario_name] = scenario_name
14
+
15
+ @all[short_file_colon_line] ||= scenario_result
16
+ end
17
+
18
+ def all
19
+ @all
20
+ end
21
+
22
+ def sort_by_property property
23
+ result = @all.sort {|a,b| a.last[property.to_sym] <=> b.last[property.to_sym]}
24
+ result
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,91 @@
1
+ module CucumberStatistics
2
+ class StepStatistics
3
+ def initialize
4
+ @all = Hash.new
5
+ end
6
+
7
+ def record step_name, duration, file_colon_line
8
+
9
+ # "/Users/kross/alienfast/acme/features/account management/admin_cancel_account.feature:8"
10
+ step_results = @all[step_name]
11
+ step_results ||= Hash.new
12
+ step_results[:instances] ||= []
13
+ step_results[:instances] << duration
14
+ begin
15
+ file = file_colon_line[file_colon_line.index('features')..-1]
16
+ step_results[:file] = file
17
+ rescue Exception => e
18
+ step_results[:file] = e.message
19
+ end
20
+
21
+ @all[step_name] ||= step_results
22
+ end
23
+
24
+ def calculate
25
+ @all.each do |step_name, step_results|
26
+ step_results[:total] = step_results[:instances].inject{|sum,x| sum + x }
27
+ step_results[:count] = step_results[:instances].count
28
+ step_results[:average] = step_results[:total].to_f / step_results[:count].to_f
29
+ step_results[:fastest] = step_results[:instances].sort.first
30
+ step_results[:slowest] = step_results[:instances].sort.last
31
+ step_results[:variation] = step_results[:slowest] - step_results[:fastest]
32
+ step_results[:variance] = self.sample_variance step_results[:instances]
33
+ step_results[:standard_deviation] = self.standard_deviation step_results[:variance]
34
+ end
35
+ end
36
+
37
+ def all
38
+ @all
39
+ end
40
+
41
+ def sort_by_property property
42
+ result = @all.sort {|a,b| a.last[property.to_sym] <=> b.last[property.to_sym]}
43
+ result
44
+ end
45
+
46
+ def highest_average
47
+ sort_by_property(:average).reverse.first
48
+ end
49
+
50
+ def highest_total
51
+ sort_by_property(:total).reverse.first
52
+ end
53
+
54
+ def highest_variation
55
+ sort_by_property(:variation).reverse.first
56
+ end
57
+
58
+ def average_times_plot_data
59
+ @all.map {|step_name, data| data[:average].to_f}.sort.reverse
60
+ end
61
+
62
+ def total_times_plot_data
63
+ sort_by_property(:average).reverse.map {|step_name, data| data[:total].to_f}
64
+ end
65
+
66
+ def step_part_of_total
67
+ @all.map {|step_name, data| data[:total]}.sort.reverse
68
+ end
69
+
70
+ def total_elapsed_time
71
+ @all.map {|step_name, data| data[:total]}.inject{|sum,x| sum + x }
72
+ end
73
+
74
+ def sample_variance data
75
+ count = data.count
76
+ average = data.inject{|sum,x| sum + x } / count.to_f
77
+
78
+ return nil if count <= 1
79
+
80
+ sum = data.inject(0){|acc,i|acc.to_f + (i.to_f - average)**2.0}
81
+
82
+ return 1 / (count.to_f - 1.0) * sum.to_f
83
+ end
84
+
85
+ def standard_deviation sample_variance
86
+ return nil if sample_variance.nil?
87
+
88
+ return Math.sqrt(sample_variance)
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,18 @@
1
+ module CucumberStatistics
2
+ class UnusedSteps
3
+ def initialize
4
+ @all = Hash.new
5
+ end
6
+
7
+ def record step_name, where
8
+ result = @all[step_name]
9
+ result = where
10
+
11
+ @all[step_name] ||= result
12
+ end
13
+
14
+ def all
15
+ @all
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ module CucumberStatistics
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,299 @@
1
+ <!DOCTYPE html>
2
+ <html lang='en'>
3
+ <head>
4
+ <meta charset='utf-8'>
5
+ <meta content='IE=edge' http-equiv='X-UA-Compatible'>
6
+ <meta content='width=device-width, initial-scale=1' name='viewport'>
7
+ <meta content='Cucumber Scenario Statistics' name='description'>
8
+ <meta content='AlienFast' name='author'>
9
+ <title>Cucumber Scenario Statistics</title>
10
+ <!-- Bootstrap core CSS -->
11
+ <link href='http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css' rel='stylesheet'>
12
+ <!-- Custom styles for this layout -->
13
+ <style>
14
+ body {
15
+ min-height: 2000px;
16
+ padding-top: 70px;
17
+ }
18
+
19
+ td {
20
+ white-space: nowrap;
21
+ /*max-width: 100px;*/
22
+ }
23
+ tr td:first-child {
24
+ overflow: hidden;
25
+ text-overflow: ellipsis;
26
+ max-width: 300px;
27
+ }
28
+ </style>
29
+ <link href='https://raw.githack.com/drvic10k/bootstrap-sortable/master/Contents/bootstrap-sortable.css' rel='stylesheet'>
30
+ <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
31
+ <!--[if lt IE 9]>
32
+ <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
33
+ <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
34
+ <![endif]-->
35
+ </head>
36
+ <body>
37
+ <!-- Fixed navbar -->
38
+ <div class='navbar navbar-default navbar-fixed-top' role='navigation'>
39
+ <div class='container'>
40
+ <div class='navbar-header'>
41
+ <button class='navbar-toggle' data-target='.navbar-collapse' data-toggle='collapse' type='button'>
42
+ <span class='sr-only'>Toggle navigation</span>
43
+ <span class='icon-bar'></span>
44
+ <span class='icon-bar'></span>
45
+ <span class='icon-bar'></span>
46
+ </button>
47
+ <a class='navbar-brand' href='#'>cucumber_statistics</a>
48
+ </div>
49
+ <div class='navbar-collapse collapse'>
50
+ <ul class='nav navbar-nav navbar-right'>
51
+ <li>
52
+ <a href='https://github.com/alienfast/cucumber_statistics' target='other'>Github</a>
53
+ </li>
54
+ </ul>
55
+ </div>
56
+ </div>
57
+ </div>
58
+ <!-- /.nav-collapse -->
59
+ <div class='container'>
60
+ <div class='navbar'>
61
+ <div class='tabbable'>
62
+ <ul class='nav nav-tabs'>
63
+ <li class='active'>
64
+ <a class='content_tab' href='#steps_tab' toggle='tab'>
65
+ Steps
66
+ </a>
67
+ </li>
68
+ <li>
69
+ <a class='content_tab' href='#scenarios_tab' toggle='tab'>
70
+ Scenarios
71
+ </a>
72
+ </li>
73
+ <li>
74
+ <a class='content_tab' href='#features_tab' toggle='tab'>
75
+ Features
76
+ </a>
77
+ </li>
78
+ </ul>
79
+ </div>
80
+ <div class='container'>
81
+ <div class='tab-content'>
82
+ <div class='tab-pane active' id='steps_tab'>
83
+ <!-- Main component for a primary marketing message or call to action -->
84
+ <div class='jumbotron'>
85
+ <h1>Cucumber step statistics</h1>
86
+ <p>... allows you to easily identify long running steps.</p>
87
+ </div>
88
+ <div class='alert alert-info'>
89
+ <span>
90
+ 2 Features,
91
+ 6 Scenarios,
92
+ 24 Steps completed in 13.190s.
93
+ <span class='text-muted pull-right small'>
94
+ Finished on 08/11/2016 at 06:19PM
95
+ </span>
96
+ </span>
97
+ </div>
98
+ <table class='table table-bordered table-striped sortable'>
99
+ <thead>
100
+ <tr>
101
+ <th>Step</th>
102
+ <th>Fastest</th>
103
+ <th>Slowest</th>
104
+ <th>Variation</th>
105
+ <th>Variance</th>
106
+ <th>Std Deviation</th>
107
+ <th>Count</th>
108
+ <th>Average</th>
109
+ <th data-defaultsort='desc'>Total</th>
110
+ </tr>
111
+ </thead>
112
+ <tbody>
113
+ <tr>
114
+ <td title="features/scenarios/calculator2.feature:7">/^I have a calculator$/</td>
115
+ <td data-value="0.303663" title="0.303663">0.303s</td>
116
+ <td data-value="0.303663" title="0.303663">0.303s</td>
117
+ <td data-value="0.0" title="0.0">-</td>
118
+ <td data-value="" title="">-</td>
119
+ <td data-value="" title="">-</td>
120
+ <td data-value="1">1</td>
121
+ <td data-value="0.303663" title="0.303663">0.303s</td>
122
+ <td data-value="0.303663" title="0.303663">0.303s</td>
123
+ </tr>
124
+ <tr>
125
+ <td title="features/scenarios/calculator2.feature:31">/^I have entered (\d+(?:.\d+)?) into the calculator$/</td>
126
+ <td data-value="0.202248" title="0.202248">0.202s</td>
127
+ <td data-value="0.20617" title="0.20617">0.206s</td>
128
+ <td class="danger" data-value="0.003921999999999981" title="0.003921999999999981">0.003s</td>
129
+ <td data-value="1.7393255535714161e-06" title="1.7393255535714161e-06">< 0.000s</td>
130
+ <td data-value="0.0013188349227903453" title="0.0013188349227903453">0.001s</td>
131
+ <td data-value="8">8</td>
132
+ <td data-value="0.204455875" title="0.204455875">0.204s</td>
133
+ <td data-value="1.635647" title="1.635647">1.635s</td>
134
+ </tr>
135
+ <tr>
136
+ <td title="features/scenarios/calculator2.feature:31">/^I add$/</td>
137
+ <td data-value="0.503672" title="0.503672">0.503s</td>
138
+ <td data-value="0.505097" title="0.505097">0.505s</td>
139
+ <td data-value="0.0014250000000000096" title="0.0014250000000000096">0.001s</td>
140
+ <td data-value="4.3458091666665543e-07" title="4.3458091666665543e-07">< 0.000s</td>
141
+ <td data-value="0.0006592275151013157" title="0.0006592275151013157">< 0.000s</td>
142
+ <td data-value="4">4</td>
143
+ <td data-value="0.5045937500000001" title="0.5045937500000001">0.504s</td>
144
+ <td data-value="2.0183750000000003" title="2.0183750000000003">2.018s</td>
145
+ </tr>
146
+ <tr>
147
+ <td title="features/scenarios/calculator2.feature:31">/^the result should be (\d+(?:.\d+)?) on the screen$/</td>
148
+ <td data-value="0.60374" title="0.60374">0.603s</td>
149
+ <td data-value="0.605351" title="0.605351">0.605s</td>
150
+ <td data-value="0.001610999999999918" title="0.001610999999999918">0.001s</td>
151
+ <td data-value="5.657283333333006e-07" title="5.657283333333006e-07">< 0.000s</td>
152
+ <td data-value="0.0007521491430117437" title="0.0007521491430117437">< 0.000s</td>
153
+ <td data-value="4">4</td>
154
+ <td data-value="0.6043245" title="0.6043245">0.604s</td>
155
+ <td data-value="2.417298" title="2.417298">2.417s</td>
156
+ </tr>
157
+ <tr>
158
+ <td title="features/scenarios/demo.feature:5">/^I enter (.*) into google$/</td>
159
+ <td data-value="3.148444" title="3.148444">3.148s</td>
160
+ <td data-value="3.148444" title="3.148444">3.148s</td>
161
+ <td data-value="0.0" title="0.0">-</td>
162
+ <td data-value="" title="">-</td>
163
+ <td data-value="" title="">-</td>
164
+ <td data-value="1">1</td>
165
+ <td class="danger" data-value="3.148444" title="3.148444">3.148s</td>
166
+ <td class="danger" data-value="3.148444" title="3.148444">3.148s</td>
167
+ </tr>
168
+ <tr>
169
+ <td title="features/scenarios/demo.feature:6">/^I run the search$/</td>
170
+ <td data-value="1.820547" title="1.820547">1.820s</td>
171
+ <td data-value="1.820547" title="1.820547">1.820s</td>
172
+ <td data-value="0.0" title="0.0">-</td>
173
+ <td data-value="" title="">-</td>
174
+ <td data-value="" title="">-</td>
175
+ <td data-value="1">1</td>
176
+ <td data-value="1.820547" title="1.820547">1.820s</td>
177
+ <td data-value="1.820547" title="1.820547">1.820s</td>
178
+ </tr>
179
+ <tr>
180
+ <td title="features/scenarios/demo.feature:7">/^I see results$/</td>
181
+ <td data-value="0.855183" title="0.855183">0.855s</td>
182
+ <td data-value="0.855183" title="0.855183">0.855s</td>
183
+ <td data-value="0.0" title="0.0">-</td>
184
+ <td data-value="" title="">-</td>
185
+ <td data-value="" title="">-</td>
186
+ <td data-value="1">1</td>
187
+ <td data-value="0.855183" title="0.855183">0.855s</td>
188
+ <td data-value="0.855183" title="0.855183">0.855s</td>
189
+ </tr>
190
+ </tbody>
191
+ </table>
192
+ </div>
193
+ <!-- /container -->
194
+ <div class='tab-pane' id='scenarios_tab'>
195
+ <!-- Main component for a primary marketing message or call to action -->
196
+ <div class='jumbotron'>
197
+ <h1>Cucumber scenario statistics</h1>
198
+ <p>... find those slow scenarios.</p>
199
+ </div>
200
+ <div class='alert alert-info'>
201
+ <span>
202
+ 2 Features,
203
+ 6 Scenarios,
204
+ 24 Steps completed in 13.190s.
205
+ <span class='text-muted pull-right small'>
206
+ Finished on 08/11/2016 at 06:19PM
207
+ </span>
208
+ </span>
209
+ </div>
210
+ <table class='table table-bordered table-striped sortable'>
211
+ <thead>
212
+ <tr>
213
+ <th>Scenario File</th>
214
+ <th data-defaultsort='desc'>Time</th>
215
+ </tr>
216
+ </thead>
217
+ <tbody>
218
+ <tr>
219
+ <td title="Regular numbers">features/scenarios/calculator2.feature:10</td>
220
+ <td data-value="1.316579" title="1.316579">1.316s</td>
221
+ </tr>
222
+ <tr>
223
+ <td title="Regular numbers again">features/scenarios/calculator2.feature:16</td>
224
+ <td data-value="1.314667" title="1.314667">1.314s</td>
225
+ </tr>
226
+ <tr>
227
+ <td title="| 3.5 | 5.2 | 8.7 |">features/scenarios/calculator2.feature:31</td>
228
+ <td data-value="3.136923" title="3.136923">3.136s</td>
229
+ </tr>
230
+ <tr>
231
+ <td title="Run a google search">features/scenarios/demo.feature:4</td>
232
+ <td data-value="2.730182" title="2.730182">2.730s</td>
233
+ </tr>
234
+ </tbody>
235
+ </table>
236
+ </div>
237
+ <!-- /container -->
238
+ <div class='tab-pane' id='features_tab'>
239
+ <!-- Main component for a primary marketing message or call to action -->
240
+ <div class='jumbotron'>
241
+ <h1>Cucumber feature statistics</h1>
242
+ <p>... find those slow features.</p>
243
+ </div>
244
+ <div class='alert alert-info'>
245
+ <span>
246
+ 2 Features,
247
+ 6 Scenarios,
248
+ 24 Steps completed in 13.190s.
249
+ <span class='text-muted pull-right small'>
250
+ Finished on 08/11/2016 at 06:19PM
251
+ </span>
252
+ </span>
253
+ </div>
254
+ <table class='table table-bordered table-striped sortable'>
255
+ <thead>
256
+ <tr>
257
+ <th>Feature File</th>
258
+ <th data-defaultsort='desc'>Time</th>
259
+ </tr>
260
+ </thead>
261
+ <tbody>
262
+ <tr>
263
+ <td title="Addition
264
+ In order to check my work
265
+ As a mathematician
266
+ I want to be told the sum of two numbers">features/scenarios/calculator2.feature:1</td>
267
+ <td data-value="7.309345" title="7.309345">7.309s</td>
268
+ </tr>
269
+ <tr>
270
+ <td title="A simple test to show custom format methods">features/scenarios/demo.feature:1</td>
271
+ <td data-value="5.880826" title="5.880826">5.880s</td>
272
+ </tr>
273
+ </tbody>
274
+ </table>
275
+ </div>
276
+ </div>
277
+ </div>
278
+ </div>
279
+ </div>
280
+ <!-- /container -->
281
+ <!-- Bootstrap core JavaScript -->
282
+ <!-- \================================================== -->
283
+ <!-- Placed at the end of the document so the pages load faster -->
284
+ <script src='https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js'></script>
285
+ <script src='http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js'></script>
286
+ <script src='https://raw.githack.com/drvic10k/bootstrap-sortable/master/Scripts/moment.min.js'></script>
287
+ <script src='https://raw.githack.com/drvic10k/bootstrap-sortable/master/Scripts/bootstrap-sortable.js'></script>
288
+ <script>
289
+ // Initialise on DOM ready
290
+ $(function() {
291
+ $.bootstrapSortable(true, 'reversed');
292
+ });
293
+ $('a.content_tab').click(function (e) {
294
+ e.preventDefault();
295
+ $(e.target).tab('show');
296
+ });
297
+ </script>
298
+ </body>
299
+ </html>