gurke 2.4.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +4 -0
  3. data/bin/gurke +2 -0
  4. data/features/gurke.feature +2 -5
  5. data/features/gurke.rb +2 -1
  6. data/features/gurke/backtrace_filtering.feature +3 -4
  7. data/features/gurke/context_in_hooks.feature +1 -2
  8. data/features/gurke/filter_by_tags.feature +5 -6
  9. data/features/gurke/include_by_tags.feature +1 -2
  10. data/features/gurke/other_reporter.feature +3 -4
  11. data/features/gurke/pending_steps.feature +1 -4
  12. data/features/gurke/run_specific_directories.feature +4 -5
  13. data/features/gurke/run_specific_scenarios.feature +5 -6
  14. data/features/gurke/step_specific_definitions.feature +1 -4
  15. data/features/support/steps/cli_steps.rb +17 -8
  16. data/features/support/steps/file_steps.rb +2 -9
  17. data/gurke.gemspec +10 -9
  18. data/lib/gurke.rb +3 -0
  19. data/lib/gurke/background.rb +2 -0
  20. data/lib/gurke/builder.rb +10 -11
  21. data/lib/gurke/capybara.rb +2 -0
  22. data/lib/gurke/cli.rb +35 -27
  23. data/lib/gurke/configuration.rb +9 -6
  24. data/lib/gurke/dsl.rb +9 -5
  25. data/lib/gurke/feature.rb +6 -8
  26. data/lib/gurke/feature_list.rb +11 -7
  27. data/lib/gurke/reporter.rb +41 -34
  28. data/lib/gurke/reporters/compact_reporter.rb +137 -0
  29. data/lib/gurke/reporters/default_reporter.rb +57 -16
  30. data/lib/gurke/reporters/null_reporter.rb +4 -2
  31. data/lib/gurke/reporters/team_city_reporter.rb +11 -13
  32. data/lib/gurke/rspec.rb +2 -0
  33. data/lib/gurke/run_list.rb +2 -0
  34. data/lib/gurke/runner.rb +12 -6
  35. data/lib/gurke/scenario.rb +41 -2
  36. data/lib/gurke/step.rb +24 -14
  37. data/lib/gurke/step_definition.rb +3 -1
  38. data/lib/gurke/steps.rb +3 -1
  39. data/lib/gurke/tag.rb +5 -1
  40. data/lib/gurke/version.rb +5 -3
  41. data/spec/gurke/feature_list_spec.rb +4 -2
  42. data/spec/gurke/reporters/default_reporter_spec.rb +201 -0
  43. data/spec/gurke/run_list_spec.rb +2 -0
  44. data/spec/gurke/scenario_spec.rb +5 -3
  45. data/spec/gurke/step_definition_spec.rb +3 -1
  46. data/spec/spec_helper.rb +10 -1
  47. metadata +8 -6
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'colorize'
4
+
5
+ # Colors
6
+ # :black, :red, :green, :yellow, :blue,
7
+ # :magenta, :cyan, :white, :default, :light_black,
8
+ # :light_red, :light_green, :light_yellow, :light_blue,
9
+ # :light_magenta, :light_cyan, :light_white
10
+ #
11
+ module Gurke::Reporters
12
+ #
13
+ class CompactReporter < NullReporter
14
+ attr_reader :io
15
+
16
+ def initialize(io = $stdout)
17
+ @io = io
18
+ end
19
+
20
+ def after_step(result, scenario, *)
21
+ return unless result.state == :failed
22
+
23
+ io.print red 'E'
24
+
25
+ feature = scenario.feature
26
+
27
+ io.puts
28
+ io.print yellow('Feature')
29
+ io.print ': '
30
+ io.print scenario.feature.name
31
+ io.print ' '
32
+ io.print format_location(scenario.feature)
33
+ io.puts
34
+
35
+ io.print ' '
36
+ io.print yellow('Scenario')
37
+ io.print ': '
38
+ io.print scenario.name
39
+ io.print ' '
40
+ io.print format_location(scenario)
41
+ io.puts
42
+
43
+ background = feature.backgrounds.map(&:steps).flatten
44
+
45
+ catch(:break) do
46
+ if background.any?
47
+ io.print ' '
48
+ io.print light_black('Background')
49
+ io.print ':'
50
+ io.puts
51
+
52
+ background.each do |step|
53
+ io.print ' '
54
+ io.print yellow(step.keyword)
55
+ io.print ' '
56
+ io.print step.name.gsub(/"(.*?)"/, cyan('\0'))
57
+ io.puts
58
+
59
+ throw :break if step == result.step
60
+ end
61
+ end
62
+
63
+ scenario.steps.each do |step|
64
+ io.print ' '
65
+ io.print yellow(step.keyword)
66
+ io.print ' '
67
+ io.print step.name.gsub(/"(.*?)"/, cyan('\0'))
68
+ io.puts
69
+
70
+ throw :break if step == result.step
71
+ end
72
+ end
73
+
74
+ exout = format_exception(result.exception, backtrace: true)
75
+ io.puts red exout.join("\n").gsub(/^/, ' ')
76
+ io.puts
77
+ end
78
+
79
+ def after_scenario(scenario)
80
+ if scenario.failed?
81
+ # printed in after_step
82
+ elsif scenario.pending?
83
+ io.print yellow '?'
84
+ elsif scenario.passed?
85
+ io.print green '.'
86
+ elsif scenario.aborted?
87
+ io.puts
88
+ end
89
+ end
90
+
91
+ def after_features(features)
92
+ io.puts
93
+ io.puts
94
+
95
+ scenarios = features.map(&:scenarios).flatten
96
+
97
+ size = scenarios.size
98
+ passed = scenarios.select(&:passed?).size
99
+ failed = scenarios.select(&:failed?).size
100
+ pending = scenarios.select(&:pending?).size
101
+ not_run = size - scenarios.select(&:run?).size
102
+
103
+ message = "#{scenarios.size} scenarios: "
104
+ message += "#{passed} passed, "
105
+ message += "#{failed} failing, #{pending} pending"
106
+ message += ", #{not_run} not run" if not_run.positive?
107
+
108
+ if failed.positive?
109
+ io.puts red message
110
+ elsif pending.positive? || not_run.positive?
111
+ io.puts yellow message
112
+ else
113
+ io.puts green message
114
+ end
115
+ end
116
+
117
+ private
118
+
119
+ def format_location(obj)
120
+ file = obj.file.to_s
121
+ line = obj.line.to_s
122
+ cwd = Pathname.new(Dir.getwd)
123
+ path = Pathname.new(file).relative_path_from(cwd).to_s
124
+ path = file if path.length > file.length
125
+
126
+ light_black("# #{path}:#{line}")
127
+ end
128
+
129
+ %i[black red green yellow blue
130
+ magenta cyan white default light_black
131
+ light_red light_green light_yellow light_blue
132
+ light_magenta light_cyan light_white].each do |color|
133
+
134
+ define_method(color) {|str| io.tty? ? str.send(color) : str }
135
+ end
136
+ end
137
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'colorize'
2
4
 
