cuukie 0.1.4 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +4 -3
- data/README.markdown +20 -20
- data/Rakefile +3 -3
- data/VERSION +1 -1
- data/bin/cuukie +42 -0
- data/cuukie.gemspec +21 -16
- data/doc/backlog.txt +10 -7
- data/doc/pomodoro.txt +22 -0
- data/lib/cuukie.rb +1 -1
- data/lib/cuukie/cli.rb +48 -0
- data/lib/cuukie/code_snippets.rb +25 -0
- data/lib/cuukie/formatter.rb +88 -0
- data/lib/cuukie/public/cucumber.css +1 -1
- data/lib/cuukie/public/cuukie.js +4 -0
- data/lib/cuukie/server.rb +98 -67
- data/lib/cuukie/views/index.erb +20 -21
- data/spec/cli_spec.rb +86 -0
- data/spec/code_snippets_spec.rb +4 -4
- data/spec/commands_spec.rb +73 -22
- data/spec/cuukie_spec.rb +109 -21
- data/spec/spec_helper.rb +7 -2
- data/spec/test_project/features/1_show_scenarios.feature +3 -3
- data/spec/test_project/features/2_show_multiline_args.feature +1 -1
- data/spec/test_project/features/3_failed_background.feature +5 -7
- data/spec/test_project/features/step_definitions/main_steps.rb +5 -4
- metadata +39 -25
- data/bin/cuukie_server +0 -9
- data/lib/cuukie/cucumber/formatter/code_snippets.rb +0 -23
- data/lib/cuukie/cucumber/formatter/cuukie.rb +0 -90
data/Gemfile
CHANGED
data/README.markdown
CHANGED
@@ -4,48 +4,48 @@ Cuukie shows your Cucumber results on a web page.
|
|
4
4
|
|
5
5
|
[](http://travis-ci.org/nusco/cuukie.png)
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
Install Cuukie:
|
7
|
+
Install Cuukie via Bundler, or directly with:
|
10
8
|
|
11
9
|
gem install cuukie
|
12
10
|
|
13
|
-
|
14
|
-
|
15
|
-
Require Cuukie from any file in your _features/support_ directory:
|
11
|
+
Go to your Cucumber folder and add this line to any file in _features/support_:
|
16
12
|
|
17
13
|
require 'cuukie'
|
18
14
|
|
19
|
-
|
15
|
+
Run Cuukie:
|
20
16
|
|
21
|
-
|
17
|
+
cuukie --showpage
|
18
|
+
|
19
|
+
Cuukie passes any command-line argument that it doesn't recognize to Cucumber, so just use _cuukie_ instead of _cucumber_ when you want to see your features in the browser.
|
22
20
|
|
23
|
-
|
21
|
+
## Advanced Cuuking
|
24
22
|
|
25
|
-
|
23
|
+
Cuukie is actually two things: a server that displays running features on a web page, and a Cucumber formatter that sends data to the server. You can run these two components independently. For example, you might want to keep the server running all the time:
|
26
24
|
|
27
|
-
|
25
|
+
cuukie --server
|
26
|
+
|
27
|
+
When you run Cucumber, ask it to use the _cuukie_ formatter to send data to the server:
|
28
28
|
|
29
29
|
cucumber --format cuukie
|
30
|
-
|
31
|
-
To look at the results, open this page in a browser:
|
32
30
|
|
33
|
-
|
31
|
+
To look at the results, visit:
|
34
32
|
|
35
|
-
|
33
|
+
http://localhost:4569
|
36
34
|
|
37
|
-
You can pick a port when you start the
|
35
|
+
You can pick a port when you start the cuukie server...
|
38
36
|
|
39
|
-
|
37
|
+
cuukie --server --cuukieport 4570
|
40
38
|
|
41
39
|
...and you can tell the cuukie formatter where to look for the server:
|
42
40
|
|
43
41
|
cucumber --format cuukie CUUKIE_SERVER=http://my.server:4570
|
44
42
|
|
45
|
-
|
43
|
+
This stuff is useful if you want to put the Cuukie server on your build machine. For more options:
|
44
|
+
|
45
|
+
cuukie --help
|
46
46
|
|
47
|
-
|
47
|
+
Enjoy!
|
48
48
|
|
49
49
|
## License
|
50
50
|
|
51
|
-
MIT License. Copyright (c) 2011 Paolo "Nusco" Perrotta. I ripped a few lines of code off Cucumber's HTML formatter.
|
51
|
+
MIT License. Copyright (c) 2011 Paolo "Nusco" Perrotta. I also ripped a few lines of code off Cucumber's HTML formatter.
|
data/Rakefile
CHANGED
@@ -7,8 +7,8 @@ namespace :test do
|
|
7
7
|
desc "Run all specs"
|
8
8
|
RSpec::Core::RakeTask.new(:specs)
|
9
9
|
|
10
|
-
desc "Run Cuukie on the test project (needs a
|
11
|
-
task :
|
10
|
+
desc "Run Cuukie on the test project (needs a cuukie server on localhost, default port)"
|
11
|
+
task :manual do
|
12
12
|
system "cd spec/test_project && \
|
13
13
|
cucumber --format cuukie"
|
14
14
|
end
|
@@ -19,8 +19,8 @@ Jeweler::Tasks.new do |gem|
|
|
19
19
|
gem.name = "cuukie"
|
20
20
|
gem.homepage = "http://github.com/nusco/cuukie"
|
21
21
|
gem.license = "MIT"
|
22
|
+
gem.description = %Q{A drop-in replacement for the "cucumber" command. It shows running features on a web page.}
|
22
23
|
gem.summary = %Q{A continuous view on Cucumber features}
|
23
|
-
gem.description = %Q{Shows Cucumber results on a web page as they run.}
|
24
24
|
gem.email = "paolo.nusco.perrotta@gmail.com"
|
25
25
|
gem.authors = ['Paolo "Nusco" Perrotta']
|
26
26
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/bin/cuukie
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
lib = File.dirname(__FILE__) + '/../lib'
|
3
|
+
$:.unshift lib unless $:.include? lib
|
4
|
+
|
5
|
+
require 'cuukie/cli'
|
6
|
+
include Cuukie::Cli
|
7
|
+
options = parse_options ARGV
|
8
|
+
|
9
|
+
exit if options.empty?
|
10
|
+
|
11
|
+
server_command = "ruby #{File.dirname(__FILE__)}/../lib/cuukie/server.rb #{options[:cuukieport]}"
|
12
|
+
if options[:server]
|
13
|
+
system server_command
|
14
|
+
exit
|
15
|
+
else
|
16
|
+
Process.detach(fork { system "#{server_command} >/dev/null 2>&1" })
|
17
|
+
end
|
18
|
+
|
19
|
+
unless options[:keepserver]
|
20
|
+
at_exit do
|
21
|
+
require 'rest-client'
|
22
|
+
begin
|
23
|
+
RestClient.delete "http://localhost:#{options[:cuukieport]}"
|
24
|
+
rescue; end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
if options[:showpage]
|
29
|
+
require 'launchy'
|
30
|
+
Launchy.open("http://localhost:#{options[:cuukieport]}")
|
31
|
+
else
|
32
|
+
puts "View your features at http://localhost:#{options[:cuukieport]}"
|
33
|
+
end
|
34
|
+
|
35
|
+
# TODO: auto-require formatter (warning: if you tell Cucumber to --require
|
36
|
+
# something, it will want to --require everything!)
|
37
|
+
system "cucumber #{ARGV.join(' ')} --format cuukie"
|
38
|
+
|
39
|
+
unless options[:nowait]
|
40
|
+
puts 'Press a key to exit'
|
41
|
+
gets
|
42
|
+
end
|
data/cuukie.gemspec
CHANGED
@@ -5,14 +5,14 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "cuukie"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Paolo \"Nusco\" Perrotta"]
|
12
|
-
s.date = "2011-12-
|
13
|
-
s.description = "
|
12
|
+
s.date = "2011-12-15"
|
13
|
+
s.description = "A drop-in replacement for the \"cucumber\" command. It shows running features on a web page."
|
14
14
|
s.email = "paolo.nusco.perrotta@gmail.com"
|
15
|
-
s.executables = ["
|
15
|
+
s.executables = ["cuukie"]
|
16
16
|
s.extra_rdoc_files = [
|
17
17
|
"README.markdown"
|
18
18
|
]
|
@@ -24,19 +24,21 @@ Gem::Specification.new do |s|
|
|
24
24
|
"README.markdown",
|
25
25
|
"Rakefile",
|
26
26
|
"VERSION",
|
27
|
-
"bin/
|
27
|
+
"bin/cuukie",
|
28
28
|
"cuukie.gemspec",
|
29
29
|
"doc/LICENSE.txt",
|
30
30
|
"doc/backlog.txt",
|
31
31
|
"doc/pomodoro.txt",
|
32
32
|
"lib/cuukie.rb",
|
33
|
-
"lib/cuukie/
|
34
|
-
"lib/cuukie/
|
33
|
+
"lib/cuukie/cli.rb",
|
34
|
+
"lib/cuukie/code_snippets.rb",
|
35
|
+
"lib/cuukie/formatter.rb",
|
35
36
|
"lib/cuukie/public/cucumber.css",
|
36
37
|
"lib/cuukie/public/cuukie.js",
|
37
38
|
"lib/cuukie/public/jquery-1.7.min.js",
|
38
39
|
"lib/cuukie/server.rb",
|
39
40
|
"lib/cuukie/views/index.erb",
|
41
|
+
"spec/cli_spec.rb",
|
40
42
|
"spec/code_snippets_spec.rb",
|
41
43
|
"spec/commands_spec.rb",
|
42
44
|
"spec/cuukie_spec.rb",
|
@@ -59,24 +61,27 @@ Gem::Specification.new do |s|
|
|
59
61
|
s.specification_version = 3
|
60
62
|
|
61
63
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
62
|
-
s.add_runtime_dependency(%q<sinatra>, ["
|
63
|
-
s.add_runtime_dependency(%q<
|
64
|
-
s.add_runtime_dependency(%q<
|
64
|
+
s.add_runtime_dependency(%q<sinatra>, ["~> 1.3"])
|
65
|
+
s.add_runtime_dependency(%q<cucumber>, ["~> 1.1"])
|
66
|
+
s.add_runtime_dependency(%q<rest-client>, ["~> 1.6"])
|
67
|
+
s.add_runtime_dependency(%q<launchy>, [">= 0"])
|
65
68
|
s.add_runtime_dependency(%q<syntax>, [">= 0"])
|
66
69
|
s.add_development_dependency(%q<rake>, [">= 0"])
|
67
70
|
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
68
71
|
else
|
69
|
-
s.add_dependency(%q<sinatra>, ["
|
70
|
-
s.add_dependency(%q<
|
71
|
-
s.add_dependency(%q<
|
72
|
+
s.add_dependency(%q<sinatra>, ["~> 1.3"])
|
73
|
+
s.add_dependency(%q<cucumber>, ["~> 1.1"])
|
74
|
+
s.add_dependency(%q<rest-client>, ["~> 1.6"])
|
75
|
+
s.add_dependency(%q<launchy>, [">= 0"])
|
72
76
|
s.add_dependency(%q<syntax>, [">= 0"])
|
73
77
|
s.add_dependency(%q<rake>, [">= 0"])
|
74
78
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
75
79
|
end
|
76
80
|
else
|
77
|
-
s.add_dependency(%q<sinatra>, ["
|
78
|
-
s.add_dependency(%q<
|
79
|
-
s.add_dependency(%q<
|
81
|
+
s.add_dependency(%q<sinatra>, ["~> 1.3"])
|
82
|
+
s.add_dependency(%q<cucumber>, ["~> 1.1"])
|
83
|
+
s.add_dependency(%q<rest-client>, ["~> 1.6"])
|
84
|
+
s.add_dependency(%q<launchy>, [">= 0"])
|
80
85
|
s.add_dependency(%q<syntax>, [">= 0"])
|
81
86
|
s.add_dependency(%q<rake>, [">= 0"])
|
82
87
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
data/doc/backlog.txt
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
MMF 0.1
|
2
|
-
-
|
3
|
-
-
|
4
|
-
|
5
|
-
- show incomplete wrap-up for steps/scenarios
|
6
|
-
- show incomplete running time
|
7
|
-
MMF 0.1.6
|
1
|
+
MMF 0.2.1
|
2
|
+
- better error messages
|
3
|
+
- work on any cucumber project out of the box (no need to add require())
|
4
|
+
MMF 0.2.2
|
8
5
|
- deal with Scenario Examples
|
6
|
+
MMF 0.2.3
|
9
7
|
- open/close steps
|
8
|
+
MMF 0.2.4
|
9
|
+
- show incomplete wrap-up for steps/scenarios
|
10
10
|
MMF 1.0.0
|
11
11
|
- nice graphics
|
12
12
|
- self-updating Steps
|
@@ -22,6 +22,9 @@ Then...
|
|
22
22
|
|
23
23
|
- filter by tag
|
24
24
|
|
25
|
+
- default policy for open/close elements (like: close
|
26
|
+
successfull scenarios/steps, open unsuccessful ones)
|
27
|
+
|
25
28
|
- instead of showing scenarios that appear one by one,
|
26
29
|
show the entire suite ASAP, and then proceed to make
|
27
30
|
each scenario red or green (or whatever). this
|
data/doc/pomodoro.txt
CHANGED
@@ -1,6 +1,28 @@
|
|
1
1
|
I use this file to track my own work on the project. Each line is a pomodoro (a 25' slot).
|
2
2
|
Latest pomodoro comes first:
|
3
3
|
|
4
|
+
- release
|
5
|
+
- refactoring and README
|
6
|
+
- refactoring
|
7
|
+
- command-line options
|
8
|
+
- roll bin/cuukie_server into bin/cuukie
|
9
|
+
- command-line options
|
10
|
+
- command-line options
|
11
|
+
- command-line options
|
12
|
+
- command-line options
|
13
|
+
- command-line options
|
14
|
+
- command-line options
|
15
|
+
- command-line options
|
16
|
+
- hide stats until run completion
|
17
|
+
- show incomplete running time
|
18
|
+
- show incomplete running time
|
19
|
+
- fix feature keywords
|
20
|
+
- "cuukie" command
|
21
|
+
- "cuukie" command
|
22
|
+
- show undefined scenarios and steps
|
23
|
+
- show incomplete status bar suite
|
24
|
+
- refactoring
|
25
|
+
- refactoring
|
4
26
|
- show code snippets (and release 0.1.4)
|
5
27
|
- show code snippets
|
6
28
|
- show code snippets
|
data/lib/cuukie.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/cuukie/
|
1
|
+
require File.dirname(__FILE__) + '/cuukie/formatter'
|
data/lib/cuukie/cli.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
Version = File.read File.dirname(__FILE__) + '/../../VERSION' unless Kernel.const_defined? :Version
|
4
|
+
|
5
|
+
module Cuukie
|
6
|
+
module Cli
|
7
|
+
def parse_options(options)
|
8
|
+
to_options_hash extract_cuukie_options(options)
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def extract_cuukie_options(options)
|
14
|
+
result = []
|
15
|
+
['--server', '--showpage', '--nowait', '--keepserver', '-h', '--help'].each do |opt|
|
16
|
+
result << options.delete(opt)
|
17
|
+
end
|
18
|
+
if (options.include? '--cuukieport')
|
19
|
+
port = options.delete_at(options.index('--cuukieport') + 1)
|
20
|
+
result << options.delete('--cuukieport') << port
|
21
|
+
end
|
22
|
+
result.compact!
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_options_hash(options)
|
26
|
+
result = { :cuukieport => 4569 }
|
27
|
+
[:server, :showpage, :nowait, :keepserver].each do |opt|
|
28
|
+
result[opt] = false
|
29
|
+
end
|
30
|
+
|
31
|
+
OptionParser.new do |opts|
|
32
|
+
opts.banner = "cuukie #{::Version}\nUsage: cuukie [options] [cucumber-options]"
|
33
|
+
|
34
|
+
opts.on("--cuukieport PORT", Integer, "Start the server on PORT") {|port| result[:cuukieport] = port }
|
35
|
+
opts.on("--server", "Run as a server") { result[:server] = true }
|
36
|
+
opts.on("--showpage", "Open the features in the default browser") { result[:showpage] = true }
|
37
|
+
opts.on("--nowait", "Don't wait for keypress on exit") { result[:nowait] = true }
|
38
|
+
opts.on("--keepserver", "Leave the server running on exit") { result[:keepserver] = true }
|
39
|
+
|
40
|
+
opts.on_tail("-h", "--help", "You're looking at it") do
|
41
|
+
puts opts.help
|
42
|
+
return {}
|
43
|
+
end
|
44
|
+
end.parse! options
|
45
|
+
result
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Cuukie
|
2
|
+
module CodeSnippets
|
3
|
+
def code_snippet(file, line)
|
4
|
+
return null_snippet unless File.exist? file
|
5
|
+
|
6
|
+
all_lines = File.open(file) {|f| f.readlines}
|
7
|
+
return null_snippet unless line <= all_lines.size
|
8
|
+
|
9
|
+
first_line = [1, line - 2].max
|
10
|
+
|
11
|
+
{ :raw_lines => all_lines[(first_line - 1)..line].join,
|
12
|
+
:first_line => first_line,
|
13
|
+
:marked_line => line }
|
14
|
+
end
|
15
|
+
|
16
|
+
def backtrace_to_snippet(backtrace)
|
17
|
+
return null_snippet unless backtrace[0] =~ /(.*):(\d+)/
|
18
|
+
code_snippet $1, $2.to_i
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def null_snippet; Hash.new; end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/code_snippets'
|
2
|
+
require 'rest-client'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Cuukie
|
6
|
+
class Formatter
|
7
|
+
include CodeSnippets
|
8
|
+
|
9
|
+
def initialize(*)
|
10
|
+
@server = ENV['CUUKIE_SERVER'] || 'http://localhost:4569'
|
11
|
+
RestClient.get "#{@server}/ping"
|
12
|
+
rescue
|
13
|
+
puts "I cannot find the cuukie server on #{@server}."
|
14
|
+
puts "Please start the server with cuukie --server."
|
15
|
+
exit
|
16
|
+
end
|
17
|
+
|
18
|
+
def before_features(*)
|
19
|
+
post 'before_features'
|
20
|
+
end
|
21
|
+
|
22
|
+
def before_feature(feature)
|
23
|
+
post 'before_feature', { :short_name => feature.short_name,
|
24
|
+
:description => feature.description }
|
25
|
+
end
|
26
|
+
|
27
|
+
def feature_name(keyword, *)
|
28
|
+
post 'feature_name', { :keyword => keyword }
|
29
|
+
end
|
30
|
+
|
31
|
+
def scenario_name(keyword, name, file_colon_line, *)
|
32
|
+
post 'scenario_name', { :keyword => keyword,
|
33
|
+
:name => name,
|
34
|
+
:file_colon_line => file_colon_line }
|
35
|
+
end
|
36
|
+
|
37
|
+
def before_step(step)
|
38
|
+
post 'before_step', { :keyword => step.keyword,
|
39
|
+
:name => step.name,
|
40
|
+
:file_colon_line => step.file_colon_line }
|
41
|
+
end
|
42
|
+
|
43
|
+
def before_table_row(*)
|
44
|
+
post 'before_table_row'
|
45
|
+
end
|
46
|
+
|
47
|
+
def table_cell_value(value, *)
|
48
|
+
post 'table_cell_value', { :value => value }
|
49
|
+
end
|
50
|
+
|
51
|
+
def doc_string(string)
|
52
|
+
post 'doc_string', { :multiline_string => string }
|
53
|
+
end
|
54
|
+
|
55
|
+
def exception(exception, *)
|
56
|
+
source = backtrace_to_snippet(exception.backtrace)
|
57
|
+
post 'exception', { :message => exception.message,
|
58
|
+
:backtrace => exception.backtrace.join('\n'),
|
59
|
+
:raw_lines => source[:raw_lines],
|
60
|
+
:first_line => source[:first_line],
|
61
|
+
:marked_line => source[:marked_line] }
|
62
|
+
end
|
63
|
+
|
64
|
+
def after_step_result(keyword, step_match, multiline_arg, status, *)
|
65
|
+
post 'after_step_result', { :status => status }
|
66
|
+
end
|
67
|
+
|
68
|
+
def after_steps(*)
|
69
|
+
post 'after_steps'
|
70
|
+
end
|
71
|
+
|
72
|
+
def after_features(features)
|
73
|
+
post 'after_features', { :duration => features.duration }
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def post(url, params = {})
|
79
|
+
RestClient.post "#{@server}/#{url}", params.to_json
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
require 'cucumber/cli/options'
|
85
|
+
Cucumber::Cli::Options::BUILTIN_FORMATS['cuukie'] = [
|
86
|
+
'Cuukie::Formatter',
|
87
|
+
'Shows Cucumber results on a web page as they run'
|
88
|
+
]
|