gurke 2.4.2 → 3.0.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.
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