cuukie 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -182,7 +182,7 @@ body {
182
182
  .cucumber ol li.undefined, td ol li.undefined, th ol li.undefined {
183
183
  border-left: 5px solid #faf834;
184
184
  border-bottom: 1px solid #faf834;
185
- background: #fcfb98;
185
+ background: #aaaaaa;
186
186
  color: #131313;
187
187
  }
188
188
  .cucumber ol li.message, td ol li.message, th ol li.message {
@@ -37,3 +37,7 @@ function skippedColors(element_id) {
37
37
  $('#'+element_id).css('background', '#E0FFFF');
38
38
  $('#'+element_id).css('color', '#000000');
39
39
  }
40
+ function undefinedColors(element_id) {
41
+ $('#'+element_id).css('background', '#AAAAAA');
42
+ $('#'+element_id).css('color', '#000000');
43
+ }
@@ -5,96 +5,102 @@ require 'syntax/convertors/html'
5
5
  module Cuukie
6
6
  class Server < Sinatra::Base
7
7
  set :features, []
8
- set :build_status, nil
9
- set :duration, '?'
10
- set :stats, {:scenarios => '', :steps => ''}
8
+ set :build_status, 'undefined'
9
+ set :start_time, nil
10
+ set :duration, nil
11
+ set :stats, Hash.new('')
11
12
 
12
13
  get '/' do
13
14
  @features = settings.features
14
15
  @build_status = settings.build_status
15
- @duration = settings.duration
16
16
  @stats = settings.stats
17
17
  erb :index
18
18
  end
19
19
 
20
20
  post '/before_features' do
21
21
  settings.features.clear
22
- settings.build_status = nil
23
- settings.stats = {:scenarios => '', :steps => ''}
24
- settings.duration = '?'
25
- settings.build_status = nil
22
+ settings.build_status = 'undefined'
23
+ settings.start_time = Time.now
24
+ settings.duration = nil
25
+ settings.stats = Hash.new('')
26
26
  end
27
27
 
28
28
  post '/before_feature' do
29
29
  feature = read_from_request
30
- feature['description'] = feature['description'].split("\n")
31
- feature['scenarios'] = []
32
- feature['id'] = settings.features.size + 1
30
+ feature[:keyword] = '...'
31
+ feature[:description] = feature[:description].split("\n")
32
+ feature[:scenarios] = []
33
+ feature[:id] = settings.features.size + 1
33
34
  settings.features << feature
34
35
  'OK'
35
36
  end
36
37
 
38
+ post '/feature_name' do
39
+ current_feature.merge! read_from_request
40
+ 'OK'
41
+ end
42
+
37
43
  post '/scenario_name' do
38
44
  scenario = read_from_request
39
- scenario['steps'] = []
40
- scenario['id'] = "scenario_#{current_feature['id']}_#{current_feature['scenarios'].size + 1}"
41
- current_feature['scenarios'] << scenario
45
+ scenario[:steps] = []
46
+ scenario[:id] = "scenario_#{current_feature[:id]}_#{current_feature[:scenarios].size + 1}"
47
+ scenario[:status] = 'undefined'
48
+ current_feature[:scenarios] << scenario
42
49
  'OK'
43
50
  end
44
51
 
45
- post '/before_step_result' do
52
+ post '/before_step' do
46
53
  step = read_from_request
47
- step['table'] = []
48
- current_scenario['steps'] << step
54
+ step[:table] = []
55
+ step[:status] = 'undefined'
56
+ current_scenario[:steps] << step
49
57
  'OK'
50
58
  end
51
-
52
- post '/exception' do
53
- current_step['exception'] = read_from_request
59
+
60
+ post '/before_table_row' do
61
+ current_step[:table] << []
54
62
  'OK'
55
63
  end
56
64
 
57
- post '/after_step_result' do
58
- current_step.merge! read_from_request
59
- if current_step['status'] == 'failed'
60
- current_scenario['status'] = settings.build_status = 'failed'
61
- elsif current_step['status'] == 'pending'
62
- current_scenario['status'] = 'pending'
63
- settings.build_status ||= 'pending'
64
- end
65
+ post '/table_cell_value' do
66
+ data = read_from_request
67
+ current_step[:table].last << data[:value]
65
68
  'OK'
66
69
  end
67
-
68
- post '/after_steps' do
69
- if current_scenario['steps'].all? {|step| step['status'] == 'skipped' }
70
- current_scenario['status'] = 'skipped'
71
- end
72
- current_scenario['status'] ||= 'passed'
70
+
71
+ post '/doc_string' do
72
+ data = read_from_request
73
+ current_step[:multiline_string] = data[:multiline_string]
73
74
  'OK'
74
75
  end
75
76
 
76
- post '/before_table_row' do
77
- current_step['table'] << []
77
+ post '/exception' do
78
+ current_step[:exception] = read_from_request
78
79
  'OK'
79
80
  end
80
81
 
81
- post '/table_cell_value' do
82
- data = read_from_request
83
- current_step['table'].last << data['value']
82
+ post '/after_step_result' do
83
+ current_step.merge! read_from_request
84
+ if current_step[:status] == 'failed'
85
+ current_scenario[:status] = settings.build_status = 'failed'
86
+ elsif current_step[:status] == 'pending'
87
+ current_scenario[:status] = 'pending'
88
+ settings.build_status = 'pending' if settings.build_status == 'undefined'
89
+ end
84
90
  'OK'
85
91
  end
86
-
87
- post '/doc_string' do
88
- data = read_from_request
89
- current_step['multiline_string'] = data['multiline_string']
92
+
93
+ post '/after_steps' do
94
+ if current_scenario[:steps].all? {|step| step[:status] == 'skipped' }
95
+ current_scenario[:status] = 'skipped'
96
+ end
97
+ current_scenario[:status] = 'passed' if current_scenario[:status] == 'undefined'
90
98
  'OK'
91
99
  end
92
100
 
93
101
  post '/after_features' do
94
- data = read_from_request
95
- min, sec = data['duration'].to_f.divmod(60)
96
- settings.duration = "#{min}m#{'%.3f' % sec}s"
97
- settings.build_status ||= 'passed'
102
+ settings.duration = read_from_request[:duration]
103
+ settings.build_status = 'passed' if settings.build_status == 'undefined'
98
104
  settings.stats = stats
99
105
  'OK'
100
106
  end
@@ -103,19 +109,28 @@ module Cuukie
103
109
  delete('/') { exit! }
104
110
 
105
111
  helpers do
106
- def snippet(exception)
107
- return '' unless exception['raw_lines']
112
+ def code_snippet_for(exception)
113
+ return '' unless exception[:raw_lines]
108
114
  result = '<pre class="ruby"><code>'
109
- linenum = exception['first_line']
110
- html_lines = htmlize(exception['raw_lines']).split "\n"
115
+ linenum = exception[:first_line]
116
+ html_lines = htmlize(exception[:raw_lines]).split "\n"
111
117
  html_lines.each do |html_line|
112
118
  line = "<span class=\"linenum\">#{linenum}</span>#{html_line}"
113
- line = "<span class=\"offending\">#{line}</span>" if linenum == exception['marked_line']
119
+ line = "<span class=\"offending\">#{line}</span>" if linenum == exception[:marked_line]
114
120
  result << "#{line}<br/>"
115
121
  linenum += 1
116
122
  end
117
123
  result << '</code></pre>'
118
124
  end
125
+
126
+ def time_label
127
+ settings.duration ? "Duration" : "Running time"
128
+ end
129
+
130
+ def format_time
131
+ min, sec = time.to_i.divmod(60)
132
+ "#{min}':#{sec}''"
133
+ end
119
134
  end
120
135
 
121
136
  def current_feature
@@ -127,41 +142,47 @@ module Cuukie
127
142
  # don't have a scenario yet. this is useful to eliminate steps
128
143
  # coming from backgrounds (which will be re-sent during the
129
144
  # following scenarios anyway)
130
- return { 'steps' => [{}] } if current_feature['scenarios'].empty?
131
- current_feature['scenarios'].last
145
+ return { :steps => [{}] } if current_feature[:scenarios].empty?
146
+ current_feature[:scenarios].last
132
147
  end
133
148
 
134
149
  def current_step
135
- current_scenario['steps'].last
150
+ current_scenario[:steps].last
151
+ end
152
+
153
+ def time
154
+ return settings.duration if settings.duration
155
+ return 0 unless settings.start_time
156
+ return Time.now - settings.start_time
136
157
  end
137
158
 
138
159
  def stats
139
160
  scenarios = []
140
- settings.features.each {|feature| scenarios.concat feature['scenarios'] }
161
+ settings.features.each {|feature| scenarios.concat feature[:scenarios] }
141
162
 
142
163
  result = {:scenarios => String.new, :steps => String.new}
143
- result[:scenarios] << dump_count(scenarios.size, "scenario")
164
+ result[:scenarios] << pluralize(scenarios.size, "scenario")
144
165
  result[:scenarios] << counts(scenarios)
145
166
 
146
167
  steps = []
147
- scenarios.each {|scenario| steps.concat scenario['steps'] }
148
- result[:steps] << dump_count(steps.size, "step")
168
+ scenarios.each {|scenario| steps.concat scenario[:steps] }
169
+ result[:steps] << pluralize(steps.size, "step")
149
170
  step_count = counts steps
150
171
  result[:steps] << step_count if step_count
151
172
  result
152
173
  end
174
+
175
+ def pluralize(count, what)
176
+ "#{count} #{what}#{count == 1 ? '' : 's'}"
177
+ end
153
178
 
154
179
  def counts(elements)
155
180
  counts = ['failed', 'skipped', 'undefined', 'pending', 'passed'].map do |status|
156
- selected = elements.find_all {|element| element['status'] == status }
181
+ selected = elements.find_all {|element| element[:status] == status }
157
182
  selected.any? ? "#{selected.size} #{status}" : nil
158
183
  end.compact
159
184
  counts.any? ? " (#{counts.join(', ')})" : ''
160
185
  end
161
-
162
- def dump_count(count, what)
163
- "#{count} #{what}#{count == 1 ? '' : 's'}"
164
- end
165
186
 
166
187
  def htmlize(ruby)
167
188
  convertor = Syntax::Convertors::HTML.for_syntax("ruby")
@@ -172,10 +193,20 @@ module Cuukie
172
193
 
173
194
  def read_from_request
174
195
  data = JSON.parse request.body.read
175
- result = data.clone
176
- result.each do |k, v|
177
- result[k] = escape_html(v) if v.class == String && k !~ /^raw_/
196
+ result = {}
197
+ data.each do |k, v|
198
+ if v.class == String && k !~ /^raw_/
199
+ result[k.to_sym] = escape_html(v)
200
+ else
201
+ result[k.to_sym] = v
202
+ end
178
203
  end
204
+ result
179
205
  end
180
206
  end
181
207
  end
208
+
209
+ if __FILE__ == $0
210
+ Cuukie::Server.set :port, ARGV[0] if ARGV[0]
211
+ Cuukie::Server.run!
212
+ end
@@ -8,7 +8,6 @@
8
8
  </head>
9
9
 
10
10
  <body>
11
- <!-- header -->
12
11
  <div class="cucumber"><div id="cucumber-header"><div id="label"><h1>Cucumber Features</h1></div>
13
12
  <div id="summary">
14
13
  <p id="stats"></p>
@@ -18,7 +17,7 @@
18
17
  </div>
19
18
  <script><%= @build_status %>Colors('cucumber-header')</script>
20
19
  <script type="text/javascript">
21
- document.getElementById('duration').innerHTML = "Finished in <strong><%= @duration %> seconds</strong>";
20
+ document.getElementById('duration').innerHTML = "<%= time_label %>: <strong><%= format_time %></strong>";
22
21
  </script>
23
22
  <script type="text/javascript">
24
23
  document.getElementById('stats').innerHTML = "<%= @stats[:scenarios] %><br/><%= @stats[:steps] %>";
@@ -26,31 +25,31 @@
26
25
 
27
26
  <% @features.each do |feature| %>
28
27
  <div class="feature">
29
- <h2><span class="val">Feature: <%= feature['short_name'] %></span></h2>
30
- <p class="narrative"><%= feature['description'].join '<br/>' %><bbr/r></p>
28
+ <h2><span class="val"><%= feature[:keyword] %>: <%= feature[:short_name] %></span></h2>
29
+ <p class="narrative"><%= feature[:description].join '<br/>' %><bbr/r></p>
31
30
 
32
- <% feature['scenarios'].each do |scenario| %>
31
+ <% feature[:scenarios].each do |scenario| %>
33
32
  <div class="scenario">
34
- <span style="display: block;" class="scenario_file"><%= scenario['file_colon_line'] %></span>
35
- <h3 style="cursor: pointer;" id="<%= scenario['id'] %>">
36
- <span class="keyword"><%= scenario['keyword'] %>: </span><span class="val"><%= scenario['name'] %></span>
33
+ <span style="display: block;" class="scenario_file"><%= scenario[:file_colon_line] %></span>
34
+ <h3 style="cursor: pointer;" id="<%= scenario[:id] %>">
35
+ <span class="keyword"><%= scenario[:keyword] %>: </span><span class="val"><%= scenario[:name] %></span>
37
36
  </h3>
38
- <script><%= scenario['status'] %>Colors('<%= scenario['id'] %>');</script>
37
+ <script><%= scenario[:status] %>Colors('<%= scenario[:id] %>');</script>
39
38
  <ol style="display: block;">
40
- <% scenario['steps'].each do |step| %>
41
- <li id="features_" class="step <%= step['status'] %>">
39
+ <% scenario[:steps].each do |step| %>
40
+ <li id="features_" class="step <%= step[:status] %>">
42
41
  <div class="step_name">
43
- <span class="keyword"><%= step['keyword'] %></span><span class="step val"><%= step['name'] %></span>
42
+ <span class="keyword"><%= step[:keyword] %></span><span class="step val"><%= step[:name] %></span>
44
43
  </div>
45
- <div class="step_file"><span><%= step['file_colon_line'] %></span></div>
46
- <% if step['exception'] %>
47
- <div class="message"><pre><%= step['exception']['message'] %></pre></div>
48
- <div class="backtrace"><pre><%= step['exception']['backtrace'].gsub('\n', '<br/>') %></pre></div>
49
- <%= snippet step['exception'] %>
44
+ <div class="step_file"><span><%= step[:file_colon_line] %></span></div>
45
+ <% if step[:exception] %>
46
+ <div class="message"><pre><%= step[:exception][:message] %></pre></div>
47
+ <div class="backtrace"><pre><%= step[:exception][:backtrace].gsub('\n', '<br/>') %></pre></div>
48
+ <%= code_snippet_for step[:exception] %>
50
49
  <% end %>
51
- <% unless step['table'].empty? %>
50
+ <% unless step[:table].empty? %>
52
51
  <table>
53
- <% step['table'].each_with_index do |rowdata, row| %>
52
+ <% step[:table].each_with_index do |rowdata, row| %>
54
53
  <tr class='step' id='row_-<%= row %>'>
55
54
  <% rowdata.each_with_index do |value, col| %>
56
55
  <td class="step" id="row_-<%= row %>_<%= col %>"><div><span class="step param"><%= value %></span></div></td>
@@ -59,8 +58,8 @@
59
58
  <% end %>
60
59
  </table>
61
60
  <% end %>
62
- <% if step['multiline_string'] %>
63
- <pre class="val"><%= step['multiline_string'] %></pre>
61
+ <% if step[:multiline_string] %>
62
+ <pre class="val"><%= step[:multiline_string] %></pre>
64
63
  <% end %>
65
64
  </li>
66
65
  <% end %>
@@ -0,0 +1,86 @@
1
+ require 'cuukie/cli'
2
+ require 'stringio'
3
+
4
+ describe "The parse_options method" do
5
+ include Cuukie::Cli
6
+
7
+ before :each do
8
+ @out = ''
9
+ def @out.write(data); self << data; end
10
+ @old_stdout, $stdout = $stdout, @out
11
+ end
12
+
13
+ after :each do
14
+ $stdout = @old_stdout
15
+ end
16
+
17
+ it "recognizes --server" do
18
+ parse_options(['--server'])[:server].should be_true
19
+ end
20
+
21
+ it "defaults to --server = false" do
22
+ parse_options([])[:server].should be_false
23
+ end
24
+
25
+ it "recognizes --cuukieport" do
26
+ parse_options(['--cuukieport', '4570'])[:cuukieport].should == 4570
27
+ end
28
+
29
+ it "defaults to --cuukieport 4569" do
30
+ parse_options([])[:cuukieport].should == 4569
31
+ end
32
+
33
+ it "raises error on bad --cuukieport" do
34
+ lambda { parse_options ['--cuukieport', 'abc'] }.should raise_error
35
+ lambda { parse_options ['--cuukieport'] }.should raise_error
36
+ end
37
+
38
+ it "recognizes --showpage" do
39
+ parse_options(['--showpage'])[:showpage].should be_true
40
+ end
41
+
42
+ it "defaults to --showpage = false" do
43
+ parse_options([])[:showpage].should be_false
44
+ end
45
+
46
+ it "recognizes --nowait" do
47
+ parse_options(['--nowait'])[:nowait].should be_true
48
+ end
49
+
50
+ it "defaults to --nowait = false" do
51
+ parse_options([])[:nowait].should be_false
52
+ end
53
+
54
+ it "recognizes --keepserver" do
55
+ parse_options(['--keepserver'])[:keepserver].should be_true
56
+ end
57
+
58
+ it "defaults to --keepserver = false" do
59
+ parse_options(['--nowait'])[:keepserver].should be_false
60
+ end
61
+
62
+ it "shows the help with -h" do
63
+ parse_options ['-h']
64
+ @out.should match /Usage: cuukie \[/
65
+ end
66
+
67
+ it "shows the help with --help" do
68
+ parse_options ['--help']
69
+ @out.should match /Usage: cuukie \[/
70
+ end
71
+
72
+ it "the help text includes the version of Cuukie" do
73
+ parse_options ['-h']
74
+ @out.should match /cuukie \d+\.\d+\.\d+/
75
+ end
76
+
77
+ it "returns no result after showing help" do
78
+ parse_options(['-h']).should be_empty
79
+ end
80
+
81
+ it "consumes recognized options" do
82
+ options = ['--showpage', '--invalid', '--cuukieport', '4570']
83
+ parse_options options
84
+ options.should == ['--invalid']
85
+ end
86
+ end
@@ -1,4 +1,4 @@
1
- require 'cuukie/cucumber/formatter/code_snippets'
1
+ require 'cuukie/code_snippets'
2
2
  require 'tempfile'
3
3
 
4
4
  describe "The code_snippet method" do
@@ -31,12 +31,12 @@ SOURCE
31
31
  snippet['lines'].should be_nil
32
32
  end
33
33
 
34
- it "returns nil if the file is not valid" do
34
+ it "returns a nil snippet if the file is not valid" do
35
35
  snippet = code_snippet '', 4
36
36
  snippet['lines'].should be_nil
37
37
  end
38
38
 
39
- it "returns nil if it cannot find the line" do
39
+ it "returns a nil snippet if it cannot find the line" do
40
40
  snippet = code_snippet @source.path, 7
41
41
  snippet['lines'].should be_nil
42
42
  end
@@ -87,7 +87,7 @@ SOURCE
87
87
  end
88
88
  end
89
89
 
90
- it "returns nil if the extraction fails" do
90
+ it "returns a nil snippet if the extraction fails" do
91
91
  backtrace_to_snippet(['abcd'])['lines'].should be_nil
92
92
  end
93
93
  end