3
5
  # Colors
@@ -15,24 +17,36 @@ module Gurke::Reporters
15
17
  #
16
18
  class DefaultReporter < NullReporter
17
19
  attr_reader :io
20
+
18
21
  def initialize(io = $stdout)
19
22
  @io = io
20
23
  end
21
24
 
22
25
  def before_feature(feature)
23
- io.puts "#{yellow('Feature')}: #{feature.name}"
24
- io.puts ' ' + light_black(feature.description.split("\n").join("\n "))
26
+ io.print yellow('Feature')
27
+ io.print ': '
28
+ io.print feature.name
29
+ io.print ' '
30
+ io.print format_location(feature)
31
+ io.puts
32
+
33
+ io.print light_black(feature.description.gsub(/^/, ' '))
34
+ io.puts
25
35
  io.puts
26
36
  end
27
37
 
28
38
  def before_scenario(scenario)
29
- io.puts " #{yellow('Scenario')}: #{scenario.name}"
39
+ io.print ' '
40
+ io.print yellow('Scenario')
41
+ io.print ': '
42
+ io.print scenario.name
43
+ io.print ' '
44
+ io.print format_location(scenario)
45
+ io.puts
30
46
  end
31
47
 
32
48
  def start_background(*)
33
- unless @background
34
- io.puts light_black(' Background:')
35
- end
49
+ io.puts light_black(' Background:') unless @background
36
50
 
37
51
  @background = true
38
52
  end
@@ -45,6 +59,7 @@ module Gurke::Reporters
45
59
  io.print ' ' if @background
46
60
  io.print ' '
47
61
  io.print yellow(step.keyword)
62
+ io.print ' '
48
63
  io.print step.name.gsub(/"(.*?)"/, cyan('\0'))
49
64
  end
50
65
 
@@ -52,7 +67,7 @@ module Gurke::Reporters
52
67
  case step.state
53
68
  when :pending then print_braces yellow 'pending'
54
69
  when :failed then print_failed step
55
- when :success then print_braces green 'success'
70
+ when :passed then print_braces green 'passed'
56
71
  else print_braces cyan 'skipped'
57
72
  end
58
73
  io.puts
@@ -70,14 +85,40 @@ module Gurke::Reporters
70
85
  def after_features(features)
71
86
  scenarios = features.map(&:scenarios).flatten
