cuukie 0.1.4 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Build Status](https://secure.travis-ci.org/nusco/cuukie.png)](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
|
+
]
|