From 188981de7a607fd017d8a54abc12fb9a1bcad95d Mon Sep 17 00:00:00 2001 From: Kevin Ross Date: Sun, 16 Mar 2014 14:47:30 -0500 Subject: [PATCH] initial commit forked cucumber_timing_presenter, refactored and began to start work on new way to present. --- .document | 5 + .gitignore | 19 ++ .rvmrc | 3 + Gemfile | 3 + LICENSE.txt | 46 +++++ README.md | 23 +++ Rakefile | 7 + cucumber_statistics.gemspec | 38 ++++ lib/cucumber_statistics.rb | 12 ++ lib/cucumber_statistics/configuration.rb | 53 +++++ lib/cucumber_statistics/formatter.rb | 44 ++++ .../javascript/jquery.sparkline.min.js | 94 +++++++++ .../all_usage_results_html_presenter.rb | 16 ++ .../presenters/html_template.rb | 29 +++ .../step_average_and_total_html_presenter.rb | 18 ++ .../step_times_of_whole_html_presenter.rb | 16 ++ .../presenters/unused_steps_html_presenter.rb | 13 ++ .../presenters/usage_record_html_presenter.rb | 41 ++++ lib/cucumber_statistics/step_statistics.rb | 82 ++++++++ .../templates/all_usage_results.html | 15 ++ .../templates/step_average_and_total.html | 24 +++ .../templates/step_times_of_whole.html | 16 ++ .../templates/unused_steps.html | 0 lib/cucumber_statistics/unused_steps.rb | 18 ++ lib/cucumber_statistics/version.rb | 3 + .../view/step_statistics.html | 161 +++++++++++++++ .../view/step_statistics.html.haml | 136 ++++++++++++ notes.txt | 5 + .../cucumber_statistics/configuration_spec.rb | 20 ++ .../presenters/html_template_spec.rb | 59 ++++++ .../step_statistics_spec.rb | 193 ++++++++++++++++++ spec/cucumber_statistics/unused_steps_spec.rb | 41 ++++ spec/spec_helper.rb | 11 + 33 files changed, 1264 insertions(+) create mode 100644 .document create mode 100644 .gitignore create mode 100644 .rvmrc create mode 100644 Gemfile create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 Rakefile create mode 100644 cucumber_statistics.gemspec create mode 100644 lib/cucumber_statistics.rb create mode 100644 lib/cucumber_statistics/configuration.rb create mode 100644 lib/cucumber_statistics/formatter.rb create mode 100644 lib/cucumber_statistics/javascript/jquery.sparkline.min.js create mode 100644 lib/cucumber_statistics/presenters/all_usage_results_html_presenter.rb create mode 100644 lib/cucumber_statistics/presenters/html_template.rb create mode 100644 lib/cucumber_statistics/presenters/step_average_and_total_html_presenter.rb create mode 100644 lib/cucumber_statistics/presenters/step_times_of_whole_html_presenter.rb create mode 100644 lib/cucumber_statistics/presenters/unused_steps_html_presenter.rb create mode 100644 lib/cucumber_statistics/presenters/usage_record_html_presenter.rb create mode 100644 lib/cucumber_statistics/step_statistics.rb create mode 100644 lib/cucumber_statistics/templates/all_usage_results.html create mode 100644 lib/cucumber_statistics/templates/step_average_and_total.html create mode 100644 lib/cucumber_statistics/templates/step_times_of_whole.html create mode 100644 lib/cucumber_statistics/templates/unused_steps.html create mode 100644 lib/cucumber_statistics/unused_steps.rb create mode 100644 lib/cucumber_statistics/version.rb create mode 100644 lib/cucumber_statistics/view/step_statistics.html create mode 100644 lib/cucumber_statistics/view/step_statistics.html.haml create mode 100644 notes.txt create mode 100644 spec/cucumber_statistics/configuration_spec.rb create mode 100644 spec/cucumber_statistics/presenters/html_template_spec.rb create mode 100644 spec/cucumber_statistics/step_statistics_spec.rb create mode 100644 spec/cucumber_statistics/unused_steps_spec.rb create mode 100644 spec/spec_helper.rb diff --git a/.document b/.document new file mode 100644 index 0000000..3d618dd --- /dev/null +++ b/.document @@ -0,0 +1,5 @@ +lib/**/*.rb +bin/* +- +features/**/*.feature +LICENSE.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..54f316f --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +*.gem +*.rbc +.bundle +.config +.yardoc +Gemfile.lock +InstalledFiles +_yardoc +coverage +doc/ +lib/bundler/man +pkg +rdoc +spec/reports +test/tmp +test/version_tmp +tmp + +.idea \ No newline at end of file diff --git a/.rvmrc b/.rvmrc new file mode 100644 index 0000000..aa9112e --- /dev/null +++ b/.rvmrc @@ -0,0 +1,3 @@ +rvm use ruby-1.9.3@cucumber_statistics --create +# CI +# rvm use ruby-2.0.0@dropinhq-develop --create diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..fa75df1 --- /dev/null +++ b/Gemfile @@ -0,0 +1,3 @@ +source 'https://rubygems.org' + +gemspec diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..6f8b946 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,46 @@ +Copyright (c) 2014 AlienFast, LLC + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----------------------------------------------------------------------------------------------------------------------- +Some code originally authored by Ryan Boucher https://github.com/distributedlife/cucumber_timing_presenter + +Copyright (c) 2012 Ryan Boucher + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..1e215c4 --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# Cucumber Statistics + +An cucumber formatter that will gather statistics and generate a single page showing step time metrics. + +Work in progress: the intent is to provide a way to hook this in and always generate the file, as well as us it as a standard formatter. + +To use as a formatter: cucumber --format CucumberStatistics::Formatter + +Look in the `./tmp/cucumber_statistics` for the generated html documents. + +## Contributing + +Please contribute! + +1. Fork it +2. Create your feature branch (`git checkout -b my-new-feature`) +3. Commit your changes (`git commit -am 'Add some feature'`) +4. Push to the branch (`git push origin my-new-feature`) +5. Create new Pull Request + +## Copyright + +Copyright (c) 2014 AlienFast. See LICENSE.txt for further details. \ No newline at end of file diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..c28b463 --- /dev/null +++ b/Rakefile @@ -0,0 +1,7 @@ +require 'bundler/gem_tasks' + +# add rspec task +require 'rspec/core/rake_task' +RSpec::Core::RakeTask.new('spec') +task :default => :spec +task :test => :spec diff --git a/cucumber_statistics.gemspec b/cucumber_statistics.gemspec new file mode 100644 index 0000000..f928ce4 --- /dev/null +++ b/cucumber_statistics.gemspec @@ -0,0 +1,38 @@ +# coding: utf-8 +lib = File.expand_path('../lib', __FILE__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require "cucumber_statistics/version" + +Gem::Specification.new do |spec| + spec.name = "cucumber_statistics" + spec.version = CucumberStatistics::VERSION + spec.authors = ["Kevin Ross"] + spec.email = ["kevin.ross@alienfast.com.com"] + spec.summary = <<-TEXT + An cucumber formatter that will gather statistics and generate a single page showing step time metrics. + TEXT + spec.description = <<-TEXT + Want to know what is slowing down your build? + TEXT + + + spec.homepage = "http://github.com/alienfast/cucumber_statistics" + spec.license = 'MIT' + + spec.files = `git ls-files`.split($/).reject { |f| f =~ /^samples\// } + spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } + spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) + spec.require_paths = ['lib'] + + # development + #spec.add_development_dependency 'cucumber' + spec.add_development_dependency 'bundler', '~> 1.3' + spec.add_development_dependency 'rake' + spec.add_development_dependency 'rspec', '>= 2.14.1' + + # runtime + spec.add_runtime_dependency 'awesome_print' + spec.add_runtime_dependency 'cucumber' + + +end \ No newline at end of file diff --git a/lib/cucumber_statistics.rb b/lib/cucumber_statistics.rb new file mode 100644 index 0000000..fe0c454 --- /dev/null +++ b/lib/cucumber_statistics.rb @@ -0,0 +1,12 @@ +require 'cucumber_statistics/configuration' +require 'cucumber_statistics/step_statistics' +require 'cucumber_statistics/unused_steps' +require 'cucumber_statistics/formatter' + + +require 'cucumber_statistics/presenters/html_template' +require 'cucumber_statistics/presenters/usage_record_html_presenter' +require 'cucumber_statistics/presenters/all_usage_results_html_presenter' +require 'cucumber_statistics/presenters/unused_steps_html_presenter' +require 'cucumber_statistics/presenters/step_times_of_whole_html_presenter' +require 'cucumber_statistics/presenters/step_average_and_total_html_presenter' \ No newline at end of file diff --git a/lib/cucumber_statistics/configuration.rb b/lib/cucumber_statistics/configuration.rb new file mode 100644 index 0000000..c950fae --- /dev/null +++ b/lib/cucumber_statistics/configuration.rb @@ -0,0 +1,53 @@ +require 'fileutils' + +module CucumberStatistics + class Configuration + + class << self + + $tmp_path = 'tmp/cucumber_statistics' + + def clean_tmp_dir + FileUtils.rm_r tmp_dir + end + + def tmp_dir + dir = resolve_path_from_root $tmp_path + FileUtils.mkdir_p dir unless File.exists? dir + + dir + end + + def tmp_file(filename) + "#{tmp_dir}/#{filename}" + end + + + def resolve_path_from_root(relative_path) + if defined?(Rails) + Rails.root.join(relative_path) + elsif defined?(Rake.original_dir) + File.expand_path(relative_path, Rake.original_dir) + else + File.expand_path(relative_path, Dir.pwd) + end + end + + def all_usage_results + File.expand_path('templates/all_usage_results.html', File.dirname(__FILE__)) + end + + def unused_steps + File.expand_path('templates/unused_steps.html', File.dirname(__FILE__)) + end + + def step_times_of_whole + File.expand_path('templates/step_times_of_whole.html', File.dirname(__FILE__)) + end + + def step_average_and_total + File.expand_path('templates/step_average_and_total.html', File.dirname(__FILE__)) + end + end + end +end \ No newline at end of file diff --git a/lib/cucumber_statistics/formatter.rb b/lib/cucumber_statistics/formatter.rb new file mode 100644 index 0000000..81db318 --- /dev/null +++ b/lib/cucumber_statistics/formatter.rb @@ -0,0 +1,44 @@ +module CucumberStatistics + class Formatter + def initialize(step_mother, io, options) + @step_mother = step_mother + @io = io + @options = options + + @step_statistics = StepStatistics.new + @unused_steps = UnusedSteps.new + end + + #call backs + def before_step(step) + @start_time = Time.now + end + + def before_step_result(*args) + @duration = Time.now - @start_time + end + + def after_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line) + + step_definition = step_match.step_definition + unless step_definition.nil? # nil if it's from a scenario outline + @step_statistics.record step_definition.regexp_source, @duration + end + end + + def after_features(features) + + # gather unused steps + @step_mother.unmatched_step_definitions.each do |step_definition| + @unused_steps.record step_definition.regexp_source, step_definition.file_colon_line + end + + @step_statistics.calculate + + AllUsageResultsHtmlPresenter.new @step_statistics + UnusedStepsHtmlPresenter.new @unused_steps + StepAverageAndTotalHtmlPresenter.new @step_statistics + StepTimesOfWholeHtmlPresenter.new @step_statistics + end + end +end \ No newline at end of file diff --git a/lib/cucumber_statistics/javascript/jquery.sparkline.min.js b/lib/cucumber_statistics/javascript/jquery.sparkline.min.js new file mode 100644 index 0000000..21e22c8 --- /dev/null +++ b/lib/cucumber_statistics/javascript/jquery.sparkline.min.js @@ -0,0 +1,94 @@ +/* jquery.sparkline 1.6 - http://omnipotent.net/jquery.sparkline/ +** Licensed under the New BSD License - see above site for details */ + +(function($){var defaults={common:{type:'line',lineColor:'#00f',fillColor:'#cdf',defaultPixelsPerValue:3,width:'auto',height:'auto',composite:false,tagValuesAttribute:'values',tagOptionsPrefix:'spark',enableTagOptions:false},line:{spotColor:'#f80',spotRadius:1.5,minSpotColor:'#f80',maxSpotColor:'#f80',lineWidth:1,normalRangeMin:undefined,normalRangeMax:undefined,normalRangeColor:'#ccc',drawNormalOnTop:false,chartRangeMin:undefined,chartRangeMax:undefined,chartRangeMinX:undefined,chartRangeMaxX:undefined},bar:{barColor:'#00f',negBarColor:'#f44',zeroColor:undefined,nullColor:undefined,zeroAxis:undefined,barWidth:4,barSpacing:1,chartRangeMax:undefined,chartRangeMin:undefined,chartRangeClip:false,colorMap:undefined},tristate:{barWidth:4,barSpacing:1,posBarColor:'#6f6',negBarColor:'#f44',zeroBarColor:'#999',colorMap:{}},discrete:{lineHeight:'auto',thresholdColor:undefined,thresholdValue:0,chartRangeMax:undefined,chartRangeMin:undefined,chartRangeClip:false},bullet:{targetColor:'red',targetWidth:3,performanceColor:'blue',rangeColors:['#D3DAFE','#A8B6FF','#7F94FF'],base:undefined},pie:{sliceColors:['#f00','#0f0','#00f']},box:{raw:false,boxLineColor:'black',boxFillColor:'#cdf',whiskerColor:'black',outlierLineColor:'#333',outlierFillColor:'white',medianColor:'red',showOutliers:true,outlierIQR:1.5,spotRadius:1.5,target:undefined,targetColor:'#4a2',chartRangeMax:undefined,chartRangeMin:undefined}};var VCanvas_base,VCanvas_canvas,VCanvas_vml;$.fn.simpledraw=function(width,height,use_existing){if(use_existing&&this[0].VCanvas){return this[0].VCanvas;} +if(width===undefined){width=$(this).innerWidth();} +if(height===undefined){height=$(this).innerHeight();} +if($.browser.hasCanvas){return new VCanvas_canvas(width,height,this);}else if($.browser.msie){return new VCanvas_vml(width,height,this);}else{return false;}};var pending=[];$.fn.sparkline=function(uservalues,userOptions){return this.each(function(){var options=new $.fn.sparkline.options(this,userOptions);var render=function(){var values,width,height;if(uservalues==='html'||uservalues===undefined){var vals=this.getAttribute(options.get('tagValuesAttribute'));if(vals===undefined||vals===null){vals=$(this).html();} +values=vals.replace(/(^\s*\s*$)|\s+/g,'').split(',');}else{values=uservalues;} +width=options.get('width')=='auto'?values.length*options.get('defaultPixelsPerValue'):options.get('width');if(options.get('height')=='auto'){if(!options.get('composite')||!this.VCanvas){var tmp=document.createElement('span');tmp.innerHTML='a';$(this).html(tmp);height=$(tmp).innerHeight();$(tmp).remove();}}else{height=options.get('height');} +$.fn.sparkline[options.get('type')].call(this,values,options,width,height);};if(($(this).html()&&$(this).is(':hidden'))||($.fn.jquery<"1.3.0"&&$(this).parents().is(':hidden'))||!$(this).parents('body').length){pending.push([this,render]);}else{render.call(this);}});};$.fn.sparkline.defaults=defaults;$.sparkline_display_visible=function(){for(var i=pending.length-1;i>=0;i--){var el=pending[i][0];if($(el).is(':visible')&&!$(el).parents().is(':hidden')){pending[i][1].call(el);pending.splice(i,1);}}};var UNSET_OPTION={};var normalizeValue=function(val){switch(val){case'undefined':val=undefined;break;case'null':val=null;break;case'true':val=true;break;case'false':val=false;break;default:var nf=parseFloat(val);if(val==nf){val=nf;}} +return val;};$.fn.sparkline.options=function(tag,userOptions){var extendedOptions;this.userOptions=userOptions=userOptions||{};this.tag=tag;this.tagValCache={};var defaults=$.fn.sparkline.defaults;var base=defaults.common;this.tagOptionsPrefix=userOptions.enableTagOptions&&(userOptions.tagOptionsPrefix||base.tagOptionsPrefix);var tagOptionType=this.getTagSetting('type');if(tagOptionType===UNSET_OPTION){extendedOptions=defaults[userOptions.type||base.type];}else{extendedOptions=defaults[tagOptionType];} +this.mergedOptions=$.extend({},base,extendedOptions,userOptions);};$.fn.sparkline.options.prototype.getTagSetting=function(key){var val,i,prefix=this.tagOptionsPrefix;if(prefix===false||prefix===undefined){return UNSET_OPTION;} +if(this.tagValCache.hasOwnProperty(key)){val=this.tagValCache.key;}else{val=this.tag.getAttribute(prefix+key);if(val===undefined||val===null){val=UNSET_OPTION;}else if(val.substr(0,1)=='['){val=val.substr(1,val.length-2).split(',');for(i=val.length;i--;){val[i]=normalizeValue(val[i].replace(/(^\s*)|(\s*$)/g,''));}}else if(val.substr(0,1)=='{'){var pairs=val.substr(1,val.length-2).split(',');val={};for(i=pairs.length;i--;){var keyval=pairs[i].split(':',2);val[keyval[0].replace(/(^\s*)|(\s*$)/g,'')]=normalizeValue(keyval[1].replace(/(^\s*)|(\s*$)/g,''));}}else{val=normalizeValue(val);} +this.tagValCache.key=val;} +return val;};$.fn.sparkline.options.prototype.get=function(key){var tagOption=this.getTagSetting(key);if(tagOption!==UNSET_OPTION){return tagOption;} +return this.mergedOptions[key];};$.fn.sparkline.line=function(values,options,width,height){var xvalues=[],yvalues=[],yminmax=[];for(var i=0;imaxy){maxy=normalRangeMax;}} +if(options.get('chartRangeMin')!==undefined&&(options.get('chartRangeClip')||options.get('chartRangeMin')maxy)){maxy=options.get('chartRangeMax');} +if(options.get('chartRangeMinX')!==undefined&&(options.get('chartRangeClipX')||options.get('chartRangeMinX')maxx)){maxx=options.get('chartRangeMaxX');} +var rangex=maxx-minx===0?1:maxx-minx;var rangey=maxy-miny===0?1:maxy-miny;var vl=yvalues.length-1;if(vl<1){this.innerHTML='';return;} +var target=$(this).simpledraw(width,height,options.get('composite'));if(target){var canvas_width=target.pixel_width;var canvas_height=target.pixel_height;var canvas_top=0;var canvas_left=0;var spotRadius=options.get('spotRadius');if(spotRadius&&(canvas_width<(spotRadius*4)||canvas_height<(spotRadius*4))){spotRadius=0;} +if(spotRadius){if(options.get('minSpotColor')||(options.get('spotColor')&&yvalues[vl]==miny)){canvas_height-=Math.ceil(spotRadius);} +if(options.get('maxSpotColor')||(options.get('spotColor')&&yvalues[vl]==maxy)){canvas_height-=Math.ceil(spotRadius);canvas_top+=Math.ceil(spotRadius);} +if(options.get('minSpotColor')||options.get('maxSpotColor')&&(yvalues[0]==miny||yvalues[0]==maxy)){canvas_left+=Math.ceil(spotRadius);canvas_width-=Math.ceil(spotRadius);} +if(options.get('spotColor')||(options.get('minSpotColor')||options.get('maxSpotColor')&&(yvalues[vl]==miny||yvalues[vl]==maxy))){canvas_width-=Math.ceil(spotRadius);}} +canvas_height--;var drawNormalRange=function(){if(normalRangeMin!==undefined){var ytop=canvas_top+Math.round(canvas_height-(canvas_height*((normalRangeMax-miny)/rangey)));var height=Math.round((canvas_height*(normalRangeMax-normalRangeMin))/rangey);target.drawRect(canvas_left,ytop,canvas_width,height,undefined,options.get('normalRangeColor'));}};if(!options.get('drawNormalOnTop')){drawNormalRange();} +var path=[];var paths=[path];var x,y,vlen=yvalues.length;for(i=0;imaxy){y=maxy;} +if(!path.length){path.push([canvas_left+Math.round((x-minx)*(canvas_width/rangex)),canvas_top+canvas_height]);} +path.push([canvas_left+Math.round((x-minx)*(canvas_width/rangex)),canvas_top+Math.round(canvas_height-(canvas_height*((y-miny)/rangey)))]);}} +var lineshapes=[];var fillshapes=[];var plen=paths.length;for(i=0;i2){path[0]=[path[0][0],path[1][1]];} +lineshapes.push(path);} +plen=fillshapes.length;for(i=0;imax)){max=options.get('chartRangeMax');} +var zeroAxis=options.get('zeroAxis');if(zeroAxis===undefined){zeroAxis=min<0;} +var range=max-min===0?1:max-min;var colorMapByIndex,colorMapByValue;if($.isArray(options.get('colorMap'))){colorMapByIndex=options.get('colorMap');colorMapByValue=null;}else{colorMapByIndex=null;colorMapByValue=options.get('colorMap');} +var target=$(this).simpledraw(width,height,options.get('composite'));if(target){var color,canvas_height=target.pixel_height,yzero=min<0&&zeroAxis?canvas_height-Math.round(canvas_height*(Math.abs(min)/range))-1:canvas_height-1;for(i=values.length;i--;){var x=i*(options.get('barWidth')+options.get('barSpacing')),y,val=values[i];if(val===null){if(options.get('nullColor')){color=options.get('nullColor');val=(zeroAxis&&min<0)?0:min;height=1;y=(zeroAxis&&min<0)?yzero:canvas_height-height;}else{continue;}}else{if(valmax){val=max;} +color=(val<0)?options.get('negBarColor'):options.get('barColor');if(zeroAxis&&min<0){height=Math.round(canvas_height*((Math.abs(val)/range)))+1;y=(val<0)?yzero:yzero-height;}else{height=Math.round(canvas_height*((val-min)/range))+1;y=canvas_height-height;} +if(val===0&&options.get('zeroColor')!==undefined){color=options.get('zeroColor');} +if(colorMapByValue&&colorMapByValue[val]){color=colorMapByValue[val];}else if(colorMapByIndex&&colorMapByIndex.length>i){color=colorMapByIndex[i];} +if(color===null){continue;}} +target.drawRect(x,y,options.get('barWidth')-1,height-1,color,color);}}else{this.innerHTML='';}};$.fn.sparkline.tristate=function(values,options,width,height){values=$.map(values,Number);width=(values.length*options.get('barWidth'))+((values.length-1)*options.get('barSpacing'));var colorMapByIndex,colorMapByValue;if($.isArray(options.get('colorMap'))){colorMapByIndex=options.get('colorMap');colorMapByValue=null;}else{colorMapByIndex=null;colorMapByValue=options.get('colorMap');} +var target=$(this).simpledraw(width,height,options.get('composite'));if(target){var canvas_height=target.pixel_height,half_height=Math.round(canvas_height/2);for(var i=values.length;i--;){var x=i*(options.get('barWidth')+options.get('barSpacing')),y,color;if(values[i]<0){y=half_height;height=half_height-1;color=options.get('negBarColor');}else if(values[i]>0){y=0;height=half_height-1;color=options.get('posBarColor');}else{y=half_height-1;height=2;color=options.get('zeroBarColor');} +if(colorMapByValue&&colorMapByValue[values[i]]){color=colorMapByValue[values[i]];}else if(colorMapByIndex&&colorMapByIndex.length>i){color=colorMapByIndex[i];} +if(color===null){continue;} +target.drawRect(x,y,options.get('barWidth')-1,height-1,color,color);}}else{this.innerHTML='';}};$.fn.sparkline.discrete=function(values,options,width,height){values=$.map(values,Number);width=options.get('width')=='auto'?values.length*2:width;var interval=Math.floor(width/values.length);var target=$(this).simpledraw(width,height,options.get('composite'));if(target){var canvas_height=target.pixel_height,line_height=options.get('lineHeight')=='auto'?Math.round(canvas_height*0.3):options.get('lineHeight'),pheight=canvas_height-line_height,min=Math.min.apply(Math,values),max=Math.max.apply(Math,values);if(options.get('chartRangeMin')!==undefined&&(options.get('chartRangeClip')||options.get('chartRangeMin')max)){max=options.get('chartRangeMax');} +var range=max-min;for(var i=values.length;i--;){var val=values[i];if(valmax){val=max;} +var x=(i*interval),ytop=Math.round(pheight-pheight*((val-min)/range));target.drawLine(x,ytop,x,ytop+line_height,(options.get('thresholdColor')&&val1){var canvas_width=target.pixel_width-Math.ceil(options.get('targetWidth')/2),canvas_height=target.pixel_height,min=Math.min.apply(Math,values),max=Math.max.apply(Math,values);if(options.get('base')===undefined){min=min<0?min:0;}else{min=options.get('base');} +var range=max-min;for(var i=2,vlen=values.length;i1){var canvas_width=target.pixel_width,canvas_height=target.pixel_height,radius=Math.floor(Math.min(canvas_width,canvas_height)/2),total=0,next=0,circle=2*Math.PI;for(var i=values.length;i--;){total+=values[i];} +if(options.get('offset')){next+=(2*Math.PI)*(options.get('offset')/360);} +var vlen=values.length;for(i=0;i0){end=next+(circle*(values[i]/total));} +target.drawPieSlice(radius,radius,radius,start,end,undefined,options.get('sliceColors')[i%options.get('sliceColors').length]);next=end;}}};var quartile=function(values,q){if(q==2){var vl2=Math.floor(values.length/2);return values.length%2?values[vl2]:(values[vl2]+values[vl2+1])/2;}else{var vl4=Math.floor(values.length/4);return values.length%2?(values[vl4*q]+values[vl4*q+1])/2:values[vl4*q];}};$.fn.sparkline.box=function(values,options,width,height){values=$.map(values,Number);width=options.get('width')=='auto'?'4.0em':width;var minvalue=options.get('chartRangeMin')===undefined?Math.min.apply(Math,values):options.get('chartRangeMin'),maxvalue=options.get('chartRangeMax')===undefined?Math.max.apply(Math,values):options.get('chartRangeMax'),target=$(this).simpledraw(width,height,options.get('composite')),vlen=values.length,lwhisker,loutlier,q1,q2,q3,rwhisker,routlier;if(target&&values.length>1){var canvas_width=target.pixel_width,canvas_height=target.pixel_height;if(options.get('raw')){if(options.get('showOutliers')&&values.length>5){loutlier=values[0];lwhisker=values[1];q1=values[2];q2=values[3];q3=values[4];rwhisker=values[5];routlier=values[6];}else{lwhisker=values[0];q1=values[1];q2=values[2];q3=values[3];rwhisker=values[4];}}else{values.sort(function(a,b){return a-b;});q1=quartile(values,1);q2=quartile(values,2);q3=quartile(values,3);var iqr=q3-q1;if(options.get('showOutliers')){lwhisker=undefined;rwhisker=undefined;for(var i=0;iq1-(iqr*options.get('outlierIQR'))){lwhisker=values[i];} +if(values[i]rwhisker){target.drawCircle((routlier-minvalue)*unitsize+canvas_left,canvas_height/2,options.get('spotRadius'),options.get('outlierLineColor'),options.get('outlierFillColor'));}} +target.drawRect(Math.round((q1-minvalue)*unitsize+canvas_left),Math.round(canvas_height*0.1),Math.round((q3-q1)*unitsize),Math.round(canvas_height*0.8),options.get('boxLineColor'),options.get('boxFillColor'));target.drawLine(Math.round((lwhisker-minvalue)*unitsize+canvas_left),Math.round(canvas_height/2),Math.round((q1-minvalue)*unitsize+canvas_left),Math.round(canvas_height/2),options.get('lineColor'));target.drawLine(Math.round((lwhisker-minvalue)*unitsize+canvas_left),Math.round(canvas_height/4),Math.round((lwhisker-minvalue)*unitsize+canvas_left),Math.round(canvas_height-canvas_height/4),options.get('whiskerColor'));target.drawLine(Math.round((rwhisker-minvalue)*unitsize+canvas_left),Math.round(canvas_height/2),Math.round((q3-minvalue)*unitsize+canvas_left),Math.round(canvas_height/2),options.get('lineColor'));target.drawLine(Math.round((rwhisker-minvalue)*unitsize+canvas_left),Math.round(canvas_height/4),Math.round((rwhisker-minvalue)*unitsize+canvas_left),Math.round(canvas_height-canvas_height/4),options.get('whiskerColor'));target.drawLine(Math.round((q2-minvalue)*unitsize+canvas_left),Math.round(canvas_height*0.1),Math.round((q2-minvalue)*unitsize+canvas_left),Math.round(canvas_height*0.9),options.get('medianColor'));if(options.get('target')){var size=Math.ceil(options.get('spotRadius'));target.drawLine(Math.round((options.get('target')-minvalue)*unitsize+canvas_left),Math.round((canvas_height/2)-size),Math.round((options.get('target')-minvalue)*unitsize+canvas_left),Math.round((canvas_height/2)+size),options.get('targetColor'));target.drawLine(Math.round((options.get('target')-minvalue)*unitsize+canvas_left-size),Math.round(canvas_height/2),Math.round((options.get('target')-minvalue)*unitsize+canvas_left+size),Math.round(canvas_height/2),options.get('targetColor'));}}else{this.innerHTML='';}};if($.browser.msie&&!document.namespaces.v){document.namespaces.add('v','urn:schemas-microsoft-com:vml','#default#VML');} +if($.browser.hasCanvas===undefined){var t=document.createElement('canvas');$.browser.hasCanvas=t.getContext!==undefined;} +VCanvas_base=function(width,height,target){};VCanvas_base.prototype={init:function(width,height,target){this.width=width;this.height=height;this.target=target;if(target[0]){target=target[0];} +target.VCanvas=this;},drawShape:function(path,lineColor,fillColor,lineWidth){alert('drawShape not implemented');},drawLine:function(x1,y1,x2,y2,lineColor,lineWidth){return this.drawShape([[x1,y1],[x2,y2]],lineColor,lineWidth);},drawCircle:function(x,y,radius,lineColor,fillColor){alert('drawCircle not implemented');},drawPieSlice:function(x,y,radius,startAngle,endAngle,lineColor,fillColor){alert('drawPieSlice not implemented');},drawRect:function(x,y,width,height,lineColor,fillColor){alert('drawRect not implemented');},getElement:function(){return this.canvas;},_insert:function(el,target){$(target).html(el);}};VCanvas_canvas=function(width,height,target){return this.init(width,height,target);};VCanvas_canvas.prototype=$.extend(new VCanvas_base(),{_super:VCanvas_base.prototype,init:function(width,height,target){this._super.init(width,height,target);this.canvas=document.createElement('canvas');if(target[0]){target=target[0];} +target.VCanvas=this;$(this.canvas).css({display:'inline-block',width:width,height:height,verticalAlign:'top'});this._insert(this.canvas,target);this.pixel_height=$(this.canvas).height();this.pixel_width=$(this.canvas).width();this.canvas.width=this.pixel_width;this.canvas.height=this.pixel_height;$(this.canvas).css({width:this.pixel_width,height:this.pixel_height});},_getContext:function(lineColor,fillColor,lineWidth){var context=this.canvas.getContext('2d');if(lineColor!==undefined){context.strokeStyle=lineColor;} +context.lineWidth=lineWidth===undefined?1:lineWidth;if(fillColor!==undefined){context.fillStyle=fillColor;} +return context;},drawShape:function(path,lineColor,fillColor,lineWidth){var context=this._getContext(lineColor,fillColor,lineWidth);context.beginPath();context.moveTo(path[0][0]+0.5,path[0][1]+0.5);for(var i=1,plen=path.length;i';this.canvas.insertAdjacentHTML('beforeEnd',groupel);this.group=$(this.canvas).children()[0];},drawShape:function(path,lineColor,fillColor,lineWidth){var vpath=[];for(var i=0,plen=path.length;i'+' ';this.group.insertAdjacentHTML('beforeEnd',vel);},drawCircle:function(x,y,radius,lineColor,fillColor){x-=radius+1;y-=radius+1;var stroke=lineColor===undefined?' stroked="false" ':' strokeWeight="1" strokeColor="'+lineColor+'" ';var fill=fillColor===undefined?' filled="false"':' fillColor="'+fillColor+'" filled="true" ';var vel='';this.group.insertAdjacentHTML('beforeEnd',vel);},drawPieSlice:function(x,y,radius,startAngle,endAngle,lineColor,fillColor){if(startAngle==endAngle){return;} +if((endAngle-startAngle)==(2*Math.PI)){startAngle=0.0;endAngle=(2*Math.PI);} +var startx=x+Math.round(Math.cos(startAngle)*radius);var starty=y+Math.round(Math.sin(startAngle)*radius);var endx=x+Math.round(Math.cos(endAngle)*radius);var endy=y+Math.round(Math.sin(endAngle)*radius);if(startx==endx&&starty==endy&&(endAngle-startAngle)'+' ';this.group.insertAdjacentHTML('beforeEnd',vel);},drawRect:function(x,y,width,height,lineColor,fillColor){return this.drawShape([[x,y],[x,y+height],[x+width,y+height],[x+width,y],[x,y]],lineColor,fillColor);}});})(jQuery); \ No newline at end of file diff --git a/lib/cucumber_statistics/presenters/all_usage_results_html_presenter.rb b/lib/cucumber_statistics/presenters/all_usage_results_html_presenter.rb new file mode 100644 index 0000000..7235d8d --- /dev/null +++ b/lib/cucumber_statistics/presenters/all_usage_results_html_presenter.rb @@ -0,0 +1,16 @@ +module CucumberStatistics + class AllUsageResultsHtmlPresenter < UsageRecordHtmlPresenter + def initialize step_statistics + generate_html step_statistics + end + + def generate_html step_statistics + html = HtmlTemplate.new Configuration.all_usage_results + html.replace "PP_STEP_HIGHEST_AVERAGE", format_usage(step_statistics.highest_average) + html.replace "PP_STEP_HIGHEST_ELAPSED_TIME", format_usage(step_statistics.highest_elapsed_time) + html.replace "PP_STEP_GREATEST_VARIATION", format_usage(step_statistics.greatest_variation) + html.replace "PP_ALL_STEPS", format_all(step_statistics.all) + html.output "all_usage_results.html" + end + end +end \ No newline at end of file diff --git a/lib/cucumber_statistics/presenters/html_template.rb b/lib/cucumber_statistics/presenters/html_template.rb new file mode 100644 index 0000000..c0856fe --- /dev/null +++ b/lib/cucumber_statistics/presenters/html_template.rb @@ -0,0 +1,29 @@ +module CucumberStatistics + class HtmlTemplate + def initialize template_path + @content = '' + + File.open(template_path) do |file| + while line = file.gets + @content = "#{@content}#{line}" + end + end + end + + def output filename + absolute_file_name = Configuration.tmp_file(filename) + File.open(absolute_file_name, 'w') do |file| + file.write @content + end + absolute_file_name + end + + def content + @content + end + + def replace to_remove, to_insert + @content = "#{@content.split(to_remove).first}#{to_insert}#{@content.split(to_remove).last}" + end + end +end \ No newline at end of file diff --git a/lib/cucumber_statistics/presenters/step_average_and_total_html_presenter.rb b/lib/cucumber_statistics/presenters/step_average_and_total_html_presenter.rb new file mode 100644 index 0000000..61f1be7 --- /dev/null +++ b/lib/cucumber_statistics/presenters/step_average_and_total_html_presenter.rb @@ -0,0 +1,18 @@ +module CucumberStatistics + class StepAverageAndTotalHtmlPresenter < UsageRecordHtmlPresenter + def initialize step_statistics + generate_html step_statistics + end + + def generate_html step_statistics + html = HtmlTemplate.new Configuration.step_average_and_total + + html.replace "PP_HIGHEST_TOTAL_STEP_TIME", step_statistics.highest_elapsed_time.last[:total] + html.replace "PP_HIGHEST_AVERAGE_STEP_TIME", step_statistics.highest_average.last[:average] + html.replace "PP_AVERAGE_TIMES_PLOT_DATA", step_statistics.average_times_plot_data.join(',') + html.replace "PP_TOTAL_TIMES_PLOT_DATA", step_statistics.total_times_plot_data.join(',') + + html.output "step_average_and_total.html" + end + end +end \ No newline at end of file diff --git a/lib/cucumber_statistics/presenters/step_times_of_whole_html_presenter.rb b/lib/cucumber_statistics/presenters/step_times_of_whole_html_presenter.rb new file mode 100644 index 0000000..28fc8e7 --- /dev/null +++ b/lib/cucumber_statistics/presenters/step_times_of_whole_html_presenter.rb @@ -0,0 +1,16 @@ +module CucumberStatistics + class StepTimesOfWholeHtmlPresenter < UsageRecordHtmlPresenter + def initialize step_statistics + generate_html step_statistics + end + + def generate_html step_statistics + html = HtmlTemplate.new Configuration.step_times_of_whole + + html.replace "PP_STEP_TOTAL_TIMES_PLOT_DATA", step_statistics.step_part_of_total.join(',') + html.replace "PP_TOTAL_ELAPSED_TIME", step_statistics.total_elapsed_time / 60 + + html.output "step_times_of_whole.html" + end + end +end \ No newline at end of file diff --git a/lib/cucumber_statistics/presenters/unused_steps_html_presenter.rb b/lib/cucumber_statistics/presenters/unused_steps_html_presenter.rb new file mode 100644 index 0000000..ab607b2 --- /dev/null +++ b/lib/cucumber_statistics/presenters/unused_steps_html_presenter.rb @@ -0,0 +1,13 @@ +module CucumberStatistics + class UnusedStepsHtmlPresenter < UsageRecordHtmlPresenter + def initialize unused_steps + generate_html unused_steps + end + + def generate_html unused_steps + html = HtmlTemplate.new Configuration.unused_steps + html.replace "PP_UNUSED_STEPS", format_unused_steps(unused_steps.all) + html.output "unused_steps.html" + end + end +end \ No newline at end of file diff --git a/lib/cucumber_statistics/presenters/usage_record_html_presenter.rb b/lib/cucumber_statistics/presenters/usage_record_html_presenter.rb new file mode 100644 index 0000000..d28340a --- /dev/null +++ b/lib/cucumber_statistics/presenters/usage_record_html_presenter.rb @@ -0,0 +1,41 @@ +module CucumberStatistics + class UsageRecordHtmlPresenter + def format_usage metric_results + step_name = metric_results.first + step_usage = metric_results.last + + html = "" + html = "#{html}" + step_usage.each do |key, value| + next if key == :instances + + html = "#{html}" + end + html = "#{html}
step
#{step_name}
#{key}
#{value}
" + + html + end + + def format_unused_steps all_unused + html = "" + html = "#{html}" + + all_unused.each do |step_name, where| + html = "#{html}" + end + + html = "#{html}
stepwhere
#{step_name}
#{where}
" + html + end + + def format_all all_usage + output = "" + + all_usage.each do |result| + output = "#{output}#{format_usage(result)}
" + end + + output + end + end +end \ No newline at end of file diff --git a/lib/cucumber_statistics/step_statistics.rb b/lib/cucumber_statistics/step_statistics.rb new file mode 100644 index 0000000..6c7747b --- /dev/null +++ b/lib/cucumber_statistics/step_statistics.rb @@ -0,0 +1,82 @@ +module CucumberStatistics + class StepStatistics + def initialize + @all = Hash.new + end + + def record step_name, duration + step_results = @all[step_name] + step_results ||= Hash.new + step_results[:instances] ||= [] + step_results[:instances] << duration + + @all[step_name] ||= step_results + end + + def calculate + @all.each do |step_name, step_results| + step_results[:total] = step_results[:instances].inject{|sum,x| sum + x } + step_results[:count] = step_results[:instances].count + step_results[:average] = step_results[:total].to_f / step_results[:count].to_f + step_results[:fastest] = step_results[:instances].sort.first + step_results[:slowest] = step_results[:instances].sort.last + step_results[:variation] = step_results[:slowest] - step_results[:fastest] + step_results[:variance] = self.sample_variance step_results[:instances] + step_results[:standard_deviation] = self.standard_deviation step_results[:variance] + end + end + + def all + @all + end + + def sort_by_property property + @all.sort {|a,b| a.last[property.to_sym] <=> b.last[property.to_sym]} + end + + def highest_average + sort_by_property(:average).reverse.first + end + + def highest_elapsed_time + sort_by_property(:total).reverse.first + end + + def greatest_variation + sort_by_property(:variation).reverse.first + end + + def average_times_plot_data + @all.map {|step_name, data| data[:average].to_f}.sort.reverse + end + + def total_times_plot_data + sort_by_property(:average).reverse.map {|step_name, data| data[:total].to_f} + end + + def step_part_of_total + @all.map {|step_name, data| data[:total]}.sort.reverse + end + + def total_elapsed_time + @all.map {|step_name, data| data[:total]}.inject{|sum,x| sum + x } + end + + def sample_variance data + count = data.count + average = data.inject{|sum,x| sum + x } / count.to_f + + return nil if count <= 1 + + sum = data.inject(0){|acc,i|acc.to_f + (i.to_f - average)**2.0} + + return 1 / (count.to_f - 1.0) * sum.to_f + end + + def standard_deviation sample_variance + return nil if sample_variance.nil? + + return Math.sqrt(sample_variance) + end + end +end \ No newline at end of file diff --git a/lib/cucumber_statistics/templates/all_usage_results.html b/lib/cucumber_statistics/templates/all_usage_results.html new file mode 100644 index 0000000..75179c4 --- /dev/null +++ b/lib/cucumber_statistics/templates/all_usage_results.html @@ -0,0 +1,15 @@ + + + + +

