launcuke 0.0.0 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/Gemfile +5 -0
- data/README.md +31 -0
- data/launcuke.gemspec +22 -0
- data/lib/launcuke/index.rb +59 -0
- data/lib/launcuke/runner.rb +197 -0
- data/lib/launcuke/version.rb +3 -0
- data/lib/launcuke.rb +6 -5
- metadata +50 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ODgyNmIwNzBhOWJlNjk3NjYzN2E4NDlmOGNmZDczMDE4ZTM0ODY5OA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YzdkOTBhNjFiZDliZDA4NzFlMmE5ODU2Y2Q0MmI3NTE2YzFmYzNlOQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MjVjNWU2ZWFiM2I4MWIzYWE2MzdmZDc0NjQxOTQwODBlMDBlMWM3MjFlNTlh
|
10
|
+
Y2IwNTM1NTAyZDkzYWZmYTk0NTdhNDQxMDUyY2FkNzU3NmIwMThjM2M1MWFj
|
11
|
+
MWQ1NDlkOWQwZWQxMzM0MTliNzQzN2Q1Y2ZlN2FlN2UzYjRiNmI=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MzkwZDBjYjI0OTEwNGI4OTYzNWE5MGM3NDY5YmY5ZTU4ZjIzODBmYjVjODJl
|
14
|
+
ZWY1Njc1Yzk3NTMxYTBhODgwNzg2NDI3ODk4ZWQ5NmE5ZTkzMzJiZmMwNTIx
|
15
|
+
NTRmNTY1MmQ0MzdkMGVhZmYyZmY0YzQ0Mjc4NzQ5MmQ0MTc5YTk=
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Launcuke
|
2
|
+
|
3
|
+
Run your cucumber test and generate a index html page to show all reports by feature.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'launcuke'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install launcuke
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
TODO: Write usage instructions here
|
24
|
+
|
25
|
+
## Contributing
|
26
|
+
|
27
|
+
1. Fork it ( https://github.com/[my-github-username]/launcuke/fork )
|
28
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
29
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
30
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
31
|
+
5. Create a new Pull Request
|
data/launcuke.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/launcuke/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'launcuke'
|
6
|
+
s.date = '2014-11-24'
|
7
|
+
s.summary = "Launch cuke!"
|
8
|
+
s.description = "A simple cucumber runner gem"
|
9
|
+
s.authors = ["Yi MIN"]
|
10
|
+
s.email = 'tebat804@gmail.com'
|
11
|
+
s.files = ["lib/launcuke.rb"]
|
12
|
+
s.homepage =
|
13
|
+
'http://rubygems.org/gems/launcuke'
|
14
|
+
s.files = `git ls-files`.split($\)
|
15
|
+
s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
16
|
+
s.license = 'MIT'
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
s.version = Launcuke::VERSION
|
19
|
+
s.add_dependency 'cucumber'
|
20
|
+
s.add_dependency 'rspec'
|
21
|
+
s.add_dependency 'nokogiri'
|
22
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Launcuke
|
2
|
+
|
3
|
+
# Generate the index page reporting on the features and their status.
|
4
|
+
# Provides the links to the actual full Cucumber html reports.
|
5
|
+
class ReportsIndex
|
6
|
+
|
7
|
+
# Collection of ran features directories results used for reporting
|
8
|
+
attr_reader :features_dirs
|
9
|
+
|
10
|
+
# Full path for the index html file
|
11
|
+
attr_reader :index_path
|
12
|
+
|
13
|
+
def initialize(reports_path, features_dirs)
|
14
|
+
@features_dirs = features_dirs
|
15
|
+
@index_path = File.join(reports_path, "index.html")
|
16
|
+
end
|
17
|
+
|
18
|
+
def generate
|
19
|
+
index_file = File.new(index_path, "w")
|
20
|
+
|
21
|
+
b = Builder::XmlMarkup.new :target => index_file, :indent => 2
|
22
|
+
b.html {
|
23
|
+
b.head {
|
24
|
+
b.title("Cucumber Reports")
|
25
|
+
b.style(css_content)
|
26
|
+
}
|
27
|
+
b.body {
|
28
|
+
b.h2("Features")
|
29
|
+
b.ul {
|
30
|
+
features_dirs.each { |features_dir|
|
31
|
+
b.li(:class => (features_dir.failed? ? "failed" : "success")) {
|
32
|
+
b.a(features_dir.human_name, :href => "#{features_dir.dir_name}.html")
|
33
|
+
b.span("[#{features_dir.duration}]", :class => "duration")
|
34
|
+
b.span("Scenarios: #{features_dir.scenarios_results}, Steps: #{features_dir.steps_results}", :class => "result")
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
index_file.close
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def css_content
|
47
|
+
<<-CSS
|
48
|
+
body {font-family: "Lucida Grande", Helvetica, sans-serif; margin: 2em 8em 2em 8em;}
|
49
|
+
ul {list-style-type: square;}
|
50
|
+
li {margin: 1em 0 1em 0;}
|
51
|
+
li span {float: right; margin-left: 1em; padding: 0 0.3em;}
|
52
|
+
li.failed span.result{background: #DC6E6E;}
|
53
|
+
li.success span.result{background: #C1E799;}
|
54
|
+
span.duration {color: #999999;}
|
55
|
+
CSS
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,197 @@
|
|
1
|
+
require 'launcuke/index'
|
2
|
+
|
3
|
+
module Launcuke
|
4
|
+
|
5
|
+
# Wrapper of {Kernel#system} method for test/mock
|
6
|
+
class SystemCommand
|
7
|
+
|
8
|
+
def run(full_command_as_array)
|
9
|
+
system *full_command_as_array
|
10
|
+
end
|
11
|
+
|
12
|
+
def exit(status = 0)
|
13
|
+
Kernel.exit(status == 0)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
# Set of features under one specific directory
|
19
|
+
class FeaturesDir
|
20
|
+
|
21
|
+
# Directory name fo the features
|
22
|
+
attr_reader :dir_name
|
23
|
+
|
24
|
+
# Result string for passed/failed scenarios
|
25
|
+
attr_accessor :scenarios_results
|
26
|
+
|
27
|
+
# Result string for passed/failed steps
|
28
|
+
attr_accessor :steps_results
|
29
|
+
|
30
|
+
# Running time in ms for all features in this feature directory
|
31
|
+
attr_accessor :duration
|
32
|
+
|
33
|
+
# True if a scenario or step has failed for this set of features
|
34
|
+
attr_writer :failed
|
35
|
+
|
36
|
+
def initialize(directory_name)
|
37
|
+
@dir_name = directory_name
|
38
|
+
@failed = false
|
39
|
+
@scenarios_results = ""
|
40
|
+
@steps_results = ""
|
41
|
+
end
|
42
|
+
|
43
|
+
# True if one feature has failed
|
44
|
+
def failed?
|
45
|
+
(scenarios_results.include?"failed") || (steps_results.include?"failed")
|
46
|
+
end
|
47
|
+
|
48
|
+
# Human readable name used for index page (ex: user_logout --> User logout)
|
49
|
+
def human_name
|
50
|
+
dir_name.gsub(/[_-]/, " ").capitalize
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
# Actual clas that will spawn one command process per directory of features collected
|
56
|
+
# according to configuration
|
57
|
+
class Runner
|
58
|
+
|
59
|
+
# Root path to your features directory. Ex: your_project/features
|
60
|
+
attr_accessor :features_root_path
|
61
|
+
|
62
|
+
# Optional name for directory containing the reports. Default to 'cucumber_reports'
|
63
|
+
attr_accessor :output_dir_name
|
64
|
+
|
65
|
+
# Optional full path for generated reports. Default to ../{features_root_path}.
|
66
|
+
attr_accessor :output_path
|
67
|
+
|
68
|
+
# Optional regexp for name of features directories to exclude.
|
69
|
+
attr_accessor :excluded_dirs
|
70
|
+
|
71
|
+
# Optional only the features directories to be included
|
72
|
+
attr_accessor :included_only_dirs
|
73
|
+
|
74
|
+
# Array of extra options to pass to the command. Ex: ["-p", "my_profile", "--backtrace"]
|
75
|
+
attr_accessor :extra_options
|
76
|
+
|
77
|
+
# Define the size for the pool of forks. Default is 5
|
78
|
+
attr_accessor :forks_pool_size
|
79
|
+
|
80
|
+
# Full final path where html reports will be generated
|
81
|
+
attr_reader :reports_path
|
82
|
+
|
83
|
+
# Optional. If true will generate index file but not launch processes. Used for testing.
|
84
|
+
attr_accessor :dry_run
|
85
|
+
|
86
|
+
# Add cucumber --require option load *.rb files under features root path by default unless specified to false.
|
87
|
+
attr_accessor :require_features_root_option
|
88
|
+
|
89
|
+
# Delegate to a wrapper of system call in order mock/test
|
90
|
+
attr_accessor :system_command
|
91
|
+
|
92
|
+
def initialize(features_root)
|
93
|
+
@features_root_path = features_root
|
94
|
+
@extra_options ||= []
|
95
|
+
yield self if block_given?
|
96
|
+
|
97
|
+
@dry_run = false if dry_run.nil?
|
98
|
+
@forks_pool_size ||= 5
|
99
|
+
@require_features_root_option = true if require_features_root_option.nil?
|
100
|
+
@output_dir_name = "#{@extra_options[1]}" unless output_dir_name
|
101
|
+
@output_path = File.expand_path("../reports", output_dir_name) unless output_path
|
102
|
+
@excluded_dirs ||= []
|
103
|
+
@included_only_dirs ||= []
|
104
|
+
|
105
|
+
@reports_path = File.join(output_path, output_dir_name)
|
106
|
+
@system_command ||= SystemCommand.new
|
107
|
+
end
|
108
|
+
|
109
|
+
def start
|
110
|
+
FileUtils.mkdir_p reports_path
|
111
|
+
exit_status = launch_process_per_dir
|
112
|
+
collect_results
|
113
|
+
reports = ReportsIndex.new(reports_path, features_dirs).generate
|
114
|
+
puts "See reports index at #{reports.index_path}" if reports
|
115
|
+
system_command.exit(exit_status)
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def launch_process_per_dir
|
121
|
+
if dry_run
|
122
|
+
0
|
123
|
+
else
|
124
|
+
|
125
|
+
results = features_dirs.each { |features_dir|
|
126
|
+
report_file_path = File.join(reports_path, "#{features_dir.dir_name}.html")
|
127
|
+
feature_full_path = File.join(features_root_path, "#{features_dir.dir_name}")
|
128
|
+
main_command = %W[bundle exec cucumber #{feature_full_path}]
|
129
|
+
options = %W[--format html --out #{report_file_path}]
|
130
|
+
options.concat %W[--require #{features_root_path}] if require_features_root_option
|
131
|
+
full_command = main_command + options + extra_options
|
132
|
+
result = system_command.run full_command
|
133
|
+
puts "Features '#{features_dir.dir_name.upcase}' finished. #{result ? 'SUCCESS' : 'FAILURE'} (pid: #{Process.pid})"
|
134
|
+
result
|
135
|
+
}
|
136
|
+
|
137
|
+
|
138
|
+
global_exit_status = results.inject(0) { |acc, result|
|
139
|
+
result ? acc : acc +1
|
140
|
+
}
|
141
|
+
puts "Global exit status = #{global_exit_status}"
|
142
|
+
global_exit_status
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def collect_results
|
147
|
+
features_dirs.each { |features_dir|
|
148
|
+
feature_file = File.join(reports_path, "#{features_dir.dir_name}.html")
|
149
|
+
File.open(feature_file) { |file|
|
150
|
+
content = file.read
|
151
|
+
duration_match = content.match(/Finished in\s+<\w+>(.*?)</)
|
152
|
+
duration = duration_match ? duration_match.captures.first : ""
|
153
|
+
scenarios_match = content.match(/\d+ scenarios? \((.*?)\)/)
|
154
|
+
scenarios = scenarios_match ? scenarios_match.captures.first : ""
|
155
|
+
steps_match = content.match(/\d+ steps? \((.*?)\)/)
|
156
|
+
steps = steps_match ? steps_match.captures.first : ""
|
157
|
+
|
158
|
+
features_dir.scenarios_results = scenarios
|
159
|
+
features_dir.steps_results = steps
|
160
|
+
features_dir.duration = duration
|
161
|
+
} if File.exists?(feature_file)
|
162
|
+
}
|
163
|
+
end
|
164
|
+
|
165
|
+
def features_dirs
|
166
|
+
@features_dirs ||= resolve_features_dirs_name
|
167
|
+
end
|
168
|
+
|
169
|
+
def resolve_features_dirs_name
|
170
|
+
Dir.glob(File.join(features_root_path, "*", "*.feature")).select{ |path|
|
171
|
+
configured_dir?(path)
|
172
|
+
}.map { |feature_path|
|
173
|
+
dir_name = File.basename(File.dirname(feature_path))
|
174
|
+
FeaturesDir.new(dir_name)
|
175
|
+
}.uniq { |feature_dir|
|
176
|
+
feature_dir.dir_name
|
177
|
+
}
|
178
|
+
end
|
179
|
+
|
180
|
+
def configured_dir?(path)
|
181
|
+
if included_only_dirs.empty?
|
182
|
+
included_dir?(path)
|
183
|
+
else
|
184
|
+
exact_word_match_expressions = included_only_dirs.map { |dir_name|
|
185
|
+
"\\b#{dir_name}\\b"
|
186
|
+
}
|
187
|
+
path.match(Regexp.new(exact_word_match_expressions.join("|")))
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def included_dir?(path)
|
192
|
+
excluded_dirs.empty? || (not path.match(Regexp.new(excluded_dirs.join("|"))))
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
data/lib/launcuke.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
require "launcuke/version"
|
2
|
+
require "launcuke/runner"
|
3
|
+
|
4
|
+
require 'fileutils'
|
5
|
+
require 'builder'
|
6
|
+
require 'nokogiri'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: launcuke
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yi MIN
|
@@ -9,14 +9,62 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
date: 2014-11-24 00:00:00.000000000 Z
|
12
|
-
dependencies:
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: cucumber
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: nokogiri
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
13
55
|
description: A simple cucumber runner gem
|
14
56
|
email: tebat804@gmail.com
|
15
57
|
executables: []
|
16
58
|
extensions: []
|
17
59
|
extra_rdoc_files: []
|
18
60
|
files:
|
61
|
+
- Gemfile
|
62
|
+
- README.md
|
63
|
+
- launcuke.gemspec
|
19
64
|
- lib/launcuke.rb
|
65
|
+
- lib/launcuke/index.rb
|
66
|
+
- lib/launcuke/runner.rb
|
67
|
+
- lib/launcuke/version.rb
|
20
68
|
homepage: http://rubygems.org/gems/launcuke
|
21
69
|
licenses:
|
22
70
|
- MIT
|