cucumber_statistics 2.1.1 → 2.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: 907013082e484671f77d0cbf28fa4852d534f0d9
4
- data.tar.gz: c3cdaa1c2838e73ecf63a03fd72a965e7168cfe3
3
+ metadata.gz: f092f72aee7ed2a12f831f6121609828b7779efa
4
+ data.tar.gz: 168d3905bad7a316082ef66318e69d614842b305
5
5
  SHA512:
6
- metadata.gz: f492e8bf780dcf55339e82f242a774afc4e1f907f227f9bd973f18f59ef8803f4b5a1d48b660e62b863a214e73d2b5b2127cb02bf40392515b3ff30bfba819eb
7
- data.tar.gz: 618be5d5530b12dcb4786ddfea2099252a76bb7f353886537f91bb01903907d41f7e598570e656b9edfb3b283ec93bb7a9bda8debc4bbf1b6451f5989d5450cb
6
+ metadata.gz: 3a59558e79b0de5fc6057510d3b64e58358e5df8b091811a9ed5079849b7f484ef1ef6979c97b8b8f26924dec76479ec69d2329ff9343f793f5d30471ce568aa
7
+ data.tar.gz: 0ce6a14d9fb2fb8b008e3896da559b27381d378c3f7955622ab3dfee02a80200ee1176d8672662ed18e4663e9dfd0b45e9d2e62d9dceb43493b3d3a42b7a34c1
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- ruby-2.2.2
1
+ ruby-2.3.1
@@ -1,6 +1,8 @@
1
1
  require 'cucumber_statistics/configuration'
2
2
  require 'cucumber_statistics/step_statistics'
3
+ require 'cucumber_statistics/scenario_statistics'
4
+ require 'cucumber_statistics/feature_statistics'
3
5
  require 'cucumber_statistics/overall_statistics'
4
6
  require 'cucumber_statistics/unused_steps'
5
7
  require 'cucumber_statistics/formatter'
6
- require 'cucumber_statistics/renderer'
8
+ require 'cucumber_statistics/renderer'
@@ -26,6 +26,13 @@ module CucumberStatistics
26
26
  tmp_file('step_statistics.html')
27
27
  end
28
28
 
29
+ def result_scenario_statistics
30
+ tmp_file('scenario_statistics.html')
31
+ end
32
+
33
+ def result_feature_statistics
34
+ tmp_file('feature_statistics.html')
35
+ end
29
36
 
30
37
  def resolve_path_from_root(relative_path)
31
38
  if defined?(Rails)
@@ -54,4 +61,4 @@ module CucumberStatistics
54
61
  #end
55
62
  end
56
63
  end
57
- end
64
+ end
@@ -0,0 +1,28 @@
1
+ module CucumberStatistics
2
+ class FeatureStatistics
3
+ def initialize
4
+ @all = Hash.new
5
+ end
6
+
7
+ def record feature_name, duration, file
8
+ short_file = file[file.index('features').to_i..-1]
9
+
10
+ feature_result = @all[short_file]
11
+ feature_result ||= Hash.new
12
+ feature_result[:duration] = duration
13
+ feature_result[:feature_name] = feature_name
14
+
15
+ @all[short_file] ||= feature_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
@@ -7,6 +7,8 @@ module CucumberStatistics
7
7
 
8
8
  @overall_statistics = OverallStatistics.new
9
9
  @step_statistics = StepStatistics.new
10
+ @scenario_statistics = ScenarioStatistics.new
11
+ @feature_statistics = FeatureStatistics.new
10
12
  @unused_steps = UnusedSteps.new
11
13
  end
12
14
 
@@ -29,6 +31,29 @@ module CucumberStatistics
29
31
  end
30
32
 
31
33
 
34
+ #----------------------------------------------------
35
+ # Feature Element callbacks
36
+ #----------------------------------------------------
37
+ def before_feature_element(feature_element)
38
+ @scenario_name = ''
39
+ @scenario_file_colon_line = ''
40
+ @scenario_start_time = Time.now
41
+ end
42
+
43
+ def after_feature_element(feature_element)
44
+ @scenario_duration = Time.now - @scenario_start_time
45
+ @scenario_statistics.record @scenario_name, @scenario_duration, @scenario_file_colon_line
46
+ end
47
+
48
+ #----------------------------------------------------
49
+ # Feature callbacks
50
+ #----------------------------------------------------
51
+ def before_feature(feature)
52
+ @feature_name = ''
53
+ @feature_file = ''
54
+ @feature_start_time = Time.now
55
+ end
56
+
32
57
  #----------------------------------------------------
33
58
  # Overall callbacks
34
59
  #----------------------------------------------------
@@ -36,6 +61,13 @@ module CucumberStatistics
36
61
  #end
37
62
  def scenario_name(keyword, name, file_colon_line, source_indent)
38
63
  @overall_statistics.scenario_count_inc
64
+ @scenario_name = name
65
+ @scenario_file_colon_line = file_colon_line
66
+ end
67
+
68
+ def feature_name(keyword, name)
69
+ @overall_statistics.feature_count_inc
70
+ @feature_name = name
39
71
  end
40
72
 
41
73
  def after_step(step)
@@ -43,7 +75,9 @@ module CucumberStatistics
43
75
  end
44
76
 
45
77
  def after_feature(feature)
46
- @overall_statistics.feature_count_inc
78
+ @feature_file = feature.location.to_s
79
+ @feature_duration = Time.now - @feature_start_time
80
+ @feature_statistics.record @feature_name, @feature_duration, @feature_file
47
81
  end
48
82
 
49
83
  def before_features(features)
