# frozen_string_literal: true require 'cucumber/constantize' require 'cucumber/runtime/for_programming_languages' require 'cucumber/runtime/step_hooks' require 'cucumber/runtime/before_hooks' require 'cucumber/runtime/after_hooks' require 'cucumber/gherkin/steps_parser' require 'cucumber/step_match_search' module Cucumber class Runtime class SupportCode require 'forwardable' class StepInvoker def initialize(support_code) @support_code = support_code end def steps(steps) steps.each { |step| step(step) } end def step(step) location = Core::Ast::Location.of_caller @support_code.invoke_dynamic_step(step[:text], multiline_arg(step, location)) end def multiline_arg(step, location) argument = step[:argument] if argument if argument[:type] == :DocString MultilineArgument.from(argument[:content], location, argument[:content_type]) else MultilineArgument::DataTable.from(argument[:rows].map { |row| row[:cells].map { |cell| cell[:value] } }) end else MultilineArgument.from(nil) end end end include Constantize attr_reader :registry def initialize(user_interface, configuration=Configuration.default) @configuration = configuration # TODO: needs a better name, or inlining its methods @runtime_facade = Runtime::ForProgrammingLanguages.new(self, user_interface) @registry = Cucumber::Glue::RegistryAndMore.new(@runtime_facade, @configuration) end def configure(new_configuration) @configuration = Configuration.new(new_configuration) end # Invokes a series of steps +steps_text+. Example: # # invoke(%Q{ # Given I have 8 cukes in my belly # Then I should not be thirsty # }) def invoke_dynamic_steps(steps_text, i18n, _location) parser = Cucumber::Gherkin::StepsParser.new(StepInvoker.new(self), i18n.iso_code) parser.parse(steps_text) end # @api private # This allows users to attempt to find, match and execute steps # from code as the features are running, as opposed to regular # steps which are compiled into test steps before execution. # # These are commonly called nested steps. def invoke_dynamic_step(step_name, multiline_argument, _location=nil) matches = step_matches(step_name) raise UndefinedDynamicStep, step_name if matches.empty? matches.first.invoke(multiline_argument) end def load_files!(files) log.debug("Code:\n") files.each do |file| load_file(file) end log.debug("\n") end def load_files_from_paths(paths) files = paths.map { |path| Dir["#{path}/**/*.rb"] }.flatten load_files! files end def unmatched_step_definitions registry.unmatched_step_definitions end def fire_hook(name, *args) # TODO: kill with fire registry.send(name, *args) end def step_definitions registry.step_definitions end def find_after_step_hooks(test_case) scenario = RunningTestCase.new(test_case) hooks = registry.hooks_for(:after_step, scenario) StepHooks.new hooks end def apply_before_hooks(test_case) scenario = RunningTestCase.new(test_case) hooks = registry.hooks_for(:before, scenario) BeforeHooks.new(hooks, scenario).apply_to(test_case) end def apply_after_hooks(test_case) scenario = RunningTestCase.new(test_case) hooks = registry.hooks_for(:after, scenario) AfterHooks.new(hooks, scenario).apply_to(test_case) end def find_around_hooks(test_case) scenario = RunningTestCase.new(test_case) registry.hooks_for(:around, scenario).map do |hook| Hooks.around_hook(test_case.source) do |run_scenario| hook.invoke('Around', scenario, &run_scenario) end end end private def step_matches(step_name) StepMatchSearch.new(registry.method(:step_matches), @configuration).call(step_name) end def load_file(file) log.debug(" * #{file}\n") registry.load_code_file(file) end def log Cucumber.logger end end end end