turnip_formatter 0.0.6 → 0.1.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.
@@ -1,14 +1,44 @@
1
- @mixin step_span {
2
- &:hover { border-width: 3px; }
3
- ~ * { margin-left: 2em; }
4
- }
1
+ $red-front: #ED1C24;
2
+ $green-front: #509B49;
3
+ $yellow-front: #D6A921;
4
+ $red-background: #FFDDDD;
5
+ $green-background: #EEFFEE;
6
+ $yellow-background: #FFFFDD;
7
+ $gray-front: #7A7B7D;
8
+ $gray-background: #DDDDDD;
9
+
10
+ @mixin step_span($front, $back, $with_args: false) {
11
+ > span {
12
+ border: 1px solid $front;
13
+ padding: 0.5em;
14
+ background-color: $back;
15
+ color: $front;
16
+
17
+ &:hover { border-width: 3px; }
18
+ ~ * { margin-left: 2em; }
19
+ }
5
20
 
6
- @mixin noop_step_span {
7
- @include step_span;
21
+ @if $with_args {
8
22
 
9
- background-color: #cccccc;
10
- border: 1px solid #444444;
11
- color: #333333;
23
+ > div.args {
24
+ font-size: 11px;
25
+ padding: 1em;
26
+ background-color: $back;
27
+ border: 1px solid $front;
28
+ }
29
+
30
+ /* skip/pending step style */
31
+ ~ li > span {
32
+ background-color: $gray-background;
33
+ border-color: $gray-front;
34
+ color: $gray-front;
35
+ }
36
+ }
37
+ }
38
+
39
+ @mixin content_centering {
40
+ margin: 0 auto;
41
+ padding: 2em;
12
42
  }
13
43
 
14
44
  body {
@@ -16,30 +46,33 @@ body {
16
46
  }
17
47
 
18
48
  div#report {
19
- width: 90%;
20
- margin: 0 auto;
21
- padding: 2em;
49
+ @include content_centering;
22
50
  background: black;
23
- color: #aaffaa;
51
+ color: $green-front;
24
52
  }
25
53
 
26
54
  footer {
27
- width: 90%;
28
- margin: 0 auto;
29
- padding: 2em;
55
+ @include content_centering;
30
56
  background: black;
31
- color: #aaffaa;
57
+ color: $green-front;
32
58
  text-align: right;
33
59
  }
34
60
 
35
61
  div#main {
36
- width: 90%;
37
- margin: 0 auto;
38
- padding: 2em;
62
+ @include content_centering;
39
63
  background-color: #fff9f9;
64
+
65
+ .ui-tabs-nav {
66
+ border-width: 0;
67
+ padding: 0;
68
+ }
69
+
70
+ .ui-tabs-panel {
71
+ border: 1px solid $gray-front;
72
+ }
40
73
  }
41
74
 