Highest average run time

+ PP_STEP_HIGHEST_AVERAGE +

Greatest total time spent in step

+ PP_STEP_HIGHEST_ELAPSED_TIME +

Biggest variation between fastest and slowest step instance

+ PP_STEP_GREATEST_VARIATION +
+

All Steps

+ PP_ALL_STEPS + + \ No newline at end of file diff --git a/lib/cucumber_statistics/templates/step_average_and_total.html b/lib/cucumber_statistics/templates/step_average_and_total.html new file mode 100644 index 0000000..7e7a1fe --- /dev/null +++ b/lib/cucumber_statistics/templates/step_average_and_total.html @@ -0,0 +1,24 @@ + + + + + + + +

Step Times

+ Red is the total time that step took across the build, + Blue is the average time that step took, + The grey box is 1.0 second +
+ PP_HIGHEST_TOTAL_STEP_TIME seconds, PP_HIGHEST_AVERAGE_STEP_TIME seconds + PP_AVERAGE_TIMES_PLOT_DATA + 0.0 seconds +
+ + + + \ No newline at end of file diff --git a/lib/cucumber_statistics/templates/step_times_of_whole.html b/lib/cucumber_statistics/templates/step_times_of_whole.html new file mode 100644 index 0000000..34e8a81 --- /dev/null +++ b/lib/cucumber_statistics/templates/step_times_of_whole.html @@ -0,0 +1,16 @@ + + + + + + + +