@@ -62,7 +96,8 @@ module CucumberStatistics
62
96
  @step_statistics.calculate
63
97
 
64
98
  file = Renderer.render_step_statistics @step_statistics, @overall_statistics
65
- puts "Cucumber statistics generated to #{file.to_s}"
99
+ Renderer.render_scenario_statistics @scenario_statistics, @overall_statistics
100
+ Renderer.render_feature_statistics @feature_statistics, @overall_statistics
66
101
  end
67
102
  end
68
- end
103
+ end
@@ -20,6 +20,30 @@ module CucumberStatistics
20
20
 
21
21
  absolute_file_name
22
22
  end
23
+
24
+ def render_scenario_statistics(scenario_statistics, overall_statistics)
25
+ template = Tilt::HamlTemplate.new(File.expand_path('../view/scenario_statistics.html.haml', __FILE__))
26
+ rendered_content = template.render(RendererHelper.new, scenario_statistics: scenario_statistics, overall_statistics: overall_statistics)
27
+
28
+ absolute_file_name = Configuration.result_scenario_statistics
29
+ File.open(absolute_file_name, 'w') do |f|
30
+ f.write rendered_content
31
+ end
32
+
33
+ absolute_file_name
34
+ end
35
+
36
+ def render_feature_statistics(feature_statistics, overall_statistics)
37
+ template = Tilt::HamlTemplate.new(File.expand_path('../view/feature_statistics.html.haml', __FILE__))
38
+ rendered_content = template.render(RendererHelper.new, feature_statistics: feature_statistics, overall_statistics: overall_statistics)
39
+
40
+ absolute_file_name = Configuration.result_feature_statistics
41
+ File.open(absolute_file_name, 'w') do |f|
42
+ f.write rendered_content
43
+ end
44
+
45
+ absolute_file_name
46
+ end
23
47
  end
24
48
  end
25
- end
49
+ end
@@ -2,22 +2,38 @@ module CucumberStatistics
2
2
 
3
3
  class RendererHelper
4
4
 