42
- section.scenario {
75
+ div#steps-statistics section.scenario {
43
76
  margin: 1em 0em;
44
77
  padding-left: 1em;
45
78
  border: 2px solid green;
@@ -79,28 +112,28 @@ section.scenario {
79
112
  }
80
113
 
81
114
  &.passed {
82
- border-color: green;
115
+ border-color: $green-front;
83
116
 
84
117
  > header .scenario_name {
85
- color: #859900;
118
+ color: $green-front;
86
119
  &:before { content: "\2713\20"; }
87
120
  }
88
121
  }
89
122
 
90
123
  &.failed {
91
- border-color: #dc322f;
124
+ border-color: $red-front;
92
125
 
93
126
  > header .scenario_name {
94
- color: #dc322f;
127
+ color: $red-front;
95
128
  &:before { content: "\2717\20"; }
96
129
  }
97
130
  }
98
131
 
99
132
  &.pending {
100
- border-color: #b58900;
133
+ border-color: $yellow-front;
101
134
 
102
135
  > header .scenario_name {
103
- color: #b58900;
136
+ color: $yellow-front;
104
137
  &:before { content: "\d8\20"; }
105
138
  }
106
139
  }
@@ -114,53 +147,14 @@ section.scenario {
114
147
  font-weight: bold;
115
148
  margin: 0.5em 0em;
116
149
 
117
- > span {
118
- padding: 0.5em;
119
- background-color: #eeffee;
120
- border: 1px solid #00aa00;
121
- color: #00aa00;
122
-
123
- @include step_span;
124
- }
125
-
126
- div.args {
127
- font-size: 11px;
128
- }
150
+ @include step_span($green-front, $green-background);
129
151
 
130
152
  &.failure {
131
- > span {
132
- background-color: #ffdddd;
133
- border: 1px solid #dd0000;
134
- color: #dd0000;
135
-
136
- @include step_span;
137
- }
138
-
139
- > div.args {
140
- padding: 1em;
141
- background-color: #ffeeee;
142
- border: 1px solid #cc8888;
143
- }
144
-
145
- ~ li > span { @include noop_step_span; }
153
+ @include step_span($red-front, $red-background, true);
146
154
  }
147
155
 
148
156
  &.pending {
149
- > span {
150
- background-color: #ffffbb;
151
- border: 1px solid #666600;
152
- color: #666600;
153
-
154
- @include step_span;
155
- }
156
-
157
- > div.args {
158
- padding: 1em;
159
- background-color: #ffffaa;
160
- border: 1px solid #999944;
161
- }
162
-
163
- ~ li > span { @include noop_step_span; }
157
+ @include step_span($yellow-front, $yellow-background, true);
164
158
  }
165
159
  }
166
160
 
@@ -188,7 +182,7 @@ section.scenario {
188
182
  }
189
183
 
190
184
  div.step_exception {
191
- margin: 1em 0em 1em 0em;
185
+ margin: 1em 0em;
192
186
  padding: 1em 0em 1em 1em;
193
187
  border: 1px solid #999999;
194
188
  background-color: #eee8d5;
@@ -221,6 +215,76 @@ section.scenario {
221
215
  }
222
216
  }
223
217
 
218
+ @mixin tablesorter-header {
219
+ background-position: center right;
220
+ background-repeat: no-repeat;
221
+ cursor: pointer;
222
+ }
223
+
224
+ div#speed-statistics,
225
+ div#feature-statistics,
226
+ div#tag-statistics {
227
+ table {
228
+ width: 100%;
229
+ margin: 1em 0em;
230
+
231
+ thead {
232
+ th {
233
+ border-bottom: 1px solid $gray-front;
234
+ }
235
+ }
236
+
237
+ tbody {
238
+ tr:nth-child(odd) {
239
+ background-color: #FFFFFF;
240
+ }
241
+
242
+ tr:nth-child(even) {
243
+ background-color: $gray-background;
244
+ }
245
+
246
+ td {
247
+ border: 1px solid $gray-front;
248
+ padding: 0.3em 1em;
249
+
250
+ &.passed {
251
+ background-color: $green-background;
252
+ color: $green-front;
253
+ }
254
+ &.failed {
255
+ background-color: $red-background;
256
+ color: $red-front;
257
+ }
258
+ &.pending {
259
+ background-color: $yellow-background;
260
+ color: $yellow-front;
261
+ }
262
+ }
263
+ }
264
+ }
265
+ }
266
+
267
+ div#speed-statistics {
268
+ .tablesorter-header {
269
+ @include tablesorter-header;
270
+ background-image: url("data:image/gif;base64,R0lGODlhFQAJAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==");
271
+
272
+ &.sorter-false {
273
+ background: none;
274
+ }
275
+ }
276
+
277
+ .tablesorter-headerAsc {
278
+ @include tablesorter-header;
279
+ background-image: url("data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7");
280
+ }
281
+
282
+ .tablesorter-headerDesc {
283
+ @include tablesorter-header;
284
+ background-image: url("data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7");
285
+ }
286
+ }
287
+
224
288
  section.exception {
225
289
  margin: 1em 0em;
226
290
  border: 2px solid #268bd2;
@@ -27,6 +27,10 @@ module TurnipFormatter
27
27
  TurnipFormatter::Step.new(example, desc)
28
28
  end
29
29
  end
30
+
31
+ def id
32
+ "step_" + object_id.to_s
33
+ end
30
34
 
31
35
  #
32
36
  # @return [String] scenario name
@@ -0,0 +1,78 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'turnip_formatter/template'
4
+
5
+ module TurnipFormatter
6
+ class Template
7
+ module Tab
8
+ class FeatureStatistics
9
+ attr_reader :features
10
+
11
+ #
12
+ # @param [Array] passed_examples Array of TurnipFormatter::Scenario
13
+ #
14
+ def initialize(scenarios)
15
+ @features = scenarios.group_by { |s| s.feature_name }
16
+ end
17
+
18
+ def build
19
+ html = <<-EOS
20
+ <table>
21
+ <thead>
22
+ <tr>
23
+ <th>Feature</th>
24
+ <th>Scearios</th>
25
+ <th>passed</th>
26
+ <th>failed</th>
27
+ <th>pending</th>
28
+ <th>status</th>
29
+ </tr>
30
+ </thead>
31
+ <tbody>
32
+ EOS
33
+
34
+ html += @features.map do |feature_name, scenarios|
35
+ info = feature_analysis(feature_name, scenarios)
36
+ build_tr(info)
37
+ end.join
38
+
39
+ html += '</tbody></table>'
40
+ end
41
+
42
+ private
43
+
44
+ def feature_analysis(name, scenarios)
45
+ status_group = scenarios.group_by { |s| s.status }
46
+
47
+ info = {
48
+ name: name,
49
+ scenarios: scenarios.count,
50
+ passed: status_count(status_group["passed"]),
51
+ failed: status_count(status_group["failed"]),
52
+ pending: status_count(status_group["pending"])
53
+ }
54
+ info[:status] = info[:failed].zero? ? (info[:pending].zero? ? 'passed' : 'pending') : 'failed'
55
+
56
+ info
57
+ end
58
+
59
+ def status_count(scenarios)
60
+ scenarios.nil? ? 0 : scenarios.count
61
+ end
62
+
63
+ def build_tr(info)
64
+ <<-EOS
65
+ <tr>
66
+ <td>#{info[:name]}</td>
67
+ <td>#{info[:scenarios]}</td>
68
+ <td>#{info[:passed]}</td>
69
+ <td>#{info[:failed]}</td>
70
+ <td>#{info[:pending]}</td>
71
+ <td class="#{info[:status]}">#{info[:status]}</td>
72
+ </tr>
73
+ EOS
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,61 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'turnip_formatter/template'
4
+ require 'ostruct'
5
+
6
+ module TurnipFormatter
7
+ class Template
8
+ module Tab
9
+ class SpeedStatistics
10
+ attr_reader :scenarios
11
+
12
+ #
13
+ # @param [Array] passed_examples Array of TurnipFormatter::Scenario::Pass
14
+ #
15
+ def initialize(passed_scenarios)
16
+ @scenarios = passed_scenarios.map do |s|
17
+ OpenStruct.new(
18
+ {
19
+ id: s.id,
20
+ feature_name: s.feature_name,
21
+ name: s.name,
22
+ run_time: s.run_time
23
+ }
24
+ )
25
+ end.sort { |a, b| a.run_time <=> b.run_time }
26
+ end
27
+
28
+ def build
29
+ html = <<-EOS
30
+ <table>
31
+ <thead>
32
+ <tr>
33
+ <th>Feature</th>
34
+ <th>Scenario</th>
35
+ <th>Duration</th>
36
+ </tr>
37
+ </thead>
38
+ <tbody>
39
+ EOS
40
+
41
+ html += scenarios.map do |scenario|
42
+ <<-EOS
43
+ <tr>
44
+ <td><span>#{scenario.feature_name}</span></td>
45
+ <td><a href=\"\##{scenario.id}\">#{scenario.name}</a></td>
46
+ <td><span>#{scenario.run_time}</span> sec</td>
47
+ </tr>
48
+ EOS
49
+ end.join
50
+
51
+ html += <<-EOS
52
+ </tbody>
53
+ </table>
54
+ EOS
55
+
56
+ html
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,101 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'turnip_formatter/template'
4
+
5
+ module TurnipFormatter
6
+ class Template
7
+ module Tab
8
+ class TagStatistics
9
+ attr_reader :scenarios
10
+
11
+ #
12
+ # @param [Array] passed_examples Array of TurnipFormatter::Scenario
13
+ #
14
+ def initialize(scenarios)
15
+ @scenarios = scenarios
16
+ end
17
+
18
+ def build
19
+ html = <<-EOS
20
+ <table>
21
+ <thead>
22
+ <tr>
23
+ <th>Tag</th>
24
+ <th>Scearios</th>
25
+ <th>passed</th>
26
+ <th>failed</th>
27
+ <th>pending</th>
28
+ <th>status</th>
29
+ </tr>
30
+ </thead>
31
+ <tbody>
32
+ EOS
33
+
34
+ html += tag_analysis.map { |info| build_tr(info) }.join
35
+ html += '</tbody></table>'
36
+ end
37
+
38
+ private
39
+
40
+ def tag_analysis
41
+ group_by_tag.map do |tag, scenarios|
42
+ status_group = scenarios.group_by { |s| s[:scenario].status }
43
+ info = OpenStruct.new(
44
+ name: tag,
45
+ scenarios: scenarios.count,
46
+ passed: status_count(status_group["passed"]),
47
+ failed: status_count(status_group["failed"]),
48
+ pending: status_count(status_group["pending"]),
49
+ status: 'failed'
50
+ )
51
+ info.status = (info.pending.zero? ? 'passed' : 'pending') if info.failed.zero?
52
+ info
53
+ end
54
+ end
55
+
56
+ #
57
+ # Image...
58
+ #
59
+ # [
60
+ # { tags: [:a, :b], val: 3 },
61
+ # { tags: [:a], val: 4 },
62
+ # { tags: [:b], val: 5 },
63
+ # ]
64
+ # # => [
65
+ # a: [3, 4],
66
+ # b: [3, 5]
67
+ # ]
68
+ #
69
+ #
70
+ def group_by_tag
71
+ scenarios.map do |scenario|
72
+ if scenario.tags.empty?
73
+ { name: 'turnip', scenario: scenario }
74
+ else
75
+ scenario.tags.map do |tag|
76
+ { name: '@' + tag, scenario: scenario }
77
+ end
78
+ end
79
+ end.flatten.group_by { |s| s[:name] }.sort
80
+ end
81
+
82
+ def status_count(scenarios)
83
+ scenarios.nil? ? 0 : scenarios.count
84
+ end
85
+
86
+ def build_tr(info)
87
+ <<-EOS
88
+ <tr>
89
+ <td>#{info.name}</td>
90
+ <td>#{info.scenarios}</td>
91
+ <td>#{info.passed}</td>
92
+ <td>#{info.failed}</td>
93
+ <td>#{info.pending}</td>
94
+ <td class="#{info.status}">#{info.status}</td>
95
+ </tr>
96
+ EOS
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -2,6 +2,9 @@
2
2
 
3
3
  require 'erb'
4
4
  require 'rspec/core/formatters/helpers'
5
+ require 'turnip_formatter/template/tab/speed_statistics'
6
+ require 'turnip_formatter/template/tab/feature_statistics'
7
+ require 'turnip_formatter/template/tab/tag_statistics'
5
8
 
6
9
  module TurnipFormatter
7
10
  class Template
@@ -19,13 +22,20 @@ module TurnipFormatter
19
22
  <html>
20
23
  <head>
21
24
  <meta charset="UTF-8">
25
+ <title>turnip formatter report</title>
26
+ <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
27
+ <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js"></script>
28
+ <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.9.1/jquery.tablesorter.min.js"></script>
29
+
30
+ <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/themes/smoothness/jquery-ui.css">
22
31
  <style>
23
32
  #{File.read(File.dirname(__FILE__) + '/formatter.css')}
24
33
  </style>
25
- <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
34
+
26
35
  <script>
27
36
  $(function() {
28
37
  var scenarioHeader = 'section.scenario header';
38
+ $(scenarioHeader).siblings().hide();
29
39
 
30
40
  /**
31
41
  * Step folding/expanding
@@ -57,31 +67,91 @@ module TurnipFormatter
57
67
  }
58
68
  });
59
69
  });
70
+
71
+ /**
72
+ * Tabs
73
+ */
74
+ var tab_area = 'div#main';
75
+ $(tab_area).tabs();
76
+
77
+ $('div#speed-statistics a').click(function() {
78
+ $(tab_area).tabs("option", "active", 0);
79
+ });
80
+
81
+ $("div#speed-statistics table").tablesorter({
82
+ headers: {
83
+ 1: { sorter: false }
84
+ }
85
+ });
60
86
  });
61
87
  </script>
62
88
  </head>
63
89
  <body>
64
90
  #{report_area}
65
91
  <div id="main" role="main">
66
- <label><input type="checkbox" id="scenario_display_check">step folding</label>
92
+ <ul>
93
+ <li><a href="#steps-statistics">Steps</a></li>
94
+ <li><a href="#speed-statistics">Speed Statistics</a></li>
95
+ <li><a href="#feature-statistics">Feature Statistics</a></li>
96
+ <li><a href="#tag-statistics">Tag Statistics</a></li>
97
+ </ul>
67
98
  EOS
68
99
  end
69
100
 
70
- def print_footer(total_count, failed_count, pending_count, total_time)
101
+ def print_main_header
102
+ <<-EOS
103
+ <div id="steps-statistics">
104
+ <label><input type="checkbox" id="scenario_display_check" checked>step folding</label>
105
+ EOS
106
+ end
107
+
108
+ def print_main_footer(total_count, failed_count, pending_count, total_time)
71
109
  update_report_js_tmp = '<script type="text/javascript">document.getElementById("%s").innerHTML = "%s";</script>'
72
110
  update_report_js = ''
73
-
74
111
 
75
112
  %w{ total_count failed_count pending_count total_time }.each do |key|
76
113
  update_report_js += update_report_js_tmp % [key, eval(key)]
77
114
  end
78
115
 
116
+ "#{update_report_js}</div>"
117
+ end
118
+
119
+ def print_tab_speed_statsitics(passed_scenarios)
120
+ statistics = TurnipFormatter::Template::Tab::SpeedStatistics.new(passed_scenarios)
79
121
  <<-EOS
80
- </div>
81
- #{update_report_js}
122
+ <div id="speed-statistics">
123
+ <em>Ranking of running time of each <strong>successfully</strong> scenario:</em>
124
+ #{statistics.build}
125
+ </div>
126
+ EOS
127
+ end
128
+
129
+ def print_tab_feature_statsitics(scenarios)
130
+ statistics = TurnipFormatter::Template::Tab::FeatureStatistics.new(scenarios)
131
+ <<-EOS
132
+ <div id="feature-statistics">
133
+ <em>The results for the feature:</em>
134
+ #{statistics.build}
135
+ </div>
136
+ EOS
137
+ end
82
138
 
139
+ def print_tab_tag_statsitics(scenarios)
140
+ statistics = TurnipFormatter::Template::Tab::TagStatistics.new(scenarios)
141
+ <<-EOS
142
+ <div id="tag-statistics">
143
+ <em>The results for the tab:</em>
144
+ #{statistics.build}
145
+ </div>
146
+ EOS
147
+ end
148
+
149
+ def print_footer
150
+ <<-EOS
151
+ </div>
83
152
  <footer>
84
- Generated by <a href="https://rubygems.org/gems/turnip_formatter">turnip_formatter</a> #{TurnipFormatter::VERSION} and <a href="http://jquery.com/">jQuery</a>
153
+ <p>Generated by <a href="https://rubygems.org/gems/turnip_formatter">turnip_formatter</a> #{TurnipFormatter::VERSION}</p>
154
+ <p>Powered by <a href="http://jquery.com/">jQuery</a> 1.9.1, <a href="http://jqueryui.com/">jQuery UI</a> 1.10.2 and <a href="http://mottie.github.io/tablesorter/">tablesorter</a> 2.9.1</p>
85
155
  </footer>
86
156
  </body>
87
157
  </html>
@@ -175,9 +245,9 @@ module TurnipFormatter
175
245
  <section class="scenario <%= h(scenario.status) %>">
176
246
  <header>
177
247
  <span class="permalink">
178
- <a href="#<%= scenario.object_id %>">&para;</a>
248
+ <a href="#<%= scenario.id %>">&para;</a>
179
249
  </span>
180
- <span class="scenario_name" id="<%= scenario.object_id %>">
250
+ <span class="scenario_name" id="<%= scenario.id %>">
181
251
  Scenario: <%= h(scenario.name) %>
182
252
  </span>
183
253
  <span class="feature_name">
@@ -1,5 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  module TurnipFormatter
4
- VERSION = "0.0.6"
4
+ VERSION = "0.1.0"
5
5
  end
@@ -1,5 +1,6 @@
1
1
  Feature: Battle monsters
2
2
 
3
+ @watch
3
4
  Scenario: Escape
4
5
  Given there are monsters:
5
6
  | gargoyle |
@@ -8,3 +8,12 @@ Feature: A feature with multiline strings
8
8
  This is cool
9
9
  """
10
10
  Then the song should have 2 lines
11
+
12
+ Scenario: This is a feature with multiline strings
13
+ When a monster sings the following song
14
+ """
15
+ Oh here be monsters
16
+ This is cool
17
+ """
18
+ Then the song should have 2 lines
19
+