Step part of Total

+ PP_STEP_TOTAL_TIMES_PLOT_DATA +
+ Total Time Spend in Tests: PP_TOTAL_ELAPSED_TIME minutes +
+ + \ No newline at end of file diff --git a/lib/cucumber_statistics/templates/unused_steps.html b/lib/cucumber_statistics/templates/unused_steps.html new file mode 100644 index 0000000..e69de29 diff --git a/lib/cucumber_statistics/unused_steps.rb b/lib/cucumber_statistics/unused_steps.rb new file mode 100644 index 0000000..e5f5d52 --- /dev/null +++ b/lib/cucumber_statistics/unused_steps.rb @@ -0,0 +1,18 @@ +module CucumberStatistics + class UnusedSteps + def initialize + @all = Hash.new + end + + def record step_name, where + result = @all[step_name] + result = where + + @all[step_name] ||= result + end + + def all + @all + end + end +end \ No newline at end of file diff --git a/lib/cucumber_statistics/version.rb b/lib/cucumber_statistics/version.rb new file mode 100644 index 0000000..50473f5 --- /dev/null +++ b/lib/cucumber_statistics/version.rb @@ -0,0 +1,3 @@ +module CucumberStatistics + VERSION = "1.0.0" +end diff --git a/lib/cucumber_statistics/view/step_statistics.html b/lib/cucumber_statistics/view/step_statistics.html new file mode 100644 index 0000000..230ebf3 --- /dev/null +++ b/lib/cucumber_statistics/view/step_statistics.html @@ -0,0 +1,161 @@ + + + + + + + + + + Cucumber Step Statistics + + + + + + + + + + + + + + + + + +
+ + +
+