72
87
 
73
- io.puts " #{scenarios.size} scenarios: " \
74
- "#{scenarios.select(&:failed?).size} failing, " \
75
- "#{scenarios.select(&:pending?).size} pending"
88
+ size = scenarios.size
89
+ passed = scenarios.select(&:passed?).size
90
+ failed = scenarios.select(&:failed?).size
91
+ pending = scenarios.select(&:pending?).size
92
+ not_run = size - scenarios.select(&:run?).size
93
+
94
+ message = "#{scenarios.size} scenarios: "
95
+ message += "#{passed} passed, " unless passed == size || passed.zero?
96
+ message += "#{failed} failing, #{pending} pending"
97
+ message += ", #{not_run} not run" if not_run.positive?
98
+
99
+ if failed.positive?
100
+ io.puts red message
101
+ elsif pending.positive? || not_run.positive?
102
+ io.puts yellow message
103
+ else
104
+ io.puts green message
105
+ end
106
+
76
107
  io.puts
77
108
  end
78
109
 
79
110
  private
80
111
 
112
+ def format_location(obj)
113
+ file = obj.file.to_s
114
+ line = obj.line.to_s
115
+ cwd = Pathname.new(Dir.getwd)
116
+ path = Pathname.new(file).relative_path_from(cwd).to_s
117
+ path = file if path.length > file.length
118
+
119
+ light_black("# #{path}:#{line}")
120
+ end
121
+
81
122
  def print_braces(str)
82
123
  io.print " (#{str})"
83
124
  end
@@ -87,15 +128,15 @@ module Gurke::Reporters
87
128
  io.puts
88
129
 
89
130
  exout = format_exception(step.exception)
90
- io.puts exout.map{|s| red(" #{s}\n") }.join
131
+ io.puts exout.map {|s| red(" #{s}\n") }.join
91
132
  end
92
133
 
93
- [:black, :red, :green, :yellow, :blue,
94
- :magenta, :cyan, :white, :default, :light_black,
95
- :light_red, :light_green, :light_yellow, :light_blue,
96
- :light_magenta, :light_cyan, :light_white].each do |color|
134
+ %i[black red green yellow blue
135
+ magenta cyan white default light_black
136
+ light_red light_green light_yellow light_blue
137
+ light_magenta light_cyan light_white].each do |color|
97
138
 
98
- define_method(color){|str| io.tty? ? str.send(color) : str }
139
+ define_method(color) {|str| io.tty? ? str.send(color) : str }
99
140
  end
100
141
  end
101
142
  end
@@ -1,12 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gurke::Reporters
2
4
  #
3
5
  # The {NullReporter} does not do anything.
4
6
  #
5
7
  class NullReporter < Gurke::Reporter
6
8
  Gurke::Reporter::CALLBACKS.each do |cb|
7
- class_eval <<-EOF, __FILE__, __LINE__
9
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
8
10
  def #{cb}(*) end
9
- EOF
11
+ RUBY
10
12
  end
11
13
  end
12
14
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gurke::Reporters
2
4
  #
3
5
  # The {TeamCityReporter} prints features, scenarios and
@@ -21,9 +23,7 @@ module Gurke::Reporters
21
23
  end
22
24
 
23
25
  def start_background(*)
24
- unless @background
25
- io.puts ' Background:'
26
- end
26
+ io.puts ' Background:' unless @background
27
27
 
28
28
  @background = true
29
29
  end
@@ -77,30 +77,28 @@ module Gurke::Reporters
77
77
  io.print " (#{str})"
78
78
  end
79
79
 
80
- def print_pending(step)
80
+ def print_pending(_step)
81
81
  return if @pending == @scenario # only once per scenario
82
82
  publish :testIgnored,
83
- name: @scenario.name,
84
- message: 'Step definition missing'
83
+ name: @scenario.name,
84
+ message: 'Step definition missing'
85
85
  @pending = @scenario
86
86
  end
87
87
 
88
88
  def print_failed(step)
89
89
  publish :testFailed,
90
- name: @scenario.name,
91
- message: step.exception.inspect,
92
- backtrace: step.exception.backtrace.join('\n')
90
+ name: @scenario.name,
91
+ message: step.exception.inspect,
92
+ backtrace: step.exception.backtrace.join('\n')
93
93
  @pending = @scenario
94
94
 
95
95
  print_braces 'failure'
96
96
  io.puts
97
97
 
98
98
  exout = format_exception(step.exception)
99
- io.puts exout.map{|s| " #{s}\n" }.join
99
+ io.puts exout.map {|s| " #{s}\n" }.join
100
100
  end
101
101
 
102
-
103
- private
104
102
  def publish(message_name, args)
