cucumber_characteristics 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +19 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +98 -0
- data/Rakefile +1 -0
- data/cucumber_characteristics.gemspec +29 -0
- data/features/failure.feature +6 -0
- data/features/pending.feature +6 -0
- data/features/scenario.feature +6 -0
- data/features/scenario_outline.feature +11 -0
- data/features/scenario_outline_with_background.feature +14 -0
- data/features/scenario_with_background.feature +14 -0
- data/features/step_definitions/fail_steps.rb +3 -0
- data/features/step_definitions/wait_steps.rb +3 -0
- data/lib/cucumber_characteristics/autoload.rb +3 -0
- data/lib/cucumber_characteristics/configuration.rb +35 -0
- data/lib/cucumber_characteristics/cucumber_step_patch.rb +24 -0
- data/lib/cucumber_characteristics/exporter.rb +54 -0
- data/lib/cucumber_characteristics/formatter.rb +19 -0
- data/lib/cucumber_characteristics/profile_data.rb +98 -0
- data/lib/cucumber_characteristics/version.rb +3 -0
- data/lib/cucumber_characteristics/view/step_report.html.haml +106 -0
- data/lib/cucumber_characteristics.rb +23 -0
- metadata +189 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Stuart Ingram
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
# CucumberCharacteristics
|
2
|
+
|
3
|
+
Gem to profile cucumber steps and features
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'cucumber_characteristics'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install cucumber_characteristics
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
1. For always-on automatic loading (recommended), add `require 'cucumber_characteristics/autoload'` to `features/support/yourapp_env.rb`. It is recommended by cucumber that you do not enhance features/support/env.rb so that upgrades are painless (relatively)
|
22
|
+
|
23
|
+
2. Add it to your `cucumber.yml` by adding `--format CucumberCharacteristics::Formatter` i.e.
|
24
|
+
|
25
|
+
`std_opts = "-r features/. -r --quiet --format CucumberCharacteristics::Formatter --format progress"`
|
26
|
+
|
27
|
+
3. Use it via command line with `--format CucumberCharacteristics::Formatter`.
|
28
|
+
|
29
|
+
## Configuration
|
30
|
+
|
31
|
+
You can configure the export of step characteristics via the following (defaults are same as example)
|
32
|
+
|
33
|
+
CucumberCharacteristics.configure do |config|
|
34
|
+
config.export_json = true
|
35
|
+
config.export_html = true
|
36
|
+
config.target_filename = 'cucumber_step_characteristics'
|
37
|
+
config.relative_path = 'features/characteristics'
|
38
|
+
end
|
39
|
+
|
40
|
+
## Results
|
41
|
+
|
42
|
+
Exported characteristic information is listed out at the end of the cucumber run in a message similar to
|
43
|
+
|
44
|
+
Step characteristic report written to /home/singram/projects/gems/cucumber_characteristics/features/characteristics/cucumber_step_characteristics.html
|
45
|
+
Step characteristic report written to /home/singram/projects/gems/cucumber_characteristics/features/characteristics/cucumber_step_characteristics.json
|
46
|
+
|
47
|
+
depending on the options specified.
|
48
|
+
|
49
|
+
The JSON option is provided for convenience in case there is a further use case/analysis required that is not provided by the gem.
|
50
|
+
|
51
|
+
## Problem
|
52
|
+
|
53
|
+
The formatting hooks on the face of it provide the necessary event points to profile any given feature file.
|
54
|
+
This is true for a Scenario, but consider the following ScenaioOutline
|
55
|
+
|
56
|
+
Feature: As a user I want to understand where my tests are spending their time
|
57
|
+
|
58
|
+
Scenario Outline: Timings for scenario outline
|
59
|
+
Given I wait <given_wait> seconds
|
60
|
+
When I wait <when_wait> seconds
|
61
|
+
Then I wait <then_wait> seconds
|
62
|
+
And I wait 0.2 seconds
|
63
|
+
Examples:
|
64
|
+
| given_wait | when_wait | then_wait |
|
65
|
+
| 1 | 2 | 3 |
|
66
|
+
| 5 | 6 | 7 |
|
67
|
+
|
68
|
+
Running
|
69
|
+
|
70
|
+
cucumber --format debug features/outline.feature
|
71
|
+
|
72
|
+
A couple of problems become evident
|
73
|
+
|
74
|
+
1. There are step definitions walked prior to the examples_array. These steps are not actually invoked rendering these hooks points misleading for profiling purposes
|
75
|
+
2. There are only 3 table_cell element blocks. These can be profiled, but what about the last step that does not have an input from the examples? There are no hook points to profile this step.
|
76
|
+
|
77
|
+
This is why when you use the 'progress' formatter you would get 4 'skipped' for the initial step hooks triggered and then only 6 green dots representing steps when there should be 8 as it key's off table cells not steps.
|
78
|
+
|
79
|
+
Possible solutions
|
80
|
+
|
81
|
+
1. Introduce new hook point for all true step invokations irregardless of context.
|
82
|
+
2. Adjust table_cell hooks to include 'null' cells when considering steps without definitions.
|
83
|
+
3. Include profile information in runtime master object to parse out at end.
|
84
|
+
|
85
|
+
As it turns out it was pretty simple to enhance the runtime object to reliably return profile information.
|
86
|
+
|
87
|
+
## Contributing
|
88
|
+
|
89
|
+
1. Fork it
|
90
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
91
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
92
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
93
|
+
5. Create new Pull Request
|
94
|
+
|
95
|
+
## Credits
|
96
|
+
1. Ryan Boucher [cucumber_timing_presenter](https://github.com/distributedlife/cucumber_timing_presenter) for inspiration.
|
97
|
+
2. AlienFast [cucumber_statistics](https://github.com/alienfast/cucumber_statistics) for inspriation.
|
98
|
+
3. [Brandon Hilker](http://brandonhilkert.com/blog/ruby-gem-configuration-patterns/) for gem building tutorials
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'cucumber_characteristics/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "cucumber_characteristics"
|
8
|
+
spec.version = CucumberCharacteristics::VERSION
|
9
|
+
spec.authors = ["Stuart Ingram"]
|
10
|
+
spec.email = ["stuart.ingram@gmail.com"]
|
11
|
+
spec.description = %q{Gem to profile cucumber steps and features}
|
12
|
+
spec.summary = %q{Gem to profile cucumber steps and features}
|
13
|
+
spec.homepage = "https://github.com/singram/cucumber_characteristics"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "haml"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency "awesome_print"
|
26
|
+
spec.add_development_dependency 'simplecov', '0.8.2'
|
27
|
+
spec.add_development_dependency 'rspec', '2.14'
|
28
|
+
spec.add_development_dependency 'cucumber', '1.3.5'
|
29
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
Feature: As a user I want to understand where my tests are spending their time in a scenario outline
|
2
|
+
|
3
|
+
Scenario Outline: Timings for scenario outline
|
4
|
+
Given I wait <given_wait> seconds
|
5
|
+
When I wait <when_wait> seconds
|
6
|
+
Then I wait <then_wait> seconds
|
7
|
+
And I wait 0.2 seconds
|
8
|
+
Examples:
|
9
|
+
| given_wait | when_wait | then_wait |
|
10
|
+
| 0.1 | 0.2 | 0.3 |
|
11
|
+
| 0.5 | 0.6 | 0.7 |
|
@@ -0,0 +1,14 @@
|
|
1
|
+
Feature: As a user I want to understand where my tests are spending their time in a scenario outline with a background
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given I wait 0.4 seconds
|
5
|
+
|
6
|
+
Scenario Outline: Timings for scenario outline
|
7
|
+
Given I wait <given_wait> seconds
|
8
|
+
When I wait <when_wait> seconds
|
9
|
+
Then I wait <then_wait> seconds
|
10
|
+
And I wait 0.2 seconds
|
11
|
+
Examples:
|
12
|
+
| given_wait | when_wait | then_wait |
|
13
|
+
| 0.1 | 0.2 | 0.3 |
|
14
|
+
| 0.5 | 0.6 | 0.7 |
|
@@ -0,0 +1,14 @@
|
|
1
|
+
Feature: As a user I want to understand where my tests are spending their time in a scenaio with a background
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given I wait 0.4 seconds
|
5
|
+
|
6
|
+
Scenario: Timings for normal scenario
|
7
|
+
Given I wait 0.1 seconds
|
8
|
+
When I wait 0.2 seconds
|
9
|
+
Then I wait 0.3 seconds
|
10
|
+
|
11
|
+
Scenario: Timings for another normal scenario
|
12
|
+
Given I wait 0.5 seconds
|
13
|
+
When I wait 0.6 seconds
|
14
|
+
Then I wait 0.7 seconds
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module CucumberCharacteristics
|
2
|
+
|
3
|
+
class Configuration
|
4
|
+
|
5
|
+
attr_accessor :export_json, :export_html, :target_filename, :relative_path
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@export_json = true
|
9
|
+
@export_html = true
|
10
|
+
@target_filename = 'cucumber_step_characteristics'
|
11
|
+
@relative_path = 'features/characteristics'
|
12
|
+
end
|
13
|
+
|
14
|
+
def full_target_filename
|
15
|
+
"#{full_dir}/#{@target_filename}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def full_dir
|
19
|
+
dir = resolve_path_from_root @relative_path
|
20
|
+
FileUtils.mkdir_p dir unless File.exists? dir
|
21
|
+
dir
|
22
|
+
end
|
23
|
+
|
24
|
+
def resolve_path_from_root(rel_path)
|
25
|
+
if defined?(Rails)
|
26
|
+
Rails.root.join(rel_path)
|
27
|
+
elsif defined?(Rake.original_dir)
|
28
|
+
File.expand_path(rel_path, Rake.original_dir)
|
29
|
+
else
|
30
|
+
File.expand_path(rel_path, Dir.pwd)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#http://stackoverflow.com/questions/4470108/when-monkey-patching-a-method-can-you-call-the-overridden-method-from-the-new-i
|
2
|
+
|
3
|
+
module Cucumber
|
4
|
+
class StepMatch
|
5
|
+
old_invoke = instance_method(:invoke)
|
6
|
+
attr_reader :duration
|
7
|
+
|
8
|
+
define_method(:invoke) do | multiline_arg |
|
9
|
+
start_time = Time.now
|
10
|
+
ret = old_invoke.bind(self).(multiline_arg)
|
11
|
+
@duration = Time.now - start_time
|
12
|
+
ret
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
module Cucumber
|
19
|
+
module Ast
|
20
|
+
class StepInvocation
|
21
|
+
attr_reader :step_match
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'haml'
|
2
|
+
|
3
|
+
module CucumberCharacteristics
|
4
|
+
|
5
|
+
class Exporter
|
6
|
+
|
7
|
+
attr_reader :profile
|
8
|
+
def initialize(profile)
|
9
|
+
@profile = profile
|
10
|
+
@config = CucumberCharacteristics.configuration
|
11
|
+
end
|
12
|
+
|
13
|
+
def export
|
14
|
+
filename = @config.full_target_filename
|
15
|
+
if @config.export_html
|
16
|
+
File.open(filename+'.html', 'w') { |file| file.write(to_html) }
|
17
|
+
puts "Step characteristics report written to #{filename}.html"
|
18
|
+
end
|
19
|
+
if @config.export_json
|
20
|
+
File.open(filename+'.json', 'w') { |file| file.write(to_json) }
|
21
|
+
puts "Step characteristics report written to #{filename}.json"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_html
|
26
|
+
template = File.read(File.expand_path('../view/step_report.html.haml', __FILE__))
|
27
|
+
haml_engine = Haml::Engine.new(template)
|
28
|
+
haml_engine.render(self)
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_json
|
32
|
+
@profile.step_profiles.to_json
|
33
|
+
end
|
34
|
+
|
35
|
+
# HELPERS
|
36
|
+
|
37
|
+
def format_ts(t)
|
38
|
+
t ? sprintf("%0.4f", t) : '-'
|
39
|
+
end
|
40
|
+
|
41
|
+
def format_step_usage(step_feature_data)
|
42
|
+
step_feature_data[:feature_location].map do |location, timings|
|
43
|
+
"#{location}" + (timings.count > 1 ? " (x#{timings.count})" : '')
|
44
|
+
end.join("\n")
|
45
|
+
end
|
46
|
+
|
47
|
+
def step_status_summary(profile)
|
48
|
+
status = profile.step_count_by_status
|
49
|
+
status.keys.sort.map{|s| status[s]> 0 ? "#{s.capitalize}: #{status[s]}" : nil}.compact.join(', ')
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module CucumberCharacteristics
|
2
|
+
|
3
|
+
class Formatter
|
4
|
+
|
5
|
+
def initialize(runtime, io, options)
|
6
|
+
@runtime = runtime
|
7
|
+
@io = io
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def after_features(features)
|
12
|
+
profile = ProfileData.new(@runtime, features)
|
13
|
+
Exporter.new(profile).export
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module CucumberCharacteristics
|
2
|
+
|
3
|
+
class ProfileData
|
4
|
+
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
def_delegators :@runtime, :scenarios, :steps
|
8
|
+
attr_reader :duration
|
9
|
+
|
10
|
+
STATUS = [:passed, :failed, :skipped, :undefined ]
|
11
|
+
|
12
|
+
def initialize(runtime, features)
|
13
|
+
@runtime = runtime
|
14
|
+
@duration = features.duration
|
15
|
+
end
|
16
|
+
|
17
|
+
def step_profiles
|
18
|
+
#return @step_profiles if @step_profiles
|
19
|
+
step_profiles = {}
|
20
|
+
@runtime.steps.each do |s|
|
21
|
+
step_name = s.status == :undefined ? s.name : s.step_match.step_definition.file_colon_line
|
22
|
+
# Initialize data structure
|
23
|
+
step_profiles[step_name] ||= { :total_count => 0}
|
24
|
+
STATUS.each {|status| step_profiles[step_name][status] ||= {:count => 0, :feature_location => {} }}
|
25
|
+
feature_location = s.file_colon_line
|
26
|
+
step_profiles[step_name][s.status][:count] += 1
|
27
|
+
step_profiles[step_name][:total_count] += 1
|
28
|
+
step_profiles[step_name][s.status][:feature_location][feature_location] ||= []
|
29
|
+
if s.status != :undefined
|
30
|
+
step_profiles[step_name][:regexp] = s.step_match.step_definition.regexp_source
|
31
|
+
if s.status == :passed
|
32
|
+
step_profiles[step_name][s.status][:feature_location][feature_location] << s.step_match.duration
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
with_calculations(step_profiles)
|
37
|
+
end
|
38
|
+
|
39
|
+
def with_calculations(step_profiles)
|
40
|
+
step_profiles.each do |step, meta|
|
41
|
+
meta.merge!(fastest: nil, slowest: nil, average: nil, total_duration: nil, standard_deviation: nil, variation: nil)
|
42
|
+
next unless meta[:passed][:count] > 0
|
43
|
+
timings = []
|
44
|
+
STATUS.each do |status|
|
45
|
+
timings << meta[status][:feature_location].values
|
46
|
+
end
|
47
|
+
timings = timings.flatten.compact
|
48
|
+
|
49
|
+
step_profiles[step][:fastest] = timings.min
|
50
|
+
step_profiles[step][:slowest] = timings.max
|
51
|
+
step_profiles[step][:variation] = step_profiles[step][:slowest] - step_profiles[step][:fastest]
|
52
|
+
step_profiles[step][:total_duration] = timings.inject(:+)
|
53
|
+
step_profiles[step][:average] = step_profiles[step][:total_duration] / meta[:passed][:count]
|
54
|
+
sum = timings.inject(0){|accum, i| accum +(i-step_profiles[step][:average])**2 }
|
55
|
+
step_profiles[step][:variance] = sum/(timings.length ).to_f
|
56
|
+
step_profiles[step][:standard_deviation] = Math.sqrt( step_profiles[step][:variance])
|
57
|
+
end
|
58
|
+
step_profiles
|
59
|
+
end
|
60
|
+
|
61
|
+
def step_duration
|
62
|
+
step_duration = []
|
63
|
+
step_profiles.each do | step, meta |
|
64
|
+
STATUS.each do |status|
|
65
|
+
meta[status][:feature_location].each do | location, timings |
|
66
|
+
step_duration << timings
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
step_duration.flatten.compact.inject(:+)
|
71
|
+
end
|
72
|
+
|
73
|
+
def nonstep_duration
|
74
|
+
duration - step_duration
|
75
|
+
end
|
76
|
+
|
77
|
+
def step_count_by_status
|
78
|
+
status = {}
|
79
|
+
@runtime.steps.each do |s|
|
80
|
+
status[s.status] ||= 0
|
81
|
+
status[s.status] += 1
|
82
|
+
end
|
83
|
+
status
|
84
|
+
end
|
85
|
+
|
86
|
+
def scenario_count_by_status
|
87
|
+
status = {}
|
88
|
+
@runtime.scenarios.each do |s|
|
89
|
+
status[s.status] ||= 0
|
90
|
+
status[s.status] += 1
|
91
|
+
end
|
92
|
+
status
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
!!!
|
2
|
+
%html{:lang => "en"}
|
3
|
+
%head
|
4
|
+
%meta{:charset => "utf-8"}/
|
5
|
+
%meta{:content => "IE=edge", "http-equiv" => "X-UA-Compatible"}/
|
6
|
+
%meta{:content => "width=device-width, initial-scale=1", :name => "viewport"}/
|
7
|
+
%meta{:content => "Cucumber Step Characteristics", :name => "description"}/
|
8
|
+
%title Cucumber Step Characteristics
|
9
|
+
%link{:href => "http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css", :rel => "stylesheet"}/
|
10
|
+
%link{:href => "http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap-theme.min.css", :rel => "stylesheet"}/
|
11
|
+
/ Custom styles for this layout
|
12
|
+
:css
|
13
|
+
body {
|
14
|
+
min-height: 2000px;
|
15
|
+
padding-top: 70px;
|
16
|
+
}
|
17
|
+
|
18
|
+
td {
|
19
|
+
white-space: nowrap;
|
20
|
+
}
|
21
|
+
|
22
|
+
table.tablesorter thead tr .headerSortUp {
|
23
|
+
background-color: #8dbdd8;
|
24
|
+
}
|
25
|
+
table.tablesorter thead tr .headerSortDown {
|
26
|
+
background-color: #8dbdd8;
|
27
|
+
}
|
28
|
+
/ HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries
|
29
|
+
/[if lt IE 9]
|
30
|
+
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
|
31
|
+
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
|
32
|
+
%body
|
33
|
+
.container
|
34
|
+
.page-header
|
35
|
+
%h1 Cucumber step characteristics
|
36
|
+
.alert.alert-info
|
37
|
+
%span
|
38
|
+
#{profile.scenarios.count} Scenarios,
|
39
|
+
#{profile.steps.count} Steps completed
|
40
|
+
%span.text-muted
|
41
|
+
(#{step_status_summary(profile)})
|
42
|
+
<br>
|
43
|
+
Test duration #{format_ts(profile.duration)}s.
|
44
|
+
%span.text-muted
|
45
|
+
(#{format_ts(profile.step_duration)}s steps, #{format_ts(profile.nonstep_duration)}s non-steps)
|
46
|
+
%span.text-muted.pull-right.small
|
47
|
+
Finished on #{Time.now}
|
48
|
+
|
49
|
+
%table.table.table-striped.table-bordered.table-condensed.tablesorter#profile_table
|
50
|
+
%thead
|
51
|
+
%tr
|
52
|
+
%th Step
|
53
|
+
%th Total time
|
54
|
+
%th Passed
|
55
|
+
%th Average
|
56
|
+
%th Fastest
|
57
|
+
%th Slowest
|
58
|
+
%th Variation
|
59
|
+
%th Variance
|
60
|
+
%th Std Deviation
|
61
|
+
%th Skipped
|
62
|
+
%th Error
|
63
|
+
%th Undef
|
64
|
+
%th Total count
|
65
|
+
%tbody
|
66
|
+
- profile.step_profiles.each do |step, meta|
|
67
|
+
%tr
|
68
|
+
%td
|
69
|
+
%abbr{:title => "#{meta[:regexp]}"} #{step}
|
70
|
+
%td #{format_ts(meta[:total_duration])}
|
71
|
+
%td
|
72
|
+
- if meta[:passed][:count] > 0
|
73
|
+
%abbr{:title => "#{ format_step_usage(meta[:passed]) }" } #{meta[:passed][:count]}
|
74
|
+
- else
|
75
|
+
0
|
76
|
+
%td #{format_ts(meta[:average])}
|
77
|
+
%td #{format_ts(meta[:fastest])}
|
78
|
+
%td #{format_ts(meta[:slowest])}
|
79
|
+
%td #{format_ts(meta[:variation])}
|
80
|
+
%td #{format_ts(meta[:variance])}
|
81
|
+
%td #{format_ts(meta[:standard_deviation])}
|
82
|
+
%td
|
83
|
+
- if meta[:skipped][:count] > 0
|
84
|
+
%abbr{:title => "#{ format_step_usage(meta[:skipped]) }" } #{meta[:skipped][:count]}
|
85
|
+
- else
|
86
|
+
0
|
87
|
+
%td
|
88
|
+
- if meta[:failed][:count] > 0
|
89
|
+
%abbr{:title => "#{ format_step_usage(meta[:failed]) }" } #{meta[:failed][:count]}
|
90
|
+
- else
|
91
|
+
0
|
92
|
+
%td
|
93
|
+
- if meta[:undefined][:count] > 0
|
94
|
+
%abbr{:title => "#{ format_step_usage(meta[:undefined]) }" } #{meta[:undefined][:count]}
|
95
|
+
- else
|
96
|
+
0
|
97
|
+
%td #{meta[:total_count]}
|
98
|
+
%script{:src => "https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"}
|
99
|
+
%script{:src => "http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"}
|
100
|
+
%script{:src => "https://raw.githubusercontent.com/christianbach/tablesorter/master/jquery.tablesorter.min.js"}
|
101
|
+
:javascript
|
102
|
+
$(document).ready(function()
|
103
|
+
{
|
104
|
+
$("#profile_table").tablesorter( {sortList: [[1,1],[3,1]], widgets: ['zebra']} );
|
105
|
+
}
|
106
|
+
);
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "cucumber_characteristics/configuration"
|
2
|
+
require "cucumber_characteristics/cucumber_step_patch"
|
3
|
+
require "cucumber_characteristics/exporter"
|
4
|
+
require "cucumber_characteristics/formatter"
|
5
|
+
require "cucumber_characteristics/profile_data"
|
6
|
+
|
7
|
+
module CucumberCharacteristics
|
8
|
+
class << self
|
9
|
+
attr_writer :configuration
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.configuration
|
13
|
+
@configuration ||= Configuration.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.reset
|
17
|
+
@configuration = Configuration.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.configure
|
21
|
+
yield(configuration)
|
22
|
+
end
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cucumber_characteristics
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Stuart Ingram
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-06-07 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: haml
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: bundler
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '1.3'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '1.3'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: awesome_print
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: simplecov
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - '='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 0.8.2
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - '='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 0.8.2
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: rspec
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - '='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '2.14'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - '='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '2.14'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: cucumber
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - '='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 1.3.5
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - '='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 1.3.5
|
126
|
+
description: Gem to profile cucumber steps and features
|
127
|
+
email:
|
128
|
+
- stuart.ingram@gmail.com
|
129
|
+
executables: []
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files: []
|
132
|
+
files:
|
133
|
+
- .gitignore
|
134
|
+
- Gemfile
|
135
|
+
- LICENSE.txt
|
136
|
+
- README.md
|
137
|
+
- Rakefile
|
138
|
+
- cucumber_characteristics.gemspec
|
139
|
+
- features/failure.feature
|
140
|
+
- features/pending.feature
|
141
|
+
- features/scenario.feature
|
142
|
+
- features/scenario_outline.feature
|
143
|
+
- features/scenario_outline_with_background.feature
|
144
|
+
- features/scenario_with_background.feature
|
145
|
+
- features/step_definitions/fail_steps.rb
|
146
|
+
- features/step_definitions/wait_steps.rb
|
147
|
+
- lib/cucumber_characteristics.rb
|
148
|
+
- lib/cucumber_characteristics/autoload.rb
|
149
|
+
- lib/cucumber_characteristics/configuration.rb
|
150
|
+
- lib/cucumber_characteristics/cucumber_step_patch.rb
|
151
|
+
- lib/cucumber_characteristics/exporter.rb
|
152
|
+
- lib/cucumber_characteristics/formatter.rb
|
153
|
+
- lib/cucumber_characteristics/profile_data.rb
|
154
|
+
- lib/cucumber_characteristics/version.rb
|
155
|
+
- lib/cucumber_characteristics/view/step_report.html.haml
|
156
|
+
homepage: https://github.com/singram/cucumber_characteristics
|
157
|
+
licenses:
|
158
|
+
- MIT
|
159
|
+
post_install_message:
|
160
|
+
rdoc_options: []
|
161
|
+
require_paths:
|
162
|
+
- lib
|
163
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
164
|
+
none: false
|
165
|
+
requirements:
|
166
|
+
- - ! '>='
|
167
|
+
- !ruby/object:Gem::Version
|
168
|
+
version: '0'
|
169
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
170
|
+
none: false
|
171
|
+
requirements:
|
172
|
+
- - ! '>='
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '0'
|
175
|
+
requirements: []
|
176
|
+
rubyforge_project:
|
177
|
+
rubygems_version: 1.8.24
|
178
|
+
signing_key:
|
179
|
+
specification_version: 3
|
180
|
+
summary: Gem to profile cucumber steps and features
|
181
|
+
test_files:
|
182
|
+
- features/failure.feature
|
183
|
+
- features/pending.feature
|
184
|
+
- features/scenario.feature
|
185
|
+
- features/scenario_outline.feature
|
186
|
+
- features/scenario_outline_with_background.feature
|
187
|
+
- features/scenario_with_background.feature
|
188
|
+
- features/step_definitions/fail_steps.rb
|
189
|
+
- features/step_definitions/wait_steps.rb
|