Cucumber step statistics

+ +

... allows you to easily diagnose long running steps.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StepFastestSlowestVariationVarianceStd DeviationCountAverageTotal
/^I am logged in as ((?:(?:)|(?:(?:a|an|another|the|that) )?(?:(?:(?:(?:first|last|(?:\d+(?:st|nd|rd|th))) )?(?:paper[_ ]trail[_ ]version|acts[_ ]as[_ ]taggable[_ ]on[_ ]tag|acts[_ ]as[_ ]taggable[_ ]on[_ ]tagging|user|active[_ ]record[_ ]schema[_ ]migration|plan|feature|reference[_ ]type|allergy|relationship[_ ]type|allergy[_ ]type|medical[_ ]condition[_ ]type|account|rspec[_ ]account|address|sacred[_ ]heart[_ ]address|calendar[_ ]item|catalog|child|jack|jennifer[_ ]dillon|coupon|employment|enrollment|medical[_ ]condition|membership|organization|sacredheart|participation|person|sacredheart[_ ]person|bob|perry|carla|jordan|alienfast|alienfast[_ ]person|blake|kevin|alicia|product|relationship|subscription|rspec[_ ]subscription|tenant|transaction|admin|admin[_ ]not[_ ]owner|staff|consumer|consumer[_ ]dad|support|bmcdaniel|kross|awaters|verification))|(?:(?:paper[_ ]trail[_ ]version|acts[_ ]as[_ ]taggable[_ ]on[_ ]tag|acts[_ ]as[_ ]taggable[_ ]on[_ ]tagging|user|active[_ ]record[_ ]schema[_ ]migration|plan|feature|reference[_ ]type|allergy|relationship[_ ]type|allergy[_ ]type|medical[_ ]condition[_ ]type|account|rspec[_ ]account|address|sacred[_ ]heart[_ ]address|calendar[_ ]item|catalog|child|jack|jennifer[_ ]dillon|coupon|employment|enrollment|medical[_ ]condition|membership|organization|sacredheart|participation|person|sacredheart[_ ]person|bob|perry|carla|jordan|alienfast|alienfast[_ ]person|blake|kevin|alicia|product|relationship|subscription|rspec[_ ]subscription|tenant|transaction|admin|admin[_ ]not[_ ]owner|staff|consumer|consumer[_ ]dad|support|bmcdaniel|kross|awaters|verification)(?::? "(?:\\"|[^\"]|\.)*"))))) at (\w+)$/7.0514.0994.0990.3200.566760.49037.288
/^Blah I am logged in as ((?:(?:)|(?:(?:a|an|another|the|that) )?(?:(?:(?:(?:first|last|(?:\d+(?:st|nd|rd|th))) )?(?:paper[_ ]trail[_ ]version|acts[_ ]as[_ ]taggable[_ ]on[_ ]tag|acts[_ ]as[_ ]taggable[_ ]on[_ ]tagging|user|active[_ ]record[_ ]schema[_ ]migration|plan|feature|reference[_ ]type|allergy|relationship[_ ]type|allergy[_ ]type|medical[_ ]condition[_ ]type|account|rspec[_ ]account|address|sacred[_ ]heart[_ ]address|calendar[_ ]item|catalog|child|jack|jennifer[_ ]dillon|coupon|employment|enrollment|medical[_ ]condition|membership|organization|sacredheart|participation|person|sacredheart[_ ]person|bob|perry|carla|jordan|alienfast|alienfast[_ ]person|blake|kevin|alicia|product|relationship|subscription|rspec[_ ]subscription|tenant|transaction|admin|admin[_ ]not[_ ]owner|staff|consumer|consumer[_ ]dad|support|bmcdaniel|kross|awaters|verification))|(?:(?:paper[_ ]trail[_ ]version|acts[_ ]as[_ ]taggable[_ ]on[_ ]tag|acts[_ ]as[_ ]taggable[_ ]on[_ ]tagging|user|active[_ ]record[_ ]schema[_ ]migration|plan|feature|reference[_ ]type|allergy|relationship[_ ]type|allergy[_ ]type|medical[_ ]condition[_ ]type|account|rspec[_ ]account|address|sacred[_ ]heart[_ ]address|calendar[_ ]item|catalog|child|jack|jennifer[_ ]dillon|coupon|employment|enrollment|medical[_ ]condition|membership|organization|sacredheart|participation|person|sacredheart[_ ]person|bob|perry|carla|jordan|alienfast|alienfast[_ ]person|blake|kevin|alicia|product|relationship|subscription|rspec[_ ]subscription|tenant|transaction|admin|admin[_ ]not[_ ]owner|staff|consumer|consumer[_ ]dad|support|bmcdaniel|kross|awaters|verification)(?::? "(?:\\"|[^\"]|\.)*"))))) at (\w+)$/4.0518.0995.0990.4200.96661.49031.288
+ +
+ + + + + + + + + + + + diff --git a/lib/cucumber_statistics/view/step_statistics.html.haml b/lib/cucumber_statistics/view/step_statistics.html.haml new file mode 100644 index 0000000..9b04cc5 --- /dev/null +++ b/lib/cucumber_statistics/view/step_statistics.html.haml @@ -0,0 +1,136 @@ +!!! +%html{:lang => "en"} + %head + %meta{:charset => "utf-8"}/ + %meta{:content => "IE=edge", "http-equiv" => "X-UA-Compatible"}/ + %meta{:content => "width=device-width, initial-scale=1", :name => "viewport"}/ + %meta{:content => "Cucumber Step Statistics", :name => "description"}/ + %meta{:content => "AlienFast", :name => "author"}/ + %title Cucumber Step Statistics + / Bootstrap core CSS + %link{:href => "http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css", :rel => "stylesheet"}/ + / Custom styles for this layout + :css + body { + min-height: 2000px; + padding-top: 70px; + } + + td { + white-space: nowrap; + /*max-width: 100px;*/ + } + tr td:first-child { + overflow: hidden; + text-overflow: ellipsis; + max-width: 300px; + } + %link{:href => "https://rawgithub.com/drvic10k/bootstrap-sortable/master/Contents/bootstrap-sortable.css", :rel => "stylesheet"}/ + / HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries + /[if lt IE 9] + + + %body + / Fixed navbar + .navbar.navbar-default.navbar-fixed-top{:role => "navigation"} + .container + .navbar-header + %button.navbar-toggle{"data-target" => ".navbar-collapse", "data-toggle" => "collapse", :type => "button"} + %span.sr-only Toggle navigation + %span.icon-bar + %span.icon-bar + %span.icon-bar + %a.navbar-brand{:href => "#"} Project name + .navbar-collapse.collapse + %ul.nav.navbar-nav + %li.active + %a{:href => "#"} Home + %li + %a{:href => "#about"} About + %li + %a{:href => "#contact"} Contact + %li.dropdown + %a.dropdown-toggle{"data-toggle" => "dropdown", :href => "#"} + Dropdown + %b.caret + %ul.dropdown-menu + %li + %a{:href => "#"} Action + %li + %a{:href => "#"} Another action + %li + %a{:href => "#"} Something else here + %li.divider + %li.dropdown-header Nav header + %li + %a{:href => "#"} Separated link + %li + %a{:href => "#"} One more separated link + %ul.nav.navbar-nav.navbar-right + %li + %a{:href => "../navbar/"} Default + %li + %a{:href => "../navbar-static-top/"} Static top + %li.active + %a{:href => "./"} Fixed top + / /.nav-collapse + .container + / Main component for a primary marketing message or call to action + .jumbotron + %h1 Cucumber step statistics + %p ... allows you to easily diagnose long running steps. + / + step + fastest + slowest + variation + variance + standard_deviation + count + average + total + %table.table.table-bordered.table-striped.sortable + %thead + %tr + %th Step + %th Fastest + %th Slowest + %th Variation + %th Variance + %th Std Deviation + %th Count + %th Average + %th{"data-defaultsort" => "desc"} Total + %tbody + %tr + %td /^I am logged in as ((?:(?:)|(?:(?:a|an|another|the|that) )?(?:(?:(?:(?:first|last|(?:\d+(?:st|nd|rd|th))) )?(?:paper[_ ]trail[_ ]version|acts[_ ]as[_ ]taggable[_ ]on[_ ]tag|acts[_ ]as[_ ]taggable[_ ]on[_ ]tagging|user|active[_ ]record[_ ]schema[_ ]migration|plan|feature|reference[_ ]type|allergy|relationship[_ ]type|allergy[_ ]type|medical[_ ]condition[_ ]type|account|rspec[_ ]account|address|sacred[_ ]heart[_ ]address|calendar[_ ]item|catalog|child|jack|jennifer[_ ]dillon|coupon|employment|enrollment|medical[_ ]condition|membership|organization|sacredheart|participation|person|sacredheart[_ ]person|bob|perry|carla|jordan|alienfast|alienfast[_ ]person|blake|kevin|alicia|product|relationship|subscription|rspec[_ ]subscription|tenant|transaction|admin|admin[_ ]not[_ ]owner|staff|consumer|consumer[_ ]dad|support|bmcdaniel|kross|awaters|verification))|(?:(?:paper[_ ]trail[_ ]version|acts[_ ]as[_ ]taggable[_ ]on[_ ]tag|acts[_ ]as[_ ]taggable[_ ]on[_ ]tagging|user|active[_ ]record[_ ]schema[_ ]migration|plan|feature|reference[_ ]type|allergy|relationship[_ ]type|allergy[_ ]type|medical[_ ]condition[_ ]type|account|rspec[_ ]account|address|sacred[_ ]heart[_ ]address|calendar[_ ]item|catalog|child|jack|jennifer[_ ]dillon|coupon|employment|enrollment|medical[_ ]condition|membership|organization|sacredheart|participation|person|sacredheart[_ ]person|bob|perry|carla|jordan|alienfast|alienfast[_ ]person|blake|kevin|alicia|product|relationship|subscription|rspec[_ ]subscription|tenant|transaction|admin|admin[_ ]not[_ ]owner|staff|consumer|consumer[_ ]dad|support|bmcdaniel|kross|awaters|verification)(?::? "(?:\\"|[^\"]|\.)*"))))) at (\w+)$/ + %td 7.051 + %td 4.099 + %td 4.099 + %td 0.320 + %td 0.566 + %td 76 + %td 0.490 + %td 37.288 + %tr + %td /^Blah I am logged in as ((?:(?:)|(?:(?:a|an|another|the|that) )?(?:(?:(?:(?:first|last|(?:\d+(?:st|nd|rd|th))) )?(?:paper[_ ]trail[_ ]version|acts[_ ]as[_ ]taggable[_ ]on[_ ]tag|acts[_ ]as[_ ]taggable[_ ]on[_ ]tagging|user|active[_ ]record[_ ]schema[_ ]migration|plan|feature|reference[_ ]type|allergy|relationship[_ ]type|allergy[_ ]type|medical[_ ]condition[_ ]type|account|rspec[_ ]account|address|sacred[_ ]heart[_ ]address|calendar[_ ]item|catalog|child|jack|jennifer[_ ]dillon|coupon|employment|enrollment|medical[_ ]condition|membership|organization|sacredheart|participation|person|sacredheart[_ ]person|bob|perry|carla|jordan|alienfast|alienfast[_ ]person|blake|kevin|alicia|product|relationship|subscription|rspec[_ ]subscription|tenant|transaction|admin|admin[_ ]not[_ ]owner|staff|consumer|consumer[_ ]dad|support|bmcdaniel|kross|awaters|verification))|(?:(?:paper[_ ]trail[_ ]version|acts[_ ]as[_ ]taggable[_ ]on[_ ]tag|acts[_ ]as[_ ]taggable[_ ]on[_ ]tagging|user|active[_ ]record[_ ]schema[_ ]migration|plan|feature|reference[_ ]type|allergy|relationship[_ ]type|allergy[_ ]type|medical[_ ]condition[_ ]type|account|rspec[_ ]account|address|sacred[_ ]heart[_ ]address|calendar[_ ]item|catalog|child|jack|jennifer[_ ]dillon|coupon|employment|enrollment|medical[_ ]condition|membership|organization|sacredheart|participation|person|sacredheart[_ ]person|bob|perry|carla|jordan|alienfast|alienfast[_ ]person|blake|kevin|alicia|product|relationship|subscription|rspec[_ ]subscription|tenant|transaction|admin|admin[_ ]not[_ ]owner|staff|consumer|consumer[_ ]dad|support|bmcdaniel|kross|awaters|verification)(?::? "(?:\\"|[^\"]|\.)*"))))) at (\w+)$/ + %td 4.051 + %td 8.099 + %td 5.099 + %td 0.420 + %td 0.966 + %td 6 + %td 1.490 + %td 31.288 + / /container + / + Bootstrap core JavaScript + \================================================== + / Placed at the end of the document so the pages load faster + %script{:src => "https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"} + %script{:src => "http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"} + %script{:src => "https://rawgithub.com/drvic10k/bootstrap-sortable/master/Scripts/moment.min.js"} + %script{:src => "https://rawgithub.com/drvic10k/bootstrap-sortable/master/Scripts/bootstrap-sortable.js"} + %script{:type => "javascript"} + \// Initialise on DOM ready + \// $($.bootstrapSortable(true, 'reversed')); diff --git a/notes.txt b/notes.txt new file mode 100644 index 0000000..7e6ad09 --- /dev/null +++ b/notes.txt @@ -0,0 +1,5 @@ +http://www.oesmith.co.uk/morris.js/lines.html +http://drvic10k.github.io/bootstrap-sortable/ + +http://stackoverflow.com/questions/6125265/using-layouts-in-haml-files-independently-of-rails +http://getbootstrap.com/examples/navbar-fixed-top/ \ No newline at end of file diff --git a/spec/cucumber_statistics/configuration_spec.rb b/spec/cucumber_statistics/configuration_spec.rb new file mode 100644 index 0000000..9d76040 --- /dev/null +++ b/spec/cucumber_statistics/configuration_spec.rb @@ -0,0 +1,20 @@ +require 'spec_helper' + +module CucumberStatistics + describe Configuration do + + before do + Configuration.clean_tmp_dir + end + + it 'should auto create tmp_dir' do + + tmp_dir = Configuration.tmp_dir + Dir.exists?(tmp_dir).should == true + + Dir.delete tmp_dir + tmp_dir = Configuration.tmp_dir + Dir.exists?(tmp_dir).should == true + end + end +end \ No newline at end of file diff --git a/spec/cucumber_statistics/presenters/html_template_spec.rb b/spec/cucumber_statistics/presenters/html_template_spec.rb new file mode 100644 index 0000000..3c2e8e2 --- /dev/null +++ b/spec/cucumber_statistics/presenters/html_template_spec.rb @@ -0,0 +1,59 @@ +require 'spec_helper' + +module CucumberStatistics + describe HtmlTemplate do + + before do + # clean up before start, leave after in case we want to inspect it. + Configuration.clean_tmp_dir + end + + describe 'initialize' do + it 'should raise an exception if the template is not found' do + expect { HtmlTemplate.new 'path/does/not/exist' }.to raise_error + end + + it 'should load all the templates' do + HtmlTemplate.new Configuration.all_usage_results + HtmlTemplate.new Configuration.unused_steps + HtmlTemplate.new Configuration.step_times_of_whole + HtmlTemplate.new Configuration.step_average_and_total + end + end + + describe 'output' do + it 'should create a cucumber_statistics folder in tmp if it does not exist' do + filename = "my_file.html" + + html = HtmlTemplate.new Configuration.all_usage_results + absolute_file_name = html.output filename + File.exists?(absolute_file_name).should == true + end + + it 'should write the current content to the specified file in the tmp path' do + filename = "my_file.html" + + html = HtmlTemplate.new Configuration.all_usage_results + absolute_file_name = html.output filename + File.exists?(absolute_file_name).should == true + + file = File.open(absolute_file_name, "rb") + file_contents = file.read + html.content.should == file_contents + end + end + + describe 'replace' do + it 'should replace small strings' do + html = HtmlTemplate.new Configuration.all_usage_results + html.replace "PP_STEP_HIGHEST_AVERAGE", %{
step
/^I create a new project called "([^"]*)"$/
slowest
1.221514
average
0.718889
variation
1.00525
count
2
total
1.437778
fastest
0.216264
} + html.content.should == %{\n \n \n \n

Highest average run time

\n
step
/^I create a new project called "([^"]*)"$/
slowest
1.221514
average
0.718889
variation
1.00525
count
2
total
1.437778
fastest
0.216264
\n

