step-stats 0.0.2

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a88024d8c94f650f2d8c148fae871aa264c116f8
4
+ data.tar.gz: 4baee00e3b90efdbc040161c9a8027de31c30caf
5
+ SHA512:
6
+ metadata.gz: 4d8c7c95c70efe349294c2d80dcc5439ac8a50ec640ba359a4f05fe4f102a92e3b65486e55289b839246b1cc4ebad0fdc2ba8dc18a818141a1798c85a151d95a
7
+ data.tar.gz: f98e44c0ae794ee4d2bcba9b9955f981dd339ba5433481c6bd10f5a18aa9a47135b10fd08fc0ec86bb868f1ea75883d98405abc17149019ef53e49d4047dcaba
data/lib/step-stats.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'step_stats/step'
2
+ require 'step_stats/stats'
3
+ require 'step_stats/step_stats_formatter'
@@ -0,0 +1,54 @@
1
+ module StepStats
2
+ class Stats
3
+ attr_accessor :stats
4
+
5
+ def initialize(*args)
6
+ @stats = {}
7
+ @step_counter = "STEP-000"
8
+ @steps = {}
9
+ end
10
+
11
+ def add_stat step_definition, duration, status, location
12
+ step_number = get_step_number step_definition.regexp_source
13
+ if @stats[step_number].nil?
14
+ @stats[step_number] = Step.new(step_definition.regexp_source, step_definition.file_colon_line)
15
+ end
16
+ step_entry = {duration: duration, status: status, location: location}
17
+ @stats[step_number].add step_entry
18
+ end
19
+
20
+ def get_step_number step_regx
21
+ @steps[step_regx] = @step_counter.next!.dup if @steps[step_regx].nil?
22
+ @steps[step_regx]
23
+ end
24
+
25
+ def percent step,rounding='ceil'
26
+ ((step.total/total_time)*100).send(rounding)
27
+ end
28
+
29
+ def stats
30
+ @stats.values.sort_by{|step| step.avg * step.count}.reverse
31
+ end
32
+
33
+ def top30count
34
+ @stats.values.sort_by{|step| step.count}.reverse[0..top30]
35
+ end
36
+
37
+ def top30time
38
+ @stats.values.sort_by{|step| step.avg}.reverse[0..top30]
39
+ end
40
+
41
+ def top30
42
+ (@stats.values.count*0.3).ceil
43
+ end
44
+
45
+ def total_time
46
+ @stats.values.inject(0){|accum,step| accum+step.total}.to_f
47
+ end
48
+
49
+ def to_chart_data
50
+ @stats.values.each.map{|s|[s.name,s.total,s.location]}.to_s
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,61 @@
1
+ module StepStats
2
+ class Step
3
+ attr_accessor :name,:definition,:location
4
+
5
+ def initialize(step_def_name, step_def_location)
6
+ @name = step_def_name
7
+ @location = step_def_location
8
+ # An Array of hashs with duration, status and location
9
+ # step_info = {duration: 5.21692, status: :pass, location: 'feature/...feature:219'}
10
+ @step_entries = []
11
+ end
12
+
13
+ def durations
14
+ @durations || @step_entries.map{|step| step[:duration]}
15
+ end
16
+
17
+ def add step_entry
18
+ @step_entries << step_entry
19
+ end
20
+
21
+ def min
22
+ durations.min.to_f.round(3)
23
+ end
24
+
25
+ def max
26
+ durations.max.to_f.round(3)
27
+ end
28
+
29
+ def avg
30
+ (total / count.to_f).round(3)
31
+ end
32
+
33
+ def total
34
+ durations.sum
35
+ end
36
+
37
+ def count
38
+ durations.count
39
+ end
40
+
41
+ def stddev
42
+ return 0.to_f if count == 1
43
+ total = durations.inject(0){|accum, i| accum +(i-avg)**2 }
44
+ variance = total/(count - 1).to_f
45
+ Math.sqrt(variance).round(3)
46
+ end
47
+
48
+ def to_chart_data
49
+ @step_entries.map(&:values).each_with_index.map do |s, index|
50
+ step_entry = [(index + 1).to_s,s[0]]
51
+ if s[1] == :passed
52
+ step_entry << "green"
53
+ else
54
+ step_entry << "red"
55
+ end
56
+ step_entry << "Location: #{s[2]} \n Time: #{s[0]} seconds"
57
+ step_entry
58
+ end.to_s
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,33 @@
1
+ require 'erb'
2
+ require 'cucumber/formatter/pretty'
3
+
4
+ module StepStats
5
+ class Formatter < Cucumber::Formatter::Pretty
6
+ def initialize(step_mother, io, options)
7
+ @sss = Stats.new
8
+ super
9
+ end
10
+
11
+ def before_step(step)
12
+ @start_time = Time.now
13
+ super
14
+ end
15
+
16
+ def before_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line)
17
+ @duration = Time.now - @start_time
18
+ @sss.add_stat(step_match.step_definition,@duration,status,file_colon_line) if @duration > 0
19
+ super
20
+ end
21
+
22
+ def after_features(*args)
23
+ @path = File.dirname(__FILE__)
24
+ template = File.read(@path+"/template.erb")
25
+ @data = @sss.stats
26
+ result = ERB.new(template, 0, "", "@html").result(binding)
27
+ stats_html_file = File.new('tmp/step_stats.html','w')
28
+ stats_html_file.write(result)
29
+ stats_html_file.close
30
+ super
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,32 @@
1
+ <table id="all-table" class="data-table table table-hover">
2
+ <thead>
3
+ <td>Step</td>
4
+ <td>Definition</td>
5
+ <td>Avg</td>
6
+ <td>SD</td>
7
+ <td>Max</td>
8
+ <td>Min</td>
9
+ <td>Count</td>
10
+ </thead>
11
+ <% @data.each_with_index do |stat,index| %>
12
+ <tr data-durations="<%= ERB::Util.h(stat.to_chart_data) %>">
13
+ <td>
14
+ <span><%= index+1 %></span>
15
+ <span class="percentage">
16
+ <%= @sss.percent(stat,'floor') %>%
17
+ </span>
18
+ </td>
19
+ <td title="<%= stat.location %>" style="background: -webkit-linear-gradient(left, #DC4141 <%= @sss.percent(stat) %>%, white <%= @sss.percent(stat) %>%);"><%= stat.name %></td>
20
+ <td><%= stat.avg %></td>
21
+ <td><%= stat.stddev %></td>
22
+ <td><%= stat.max %></td>
23
+ <td><%= stat.min %></td>
24
+ <td><%= stat.count %></td>
25
+ </tr>
26
+ <tr>
27
+ <td colspan="7">
28
+ <div id="chart-<%= index+1 %>" class="details_chart">Details</div>
29
+ </td>
30
+ </tr>
31
+ <% end %>
32
+ </table>
@@ -0,0 +1,141 @@
1
+ <html>
2
+ <head>
3
+ <title>Cucumber Steps Stats</title>
4
+ <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
5
+ <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
6
+ <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
7
+ <script type="text/javascript"
8
+ src="https://www.google.com/jsapi?autoload={
9
+ 'modules':[{
10
+ 'name':'visualization',
11
+ 'version':'1',
12
+ 'packages':['corechart']
13
+ }]
14
+ }"></script>
15
+ <style>
16
+ nav#top-menu{border-color: #2F2F2F!important;}
17
+ body{padding-top: 50px;}
18
+ ul.side-bar{height: 100%;}
19
+ .tabs-left > div.side-bar {position:fixed; height: 100%;}
20
+ .tabs-left > div.tab-content {margin-left: 200px;}
21
+ .tabs-left > div > .nav-tabs > li{float: none;}
22
+ .tabs-left > div > .nav-tabs > li > a{min-width: 74px;margin-right: 0;margin-bottom: 3px;}
23
+ .tabs-left > div > .nav-tabs {background-color: #222;float: left;margin-right: 19px;border-right: 1px solid #ddd;}
24
+ .tabs-left > div > .nav-tabs > li > a {margin-right: -1px;-webkit-border-radius: 4px 0 0 4px;-moz-border-radius: 4px 0 0 4px;border-radius: 4px 0 0 4px;color:#9d9d9d}
25
+ .tabs-left > div > .nav-tabs > li > a:hover,
26
+ .tabs-left > div > .nav-tabs > li > a:focus {border-color: #eeeeee #5f635d #eeeeee #eeeeee;}
27
+ .tabs-left > div > .nav-tabs .active > a,
28
+ .tabs-left > div > .nav-tabs .active > a:hover,
29
+ .tabs-left > div > .nav-tabs .active > a:focus {border-color: #ddd transparent #ddd #ddd;*border-right-color: #ffffff;}
30
+ .tabs-left > div > .tab-pane {float: left;width: 99%;}
31
+ span.percentage{float: right;}
32
+ div.details_chart{height: 400px;}
33
+ div.tps_chart{height: 800px;}
34
+ </style>
35
+ </head>
36
+ <body>
37
+ <nav id="top-menu" class="navbar navbar-inverse navbar-fixed-top">
38
+ <div class="container-fluid">
39
+ <div class="navbar-header">
40
+ <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
41
+ <span class="sr-only">Toggle navigation</span>
42
+ <span class="icon-bar"></span>
43
+ <span class="icon-bar"></span>
44
+ <span class="icon-bar"></span>
45
+ </button>
46
+ <a class="navbar-brand" href="#"><%= Rails.application.class.parent_name %> - Cucumber Steps Stats</a>
47
+ </div>
48
+ <div id="navbar" class="navbar-collapse collapse">
49
+ <ul class="nav navbar-nav navbar-right">
50
+ <li><a href="#dashboard">Dashboard</a></li>
51
+ </ul>
52
+ </div>
53
+ </div>
54
+ </nav>
55
+ <div class="tabbable tabs-left">
56
+ <!-- Nav tabs -->
57
+ <div class="side-bar">
58
+ <ul class="nav nav-tabs side-bar" role="tablist">
59
+ <li role="presentation" class="active"><a href="#all" aria-controls="all" role="tab" data-toggle="tab">All Steps</a></li>
60
+ <li role="presentation"><a href="#top30time" aria-controls="top30time" role="tab" data-toggle="tab">Top 30% Steps by Time</a></li>
61
+ <li role="presentation"><a href="#top30count" aria-controls="top30count" role="tab" data-toggle="tab">Top 30% Steps by Count</a></li>
62
+ <li role="presentation"><a href="#timeperstep" aria-controls="timeperstep" role="tab" data-toggle="tab">Time Spent per Step</a></li>
63
+ </ul>
64
+ </div>
65
+ <!-- Tab panes -->
66
+ <div class="tab-content table-responsive">
67
+ <div role="tabpanel" class="tab-pane active" id="all">
68
+ <%= ERB.new(File.read(@path+"/table_partial.erb")).result(binding) %>
69
+ </div>
70
+ <div role="tabpanel" class="tab-pane" id="top30time">
71
+ <% @data = @sss.top30time %>
72
+ <%= ERB.new(File.read(@path+"/table_partial.erb")).result(binding) %>
73
+ </div>
74
+ <div role="tabpanel" class="tab-pane" id="top30count">
75
+ <% @data = @sss.top30count %>
76
+ <%= ERB.new(File.read(@path+"/table_partial.erb")).result(binding) %>
77
+ </div>
78
+ <div role="tabpanel" class="tab-pane" id="timeperstep">
79
+ <span data-results="<%= ERB::Util.h(@sss.to_chart_data) %>"></span>
80
+ <div class="tps_chart"></div>
81
+ </div>
82
+ </div>
83
+ </div>
84
+ <script>
85
+ $(document).ready(function(){
86
+ $.each($(".data-table"),function(i,table){$(table).find("tr:odd").addClass("master");});
87
+ $.each($(".data-table"),function(i,table){
88
+ $(table).find("tr:not(.master)").hide();
89
+ $(table).find("tr:first-child").show();
90
+ $(table).find("tr.master").click(function(){
91
+ var chart_data = eval($(this).data("durations"));
92
+ $(this).next("tr").toggle();
93
+ drawDetailsChart(this, chart_data);
94
+ });
95
+ });
96
+ $("a[href='#timeperstep']").click(function(){
97
+ drawTimePerStepChart();
98
+ });
99
+ });
100
+ function drawDetailsChart(elem,raw_data) {
101
+ var dataTable= new google.visualization.DataTable();
102
+ dataTable.addColumn('string', 'Count');
103
+ dataTable.addColumn('number', 'Duration in Seconds');
104
+ dataTable.addColumn({type: 'string', role: 'style' });
105
+ dataTable.addColumn({type: 'string', role: 'tooltip'});
106
+
107
+ dataTable.addRows(raw_data);
108
+
109
+ var options = {
110
+ title: 'Timming of all the calls for the above step.',
111
+ vAxis: {viewWindow: {min:0} },
112
+ legend: { position: 'bottom' }
113
+ };
114
+
115
+ var chart = new google.visualization.ColumnChart($(elem).next().find('.details_chart')[0]);
116
+ chart.draw(dataTable, options);
117
+ }
118
+ function drawTimePerStepChart() {
119
+ var chart_data = eval($('div#timeperstep').find('span').data("results"));
120
+
121
+ var dataTable= new google.visualization.DataTable();
122
+ dataTable.addColumn('string', 'Name');
123
+ dataTable.addColumn('number', 'Duration in Seconds');
124
+ dataTable.addColumn({type: 'string', role: 'tooltip'});
125
+
126
+ dataTable.addRows(chart_data);
127
+
128
+ var options = {
129
+ title: 'Which Step took most of the time ?',
130
+ is3D: true
131
+ };
132
+
133
+ var chart = new google.visualization.PieChart($('div#timeperstep').find('.tps_chart')[0]);
134
+ setTimeout(function(){
135
+ chart.draw(dataTable, options);
136
+ },1);
137
+
138
+ }
139
+ </script>
140
+ </body>
141
+ </html>
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: step-stats
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Sundus Yousuf
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-11-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: cucumber
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: Cucumber formatter that generates stats on all steps that are used during
28
+ testing.
29
+ email: sundus2y@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - lib/step-stats.rb
35
+ - lib/step_stats/stats.rb
36
+ - lib/step_stats/step.rb
37
+ - lib/step_stats/step_stats_formatter.rb
38
+ - lib/step_stats/table_partial.erb
39
+ - lib/step_stats/template.erb
40
+ homepage: https://github.com/sundus-y/step-stats
41
+ licenses:
42
+ - MIT
43
+ metadata: {}
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubyforge_project:
60
+ rubygems_version: 2.4.3
61
+ signing_key:
62
+ specification_version: 4
63
+ summary: Cucumber formatter that generates stats on all steps that are used during
64
+ testing.
65
+ test_files: []