Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display snippet for missing parameter types #1413

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Please visit [cucumber/CONTRIBUTING.md](https://github.com/cucumber/cucumber/blo

### Improved

* N/A
* Display snippet when using undefined parameter type [#1411](https://github.com/cucumber/cucumber-ruby/issues/1411)

## [4.0.0.rc.6](https://github.com/cucumber/cucumber-ruby/compare/v4.0.0.rc.5...4.0.0.rc.6)

Expand Down
28 changes: 28 additions & 0 deletions features/docs/defining_steps/snippets.feature
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,31 @@ Feature: Snippets
pending # Write code here that turns the phrase above into concrete actions
end
"""

Scenario: Snippet for step definition with undefined parameter type
Given a file named "features/undefined_parameter_type.feature" with:
"""
Feature:
Scenario: Delayed flight
Given leg LHR-OSL is cancelled
"""
And a file named "features/steps.rb" with:
"""
Given('leg {flight-leg} is cancelled') do |flight|
log flight.to_s
end
"""
When I run `cucumber features/undefined_parameter_type.feature -s`
Then the output should contain:
"""
The parameter flight-leg is not defined. You can define a new one with:

ParameterType(
name: 'flight-leg',
regexp: /some regexp here/,
type: FlightLeg,
# The transformer takes as many arguments as there are capture groups in the regexp,
# or just one if there are none.
transformer: ->(s) { FlightLeg.new(s) }
)
"""
3 changes: 2 additions & 1 deletion lib/cucumber/events.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ def self.registry
TestStepCreated,
TestStepFinished,
TestStepStarted,
Envelope
Envelope,
UndefinedParameterType
)
end
end
Expand Down
10 changes: 10 additions & 0 deletions lib/cucumber/events/undefined_parameter_type.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
require 'cucumber/core/events'

module Cucumber
module Events
class UndefinedParameterType < Core::Event.new(:type_name, :expression)
attr_reader :type_name
attr_reader :expression
end
end
end
32 changes: 30 additions & 2 deletions lib/cucumber/formatter/console.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# frozen_string_literal: true

# rubocop:disable Metrics/ModuleLength

require 'cucumber/formatter/ansicolor'
require 'cucumber/formatter/duration'
require 'cucumber/gherkin/i18n'
Expand Down Expand Up @@ -116,14 +118,21 @@ def collect_snippet_data(test_step, ast_lookup)
@snippets_input << Console::SnippetData.new(keyword, test_step)
end

def collect_undefined_parameter_type_names(undefined_parameter_type)
@undefined_parameter_types << undefined_parameter_type.type_name
end

def print_snippets(options)
return unless options[:snippets]
return if @snippets_input.empty?

snippet_text_proc = lambda do |step_keyword, step_name, multiline_arg|
snippet_text(step_keyword, step_name, multiline_arg)
end
do_print_snippets(snippet_text_proc)
do_print_snippets(snippet_text_proc) unless @snippets_input.empty?

@undefined_parameter_types.map do |type_name|
do_print_undefined_parameter_type_snippet(type_name)
end
end

def do_print_snippets(snippet_text_proc)
Expand Down Expand Up @@ -181,6 +190,24 @@ def do_print_profile_information(profiles)
@io.puts "Using the #{profiles_sentence} profile#{'s' if profiles.size > 1}..."
end

def do_print_undefined_parameter_type_snippet(type_name)
camelized = type_name.split(/_|-/).collect(&:capitalize).join

@io.puts [
"The parameter #{type_name} is not defined. You can define a new one with:",
'',
'ParameterType(',
" name: '#{type_name}',",
' regexp: /some regexp here/,',
" type: #{camelized},",
' # The transformer takes as many arguments as there are capture groups in the regexp,',
' # or just one if there are none.',
" transformer: ->(s) { #{camelized}.new(s) }",
')',
''
].join("\n")
end

private

FORMATS = Hash.new { |hash, format| hash[format] = method(format).to_proc }
Expand Down Expand Up @@ -219,3 +246,4 @@ def initialize(actual_keyword, step)
end
end
end
# rubocop:enable Metrics/ModuleLength
12 changes: 12 additions & 0 deletions lib/cucumber/formatter/message_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def initialize(config)
config.on_event :test_step_finished, &method(:on_test_step_finished)
config.on_event :test_case_finished, &method(:on_test_case_finished)
config.on_event :test_run_finished, &method(:on_test_run_finished)
config.on_event :undefined_parameter_type, &method(:on_undefined_parameter_type)

@test_case_by_step_id = {}
@current_test_case_started_id = nil
Expand Down Expand Up @@ -235,6 +236,17 @@ def on_test_run_finished(*)
output_envelope(message)
end

def on_undefined_parameter_type(event)
message = Cucumber::Messages::Envelope.new(
undefined_parameter_type: Cucumber::Messages::UndefinedParameterType.new(
name: event.type_name,
expression: event.expression
)
)

output_envelope(message)
end

def test_case_started_id(test_case)
@test_case_started_by_test_case.test_case_started_id_by_test_case(test_case)
end
Expand Down
7 changes: 7 additions & 0 deletions lib/cucumber/formatter/pretty.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def initialize(config)
@config = config
@options = config.to_hash
@snippets_input = []
@undefined_parameter_types = []
@total_duration = 0
@exceptions = []
@gherkin_sources = {}
Expand All @@ -54,13 +55,19 @@ def initialize(config)
@passed_test_cases = []
@source_indent = 0
@next_comment_to_be_printed = 0

bind_events(config)
end

def bind_events(config)
config.on_event :gherkin_source_read, &method(:on_gherkin_source_read)
config.on_event :step_activated, &method(:on_step_activated)
config.on_event :test_case_started, &method(:on_test_case_started)
config.on_event :test_step_started, &method(:on_test_step_started)
config.on_event :test_step_finished, &method(:on_test_step_finished)
config.on_event :test_case_finished, &method(:on_test_case_finished)
config.on_event :test_run_finished, &method(:on_test_run_finished)
config.on_event :undefined_parameter_type, &method(:collect_undefined_parameter_type_names)
end

def on_gherkin_source_read(event)
Expand Down
2 changes: 2 additions & 0 deletions lib/cucumber/formatter/progress.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def initialize(config)
@config = config
@io = ensure_io(config.out_stream)
@snippets_input = []
@undefined_parameter_types = []
@total_duration = 0
@matches = {}
@pending_step_matches = []
Expand All @@ -36,6 +37,7 @@ def initialize(config)
config.on_event :test_step_finished, &method(:on_test_step_finished)
config.on_event :test_case_finished, &method(:on_test_case_finished)
config.on_event :test_run_finished, &method(:on_test_run_finished)
config.on_event :undefined_parameter_type, &method(:collect_undefined_parameter_type_names)
end

def on_step_activated(event)
Expand Down
7 changes: 1 addition & 6 deletions lib/cucumber/glue/registry_and_more.rb
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,7 @@ def register_rb_step_definition(string_or_regexp, proc_or_sym, options)
# TODO: add a way to extract the parameter type directly from the error.
type_name = e.message.match(/^Undefined parameter type \{(.*)\}$/)[1]

@configuration.notify :envelope, Cucumber::Messages::Envelope.new(
undefined_parameter_type: Cucumber::Messages::UndefinedParameterType.new(
name: type_name,
expression: string_or_regexp
)
)
@configuration.notify :undefined_parameter_type, type_name, string_or_regexp
end

def build_rb_world_factory(world_modules, namespaced_world_modules, proc)
Expand Down