Greatest total time spent in step

\n PP_STEP_HIGHEST_ELAPSED_TIME\n

Biggest variation between fastest and slowest step instance

\n PP_STEP_GREATEST_VARIATION\n
\n

All Steps

\n PP_ALL_STEPS\n \n} + end + it 'should insert large strings' do + html = HtmlTemplate.new Configuration.all_usage_results + html.replace "PP_ALL_STEPS", %{
step
/^I change my email address to "([^"]*)"$/
slowest
0.268031
average
0.268031
variation
0.0
count
1
total
0.268031
fastest
0.268031

step
/^(?:|I )click on "([^"]*)"$/
slowest
0.155292
average
0.0862586666666667
variation
0.106146
count
3
total
0.258776
fastest
0.049146

step
/^I go to the "([^"]*)" page$/
slowest
0.213795
average
0.0836632
variation
0.183576
count
5
total
0.418316
fastest
0.030219

step
/^I complete the task$/
slowest
0.095895
average
0.095895
variation
0.0
count
1
total
0.095895
fastest
0.095895

step
/^I will be on the "([^"]*)" project page$/
slowest
0.005081
average
0.0041195
variation
0.001923
count
2
total
0.008239
fastest
0.003158

step
/^the "([^"]*)" project will created$/
slowest
0.003475
average
0.003475
variation
0.0
count
1
total
0.003475
fastest
0.003475