105
103
  args = [] << message_name.to_s << escaped_array_of(args)
106
104
  args = args.flatten.reject(&:nil?)
@@ -116,7 +114,7 @@ module Gurke::Reporters
116
114
  return [] if args.nil?
117
115
 
118
116
  if args.is_a? Hash
119
- args.map { |key, value| "#{key.to_s}='#{escape value.to_s}'" }
117
+ args.map {|key, value| "#{key}='#{escape value.to_s}'" }
120
118
  else
121
119
  "'#{escape args}'"
122
120
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rspec/expectations'
2
4
 
3
5
  Gurke.configure do |c|
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gurke
2
4
  #
3
5
  # A {RunList} is a list of {Background}, {Scenario}
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gurke
2
4
  class Runner
3
5
  attr_reader :config, :options
@@ -9,7 +11,11 @@ module Gurke
9
11
 
10
12
  def reporter
11
13
  @reporter ||= begin
12
- r = (options[:formatter] + '_reporter').split('_').map(&:capitalize).join
14
+ r = (options[:formatter] + '_reporter')
15
+ .split('_')
16
+ .map(&:capitalize)
17
+ .join
18
+
13
19
  Reporters.const_get(r).new
14
20
  end
15
21
  end
@@ -21,10 +27,10 @@ module Gurke
21
27
  def run(files, reporter = self.reporter)
22
28
  files.map! do |file|
23
29
  split = file.split(':')
24
- [split[0], split[1..-1].map{|i| Integer(i) }]
30
+ [split[0], split[1..-1].map {|i| Integer(i) }]
25
31
  end
26
32
 
27
- features = builder.load files.map{|file, _| file }
33
+ features = builder.load(files.map {|file, _| file })
28
34
  features.filter(options, files).run self, reporter
29
35
  end
30
36
 
@@ -34,10 +40,10 @@ module Gurke
34
40
 
35
41
  def with_filtered_backtrace
36
42
  yield
37
- rescue => e
43
+ rescue StandardError => e
38
44
  unless options[:backtrace]
39
45
  base = File.expand_path(Gurke.root.dirname)
40
- e.backtrace.select!{|l| File.expand_path(l)[0...base.size] == base }
46
+ e.backtrace.select! {|l| File.expand_path(l)[0...base.size] == base }
41
47
  end
42
48
  raise
43
49
  end
@@ -53,7 +59,7 @@ module Gurke
53
59
  class DRbServer < Runner
54
60
  URI = 'druby://localhost:8789'
55
61
 
56
- def run(files)
62
+ def run(_files)
57
63
  require 'drb'
58
64
 
59
65
  hook :system, nil, nil do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gurke
2
4
  class Scenario
3
5
  #
@@ -42,6 +44,7 @@ module Gurke
42
44
  @line = line
43
45
  @tags = tags
44
46
  @raw = raw
47
+ @state = nil
45
48
  end
46
49
 
47
50
  # Return name of the scenario.
@@ -86,6 +89,28 @@ module Gurke
86
89
  @state == :failed
87
90
  end
88
91
 
92
+ # Check if scenario has passed.
93
+ #
94
+ # @return [Boolean] True if scenario passed, false otherwise.
95
+ #
96
+ def passed?
97
+ @state == :passed
98
+ end
99
+
100
+ # Check if scenario was aborted.
101
+ #
102
+ # @return [Boolean] True if aborted, false otherwise.
103
+ #
104
+ def aborted?
105
+ @state == :aborted
106
+ end
107
+
108
+ # Check if scenario was run and the state has changed.
109
+ #
110
+ def run?
111
+ !@state.nil?
112
+ end
113
+
89
114
  # Exception that led to either pending or failed state.
90
115
  #
91
116
  # @return [Exception] Exception or nil of none given.
@@ -107,12 +132,24 @@ module Gurke
107
132
  # @param error [Exception] Given an exception as reason.
108
133
  #
109
134
  def pending!(error)
110
- return if failed?
111
-
112
135
  @exception = error
113
136
  @state = :pending
114
137
  end
115
138
 
139
+ # @api private
140
+ #
141
+ def passed!
142
+ @exception = nil
143
+ @state = :passed
144
+ end
145
+
146
+ # @api private
147
+ #
148
+ def abort!
149
+ @exception = nil
150
+ @state = :aborted
151
+ end
152
+
116
153
  # @api private
117
154
  #
118
155
  def run(runner, reporter)
@@ -132,6 +169,8 @@ module Gurke
132
169
 
133
170
  feature.backgrounds.run runner, reporter, self, world
134
171
  steps.run runner, reporter, self, world
172
+
173
+ passed! unless @state
135
174
  ensure
136
175
  reporter.invoke :end_scenario, self
137
176
  end