5
- def name_td(step_results)
6
- %{<td title="#{step_results[1][:file]}">#{step_results[0]}</td>}
5
+ def name_td(results)
6
+ %{<td title="#{results[1][:file]}">#{results[0]}</td>}
7
7
  end
8
8
 
9
- def time_td(step_results, metric, *warning_step_results)
10
- duration = step_results[1][metric]
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
11
26
 
12
- %{<td #{warning_class(step_results, warning_step_results)} data-value="#{duration}" title="#{duration}">#{format(duration)}</td>}
27
+ def std_time_td(duration)
28
+ %{<td data-value="#{duration}" title="#{duration}">#{format(duration)}</td>}
13
29
  end
14
30
 
15
- def warning_class(step_results, warning_step_results)
31
+ def warning_class(results, warning_results)
16
32
 
17
- if warning_step_results.nil? || warning_step_results.empty?
33
+ if warning_results.nil? || warning_results.empty?
18
34
  should_warn = false
19
35
  else
20
- should_warn = (step_results[0].eql? warning_step_results[0][0])
36
+ should_warn = (results[0].eql? warning_results[0][0])
21
37
  end
22
38
  if should_warn
23
39
  %{class="danger"}
@@ -26,8 +42,8 @@ module CucumberStatistics
26
42
  end
27
43
  end
28
44
 
29
- def count_td(step_results, metric)
30
- value = step_results[1][metric]
45
+ def count_td(results, metric)
46
+ value = results[1][metric]
31
47
  %{<td data-value="#{value}">#{value}</td>}
32
48
  end
33
49
 
@@ -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
@@ -1,3 +1,3 @@
1
1
  module CucumberStatistics
2
- VERSION = '2.1.1'
2
+ VERSION = '2.2.0'
3
3
  end
@@ -0,0 +1,116 @@
1
+ !!!
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 Feature Statistics", :name => "description"}/
8
+ %meta{:content => "AlienFast", :name => "author"}/
9
+ %title Cucumber Feature Statistics
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
+ :css
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
+ %link{:href => "https://raw.githack.com/drvic10k/bootstrap-sortable/master/Contents/bootstrap-sortable.css", :rel => "stylesheet"}/
29
+ / HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries
30
+ /[if lt IE 9]
31
+ <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
32
+ <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
33
+ %body
34
+ / Fixed navbar
35
+ .navbar.navbar-default.navbar-fixed-top{:role => "navigation"}
36
+ .container
37
+ .navbar-header
38
+ %button.navbar-toggle{"data-target" => ".navbar-collapse", "data-toggle" => "collapse", :type => "button"}
39
+ %span.sr-only Toggle navigation
40
+ %span.icon-bar
41
+ %span.icon-bar
42
+ %span.icon-bar
43
+ %a.navbar-brand{:href => "#"} cucumber_statistics
44
+ .navbar-collapse.collapse
45
+ -#%ul.nav.navbar-nav
46
+ %li.active
47
+ %a{:href => "#"} Home
48
+ %li
49
+ %a{:href => "#about"} About
50
+ %li
51
+ %a{:href => "#contact"} Contact
52
+ %li.dropdown
53
+ %a.dropdown-toggle{"data-toggle" => "dropdown", :href => "#"}
54
+ Dropdown
55
+ %b.caret
56
+ %ul.dropdown-menu
57
+ %li
58
+ %a{:href => "#"} Action
59
+ %li
60
+ %a{:href => "#"} Another action
61
+ %li
62
+ %a{:href => "#"} Something else here
63
+ %li.divider
64
+ %li.dropdown-header Nav header
65
+ %li
66
+ %a{:href => "#"} Separated link
67
+ %li
68
+ %a{:href => "#"} One more separated link
69
+ %ul.nav.navbar-nav.navbar-right
70
+ -#%li
71
+ -# %a{:href => "../navbar/"} Default
72
+ -#%li
73
+ -# %a{:href => "../navbar-static-top/"} Static top
74
+ %li
75
+ %a{:href => "https://github.com/alienfast/cucumber_statistics", :target => 'other'} Github
76
+ / /.nav-collapse
77
+ .container
78
+ / Main component for a primary marketing message or call to action
79
+ .jumbotron
80
+ %h1 Cucumber feature statistics
81
+ %p ... find those slow features.
82
+
83
+ .alert.alert-info
84
+ %span
85
+ #{overall_statistics.feature_count} Features,
86
+ #{overall_statistics.scenario_count} Scenarios,
87
+ #{overall_statistics.step_count} Steps completed in #{format(overall_statistics.duration)}.
88
+ %span.text-muted.pull-right.small
89
+ Finished on #{format_date_time(overall_statistics.end_time)}
90
+
91
+ %table.table.table-bordered.table-striped.sortable
92
+ %thead
93
+ %tr
94
+ %th Feature File
95
+ %th{"data-defaultsort" => "desc"} Time
96
+ %tbody
97
+
98
+ - feature_statistics.all.each do |file_name, feature_result|
99
+
100
+ %tr
101
+ = std_file_td file_name, feature_result[:feature_name]
102
+ = std_time_td feature_result[:duration]
103
+ / /container
104
+ /
105
+ Bootstrap core JavaScript
106
+ \==================================================
107
+ / Placed at the end of the document so the pages load faster
108
+ %script{:src => "https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"}
109
+ %script{:src => "http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"}
110
+ %script{:src => "https://raw.githack.com/drvic10k/bootstrap-sortable/master/Scripts/moment.min.js"}
111
+ %script{:src => "https://raw.githack.com/drvic10k/bootstrap-sortable/master/Scripts/bootstrap-sortable.js"}
112
+ :javascript
113
+ // Initialise on DOM ready
114
+ $(function() {
115
+ $.bootstrapSortable(true, 'reversed');
116
+ });
@@ -0,0 +1,116 @@
1
+ !!!
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
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
+ :css
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
+ %link{:href => "https://raw.githack.com/drvic10k/bootstrap-sortable/master/Contents/bootstrap-sortable.css", :rel => "stylesheet"}/
29
+ / HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries
30
+ /[if lt IE 9]
31
+ <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
32
+ <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
33
+ %body
34
+ / Fixed navbar
35
+ .navbar.navbar-default.navbar-fixed-top{:role => "navigation"}
36
+ .container
37
+ .navbar-header
38
+ %button.navbar-toggle{"data-target" => ".navbar-collapse", "data-toggle" => "collapse", :type => "button"}
39
+ %span.sr-only Toggle navigation
40
+ %span.icon-bar
41
+ %span.icon-bar
42
+ %span.icon-bar
43
+ %a.navbar-brand{:href => "#"} cucumber_statistics
44
+ .navbar-collapse.collapse
45
+ -#%ul.nav.navbar-nav
46
+ %li.active
47
+ %a{:href => "#"} Home
48
+ %li
49
+ %a{:href => "#about"} About
50
+ %li
51
+ %a{:href => "#contact"} Contact
52
+ %li.dropdown
53
+ %a.dropdown-toggle{"data-toggle" => "dropdown", :href => "#"}
54
+ Dropdown
55
+ %b.caret
56
+ %ul.dropdown-menu
57
+ %li
58
+ %a{:href => "#"} Action
59
+ %li
60
+ %a{:href => "#"} Another action
61
+ %li
62
+ %a{:href => "#"} Something else here
63
+ %li.divider
64
+ %li.dropdown-header Nav header
65
+ %li
66
+ %a{:href => "#"} Separated link
67
+ %li
68
+ %a{:href => "#"} One more separated link
69
+ %ul.nav.navbar-nav.navbar-right
70
+ -#%li
71
+ -# %a{:href => "../navbar/"} Default
72
+ -#%li
73
+ -# %a{:href => "../navbar-static-top/"} Static top
74
+ %li
75
+ %a{:href => "https://github.com/alienfast/cucumber_statistics", :target => 'other'} Github
76
+ / /.nav-collapse
77
+ .container
78
+ / Main component for a primary marketing message or call to action
79
+ .jumbotron
80
+ %h1 Cucumber scenario statistics
81
+ %p ... find those slow scenarios.
82
+
83
+ .alert.alert-info
84
+ %span
85
+ #{overall_statistics.feature_count} Features,
86
+ #{overall_statistics.scenario_count} Scenarios,
87
+ #{overall_statistics.step_count} Steps completed in #{format(overall_statistics.duration)}.
88
+ %span.text-muted.pull-right.small
89
+ Finished on #{format_date_time(overall_statistics.end_time)}
90
+
91
+ %table.table.table-bordered.table-striped.sortable
92
+ %thead
93
+ %tr
94
+ %th Scenario File
95
+ %th{"data-defaultsort" => "desc"} Time
96
+ %tbody
97
+
98
+ - scenario_statistics.all.each do |file_name, scenario_result|
99
+
100
+ %tr
101
+ = std_file_td file_name, scenario_result[:scenario_name]
102
+ = std_time_td scenario_result[:duration]
103
+ / /container
104
+ /
105
+ Bootstrap core JavaScript
106
+ \==================================================
107
+ / Placed at the end of the document so the pages load faster
108
+ %script{:src => "https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"}
109
+ %script{:src => "http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"}
110
+ %script{:src => "https://raw.githack.com/drvic10k/bootstrap-sortable/master/Scripts/moment.min.js"}
111
+ %script{:src => "https://raw.githack.com/drvic10k/bootstrap-sortable/master/Scripts/bootstrap-sortable.js"}
112
+ :javascript
113
+ // Initialise on DOM ready
114
+ $(function() {
115
+ $.bootstrapSortable(true, 'reversed');
116
+ });
@@ -10,11 +10,11 @@ module CucumberStatistics
10
10
  it 'should auto create tmp_dir' do
11
11
 
12
12
  tmp_dir = Configuration.tmp_dir
13
- Dir.exists?(tmp_dir).should == true
13
+ expect(Dir.exists?(tmp_dir)).to be_truthy
14
14
 
15
15
  Dir.delete tmp_dir
16
16
  tmp_dir = Configuration.tmp_dir
17
- Dir.exists?(tmp_dir).should == true
17
+ expect(Dir.exists?(tmp_dir)).to be_truthy
18
18
  end
19
19
  end
20
20
  end
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+
3
+ module CucumberStatistics
4
+ describe FeatureStatistics do
5
+
6
+ subject(:feature_statistics) { FeatureStatistics.new }
7
+ subject(:overall_statistics) { OverallStatistics.new } #not sure if really need
8
+
9
+ describe 'record' do
10
+ it 'should create a record' do
11
+ record 'my feature', 50, 'features/admin_cancel_account.feature'
12
+
13
+ expect(feature_statistics.all.count).to eq 1
14
+ expect(feature_statistics.all['features/admin_cancel_account.feature'][:duration]).to eq 50
15
+ end
16
+
17
+ it 'should support multiple scenarios with the same name' do
18
+ record 'my feature', 50, 'admin_cancel_account.feature'
19
+ record 'my feature', 75, 'noise/features/super_admin/admin_cancel_account.feature'
20
+
21
+ expect(feature_statistics.all.count).to eq 2
22
+ expect(feature_statistics.all['admin_cancel_account.feature'][:duration]).to eq 50
23
+ expect(feature_statistics.all['features/super_admin/admin_cancel_account.feature'][:duration]).to eq 75
24
+ end
25
+
26
+ it 'chops off file path up to features/' do
27
+ record 'my feature', 50, '/User/some/file/path/that/doesnt/matter really/features/admin_cancel_account.feature'
28
+ expect(feature_statistics.all.keys.first).to eq 'features/admin_cancel_account.feature'
29
+ end
30
+
31
+ it 'uses the whole string if the filepath doesnt include the features folder' do
32
+ record 'my feature', 50, 'admin_cancel_account.feature'
33
+ expect(feature_statistics.all.keys.first).to eq 'admin_cancel_account.feature'
34
+ end
35
+ end
36
+
37
+ describe 'all' do
38
+ before(:each) do
39
+ record 'my feature', 24, 'admin_cancel_account.feature'
40
+ record 'my feature', 50, 'admin_edit_account.feature'
41
+ end
42
+
43
+ it 'should return all records' do
44
+ expect(feature_statistics.all.count).to eq 2
45
+ feature_statistics.all.each_with_index do |file_colon_line, data, index|
46
+ case index
47
+ when 1
48
+ expect(file_colon_line).to eq 'admin_cancel_account.feature'
49
+ when 2
50
+ expect(file_colon_line).to eq 'admin_edit_account.feature'
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ describe 'set operations' do
57
+ before(:each) do
58
+ record 'a', 25, 'admin_cancel_account.feature'
59
+ record 'c', 51, 'view_account.feature'
60
+ record 'b', 75, 'edit_account.feature'
61
+ end
62
+
63
+ describe 'sort_by_property' do
64
+ context 'should sort all records by any property' do
65
+ it { expect(feature_statistics.sort_by_property(:feature_name).first[0]).to eq 'admin_cancel_account.feature' }
66
+ it { expect(feature_statistics.sort_by_property(:feature_name).last[0]).to eq 'view_account.feature' }
67
+
68
+ it { expect(feature_statistics.sort_by_property(:duration).first[0]).to eq 'admin_cancel_account.feature' }
69
+ it { expect(feature_statistics.sort_by_property(:duration).last[0]).to eq 'edit_account.feature' }
70
+ end
71
+ end
72
+ end
73
+
74
+ def record(feature_name, duration, file)
75
+ feature_statistics.record feature_name, duration, file
76
+ end
77
+ end
78
+ end
@@ -4,6 +4,8 @@ module CucumberStatistics
4
4
  describe Renderer do
5
5
 
6
6
  subject(:step_statistics) { StepStatistics.new }
7
+ subject(:scenario_statistics) { ScenarioStatistics.new }
8
+ subject(:feature_statistics) { FeatureStatistics.new }
7
9
  subject(:overall_statistics) { OverallStatistics.new }
8
10
 
9
11
  before(:each) do
@@ -23,21 +25,37 @@ module CucumberStatistics
23
25
  record 'my step 4', 4.21
24
26
  record 'my step 4', 4.21
25
27
 
28
+ record_scenario 'my scenario 1', 10.2, '/Users/kross/alienfast/acme/features/account management/admin_cancel_account.feature:8'
29
+ record_scenario 'my scenario 2', 30.2, '/Users/kross/alienfast/acme/features/account management/admin_cancel_account.feature:13'
30
+ record_scenario 'my scenario 3', 17.342, '/Users/kross/alienfast/acme/features/user experience/view.feature:2'
31
+ record_scenario 'my scenario 3', 3.2, '/Users/kross/alienfast/acme/features/user experience/view.feature:23'
32
+
26
33
  overall_statistics.end_time = Time.now
27
34
  step_statistics.calculate
28
35
  end
29
36
 
30
37
 
31
- describe 'render_step_statistics' do
32
- it 'should render content' do
38
+ describe 'render statistics' do
39
+ context 'should render content' do
40
+
41
+ it 'renders step results file' do
42
+ expect(File.exists?(Configuration.result_step_statistics)).to eql false
43
+ absolute_file_name = Renderer.render_step_statistics step_statistics, overall_statistics
44
+ expect(File.exists?(absolute_file_name)).to eql true
45
+ end
33
46
 
34
- expect(File.exists?(Configuration.result_step_statistics)).to eql false
47
+ it 'renders scenario results file' do
48
+ expect(File.exists?(Configuration.result_scenario_statistics)).to eql false
49
+ absolute_file_name = Renderer.render_scenario_statistics scenario_statistics, overall_statistics
50
+ expect(File.exists?(absolute_file_name)).to eql true
51
+ end
35
52
 
36
- absolute_file_name = Renderer.render_step_statistics step_statistics, overall_statistics
37
- expect(File.exists?(absolute_file_name)).to eql true
53
+ it 'renders feature results file' do
54
+ expect(File.exists?(Configuration.result_feature_statistics)).to eql false
55
+ absolute_file_name = Renderer.render_feature_statistics feature_statistics, overall_statistics
56
+ expect(File.exists?(absolute_file_name)).to eql true
57
+ end
38
58
 
39
- #file = File.open(absolute_file_name, 'rb')
40
- #file_contents = file.read
41
59
  end
42
60
  end
43
61
 
@@ -46,5 +64,11 @@ module CucumberStatistics
46
64
  step_statistics.record step_name, duration, '/Users/kross/alienfast/acme/features/account management/admin_cancel_account.feature:8'
47
65
  overall_statistics.step_count_inc
48
66
  end
67
+
68
+ def record_scenario(scenario_name, duration, file_colon_line)
69
+ # fake a source for convenience
70
+ scenario_statistics.record scenario_name, duration, file_colon_line
71
+ overall_statistics.scenario_count_inc
72
+ end
49
73
  end
50
74
  end
@@ -0,0 +1,86 @@
1
+ require 'spec_helper'
2
+
3
+ module CucumberStatistics
4
+ describe ScenarioStatistics do
5
+
6
+ subject(:scenario_statistics) { ScenarioStatistics.new }
7
+ subject(:overall_statistics) { OverallStatistics.new } #not sure if really need
8
+
9
+ describe 'record' do
10
+ it 'should create a record' do
11
+ record 'my scenario', 50, 'features/admin_cancel_account.feature:8'
12
+
13
+ expect(scenario_statistics.all.count).to eq 1
14
+ expect(scenario_statistics.all['features/admin_cancel_account.feature:8'][:duration]).to eq 50
15
+ end
16
+
17
+ it 'should support multiple scenarios with the same name' do
18
+ record 'my scenario', 50, 'admin_cancel_account.feature:8'
19
+ record 'my scenario', 75, 'noise/features/super_admin/admin_cancel_account.feature:8'
20
+
21
+ expect(scenario_statistics.all.count).to eq 2
22
+ expect(scenario_statistics.all['admin_cancel_account.feature:8'][:duration]).to eq 50
23
+ expect(scenario_statistics.all['features/super_admin/admin_cancel_account.feature:8'][:duration]).to eq 75
24
+ end
25
+
26
+ it 'chops off file path up to features/' do
27
+ record 'my scenario', 50, '/User/some/file/path/that/doesnt/matter really/features/admin_cancel_account.feature:8'
28
+ expect(scenario_statistics.all.keys.first).to eq 'features/admin_cancel_account.feature:8'
29
+ end
30
+
31
+ it 'uses the whole string if the filepath doesnt include the features folder' do
32
+ record 'my scenario', 50, 'admin_cancel_account.feature:8'
33
+ expect(scenario_statistics.all.keys.first).to eq 'admin_cancel_account.feature:8'
34
+ end
35
+ end
36
+
37
+ describe 'all' do
38
+ before(:each) do
39
+ record 'my scenario 1', 24, 'admin_cancel_account.feature:8'
40
+ record 'my scenario 1', 50, 'admin_cancel_account.feature:18'
41
+ record 'my scenario 2', 75, 'admin_cancel_account.feature:38'
42
+ end
43
+
44
+ it 'should return all records' do
45
+ expect(scenario_statistics.all.count).to eq 3
46
+ scenario_statistics.all.each_with_index do |file_colon_line, data, index|
47
+ case index
48
+ when 1
49
+ expect(file_colon_line).to eq 'admin_cancel_account.feature:8'
50
+ when 2
51
+ expect(file_colon_line).to eq 'admin_cancel_account.feature:18'
52
+ when 3
53
+ expect(file_colon_line).to eq 'admin_cancel_account.feature:38'
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ describe 'set operations' do
60
+ before(:each) do
61
+ record 'my scenario 1', 25, 'admin_cancel_account.feature:8'
62
+ record 'my scenario 2', 50, 'admin_cancel_account.feature:13'
63
+ record 'my scenario 3', 49, 'admin_cancel_account.feature:15'
64
+ record 'my scenario 1', 51, 'view_account.feature:3'
65
+ record 'my scenario 2', 75, 'view_account.feature:6'
66
+ record 'my scenario 3', 10, 'view_account.feature:22'
67
+ end
68
+
69
+ describe 'sort_by_property' do
70
+ context 'should sort all records by any property' do
71
+ it { expect(scenario_statistics.sort_by_property(:scenario_name).first[0]).to eq 'admin_cancel_account.feature:8' }
72
+ it { expect(scenario_statistics.sort_by_property(:scenario_name).last[0]).to eq 'view_account.feature:22' }
73
+
74
+ it { expect(scenario_statistics.sort_by_property(:duration).first[0]).to eq 'view_account.feature:22' }
75
+ it { expect(scenario_statistics.sort_by_property(:duration).last[0]).to eq 'view_account.feature:6' }
76
+ end
77
+ end
78
+ end
79
+
80
+ def record(scenario_name, duration, file_colon_line)
81
+ # fake a source for convenience
82
+ scenario_statistics.record scenario_name, duration, file_colon_line
83
+ #overall_statistics.step_count_inc
84
+ end
85
+ end
86
+ end
@@ -8,81 +8,81 @@ module CucumberStatistics
8
8
 
9
9
  describe 'record' do
10
10
  it 'should create a record' do
11
- record "my step", 50
11
+ record 'my step', 50
12
12
 
13
- step_statistics.all.count.should == 1
14
- step_statistics.all['my step'][:instances].count.should == 1
15
- step_statistics.all['my step'][:instances].first.should == 50
13
+ expect(step_statistics.all.count).to eq 1
14
+ expect(step_statistics.all['my step'][:instances].count).to eq 1
15
+ expect(step_statistics.all['my step'][:instances].first).to eq 50
16
16
  end
17
17
 
18
18
  it 'should support multiple instances of record' do
19
- record "my step", 50
20
- record "my step", 75
19
+ record 'my step', 50
20
+ record 'my step', 75
21
21
 
22
- step_statistics.all.count.should == 1
23
- step_statistics.all['my step'][:instances].count.should == 2
24
- step_statistics.all['my step'][:instances].first.should == 50
25
- step_statistics.all['my step'][:instances].last.should == 75
22
+ expect(step_statistics.all.count).to eq 1
23
+ expect(step_statistics.all['my step'][:instances].count).to eq 2
24
+ expect(step_statistics.all['my step'][:instances].first).to eq 50
25
+ expect(step_statistics.all['my step'][:instances].last).to eq 75
26
26
  end
27
27
  end
28
28
 
29
29
  describe 'calculate' do
30
30
  before(:each) do
31
- record "my step", 25
32
- record "my step", 50
33
- record "my step", 75
31
+ record 'my step', 25
32
+ record 'my step', 50
33
+ record 'my step', 75
34
34
 
35
35
  step_statistics.calculate
36
36
  end
37
37
 
38
38
  it 'should calculate the total elapsed time' do
39
- step_statistics.all["my step"][:total].should == 150
39
+ expect(step_statistics.all['my step'][:total]).to eq 150
40
40
  end
41
41
 
42
42
  it 'should calculate the number of count' do
43
- step_statistics.all["my step"][:count].should == 3
43
+ expect(step_statistics.all['my step'][:count]).to eq 3
44
44
  end
45
45
 
46
46
  it 'should calculate the average time' do
47
- step_statistics.all["my step"][:average].should == 50
47
+ expect(step_statistics.all['my step'][:average]).to eq 50
48
48
  end
49
49
 
50
50
  it 'should calculate the fastest step' do
51
- step_statistics.all["my step"][:fastest].should == 25
51
+ expect(step_statistics.all['my step'][:fastest]).to eq 25
52
52
  end
53
-
53
+
54
54
  it 'should calculate the slowest step' do
55
- step_statistics.all["my step"][:slowest].should == 75
55
+ expect(step_statistics.all['my step'][:slowest]).to eq 75
56
56
  end
57
57
 
58
58
  it 'should calculate the variation' do
59
- step_statistics.all["my step"][:variation].should == 50
59
+ expect(step_statistics.all['my step'][:variation]).to eq 50
60
60
  end
61
61
 
62
62
  it 'should calculate the standard deviation' do
63
- step_statistics.all["my step"][:standard_deviation].should == 25
63
+ expect(step_statistics.all['my step'][:standard_deviation]).to eq 25
64
64
  end
65
65
 
66
66
  it 'should calculate the variance' do
67
- step_statistics.all["my step"][:variance].should == 625
67
+ expect(step_statistics.all['my step'][:variance]).to eq 625
68
68
  end
69
69
  end
70
70
 
71
71
  describe 'all' do
72
72
  before(:each) do
73
- record "my step 1", 24
74
- record "my step 1", 50
75
- record "my step 2", 75
73
+ record 'my step 1', 24
74
+ record 'my step 1', 50
75
+ record 'my step 2', 75
76
76
  end
77
77
 
78
78
  it 'should return all records' do
79
- step_statistics.all.count.should == 2
79
+ expect(step_statistics.all.count).to eq 2
80
80
  step_statistics.all.each_with_index do |step_name, data, index|
81
81
  case index
82
- when 1
83
- step_name.should == "my_step 2"
84
- when 2
85
- step_name.should == "my_step 1"
82
+ when 1
83
+ expect(step_name).to eq 'my_step 2'
84
+ when 2
85
+ expect(step_name).to eq 'my_step 1'
86
86
  end
87
87
  end
88
88
  end
@@ -90,103 +90,103 @@ module CucumberStatistics
90
90
 
91
91
  describe 'set operations' do
92
92
  before(:each) do
93
- record "my step 1", 25
94
- record "my step 1", 50
95
- record "my step 2", 49
96
- record "my step 2", 51
97
- record "my step 3", 75
98
- record "my step 3", 10
93
+ record 'my step 1', 25
94
+ record 'my step 1', 50
95
+ record 'my step 2', 49
96
+ record 'my step 2', 51
97
+ record 'my step 3', 75
98
+ record 'my step 3', 10
99
99
 
100
100
  step_statistics.calculate
101
101
  end
102
102
 
103
103
  describe 'sort_by_property' do
104
104
  it 'should sort all records by any property' do
105
- step_statistics.sort_by_property(:total).first.first.should == "my step 1"
106
- step_statistics.sort_by_property(:total).last.first.should == "my step 2"
105
+ expect(step_statistics.sort_by_property(:total).first.first).to eq 'my step 1'
106
+ expect(step_statistics.sort_by_property(:total).last.first).to eq 'my step 2'
107
107
 
108
- step_statistics.sort_by_property(:fastest).first.first.should == "my step 3"
109
- step_statistics.sort_by_property(:fastest).last.first.should == "my step 2"
108
+ expect(step_statistics.sort_by_property(:fastest).first.first).to eq 'my step 3'
109
+ expect(step_statistics.sort_by_property(:fastest).last.first).to eq 'my step 2'
110
110
  end
111
111
  end
112
112
 
113
113
  describe 'highest_average' do
114
114
  it 'should return the record with the highest average' do
115
- step_statistics.highest_average.first.should == "my step 2"
115
+ expect(step_statistics.highest_average.first).to eq 'my step 2'
116
116
  end
117
117
  end
118
118
 
119
119
  describe 'highest_elapsed_time' do
120
120
  it 'should return the record with the highest elapsed time' do
121
- step_statistics.highest_total.first.should == "my step 2"
121
+ expect(step_statistics.highest_total.first).to eq 'my step 2'
122
122
  end
123
123
  end
124
124
 
125
125
  describe 'greatest_variation' do
126
126
  it 'should return the record with the greatest variation between slow and fast' do
127
- step_statistics.highest_variation.first.should == "my step 3"
127
+ expect(step_statistics.highest_variation.first).to eq 'my step 3'
128
128
  end
129
129
  end
130
130
 
131
131
  describe 'step_part_of_total' do
132
132
  it 'should return the total times of each step from largest to smallest' do
133
- step_statistics.step_part_of_total.should == [100.0, 85.0, 75.0]
133
+ expect(step_statistics.step_part_of_total).to eq [100.0, 85.0, 75.0]
134
134
  end
135
135
  end
136
136
 
137
137
  describe 'total_elapsed_time' do
138
138
  it 'should return the count of all steps' do
139
- step_statistics.total_elapsed_time.should == 260
139
+ expect(step_statistics.total_elapsed_time).to eq 260
140
140
  end
141
141
  end
142
142
 
143
143
  describe 'average_times_plot_data' do
144
144
  it 'should return all the averages sorted by average amount descending' do
145
- record "my step 1", 25
146
- record "my step 1", 50
147
- record "my step 2", 49
148
- record "my step 2", 51
149
- record "my step 3", 75
150
- record "my step 3", 10
145
+ record 'my step 1', 25
146
+ record 'my step 1', 50
147
+ record 'my step 2', 49
148
+ record 'my step 2', 51
149
+ record 'my step 3', 75
150
+ record 'my step 3', 10
151
151
 
152
152
  step_statistics.calculate
153
-
154
- step_statistics.average_times_plot_data.should == [50.0, 42.5, 37.5]
153
+
154
+ expect(step_statistics.average_times_plot_data).to eq [50.0, 42.5, 37.5]
155
155
  end
156
156
  end
157
157
 
158
158
  describe 'total_times_plot_data' do
159
159
  it 'should return the total times of each step sorted by average amount descending' do
160
- record "my step 1", 25
161
- record "my step 1", 50
162
- record "my step 3", 75
163
- record "my step 3", 10
160
+ record 'my step 1', 25
161
+ record 'my step 1', 50
162
+ record 'my step 3', 75
163
+ record 'my step 3', 10
164
164
 
165
165
  step_statistics.calculate
166
166
 
167
- step_statistics.total_times_plot_data.should == [100.0, 170, 150.0]
167
+ expect(step_statistics.total_times_plot_data).to eq [100.0, 170, 150.0]
168
168
  end
169
169
  end
170
170
  end
171
171
 
172
172
  describe 'sample_variance' do
173
173
  it 'should calculate the variance' do
174
- step_statistics.sample_variance([1,2,3,4,5,6]).should be_within(0.1).of(3.5)
175
- step_statistics.sample_variance([2,4,4,4,5,5,7,9]).should be_within(0.1).of(4.57)
176
- step_statistics.sample_variance([25,50,75]).should be_within(0.1).of(625)
174
+ expect(step_statistics.sample_variance([1, 2, 3, 4, 5, 6])).to be_within(0.1).of(3.5)
175
+ expect(step_statistics.sample_variance([2, 4, 4, 4, 5, 5, 7, 9])).to be_within(0.1).of(4.57)
176
+ expect(step_statistics.sample_variance([25, 50, 75])).to be_within(0.1).of(625)
177
177
  end
178
178
  end
179
179
 
180
180
  describe 'standard_deviation' do
181
181
  it 'should calculate the standard deviation' do
182
- sample_variance = step_statistics.sample_variance([1,2,3,4,5,6])
183
- step_statistics.standard_deviation(sample_variance).should be_within(0.1).of(1.87)
184
-
185
- sample_variance = step_statistics.sample_variance([2,4,4,4,5,5,7,9])
186
- step_statistics.standard_deviation(sample_variance).should be_within(0.1).of(2.13)
187
-
188
- sample_variance = step_statistics.sample_variance([25,50,75])
189
- step_statistics.standard_deviation(sample_variance).should be_within(0.1).of(25)
182
+ sample_variance = step_statistics.sample_variance([1, 2, 3, 4, 5, 6])
183
+ expect(step_statistics.standard_deviation(sample_variance)).to be_within(0.1).of(1.87)
184
+
185
+ sample_variance = step_statistics.sample_variance([2, 4, 4, 4, 5, 5, 7, 9])
186
+ expect(step_statistics.standard_deviation(sample_variance)).to be_within(0.1).of(2.13)
187
+
188
+ sample_variance = step_statistics.sample_variance([25, 50, 75])
189
+ expect(step_statistics.standard_deviation(sample_variance)).to be_within(0.1).of(25)
190
190
  end
191
191
  end
192
192
 
@@ -8,29 +8,29 @@ module CucumberStatistics
8
8
 
9
9
  describe 'record' do
10
10
  it 'should create a record' do
11
- subject.record "my_step", "some code somewhere"
12
- subject.all['my_step'].should == "some code somewhere"
11
+ subject.record 'my_step', 'some code somewhere'
12
+ expect(subject.all['my_step']).to eq 'some code somewhere'
13
13
  end
14
14
  end
15
15
 
16
16
  describe 'all' do
17
17
  it 'should return all records sorted alphabetically' do
18
- subject.record "my_step 3", "some code somewhere 3"
19
- subject.record "my_step 2", "some code somewhere 2"
20
- subject.record "my_step 1", "some code somewhere 1"
18
+ subject.record 'my_step 3', 'some code somewhere 3'
19
+ subject.record 'my_step 2', 'some code somewhere 2'
20
+ subject.record 'my_step 1', 'some code somewhere 1'
21
21
 
22
- subject.all.count.should == 3
22
+ expect(subject.all.count).to eq 3
23
23
  subject.all.each_with_index do |step_name, where, index|
24
24
  case index
25
- when 1
26
- step_name.should == "my_step 1"
27
- where.should == "some code somewhere 1"
28
- when 2
29
- step_name.should == "my_step 2"
30
- where.should == "some code somewhere 1"
31
- when 3
32
- step_name.should == "my_step 3"
33
- where.should == "some code somewhere 1"
25
+ when 1
26
+ expect(step_name).to eq 'my_step 1'
27
+ expect(where).to eq 'some code somewhere 1'
28
+ when 2
29
+ expect(step_name).to eq 'my_step 2'
30
+ expect(where).to eq 'some code somewhere 1'
31
+ when 3
32
+ expect(step_name).to eq 'my_step 3'
33
+ expect(where).to eq 'some code somewhere 1'
34
34
  end
35
35
  end
36
36
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cucumber_statistics
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Ross
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-15 00:00:00.000000000 Z
11
+ date: 2016-08-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -108,8 +108,7 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
- description: |2
112
- Want to know what is slowing down your build?
111
+ description: " Want to know what is slowing down your build?\n"
113
112
  email:
114
113
  - kevin.ross@alienfast.com.com
115
114
  executables: []
@@ -128,19 +127,25 @@ files:
128
127
  - lib/cucumber_statistics.rb
129
128
  - lib/cucumber_statistics/autoload.rb
130
129
  - lib/cucumber_statistics/configuration.rb
130
+ - lib/cucumber_statistics/feature_statistics.rb
131
131
  - lib/cucumber_statistics/formatter.rb
132
132
  - lib/cucumber_statistics/overall_statistics.rb
133
133
  - lib/cucumber_statistics/renderer.rb
134
134
  - lib/cucumber_statistics/renderer_helper.rb
135
+ - lib/cucumber_statistics/scenario_statistics.rb
135
136
  - lib/cucumber_statistics/step_statistics.rb
136
137
  - lib/cucumber_statistics/unused_steps.rb
137
138
  - lib/cucumber_statistics/version.rb
139
+ - lib/cucumber_statistics/view/feature_statistics.html.haml
140
+ - lib/cucumber_statistics/view/scenario_statistics.html.haml
138
141
  - lib/cucumber_statistics/view/step_statistics.html
139
142
  - lib/cucumber_statistics/view/step_statistics.html.haml
140
143
  - notes.txt
141
144
  - spec/cucumber_statistics/configuration_spec.rb
145
+ - spec/cucumber_statistics/feature_statistics_spec.rb
142
146
  - spec/cucumber_statistics/renderer_helper_spec.rb
143
147
  - spec/cucumber_statistics/renderer_spec.rb
148
+ - spec/cucumber_statistics/scenario_statistics_spec.rb
144
149
  - spec/cucumber_statistics/step_statistics_spec.rb
145
150
  - spec/cucumber_statistics/unused_steps_spec.rb
146
151
  - spec/spec_helper.rb
@@ -164,15 +169,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
169
  version: '0'
165
170
  requirements: []
166
171
  rubyforge_project:
167
- rubygems_version: 2.4.8
172
+ rubygems_version: 2.5.1
168
173
  signing_key:
169
174
  specification_version: 4
170
175
  summary: An cucumber formatter that will gather statistics and generate a single page
171
176
  showing step time metrics.
172
177
  test_files:
173
178
  - spec/cucumber_statistics/configuration_spec.rb
179
+ - spec/cucumber_statistics/feature_statistics_spec.rb
174
180
  - spec/cucumber_statistics/renderer_helper_spec.rb
175
181
  - spec/cucumber_statistics/renderer_spec.rb
182
+ - spec/cucumber_statistics/scenario_statistics_spec.rb
176
183
  - spec/cucumber_statistics/step_statistics_spec.rb
177
184
  - spec/cucumber_statistics/unused_steps_spec.rb
178
185
  - spec/spec_helper.rb