step
/^I can delete the project$/
slowest
0.059107
average
0.059107
variation
0.0
count
1
total
0.059107
fastest
0.059107

step
/^I can edit the "([^"]*)" project$/
slowest
0.216079
average
0.216079
variation
0.0
count
1
total
0.216079
fastest
0.216079

step
/^I log in as "([^"]*)"$/
slowest
0.146968
average
0.146968
variation
0.0
count
1
total
0.146968
fastest
0.146968

step
/^I should see the "([^"]*)" task in the history$/
slowest
0.00451
average
0.003211
variation
0.002005
count
3
total
0.009633
fastest
0.002505

step
/^I should see the "([^"]*)" task in the backlog$/
slowest
0.003367
average
0.003367
variation
0.0
count
1
total
0.003367
fastest
0.003367

step
/^I change my password to "([^"]*)"$/
slowest
0.215791
average
0.215791
variation
0.0
count
1
total
0.215791
fastest
0.215791

step
/^I create an account for "([^"]*)"$/
slowest
0.158814
average
0.158814
variation
0.0
count
1
total
0.158814
fastest
0.158814

step
/^I create a new project called "([^"]*)"$/
slowest
1.221514
average
0.718889
variation
1.00525
count
2
total
1.437778
fastest
0.216264

step
/^I view the "([^"]*)" project$/
slowest
0.221571
average
0.138235
variation
0.166672
count
2
total
0.27647
fastest
0.054899

