aslakhellesoy-cucumber 0.1.12 → 0.1.13
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +38 -3
- data/Manifest.txt +17 -1
- data/README.txt +2 -39
- data/bin/cucumber +1 -1
- data/examples/calculator_ruby_features/features/addition.rb +16 -0
- data/examples/i18n/ar/features/step_definitons/calculator_steps.rb +1 -1
- data/examples/i18n/da/features/step_definitons/kalkulator_steps.rb +1 -0
- data/examples/i18n/de/features/step_definitons/calculator_steps.rb +1 -0
- data/examples/i18n/en/features/step_definitons/calculator_steps.rb +1 -0
- data/examples/i18n/es/features/step_definitons/calculador_steps.rb +1 -0
- data/examples/i18n/et/features/step_definitions/kalkulaator_steps.rb +1 -0
- data/examples/i18n/fr/features/addition.feature +13 -11
- data/examples/i18n/fr/features/step_definitions/calculatrice_steps.rb +6 -2
- data/examples/i18n/id/features/step_definitons/calculator_steps.rb +1 -0
- data/examples/i18n/it/features/step_definitons/calcolatrice_steps.rb +1 -0
- data/examples/i18n/ja/features/step_definitons/calculator_steps.rb +2 -0
- data/examples/i18n/lt/features/step_definitons/calculator_steps.rb +1 -0
- data/examples/i18n/no/features/step_definitons/kalkulator_steps.rb +1 -0
- data/examples/i18n/pt/features/step_definitions/calculadora_steps.rb +1 -0
- data/examples/i18n/ro/features/step_definitons/calculator_steps.rb +1 -0
- data/examples/i18n/se/features/step_definitons/kalkulator_steps.rb +1 -0
- data/examples/i18n/zh-CN/features/step_definitons/calculator_steps.rb +1 -0
- data/examples/selenium/features/search.feature +1 -1
- data/examples/selenium/features/step_definitons/stories_steps.rb +2 -3
- data/examples/tickets/features/lib/eatting_machine.rb +18 -0
- data/examples/tickets/features/lib/pantry.rb +20 -0
- data/examples/tickets/features/scenario_outline.feature +64 -0
- data/examples/tickets/features/step_definitons/scenario_outline_steps.rb +34 -0
- data/examples/tickets/features/step_definitons/tickets_steps.rb +4 -0
- data/gem_tasks/fix_cr_lf.rake +1 -1
- data/gem_tasks/yard.rake +8 -0
- data/lib/autotest/cucumber_mixin.rb +3 -3
- data/lib/cucumber/broadcaster.rb +1 -1
- data/lib/cucumber/cli.rb +87 -42
- data/lib/cucumber/core_ext/exception.rb +20 -0
- data/lib/cucumber/core_ext/string.rb +1 -1
- data/lib/cucumber/executor.rb +35 -18
- data/lib/cucumber/formatters/ansicolor.rb +65 -74
- data/lib/cucumber/formatters/html_formatter.rb +33 -10
- data/lib/cucumber/formatters/pretty_formatter.rb +58 -16
- data/lib/cucumber/formatters/progress_formatter.rb +3 -0
- data/lib/cucumber/formatters/unicode.rb +27 -0
- data/lib/cucumber/languages.yml +6 -4
- data/lib/cucumber/platform.rb +1 -0
- data/lib/cucumber/rails/world.rb +6 -6
- data/lib/cucumber/step_mother.rb +3 -0
- data/lib/cucumber/tree/feature.rb +28 -2
- data/lib/cucumber/tree/scenario.rb +62 -1
- data/lib/cucumber/tree/step.rb +32 -1
- data/lib/cucumber/treetop_parser/feature.treetop.erb +54 -7
- data/lib/cucumber/treetop_parser/feature_ar.rb +377 -18
- data/lib/cucumber/treetop_parser/feature_cy.rb +377 -18
- data/lib/cucumber/treetop_parser/feature_da.rb +377 -18
- data/lib/cucumber/treetop_parser/feature_de.rb +377 -18
- data/lib/cucumber/treetop_parser/feature_en-lol.rb +377 -18
- data/lib/cucumber/treetop_parser/feature_en-tx.rb +377 -18
- data/lib/cucumber/treetop_parser/feature_en.rb +377 -18
- data/lib/cucumber/treetop_parser/feature_es.rb +377 -18
- data/lib/cucumber/treetop_parser/feature_et.rb +377 -18
- data/lib/cucumber/treetop_parser/feature_fr.rb +389 -30
- data/lib/cucumber/treetop_parser/feature_id.rb +377 -18
- data/lib/cucumber/treetop_parser/feature_it.rb +377 -18
- data/lib/cucumber/treetop_parser/feature_ja.rb +377 -18
- data/lib/cucumber/treetop_parser/feature_lt.rb +377 -18
- data/lib/cucumber/treetop_parser/feature_nl.rb +377 -18
- data/lib/cucumber/treetop_parser/feature_no.rb +377 -18
- data/lib/cucumber/treetop_parser/feature_pl.rb +377 -18
- data/lib/cucumber/treetop_parser/feature_pt.rb +377 -18
- data/lib/cucumber/treetop_parser/feature_ro.rb +377 -18
- data/lib/cucumber/treetop_parser/feature_ro2.rb +377 -18
- data/lib/cucumber/treetop_parser/feature_ru.rb +377 -18
- data/lib/cucumber/treetop_parser/feature_se.rb +377 -18
- data/lib/cucumber/treetop_parser/feature_zh-CN.rb +377 -18
- data/lib/cucumber/version.rb +1 -1
- data/lib/cucumber/world/pending.rb +22 -0
- data/lib/cucumber/world.rb +1 -0
- data/lib/cucumber.rb +2 -0
- data/rails_generators/cucumber/templates/env.rb +1 -0
- data/rails_generators/feature/feature_generator.rb +22 -2
- data/rails_generators/feature/templates/feature.erb +15 -12
- data/rails_generators/feature/templates/steps.erb +16 -14
- data/spec/cucumber/cli_spec.rb +87 -6
- data/spec/cucumber/executor_spec.rb +102 -30
- data/spec/cucumber/formatters/ansicolor_spec.rb +10 -10
- data/spec/cucumber/formatters/html_formatter_spec.rb +30 -0
- data/spec/cucumber/formatters/pretty_formatter_spec.rb +139 -4
- data/spec/cucumber/formatters/progress_formatter_spec.rb +16 -0
- data/spec/cucumber/tree/feature_spec.rb +84 -5
- data/spec/cucumber/tree/row_scenario_outline_spec.rb +73 -0
- data/spec/cucumber/tree/row_step_outline_spec.rb +38 -0
- data/spec/cucumber/tree/scenario_outline_spec.rb +50 -0
- data/spec/cucumber/tree/step_outline_spec.rb +17 -0
- data/spec/cucumber/tree/step_spec.rb +9 -0
- data/spec/cucumber/treetop_parser/empty_scenario_outline.feature +3 -0
- data/spec/cucumber/treetop_parser/feature_parser_spec.rb +22 -0
- data/spec/cucumber/treetop_parser/invalid_scenario_outlines.feature +7 -0
- data/spec/cucumber/treetop_parser/scenario_outline.feature +16 -0
- data/spec/cucumber/world/pending_spec.rb +46 -0
- data/spec/spec_helper.rb +2 -1
- metadata +19 -4
- data/TODO.txt +0 -26
data/lib/cucumber/cli.rb
CHANGED
@@ -2,13 +2,15 @@ require 'optparse'
|
|
2
2
|
require 'cucumber'
|
3
3
|
|
4
4
|
module Cucumber
|
5
|
+
class YmlLoadError < StandardError; end
|
6
|
+
|
5
7
|
class CLI
|
6
8
|
class << self
|
7
9
|
attr_writer :step_mother, :executor, :features
|
8
10
|
|
9
|
-
def execute
|
11
|
+
def execute(args)
|
10
12
|
@execute_called = true
|
11
|
-
parse(
|
13
|
+
parse(args).execute!(@step_mother, @executor, @features)
|
12
14
|
end
|
13
15
|
|
14
16
|
def execute_called?
|
@@ -44,11 +46,16 @@ module Cucumber
|
|
44
46
|
end
|
45
47
|
|
46
48
|
def parse_options!(args)
|
49
|
+
@args = args
|
47
50
|
return parse_args_from_profile('default') if args.empty?
|
48
51
|
args.extend(OptionParser::Arguable)
|
49
52
|
|
50
53
|
args.options do |opts|
|
51
|
-
opts.banner = "Usage: cucumber [options] FILES|DIRS"
|
54
|
+
opts.banner = ["Usage: cucumber [options] [[FILE[:LINE[:LINE]*]] | [FILES|DIRS]]", "",
|
55
|
+
"Examples:",
|
56
|
+
"cucumber examples/i18n/en/features",
|
57
|
+
"cucumber --language it examples/i18n/it/features/somma.feature:6:98:113", "", ""
|
58
|
+
].join("\n")
|
52
59
|
opts.on("-r LIBRARY|DIR", "--require LIBRARY|DIR", "Require files before executing the features.",
|
53
60
|
"If this option is not specified, all *.rb files that",
|
54
61
|
"are siblings or below the features will be autorequired",
|
@@ -62,7 +69,7 @@ module Cucumber
|
|
62
69
|
@options[:scenario_names] ||= []
|
63
70
|
@options[:scenario_names] << v
|
64
71
|
end
|
65
|
-
opts.on("-
|
72
|
+
opts.on("-l LANG", "--language LANG", "Specify language for features (Default: #{@options[:lang]})",
|
66
73
|
"Available languages: #{Cucumber.languages.join(", ")}",
|
67
74
|
"Look at #{Cucumber::LANGUAGE_FILE} for keywords") do |v|
|
68
75
|
@options[:lang] = v
|
@@ -113,6 +120,9 @@ module Cucumber
|
|
113
120
|
@options[:snippets] = false
|
114
121
|
@options[:source] = false
|
115
122
|
end
|
123
|
+
opts.on("-b", "--backtrace", "Show full backtrace for all errors") do
|
124
|
+
Exception.cucumber_full_backtrace = true
|
125
|
+
end
|
116
126
|
opts.on("-v", "--verbose", "Show the files and features loaded") do
|
117
127
|
@options[:verbose] = true
|
118
128
|
end
|
@@ -135,33 +145,12 @@ module Cucumber
|
|
135
145
|
@paths += args
|
136
146
|
end
|
137
147
|
|
138
|
-
def parse_args_from_profile(profile)
|
139
|
-
unless File.exist?('cucumber.yml')
|
140
|
-
return exit_with_error("cucumber.yml was not found. Please define your '#{profile}' and other profiles in cucumber.yml.\n"+
|
141
|
-
"Type 'cucumber --help' for usage.\n")
|
142
|
-
end
|
143
|
-
|
144
|
-
require 'yaml'
|
145
|
-
cucumber_yml = YAML::load(IO.read('cucumber.yml'))
|
146
|
-
args_from_yml = cucumber_yml[profile]
|
147
|
-
if args_from_yml.nil?
|
148
|
-
exit_with_error <<-END_OF_ERROR
|
149
|
-
Could not find profile: '#{profile}'
|
150
|
-
|
151
|
-
Defined profiles in cucumber.yml:
|
152
|
-
* #{cucumber_yml.keys.join("\n * ")}
|
153
|
-
END_OF_ERROR
|
154
|
-
elsif !args_from_yml.is_a?(String)
|
155
|
-
exit_with_error "Profiles must be defined as a String. The '#{profile}' profile was #{args_from_yml.inspect} (#{args_from_yml.class}).\n"
|
156
|
-
else
|
157
|
-
parse_options!(args_from_yml.split(' '))
|
158
|
-
end
|
159
|
-
end
|
160
148
|
|
161
149
|
def execute!(step_mother, executor, features)
|
162
150
|
Term::ANSIColor.coloring = @options[:color] unless @options[:color].nil?
|
163
151
|
Cucumber.load_language(@options[:lang])
|
164
152
|
require_files
|
153
|
+
enable_diffing
|
165
154
|
executor.formatters = build_formatter_broadcaster(step_mother)
|
166
155
|
load_plain_text_features(features)
|
167
156
|
executor.lines_for_features = @options[:lines_for_features]
|
@@ -183,20 +172,60 @@ Defined profiles in cucumber.yml:
|
|
183
172
|
arg
|
184
173
|
end
|
185
174
|
end
|
186
|
-
|
175
|
+
|
176
|
+
def cucumber_yml
|
177
|
+
return @cucumber_yml if @cucumber_yml
|
178
|
+
unless File.exist?('cucumber.yml')
|
179
|
+
raise(YmlLoadError,"cucumber.yml was not found. Please refer to cucumber's documentaion on defining profiles in cucumber.yml. You must define a 'default' profile to use the cucumber command without any arguments.\nType 'cucumber --help' for usage.\n")
|
180
|
+
end
|
181
|
+
|
182
|
+
require 'yaml'
|
183
|
+
begin
|
184
|
+
@cucumber_yml = YAML::load(IO.read('cucumber.yml'))
|
185
|
+
rescue Exception => e
|
186
|
+
raise(YmlLoadError,"cucumber.yml was found, but could not be parsed. Please refer to cucumber's documentaion on correct profile usage.\n")
|
187
|
+
end
|
188
|
+
|
189
|
+
if @cucumber_yml.nil? || !@cucumber_yml.is_a?(Hash)
|
190
|
+
raise(YmlLoadError,"cucumber.yml was found, but was blank or malformed. Please refer to cucumber's documentaion on correct profile usage.\n")
|
191
|
+
end
|
192
|
+
|
193
|
+
return @cucumber_yml
|
194
|
+
end
|
195
|
+
|
196
|
+
def parse_args_from_profile(profile)
|
197
|
+
unless cucumber_yml.has_key?(profile)
|
198
|
+
return(exit_with_error <<-END_OF_ERROR)
|
199
|
+
Could not find profile: '#{profile}'
|
200
|
+
|
201
|
+
Defined profiles in cucumber.yml:
|
202
|
+
* #{cucumber_yml.keys.join("\n * ")}
|
203
|
+
END_OF_ERROR
|
204
|
+
end
|
205
|
+
|
206
|
+
args_from_yml = cucumber_yml[profile] || ''
|
207
|
+
|
208
|
+
if !args_from_yml.is_a?(String)
|
209
|
+
exit_with_error "Profiles must be defined as a String. The '#{profile}' profile was #{args_from_yml.inspect} (#{args_from_yml.class}).\n"
|
210
|
+
elsif args_from_yml =~ /^\s*$/
|
211
|
+
exit_with_error "The 'foo' profile in cucumber.yml was blank. Please define the command line arguments for the 'foo' profile in cucumber.yml.\n"
|
212
|
+
else
|
213
|
+
parse_options!(args_from_yml.split(' '))
|
214
|
+
end
|
215
|
+
|
216
|
+
rescue YmlLoadError => e
|
217
|
+
exit_with_error(e.message)
|
218
|
+
end
|
219
|
+
|
220
|
+
|
187
221
|
# Requires files - typically step files and ruby feature files.
|
188
222
|
def require_files
|
189
|
-
|
223
|
+
@args.clear # Shut up RSpec
|
190
224
|
require "cucumber/treetop_parser/feature_#{@options[:lang]}"
|
191
225
|
require "cucumber/treetop_parser/feature_parser"
|
192
226
|
|
193
227
|
verbose_log("Ruby files required:")
|
194
|
-
|
195
|
-
libs = requires.map do |path|
|
196
|
-
path = path.gsub(/\\/, '/') # In case we're on windows. Globs don't work with backslashes.
|
197
|
-
File.directory?(path) ? Dir["#{path}/**/*.rb"] : path
|
198
|
-
end.flatten.uniq
|
199
|
-
libs.each do |lib|
|
228
|
+
files_to_require.each do |lib|
|
200
229
|
begin
|
201
230
|
require lib
|
202
231
|
verbose_log(" * #{lib}")
|
@@ -207,6 +236,15 @@ Defined profiles in cucumber.yml:
|
|
207
236
|
end
|
208
237
|
verbose_log("\n")
|
209
238
|
end
|
239
|
+
|
240
|
+
def files_to_require
|
241
|
+
requires = @options[:require] || feature_dirs
|
242
|
+
files = requires.map do |path|
|
243
|
+
path = path.gsub(/\\/, '/') # In case we're on windows. Globs don't work with backslashes.
|
244
|
+
File.directory?(path) ? Dir["#{path}/**/*.rb"] : path
|
245
|
+
end.flatten.uniq
|
246
|
+
files.sort { |a,b| (b =~ %r{/support/} || -1) <=> (a =~ %r{/support/} || -1) }
|
247
|
+
end
|
210
248
|
|
211
249
|
def feature_files
|
212
250
|
potential_feature_files = @paths.map do |path|
|
@@ -280,14 +318,14 @@ Defined profiles in cucumber.yml:
|
|
280
318
|
private
|
281
319
|
|
282
320
|
def constantize(camel_cased_word)
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
321
|
+
names = camel_cased_word.split('::')
|
322
|
+
names.shift if names.empty? || names.first.empty?
|
323
|
+
|
324
|
+
constant = Object
|
325
|
+
names.each do |name|
|
326
|
+
constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
|
327
|
+
end
|
328
|
+
constant
|
291
329
|
end
|
292
330
|
|
293
331
|
def verbose_log(string)
|
@@ -303,6 +341,13 @@ Defined profiles in cucumber.yml:
|
|
303
341
|
Kernel.exit 1
|
304
342
|
end
|
305
343
|
|
344
|
+
def enable_diffing
|
345
|
+
if defined?(::Spec)
|
346
|
+
require 'spec/expectations/differs/default'
|
347
|
+
options = ::Spec::Runner::Options.new(nil, nil)
|
348
|
+
::Spec::Expectations.differ = ::Spec::Expectations::Differs::Default.new(options)
|
349
|
+
end
|
350
|
+
end
|
306
351
|
end
|
307
352
|
end
|
308
353
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Exception
|
2
|
+
CUCUMBER_FILTER_PATTERNS = [
|
3
|
+
/vendor\/rails/,
|
4
|
+
/vendor\/plugins\/cucumber/,
|
5
|
+
/spec\/expectations/,
|
6
|
+
/spec\/matchers/
|
7
|
+
]
|
8
|
+
|
9
|
+
def self.cucumber_full_backtrace=(v)
|
10
|
+
@@cucumber_full_backtrace = v
|
11
|
+
end
|
12
|
+
self.cucumber_full_backtrace = false
|
13
|
+
|
14
|
+
def cucumber_backtrace
|
15
|
+
return (backtrace || []) if @@cucumber_full_backtrace
|
16
|
+
(backtrace || []).map {|b| b.split("\n") }.flatten.reject do |line|
|
17
|
+
CUCUMBER_FILTER_PATTERNS.detect{|p| line =~ p}
|
18
|
+
end.map { |line| line.strip }
|
19
|
+
end
|
20
|
+
end
|
data/lib/cucumber/executor.rb
CHANGED
@@ -65,6 +65,10 @@ module Cucumber
|
|
65
65
|
visit_scenario(scenario)
|
66
66
|
end
|
67
67
|
|
68
|
+
def visit_scenario_outline(scenario)
|
69
|
+
visit_regular_scenario(scenario)
|
70
|
+
end
|
71
|
+
|
68
72
|
def visit_scenario(scenario)
|
69
73
|
if accept_scenario?(scenario)
|
70
74
|
@executed_scenarios[scenario.name] = true
|
@@ -77,8 +81,6 @@ module Cucumber
|
|
77
81
|
@pending = nil
|
78
82
|
|
79
83
|
@world = create_world
|
80
|
-
@world.extend(Spec::Matchers) if defined?(Spec::Matchers)
|
81
|
-
define_step_call_methods(@world)
|
82
84
|
|
83
85
|
formatters.scenario_executing(scenario)
|
84
86
|
@before_scenario_procs.each{|p| p.call_in(@world, *[])}
|
@@ -104,6 +106,11 @@ module Cucumber
|
|
104
106
|
visit_step(step)
|
105
107
|
end
|
106
108
|
|
109
|
+
def visit_step_outline(step)
|
110
|
+
regexp, args, proc = step.regexp_args_proc(@step_mother)
|
111
|
+
formatters.step_traced(step, regexp, args)
|
112
|
+
end
|
113
|
+
|
107
114
|
def visit_step(step)
|
108
115
|
unless @pending || @error
|
109
116
|
begin
|
@@ -112,6 +119,9 @@ module Cucumber
|
|
112
119
|
step.execute_in(@world, regexp, args, proc)
|
113
120
|
@after_step_procs.each{|p| p.call_in(@world, *[])}
|
114
121
|
formatters.step_passed(step, regexp, args)
|
122
|
+
rescue ForcedPending => e
|
123
|
+
step.error = e
|
124
|
+
record_pending_step(step, regexp, args)
|
115
125
|
rescue Pending
|
116
126
|
record_pending_step(step, regexp, args)
|
117
127
|
rescue => e
|
@@ -124,6 +134,9 @@ module Cucumber
|
|
124
134
|
regexp, args, proc = step.regexp_args_proc(@step_mother)
|
125
135
|
step.execute_in(@world, regexp, args, proc)
|
126
136
|
formatters.step_skipped(step, regexp, args)
|
137
|
+
rescue ForcedPending => e
|
138
|
+
step.error = e
|
139
|
+
record_pending_step(step, regexp, args)
|
127
140
|
rescue Pending
|
128
141
|
record_pending_step(step, regexp, args)
|
129
142
|
rescue Exception
|
@@ -137,22 +150,6 @@ module Cucumber
|
|
137
150
|
formatters.step_pending(step, regexp, args)
|
138
151
|
end
|
139
152
|
|
140
|
-
def define_step_call_methods(world)
|
141
|
-
world.instance_variable_set('@__executor', self)
|
142
|
-
world.instance_eval do
|
143
|
-
class << self
|
144
|
-
def run_step(name)
|
145
|
-
_, args, proc = @__executor.instance_variable_get(:@step_mother).regexp_args_proc(name)
|
146
|
-
proc.call_in(self, *args)
|
147
|
-
end
|
148
|
-
|
149
|
-
%w{given when then and but}.each do |keyword|
|
150
|
-
alias_method Cucumber.language[keyword], :run_step
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
153
|
def executing_unprepared_row_scenario?(scenario)
|
157
154
|
accept_scenario?(scenario) && !@executed_scenarios[scenario.name]
|
158
155
|
end
|
@@ -182,7 +179,27 @@ module Cucumber
|
|
182
179
|
@world_procs.each do |world_proc|
|
183
180
|
world = world_proc.call(world)
|
184
181
|
end
|
182
|
+
|
183
|
+
world.extend(World::Pending)
|
184
|
+
world.extend(::Spec::Matchers) if defined?(::Spec::Matchers)
|
185
|
+
define_step_call_methods(world)
|
185
186
|
world
|
186
187
|
end
|
188
|
+
|
189
|
+
def define_step_call_methods(world)
|
190
|
+
world.instance_variable_set('@__executor', self)
|
191
|
+
world.instance_eval do
|
192
|
+
class << self
|
193
|
+
def run_step(name)
|
194
|
+
_, args, proc = @__executor.instance_variable_get(:@step_mother).regexp_args_proc(name)
|
195
|
+
proc.call_in(self, *args)
|
196
|
+
end
|
197
|
+
|
198
|
+
%w{given when then and but}.each do |keyword|
|
199
|
+
alias_method Cucumber.language[keyword], :run_step
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
187
204
|
end
|
188
205
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# Hack to work around Win32/Console, which bundles a licence-violating, outdated
|
2
|
-
# copy of term/ansicolor that doesn't implement Term::ANSIColor#coloring=.
|
2
|
+
# copy of term/ansicolor that doesn't implement Term::ANSIColor#coloring=.
|
3
3
|
# We want the official one!
|
4
4
|
gem 'term-ansicolor'
|
5
5
|
$LOAD_PATH.each{|path| $LOAD_PATH.unshift($LOAD_PATH.delete(path)) if path =~ /term-ansicolor/}
|
@@ -7,7 +7,7 @@ require 'term/ansicolor'
|
|
7
7
|
|
8
8
|
if $CUCUMBER_WINDOWS_MRI
|
9
9
|
begin
|
10
|
-
require 'Win32/Console/ANSI'
|
10
|
+
require 'Win32/Console/ANSI'
|
11
11
|
rescue LoadError
|
12
12
|
STDERR.puts "You must gem install win32console to get coloured output on MRI/Windows"
|
13
13
|
Term::ANSIColor.coloring = false
|
@@ -18,92 +18,83 @@ Term::ANSIColor.coloring = false if !STDOUT.tty? || ($CUCUMBER_WINDOWS && !$CUCU
|
|
18
18
|
|
19
19
|
module Cucumber
|
20
20
|
module Formatters
|
21
|
-
#
|
22
|
-
#
|
21
|
+
# Defines aliases for coloured output. You can tweak the colours by defining
|
22
|
+
# a <tt>$CUCUMBER_COLORS</tt> variable in your shell, very much like you can
|
23
|
+
# tweak the familiar POSIX command <tt>ls</tt> with
|
24
|
+
# <a href="http://mipsisrisc.com/rambling/2008/06/27/lscolorsls_colors-now-with-linux-support/">$LSCOLORS/$LS_COLORS</a>
|
23
25
|
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
# The string must be a series of key=value pairs where:
|
26
|
+
# The colours that you can change are:
|
27
27
|
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
# ** bold
|
39
|
-
# ** dark
|
40
|
-
# ** italic
|
41
|
-
# ** underline
|
42
|
-
# ** underscore
|
43
|
-
# ** blink
|
44
|
-
# ** rapid_blink
|
45
|
-
# ** negative
|
46
|
-
# ** concealed
|
47
|
-
# ** strikethrough
|
48
|
-
# ** black
|
49
|
-
# ** red
|
50
|
-
# ** green
|
51
|
-
# ** yellow
|
52
|
-
# ** blue
|
53
|
-
# ** magenta
|
54
|
-
# ** cyan
|
55
|
-
# ** white
|
56
|
-
# ** grey
|
57
|
-
# ** on_black
|
58
|
-
# ** on_red
|
59
|
-
# ** on_green
|
60
|
-
# ** on_yellow
|
61
|
-
# ** on_blue
|
62
|
-
# ** on_magenta
|
63
|
-
# ** on_cyan
|
64
|
-
# ** on_white
|
28
|
+
# * <tt>pending</tt> - defaults to <tt>yellow</tt>
|
29
|
+
# * <tt>pending_param</tt> - defaults to <tt>yellow,bold</tt>
|
30
|
+
# * <tt>failed</tt> - defaults to <tt>red</tt>
|
31
|
+
# * <tt>failed_param</tt> - defaults to <tt>red,bold</tt>
|
32
|
+
# * <tt>passed</tt> - defaults to <tt>green</tt>
|
33
|
+
# * <tt>passed_param</tt> - defaults to <tt>green,bold</tt>
|
34
|
+
# * <tt>skipped</tt> - defaults to <tt>cyan</tt>
|
35
|
+
# * <tt>skipped_param</tt> - defaults to <tt>cyan,bold</tt>
|
36
|
+
# * <tt>comment</tt> - defaults to <tt>grey</tt>
|
37
|
+
# * <tt>tag</tt> - defaults to <tt>blue</tt>
|
65
38
|
#
|
39
|
+
# For instance, if your shell has a black background and a green font (like the
|
40
|
+
# "Homebrew" settings for OS X' Terminal.app), you may want to override passed
|
41
|
+
# steps to be white instead of green. Examples:
|
42
|
+
#
|
43
|
+
# export CUCUMBER_COLORS="passed=white"
|
44
|
+
# export CUCUMBER_COLORS="passed=white,bold:passed_param=white,bold,underline"
|
45
|
+
#
|
46
|
+
# (If you're on Windows, use SET instead of export).
|
47
|
+
# To see what colours and effects are available, just run this in your shell:
|
48
|
+
#
|
49
|
+
# ruby -e "require 'rubygems'; require 'term/ansicolor'; puts Term::ANSIColor.attributes"
|
50
|
+
#
|
51
|
+
# Although not listed, you can also use <tt>grey</tt>
|
66
52
|
module ANSIColor
|
67
|
-
include
|
68
|
-
|
69
|
-
# Params are underlined bold, except in windows, which doesn't support underline. Use non-bold colour.
|
70
|
-
param = PLATFORM =~ /mswin|mingw/ ? '' : 'underline,bold,'
|
53
|
+
include Term::ANSIColor
|
71
54
|
|
72
|
-
# Default aliases
|
73
|
-
ALIASES = {
|
74
|
-
:passed => 'bold,green',
|
75
|
-
:passed_param => "#{param}green",
|
76
|
-
:failed => 'bold,red',
|
77
|
-
:failed_param => "#{param}red",
|
78
|
-
:skipped => 'bold,cyan',
|
79
|
-
:skipped_param => "#{param}cyan",
|
80
|
-
:pending => 'bold,yellow', # No pending_param
|
81
|
-
:comment => 'grey'
|
82
|
-
}
|
83
|
-
if ENV['CUCUMBER_COLORS']
|
84
|
-
ENV['CUCUMBER_COLORS'].split(':').each do |pair|
|
85
|
-
a = pair.split('=')
|
86
|
-
ALIASES[a[0].to_sym] = a[1]
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
55
|
# Not supported in Term::ANSIColor
|
91
56
|
def grey(m)
|
92
57
|
if ::Term::ANSIColor.coloring?
|
93
|
-
"\e[90m#{m}\e[0m"
|
58
|
+
"\e[90m#{m}\e[0m"
|
94
59
|
else
|
95
60
|
m
|
96
61
|
end
|
97
62
|
end
|
98
|
-
|
99
|
-
ALIASES.
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
63
|
+
|
64
|
+
ALIASES = Hash.new do |h,k|
|
65
|
+
if k.to_s =~ /(.*)_param/
|
66
|
+
h[$1] + ',bold'
|
67
|
+
end
|
68
|
+
end.merge({
|
69
|
+
'pending' => 'yellow',
|
70
|
+
'failed' => 'red',
|
71
|
+
'passed' => 'green',
|
72
|
+
'skipped' => 'cyan',
|
73
|
+
'comment' => 'grey',
|
74
|
+
'tag' => 'blue'
|
75
|
+
})
|
76
|
+
|
77
|
+
if ENV['CUCUMBER_COLORS'] # Example: export CUCUMBER_COLORS="passed=red:failed=yellow"
|
78
|
+
ENV['CUCUMBER_COLORS'].split(':').each do |pair|
|
79
|
+
a = pair.split('=')
|
80
|
+
ALIASES[a[0]] = a[1]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
ALIASES.each do |method, color|
|
85
|
+
unless method =~ /.*_param/
|
86
|
+
code = <<-EOF
|
87
|
+
def #{method}(string=nil, &proc)
|
88
|
+
#{ALIASES[method].split(",").join("(") + "(string, &proc" + ")" * ALIASES[method].split(",").length}
|
104
89
|
end
|
90
|
+
# This resets the colour to the non-param colour
|
91
|
+
def #{method}_param(string=nil, &proc)
|
92
|
+
#{ALIASES[method+'_param'].split(",").join("(") + "(string, &proc" + ")" * ALIASES[method+'_param'].split(",").length} + #{ALIASES[method].split(",").join(' + ')}
|
93
|
+
end
|
94
|
+
EOF
|
95
|
+
eval(code)
|
105
96
|
end
|
106
97
|
end
|
107
98
|
end
|
108
99
|
end
|
109
|
-
end
|
100
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
1
3
|
module Cucumber
|
2
4
|
module Formatters
|
3
5
|
class HtmlFormatter
|
@@ -53,15 +55,11 @@ HTML
|
|
53
55
|
end
|
54
56
|
|
55
57
|
def visit_regular_scenario(scenario)
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
scenario.accept(self)
|
62
|
-
@io.puts %{ </ul>}
|
63
|
-
@io.puts %{ </dd>}
|
64
|
-
@io.puts %{ </dl>}
|
58
|
+
visit_scenario(scenario, Cucumber.language['scenario'])
|
59
|
+
end
|
60
|
+
|
61
|
+
def visit_scenario_outline(scenario)
|
62
|
+
visit_scenario(scenario, Cucumber.language['scenario_outline'])
|
65
63
|
end
|
66
64
|
|
67
65
|
def visit_row_scenario(scenario)
|
@@ -86,6 +84,7 @@ HTML
|
|
86
84
|
|
87
85
|
def visit_row_step(step)
|
88
86
|
_, args, _ = step.regexp_args_proc(@step_mother)
|
87
|
+
args = step.visible_args if step.outline?
|
89
88
|
args.each do |arg|
|
90
89
|
@io.puts %{ <td id="#{step.id}"><span>#{arg}</span></td>}
|
91
90
|
end
|
@@ -95,6 +94,11 @@ HTML
|
|
95
94
|
regexp, _, _ = step.regexp_args_proc(@step_mother)
|
96
95
|
@io.puts %{ <li class="new" id="#{step.id}">#{step.keyword} #{step.format(regexp, '<span>%s</span>')}</li>}
|
97
96
|
end
|
97
|
+
|
98
|
+
def visit_step_outline(step)
|
99
|
+
regexp, _, _ = step.regexp_args_proc(@step_mother)
|
100
|
+
@io.puts %{ <li class="new" id="#{step.id}">#{step.keyword} #{CGI.escapeHTML(step.format(nil))}</li>}
|
101
|
+
end
|
98
102
|
|
99
103
|
def step_passed(step, regexp, args)
|
100
104
|
print_javascript_tag("stepPassed(#{step.id})")
|
@@ -112,7 +116,11 @@ HTML
|
|
112
116
|
def step_skipped(step, regexp, args)
|
113
117
|
# noop
|
114
118
|
end
|
115
|
-
|
119
|
+
|
120
|
+
def step_traced(step, regexp, args)
|
121
|
+
# noop
|
122
|
+
end
|
123
|
+
|
116
124
|
def print_javascript_tag(js)
|
117
125
|
@io.puts %{ <script type="text/javascript">#{js}</script>}
|
118
126
|
end
|
@@ -123,6 +131,21 @@ HTML
|
|
123
131
|
</html>
|
124
132
|
HTML
|
125
133
|
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
def visit_scenario(scenario, scenario_or_scenario_outline_keyword)
|
138
|
+
@scenario_table_header = scenario.table_header
|
139
|
+
@io.puts %{ <dl class="new">}
|
140
|
+
@io.puts %{ <dt>#{scenario_or_scenario_outline_keyword}: #{scenario.name}</dt>}
|
141
|
+
@io.puts %{ <dd>}
|
142
|
+
@io.puts %{ <ul>}
|
143
|
+
scenario.accept(self)
|
144
|
+
@io.puts %{ </ul>}
|
145
|
+
@io.puts %{ </dd>}
|
146
|
+
@io.puts %{ </dl>}
|
147
|
+
end
|
148
|
+
|
126
149
|
end
|
127
150
|
end
|
128
151
|
end
|