step
/^I can see "([^"]*)" project$/
slowest
0.00497
average
0.0043055
variation
0.001329
count
2
total
0.008611
fastest
0.003641

step
/^I should be on the "([^"]*)" page$/
slowest
0.126848
average
0.0253203333333333
variation
0.123835
count
6
total
0.151922
fastest
0.003013

step
/^I will see that projects must have a unique name$/
slowest
0.001412
average
0.001412
variation
0.0
count
1
total
0.001412
fastest
0.001412

step
/^I can create a new project$/
slowest
0.047412
average
0.047412
variation
0.0
count
1
total
0.047412
fastest
0.047412

step
/^I can view the project backlog$/
slowest
0.071688
average
0.071688
variation
0.0
count
1
total
0.071688
fastest
0.071688

step
/^I am a new, authenticated user$/
slowest
0.384872
average
0.3464892
variation
0.139513
count
5
total
1.732446
fastest
0.245359

step
/^the task will be done$/
slowest
0.002362
average
0.002362
variation
0.0
count
1
total
0.002362
fastest
0.002362

step
/^I edit the project "([^"]*)" to:$/
slowest
0.247047
average
0.2460855
variation
0.00192299999999995
count
2
total
0.492171
fastest
0.245124

step
/^then I can go to the "([^"]*)" project page$/
slowest
0.122981
average
0.0948935
variation
0.056175
count
2
total
0.189787
fastest
0.066806

step
/^I can go to the projects page$/
slowest
0.241623
average
0.200115666666667
variation
0.068747
count
3
total
0.600347
fastest
0.172876

step
/^I cancel my account$/
slowest
0.044494
average
0.044494
variation
0.0
count
1
total
0.044494
fastest
0.044494

step
/^I should see the "([^"]*)" task on the project page$/
slowest
0.059446
average
0.059446
variation
0.0
count
1
total
0.059446
fastest
0.059446

step
/^I make the task active$/
slowest
0.079211
average
0.079211
variation
0.0
count
1
total
0.079211
fastest
0.079211

step
/^the "([^"]*)" task exists in the "([^"]*)" project blacklog$/
slowest
0.434581
average
0.417437
variation
0.031844
count
4
total
1.669748
fastest
0.402737

step
/^I am a new, authenticated, admin user$/
slowest
0.271754
average
0.271754
variation
0.0
count
1
total
0.271754
fastest
0.271754

step
/^the task will be active$/
slowest
0.00245
average
0.00245
variation
0.0
count
1
total
0.00245
fastest
0.00245

step
/^the "([^"]*)" task exists in the "([^"]*)" project and is done$/
slowest
0.026986
average
0.022574
variation
0.008824
count
2
total
0.045148
fastest
0.018162

step
/^I view all projects$/
slowest
0.030079
average
0.030079
variation
0.0
count
1
total
0.030079
fastest
0.030079

step
/^there should be no pending accounts$/
slowest
0.00155
average
0.00155
variation
0.0
count
1
total
0.00155
fastest
0.00155

step
/^an unapproved account exists$/
slowest
0.088353
average
0.088353
variation
0.0
count
1
total
0.088353
fastest
0.088353

step
/^my account should be deleted$/
slowest
0.00188
average
0.00188
variation
0.0
count
1
total
0.00188
fastest
0.00188

step
/^I should not see the "([^"]*)" task in the backlog$/
slowest
0.001214
average
0.00121
variation
7.99999999999998e-06
count
2
total
0.00242
fastest
0.001206

step
/^the "([^"]*)" project will exist$/
slowest
0.014723
average
0.007595
variation
0.011958
count
4
total
0.03038
fastest
0.002765

step
/^I will be told that projets require a unique name$/
slowest
0.001984
average
0.001984
variation
0.0
count
1
total
0.001984
fastest
0.001984

step
/^there will be only one "([^"]*)" project$/
slowest
0.002832
average
0.002832
variation
0.0
count
1
total
0.002832
fastest
0.002832

step
/^I am on the "([^"]*)" project page$/
slowest
0.003658
average
0.003658
variation
0.0
count
1
total
0.003658
fastest
0.003658

step
/^I approve the account$/
slowest
0.224123
average
0.224123
variation
0.0
count
1
total
0.224123
fastest
0.224123

step
/^I log in using a password of "([^"]*)"$/
slowest
0.171467
average
0.171467
variation
0.0
count
1
total
0.171467
fastest
0.171467

step
/^the "([^"]*)" task exists in the "([^"]*)" project and is active$/
slowest
0.460897
average
0.166580333333333
variation
0.442096
count
3
total
0.499741
fastest
0.018801

step
/^I delete the "([^"]*)" project$/
slowest
0.09156
average
0.09156
variation
0.0
count
1
total
0.09156
fastest
0.09156

step
/^I view the "([^"]*)" project history$/
slowest
0.035948
average
0.035948
variation
0.0
count
1
total
0.035948
fastest
0.035948

step
/^I view the "([^"]*)" project backlog$/
slowest
0.032592
average
0.032592
variation
0.0
count
1
total
0.032592
fastest
0.032592

step
/^the task will be created and associated with the project$/
slowest
0.023357
average
0.023357
variation
0.0
count
1
total
0.023357
fastest
0.023357

step
/^I create a task in a project$/
slowest
0.63809
average
0.63809
variation
0.0
count
1
total
0.63809
fastest
0.63809

step
/^I will be on the edit project page$/
slowest
0.00225
average
0.00225
variation
0.0
count
1
total
0.00225
fastest
0.00225

step
/^there will be no project "([^"]*)"$/
slowest
0.006473
average
0.004116
variation
0.004714
count
2
total
0.008232
fastest
0.001759

step
/^I will be on the new project page$/
slowest
0.003574
average
0.003574
variation
0.0
count
1
total
0.003574
fastest
0.003574

step
/^I am on the user home page$/
slowest
0.048025
average
0.0405643333333333
variation
0.011906
count
3
total
0.121693
fastest
0.036119

step
/^the following projects:$/
slowest
1.02984
average
0.447912666666667
variation
0.697276
count
9
total
4.031214
fastest
0.332564
} + html.content.should == %{\n \n \n \n

Highest average run time

\n PP_STEP_HIGHEST_AVERAGE\n

Greatest total time spent in step

\n PP_STEP_HIGHEST_ELAPSED_TIME\n

Biggest variation between fastest and slowest step instance

\n PP_STEP_GREATEST_VARIATION\n
\n

All Steps

\n
step
/^I change my email address to "([^"]*)"$/
slowest
0.268031
average
0.268031
variation
0.0
count
1
total
0.268031
fastest
0.268031

step
/^(?:|I )click on "([^"]*)"$/
slowest
0.155292
average
0.0862586666666667
variation
0.106146
count
3
total
0.258776
fastest
0.049146

step
/^I go to the "([^"]*)" page$/
slowest
0.213795
average
0.0836632
variation
0.183576
count
5
total
0.418316
fastest
0.030219

step
/^I complete the task$/
slowest
0.095895
average
0.095895
variation
0.0
count
1
total
0.095895
fastest
0.095895

step
/^I will be on the "([^"]*)" project page$/
slowest
0.005081
average
0.0041195
variation
0.001923
count
2
total
0.008239
fastest
0.003158

step
/^the "([^"]*)" project will created$/
slowest
0.003475
average
0.003475
variation
0.0
count
1
total
0.003475
fastest
0.003475

step
/^I can delete the project$/
slowest
0.059107
average
0.059107
variation
0.0
count
1
total
0.059107
fastest
0.059107

step
/^I can edit the "([^"]*)" project$/
slowest
0.216079
average
0.216079
variation
0.0
count
1
total
0.216079
fastest
0.216079

step
/^I log in as "([^"]*)"$/
slowest
0.146968
average
0.146968
variation
0.0
count
1
total
0.146968
fastest
0.146968

step
/^I should see the "([^"]*)" task in the history$/
slowest
0.00451
average
0.003211
variation
0.002005
count
3
total
0.009633
fastest
0.002505

step
/^I should see the "([^"]*)" task in the backlog$/
slowest
0.003367
average
0.003367
variation
0.0
count
1
total
0.003367
fastest
0.003367

step
/^I change my password to "([^"]*)"$/
slowest
0.215791
average
0.215791
variation
0.0
count
1
total
0.215791
fastest
0.215791

step
/^I create an account for "([^"]*)"$/
slowest
0.158814
average
0.158814
variation
0.0
count
1
total
0.158814
fastest
0.158814

step
/^I create a new project called "([^"]*)"$/
slowest
1.221514
average
0.718889
variation
1.00525
count
2
total
1.437778
fastest
0.216264

step
/^I view the "([^"]*)" project$/
slowest
0.221571
average
0.138235
variation
0.166672
count
2
total
0.27647
fastest
0.054899

step
/^I can see "([^"]*)" project$/
slowest
0.00497
average
0.0043055
variation
0.001329
count
2
total
0.008611
fastest
0.003641

step
/^I should be on the "([^"]*)" page$/
slowest
0.126848
average
0.0253203333333333
variation
0.123835
count
6
total
0.151922
fastest
0.003013

step
/^I will see that projects must have a unique name$/
slowest
0.001412
average
0.001412
variation
0.0
count
1
total
0.001412
fastest
0.001412

step
/^I can create a new project$/
slowest
0.047412
average
0.047412
variation
0.0
count
1
total
0.047412
fastest
0.047412

step
/^I can view the project backlog$/
slowest
0.071688
average
0.071688
variation
0.0
count
1
total
0.071688
fastest
0.071688

step
/^I am a new, authenticated user$/
slowest
0.384872
average
0.3464892
variation
0.139513
count
5
total
1.732446
fastest
0.245359

step
/^the task will be done$/
slowest
0.002362
average
0.002362
variation
0.0
count
1
total
0.002362
fastest
0.002362

step
/^I edit the project "([^"]*)" to:$/
slowest
0.247047
average
0.2460855
variation
0.00192299999999995
count
2
total
0.492171
fastest
0.245124

step
/^then I can go to the "([^"]*)" project page$/
slowest
0.122981
average
0.0948935
variation
0.056175
count
2
total
0.189787
fastest
0.066806

step
/^I can go to the projects page$/
slowest
0.241623
average
0.200115666666667
variation
0.068747
count
3
total
0.600347
fastest
0.172876

step
/^I cancel my account$/
slowest
0.044494
average
0.044494
variation
0.0
count
1
total
0.044494
fastest
0.044494

step
/^I should see the "([^"]*)" task on the project page$/
slowest
0.059446
average
0.059446
variation
0.0
count
1
total
0.059446
fastest
0.059446

step
/^I make the task active$/
slowest
0.079211
average
0.079211
variation
0.0
count
1
total
0.079211
fastest
0.079211

step
/^the "([^"]*)" task exists in the "([^"]*)" project blacklog$/
slowest
0.434581
average
0.417437
variation
0.031844
count
4
total
1.669748
fastest
0.402737

step
/^I am a new, authenticated, admin user$/
slowest
0.271754
average
0.271754
variation
0.0
count
1
total
0.271754
fastest
0.271754

step
/^the task will be active$/
slowest
0.00245
average
0.00245
variation
0.0
count
1
total
0.00245
fastest
0.00245

step
/^the "([^"]*)" task exists in the "([^"]*)" project and is done$/
slowest
0.026986
average
0.022574
variation
0.008824
count
2
total
0.045148
fastest
0.018162

step
/^I view all projects$/
slowest
0.030079
average
0.030079
variation
0.0
count
1
total
0.030079
fastest
0.030079

step
/^there should be no pending accounts$/
slowest
0.00155
average
0.00155
variation
0.0
count
1
total
0.00155
fastest
0.00155

step
/^an unapproved account exists$/
slowest
0.088353
average
0.088353
variation
0.0
count
1
total
0.088353
fastest
0.088353

step
/^my account should be deleted$/
slowest
0.00188
average
0.00188
variation
0.0
count
1
total
0.00188
fastest
0.00188

step
/^I should not see the "([^"]*)" task in the backlog$/
slowest
0.001214
average
0.00121
variation
7.99999999999998e-06
count
2
total
0.00242
fastest
0.001206

step
/^the "([^"]*)" project will exist$/
slowest
0.014723
average
0.007595
variation
0.011958
count
4
total
0.03038
fastest
0.002765

step
/^I will be told that projets require a unique name$/
slowest
0.001984
average
0.001984
variation
0.0
count
1
total
0.001984
fastest
0.001984

step
/^there will be only one "([^"]*)" project$/
slowest
0.002832
average
0.002832
variation
0.0
count
1
total
0.002832
fastest
0.002832

step
/^I am on the "([^"]*)" project page$/
slowest
0.003658
average
0.003658
variation
0.0
count
1
total
0.003658
fastest
0.003658

step
/^I approve the account$/
slowest
0.224123
average
0.224123
variation
0.0
count
1
total
0.224123
fastest
0.224123

step
/^I log in using a password of "([^"]*)"$/
slowest
0.171467
average
0.171467
variation
0.0
count
1
total
0.171467
fastest
0.171467

step
/^the "([^"]*)" task exists in the "([^"]*)" project and is active$/
slowest
0.460897
average
0.166580333333333
variation
0.442096
count
3
total
0.499741
fastest
0.018801

step
/^I delete the "([^"]*)" project$/
slowest
0.09156
average
0.09156
variation
0.0
count
1
total
0.09156
fastest
0.09156

step
/^I view the "([^"]*)" project history$/
slowest
0.035948
average
0.035948
variation
0.0
count
1
total
0.035948
fastest
0.035948

step
/^I view the "([^"]*)" project backlog$/
slowest
0.032592
average
0.032592
variation
0.0
count
1
total
0.032592
fastest
0.032592

step
/^the task will be created and associated with the project$/
slowest
0.023357
average
0.023357
variation
0.0
count
1
total
0.023357
fastest
0.023357

step
/^I create a task in a project$/
slowest
0.63809
average
0.63809
variation
0.0
count
1
total
0.63809
fastest
0.63809

step
/^I will be on the edit project page$/
slowest
0.00225
average
0.00225
variation
0.0
count
1
total
0.00225
fastest
0.00225

step
/^there will be no project "([^"]*)"$/
slowest
0.006473
average
0.004116
variation
0.004714
count
2
total
0.008232
fastest
0.001759

step
/^I will be on the new project page$/
slowest
0.003574
average
0.003574
variation
0.0
count
1
total
0.003574
fastest
0.003574

step
/^I am on the user home page$/
slowest
0.048025
average
0.0405643333333333
variation
0.011906
count
3
total
0.121693
fastest
0.036119

step
/^the following projects:$/
slowest
1.02984
average
0.447912666666667
variation
0.697276
count
9
total
4.031214
fastest
0.332564
\n \n} + end + end + end +end \ No newline at end of file diff --git a/spec/cucumber_statistics/step_statistics_spec.rb b/spec/cucumber_statistics/step_statistics_spec.rb new file mode 100644 index 0000000..45a22a8 --- /dev/null +++ b/spec/cucumber_statistics/step_statistics_spec.rb @@ -0,0 +1,193 @@ +require 'spec_helper' + +module CucumberStatistics + describe StepStatistics do + subject do + StepStatistics.new + end + + describe 'record' do + it 'should create a record' do + subject.record "my step", 50 + + subject.all.count.should == 1 + subject.all['my step'][:instances].count.should == 1 + subject.all['my step'][:instances].first.should == 50 + end + + it 'should support multiple instances of record' do + subject.record "my step", 50 + subject.record "my step", 75 + + subject.all.count.should == 1 + subject.all['my step'][:instances].count.should == 2 + subject.all['my step'][:instances].first.should == 50 + subject.all['my step'][:instances].last.should == 75 + end + end + + describe 'calculate' do + before(:each) do + subject.record "my step", 25 + subject.record "my step", 50 + subject.record "my step", 75 + + subject.calculate + end + + it 'should calculate the total elapsed time' do + subject.all["my step"][:total].should == 150 + end + + it 'should calculate the number of count' do + subject.all["my step"][:count].should == 3 + end + + it 'should calculate the average time' do + subject.all["my step"][:average].should == 50 + end + + it 'should calculate the fastest step' do + subject.all["my step"][:fastest].should == 25 + end + + it 'should calculate the slowest step' do + subject.all["my step"][:slowest].should == 75 + end + + it 'should calculate the variation' do + subject.all["my step"][:variation].should == 50 + end + + it 'should calculate the standard deviation' do + subject.all["my step"][:standard_deviation].should == 25 + end + + it 'should calculate the variance' do + subject.all["my step"][:variance].should == 625 + end + end + + describe 'all' do + before(:each) do + subject.record "my step 1", 24 + subject.record "my step 1", 50 + subject.record "my step 2", 75 + end + + it 'should return all records' do + subject.all.count.should == 2 + subject.all.each_with_index do |step_name, data, index| + case index + when 1 + step_name.should == "my_step 2" + when 2 + step_name.should == "my_step 1" + end + end + end + end + + describe 'set operations' do + before(:each) do + subject.record "my step 1", 25 + subject.record "my step 1", 50 + subject.record "my step 2", 49 + subject.record "my step 2", 51 + subject.record "my step 3", 75 + subject.record "my step 3", 10 + + subject.calculate + end + + describe 'sort_by_property' do + it 'should sort all records by any property' do + subject.sort_by_property(:total).first.first.should == "my step 1" + subject.sort_by_property(:total).last.first.should == "my step 2" + + subject.sort_by_property(:fastest).first.first.should == "my step 3" + subject.sort_by_property(:fastest).last.first.should == "my step 2" + end + end + + describe 'highest_average' do + it 'should return the record with the highest average' do + subject.highest_average.first.should == "my step 2" + end + end + + describe 'highest_elapsed_time' do + it 'should return the record with the highest elapsed time' do + subject.highest_elapsed_time.first.should == "my step 2" + end + end + + describe 'greatest_variation' do + it 'should return the record with the greatest variation between slow and fast' do + subject.greatest_variation.first.should == "my step 3" + end + end + + describe 'step_part_of_total' do + it 'should return the total times of each step from largest to smallest' do + subject.step_part_of_total.should == [100.0, 85.0, 75.0] + end + end + + describe 'total_elapsed_time' do + it 'should return the count of all steps' do + subject.total_elapsed_time.should == 260 + end + end + + describe 'average_times_plot_data' do + it 'should return all the averages sorted by average amount descending' do + subject.record "my step 1", 25 + subject.record "my step 1", 50 + subject.record "my step 2", 49 + subject.record "my step 2", 51 + subject.record "my step 3", 75 + subject.record "my step 3", 10 + + subject.calculate + + subject.average_times_plot_data.should == [50.0, 42.5, 37.5] + end + end + + describe 'total_times_plot_data' do + it 'should return the total times of each step sorted by average amount descending' do + subject.record "my step 1", 25 + subject.record "my step 1", 50 + subject.record "my step 3", 75 + subject.record "my step 3", 10 + + subject.calculate + + subject.total_times_plot_data.should == [100.0, 170, 150.0] + end + end + end + + describe 'sample_variance' do + it 'should calculate the variance' do + subject.sample_variance([1,2,3,4,5,6]).should be_within(0.1).of(3.5) + subject.sample_variance([2,4,4,4,5,5,7,9]).should be_within(0.1).of(4.57) + subject.sample_variance([25,50,75]).should be_within(0.1).of(625) + end + end + + describe 'standard_deviation' do + it 'should calculate the standard deviation' do + sample_variance = subject.sample_variance([1,2,3,4,5,6]) + subject.standard_deviation(sample_variance).should be_within(0.1).of(1.87) + + sample_variance = subject.sample_variance([2,4,4,4,5,5,7,9]) + subject.standard_deviation(sample_variance).should be_within(0.1).of(2.13) + + sample_variance = subject.sample_variance([25,50,75]) + subject.standard_deviation(sample_variance).should be_within(0.1).of(25) + end + end + end +end \ No newline at end of file diff --git a/spec/cucumber_statistics/unused_steps_spec.rb b/spec/cucumber_statistics/unused_steps_spec.rb new file mode 100644 index 0000000..52387cb --- /dev/null +++ b/spec/cucumber_statistics/unused_steps_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' +require 'ap' + +module CucumberStatistics + describe UnusedSteps do + subject do + UnusedSteps.new + end + + describe 'record' do + it 'should create a record' do + subject.record "my_step", "some code somewhere" + + subject.all['my_step'].should == "some code somewhere" + end + end + + describe 'all' do + it 'should return all records sorted alphabetically' do + subject.record "my_step 3", "some code somewhere 3" + subject.record "my_step 2", "some code somewhere 2" + subject.record "my_step 1", "some code somewhere 1" + + subject.all.count.should == 3 + subject.all.each_with_index do |step_name, where, index| + case index + when 1 + step_name.should == "my_step 1" + where.should == "some code somewhere 1" + when 2 + step_name.should == "my_step 2" + where.should == "some code somewhere 1" + when 3 + step_name.should == "my_step 3" + where.should == "some code somewhere 1" + end + end + end + end + end +end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..dd9720c --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,11 @@ +# Requires supporting ruby files with custom matchers and macros, etc, +# in spec/support/ and its subdirectories. +Dir["support/**/*.rb"].each {|f| require f} + +require 'cucumber_statistics' + +RSpec.configure do |config| + config.mock_with :rspec + + config.color_enabled = true +end \ No newline at end of file